Add migration plan and backlog tasks for canvas-website to FolkJS transition
This commit is contained in:
parent
0df7cd04af
commit
00db0d4f63
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
id: task-2
|
||||
title: 'Phase 1: FolkJS Foundation - Port Simple Shapes'
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2026-01-02 14:42'
|
||||
labels:
|
||||
- foundation
|
||||
- migration
|
||||
- shapes
|
||||
dependencies: []
|
||||
priority: high
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
Port the 4 simplest shapes from canvas-website to FolkJS web components:
|
||||
- SlideShapeUtil (passive display)
|
||||
- ChatBoxShapeUtil (real-time chat)
|
||||
- GoogleItemShapeUtil (data display)
|
||||
- SharedPianoShapeUtil (interactive music)
|
||||
|
||||
Key simplifications vs tldraw:
|
||||
- No BaseBoxShapeUtil inheritance, use FolkShape directly
|
||||
- No React - pure web components with lit-style templates
|
||||
- Hooks become class methods or standalone utilities
|
||||
- StandardizedToolWrapper already ported as FolkWrapper
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 folk-slide component created
|
||||
- [ ] #2 folk-chat component created
|
||||
- [ ] #3 folk-google-item component created
|
||||
- [ ] #4 folk-piano component created
|
||||
<!-- AC:END -->
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
id: task-3
|
||||
title: 'Phase 2: Core Data Shapes - Embed, Markdown, Calendar, Map'
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2026-01-02 14:42'
|
||||
labels:
|
||||
- migration
|
||||
- shapes
|
||||
- core
|
||||
dependencies: []
|
||||
priority: high
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
Port medium-complexity shapes that form the core data visualization layer:
|
||||
|
||||
1. **folk-embed** (565 LOC) - URL embeds (YouTube, Maps, Twitter)
|
||||
- URL transformation patterns
|
||||
- Interaction state management
|
||||
|
||||
2. **folk-calendar** (644 LOC) - Unified calendar widget
|
||||
- Browser/widget/year views
|
||||
- Event detection from CalendarPanel/YearViewPanel
|
||||
|
||||
3. **folk-map** (2,168 LOC - LARGEST) - Collaborative Mapbox/MapLibre
|
||||
- Real-time presence cursors
|
||||
- Drawing annotations (markers, lines, areas)
|
||||
- Search via Nominatim, routing via OSRM
|
||||
- GPS location sharing
|
||||
|
||||
Simplifications:
|
||||
- Replace React state with reactive properties
|
||||
- Replace context providers with event-based communication
|
||||
- Calendar/Map can be separate packages imported as needed
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 folk-embed component with URL detection
|
||||
- [ ] #2 folk-calendar with month/year views
|
||||
- [ ] #3 folk-map with MapLibre integration
|
||||
- [ ] #4 Real-time presence on map working
|
||||
<!-- AC:END -->
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
id: task-4
|
||||
title: 'Phase 3: AI Integration Shapes'
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2026-01-02 15:54'
|
||||
labels:
|
||||
- migration
|
||||
- shapes
|
||||
- ai
|
||||
dependencies: []
|
||||
priority: medium
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
Port AI-powered shapes using existing MCP servers and APIs:
|
||||
|
||||
1. **folk-image-gen** - Image generation (fal.ai Flux)
|
||||
- Prompt input, image history thread
|
||||
- Loading states, error handling
|
||||
- Uses: mcp__fal-ai__fal_generate_image
|
||||
|
||||
2. **folk-video-gen** - Video generation (WAN 2.1)
|
||||
- Image-to-video, text-to-video
|
||||
- Duration control, queue polling
|
||||
- Uses: mcp__fal-ai__fal_generate_video
|
||||
|
||||
3. **folk-prompt** - LLM prompt executor
|
||||
- Agent binding, multiple personalities
|
||||
- Output streaming
|
||||
- Uses: mcp__gemini__gemini_generate or direct Anthropic API
|
||||
|
||||
4. **folk-transcription** - Audio transcription (Whisper)
|
||||
- Real-time transcription, pause/resume
|
||||
- Speaker diarization
|
||||
- Uses: Web Speech API fallback + Whisper API
|
||||
|
||||
Simplifications:
|
||||
- Use MCP tools directly instead of custom API clients
|
||||
- Simplify loading states to CSS classes
|
||||
- Remove complex React hooks, use async/await patterns
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 folk-image-gen with fal.ai integration
|
||||
- [ ] #2 folk-video-gen with video generation
|
||||
- [ ] #3 folk-prompt with LLM streaming
|
||||
- [ ] #4 folk-transcription with Whisper
|
||||
<!-- AC:END -->
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
id: task-5
|
||||
title: 'Phase 4: Advanced Shapes - Video Chat, Notes, Workflows'
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2026-01-02 16:04'
|
||||
labels:
|
||||
- migration
|
||||
- shapes
|
||||
- advanced
|
||||
dependencies: []
|
||||
priority: medium
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
Port remaining complex shapes:
|
||||
|
||||
1. **folk-video-chat** - Video conferencing (Daily.co)
|
||||
- Meeting creation, recording, permissions
|
||||
- WebRTC integration
|
||||
|
||||
2. **folk-obs-note** - Rich markdown from Obsidian
|
||||
- MDX editing, vault sync
|
||||
- Change detection, save/sync
|
||||
|
||||
3. **folk-holon** - Holosphere node with H3 geo-indexing
|
||||
- Hierarchical geospatial indexing
|
||||
- Connection management
|
||||
|
||||
4. **folk-workflow-block** - Visual workflow automation
|
||||
- Typed input/output ports
|
||||
- Connection support via folk-arrow
|
||||
- Execution state visualization
|
||||
|
||||
5. **folk-zine-generator** - AI zine creation
|
||||
- 5-phase workflow
|
||||
- Page generation with feedback loop
|
||||
|
||||
Simplifications:
|
||||
- Use existing folk-arrow for connections
|
||||
- Workflows use event-based execution instead of complex state machines
|
||||
- Obsidian sync can be optional/pluggable
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 folk-video-chat with Daily.co
|
||||
- [ ] #2 folk-obs-note with markdown editing
|
||||
- [ ] #3 folk-workflow-block with typed ports
|
||||
- [ ] #4 Workflow execution via folk-arrow connections
|
||||
<!-- AC:END -->
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
id: task-6
|
||||
title: Mobile touch support for canvas
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2026-01-02 16:07'
|
||||
labels:
|
||||
- feature
|
||||
- mobile
|
||||
- ux
|
||||
dependencies: []
|
||||
priority: medium
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
Enable touch interactions on mobile devices:
|
||||
- Touch drag for moving shapes
|
||||
- Pinch-to-zoom for canvas
|
||||
- Two-finger pan for canvas navigation
|
||||
- Touch-friendly resize handles (larger hit areas)
|
||||
- Long-press for context menu
|
||||
|
||||
FolkShape already has touchmove handler, needs enhancement for multi-touch gestures.
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 Single touch drag works on shapes
|
||||
- [ ] #2 Pinch-to-zoom works on canvas
|
||||
- [ ] #3 Two-finger pan works
|
||||
- [ ] #4 Tested on iOS Safari and Android Chrome
|
||||
<!-- AC:END -->
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
id: task-7
|
||||
title: Real-time presence cursors
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2026-01-02 16:08'
|
||||
labels:
|
||||
- feature
|
||||
- collaboration
|
||||
- sync
|
||||
dependencies: []
|
||||
priority: medium
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
Show other users cursors and selections in real-time:
|
||||
- Broadcast cursor position via WebSocket presence messages
|
||||
- Display colored cursor with username label
|
||||
- Show selection highlight when user has shape selected
|
||||
- Fade out cursors after inactivity
|
||||
- Different cursor colors per user
|
||||
|
||||
WebSocket already handles presence messages (see server/index.ts line 221-235), needs client-side rendering.
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 Cursor position broadcasts on mousemove
|
||||
- [ ] #2 Other users cursors visible with name labels
|
||||
- [ ] #3 Selection state shared between users
|
||||
- [ ] #4 Cursors fade after 5s inactivity
|
||||
<!-- AC:END -->
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
id: task-8
|
||||
title: Port shared hooks as FolkJS utilities
|
||||
status: To Do
|
||||
assignee: []
|
||||
created_date: '2026-01-02 16:10'
|
||||
labels:
|
||||
- foundation
|
||||
- utilities
|
||||
- migration
|
||||
dependencies: []
|
||||
priority: high
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
Convert canvas-website React hooks to FolkJS-compatible utilities:
|
||||
|
||||
1. **useMaximize** → maximizeShape(shape) utility
|
||||
- Store original dimensions
|
||||
- Animate to viewport fill
|
||||
- Restore on toggle
|
||||
|
||||
2. **usePinnedToView** → PinnedViewManager class
|
||||
- Keep shape fixed as camera moves
|
||||
- Support multiple pin positions
|
||||
- Zero-lag with requestAnimationFrame
|
||||
|
||||
3. **Shape serialization** - toJSON/fromJSON pattern
|
||||
- Already implemented in folk-markdown
|
||||
- Standardize across all shapes
|
||||
|
||||
These utilities enable the StandardizedToolWrapper features (maximize, pin, close) across all FolkJS shapes.
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [ ] #1 maximizeShape utility working
|
||||
- [ ] #2 PinnedViewManager class working
|
||||
- [ ] #3 All shapes have consistent toJSON/fromJSON
|
||||
<!-- AC:END -->
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
# 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 | To Do |
|
||||
| usePinnedToView | PinnedViewManager class | To Do |
|
||||
| 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)
|
||||
Loading…
Reference in New Issue