# Canvas-Website to FolkJS Migration Plan

## Overview

This document outlines the transition from canvas-website (React + tldraw) to rspace-online (FolkJS web components). The goal is to simplify the architecture while preserving core functionality.

## Architecture Comparison

| Aspect | canvas-website (tldraw) | rspace-online (FolkJS) |
|--------|------------------------|------------------------|
| **Framework** | React 18 + tldraw v3 | Web Components (Lit-style) |
| **State** | tldraw store + Jotai atoms | Reactive properties + Automerge |
| **Sync** | Cloudflare Durable Objects | WebSocket + Automerge CRDT |
| **Shapes** | BaseBoxShapeUtil classes | FolkShape subclasses |
| **Styling** | CSS-in-JS / CSS modules | CSS in template literals |
| **Hooks** | React hooks (9 shared) | Class methods + utilities |

## Key Simplifications

### 1. No React
- **Before**: JSX, useState, useEffect, useCallback, useMemo
- **After**: Template literals, reactive properties, event listeners

### 2. No tldraw Abstraction Layer
- **Before**: BaseBoxShapeUtil, editor.updateShape(), shape migrations
- **After**: FolkShape base class, direct property updates, Automerge patches

### 3. Simpler State Management
- **Before**: tldraw store → Automerge → tldraw store (bidirectional sync)
- **After**: FolkShape → Automerge → FolkShape (direct sync via CommunitySync)

### 4. Web-Native APIs
- **Before**: React context providers for auth, notifications, file system
- **After**: Custom events, localStorage, native browser APIs

## Shape Porting Pattern

### tldraw Shape (Before)
```tsx
export class MyShapeUtil extends BaseBoxShapeUtil<MyShape> {
  static type = 'my-shape'

  getDefaultProps(): MyShape['props'] {
    return { w: 300, h: 200, content: '' }
  }

  component(shape: MyShape) {
    const { content } = shape.props
    const handleChange = useCallback((e) => {
      this.editor.updateShape({ id: shape.id, props: { content: e.target.value } })
    }, [shape.id])

    return (
      <StandardizedToolWrapper shape={shape}>
        <textarea value={content} onChange={handleChange} />
      </StandardizedToolWrapper>
    )
  }
}
```

### FolkJS Shape (After)
```typescript
export class FolkMyShape extends FolkShape {
  static tagName = 'folk-my-shape'

  #content = ''
  get content() { return this.#content }
  set content(value: string) {
    this.#content = value
    this.requestUpdate('content')
    this.dispatchEvent(new CustomEvent('content-change', { detail: { content: value } }))
  }

  override createRenderRoot() {
    const root = super.createRenderRoot()
    // Add UI to shadow DOM
    const wrapper = document.createElement('div')
    wrapper.innerHTML = `
      <div class="header" data-drag>
        <span>My Shape</span>
        <button class="close-btn">×</button>
      </div>
      <div class="content">
        <textarea></textarea>
      </div>
    `
    // Event listeners...
    return root
  }
}
```

## Migration Phases

### Phase 1: Foundation (4 shapes)
**Status**: To Do
- folk-slide (passive display)
- folk-chat (real-time chat)
- folk-google-item (data display)
- folk-piano (interactive music)

### Phase 2: Core Data (4 shapes)
**Status**: To Do
- folk-embed (URL embeds)
- folk-markdown (already done!)
- folk-calendar (date picker + events)
- folk-map (Mapbox/MapLibre collaborative maps)

### Phase 3: AI Integration (4 shapes)
**Status**: To Do
- folk-image-gen (fal.ai Flux)
- folk-video-gen (WAN 2.1)
- folk-prompt (LLM execution)
- folk-transcription (Whisper)

### Phase 4: Advanced (5+ shapes)
**Status**: To Do
- folk-video-chat (Daily.co)
- folk-obs-note (Obsidian sync)
- folk-holon (H3 geo-indexing)
- folk-workflow-block (visual workflows)
- folk-zine-generator (AI zine creation)

## Shared Utilities to Port

| React Hook | FolkJS Equivalent | Status |
|------------|-------------------|--------|
| useMaximize | maximizeShape() utility | ✅ Done |
| usePinnedToView | PinnedViewManager class | ✅ Done |
| useCalendarEvents | CalendarService class | To Do |
| useWhisperTranscription | WhisperService class | To Do |
| useLiveImage | LiveImageService class | To Do |

## Already Completed

- [x] FolkShape base class with drag/resize/rotate
- [x] FolkMarkdown (markdown editing)
- [x] FolkWrapper (standardized header/actions)
- [x] FolkArrow (shape connections)
- [x] CommunitySync (Automerge integration)
- [x] Server with WebSocket sync
- [x] Subdomain routing for communities

## External Dependencies

### Keep (MCP or direct API)
- fal.ai (image/video gen) - via MCP
- Gemini (text gen) - via MCP
- MapLibre GL (maps)
- Daily.co (video chat)
- Whisper API (transcription)

### Replace/Simplify
- MDXEditor → simpler markdown renderer (already done)
- tldraw → FolkJS (in progress)
- React contexts → custom events + services

### Remove (tldraw-specific)
- BaseBoxShapeUtil
- Shape migrations
- tldraw editor commands
- tldraw store subscriptions

## Success Criteria

1. All 28 shapes ported to FolkJS web components
2. Real-time collaboration working via Automerge
3. Mobile touch support
4. Presence cursors showing other users
5. No React dependencies in runtime
6. Bundle size < 500KB (vs ~2MB current)
