Adrian Perez 42bd05db9c docs(mcp): add 10-agent research on scene-save workflow
10 parallel research agents (R1-R10) investigated whether MCP can save
scenes as saveable entities that the user later opens in the editor —
rather than injecting via a dev-only window.__pascalScene hook.

Key findings:
- Editor is already backend-agnostic via onLoad/onSave callbacks (R2,R7)
- Current persistence is localStorage-only, single key (R1)
- Zero dynamic routes and no backend code yet — env declared (R4,R5)
- File import exists as "Load Build" but lacks Zod validation (R6)
- MCP-written scenes load cleanly into the editor today (R6, Casa del
  Sol test already proved this)
- Best path: filesystem-handoff this week, Supabase in weeks 2-4,
  Supabase Realtime for live mode in Q2. Skip Yjs for now. (R8)
- 4-5 weeks to private beta, 10-14 to GA (R9)
- 10 high-value ideas ranked; "photo -> scene" is the unblocker (R10)

SYNTHESIS.md pulls all 10 reports together with the recommended
implementation plan.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 18:47:36 +02:00

50 lines
2.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# R1 — Persistence layer
## TL;DR
- **Scene data:** single-key localStorage, `pascal-editor-scene`, shape `{ nodes, rootNodeIds }`. Written by the autosave hook with 1 s debounce; flushed on `beforeunload`.
- **UI preferences, viewer prefs, audio:** three separate Zustand-persist stores, each with its own localStorage key.
- **Asset binaries (textures):** IndexedDB via `idb-keyval`, keys `asset_data:<uuid>`.
- **Backend persistence:** NONE in this repo. No Supabase calls, no API routes for scenes, no database integration.
- **Scene identity / listing:** NONE. One scene per origin per browser.
## Write pathways
| When | What | Where |
|---|---|---|
| 1 s after any scene mutation | `{ nodes, rootNodeIds }` → `onSave` callback (if provided) else `localStorage['pascal-editor-scene']` | `packages/editor/src/hooks/use-auto-save.ts:104–135` |
| Every UI state mutation | `pascal-editor-ui-preferences` | Zustand persist in `use-editor.tsx:372–607` |
| Every viewer state mutation | `viewer-preferences` | Zustand persist in `use-viewer.ts:81–220` |
| Every audio state mutation | `pascal-audio-settings` | `use-audio.tsx:22–43` |
| On `beforeunload` | Final scene snapshot | `use-auto-save.ts:137–147` |
## Read pathways
1. **Editor mount** (`editor/index.tsx:765–796`):
- If host supplied `onLoad` → `await onLoad()`
- Else → `loadSceneFromLocalStorage()`
- Apply via `useScene.setScene(nodes, rootNodeIds)`
2. **Selection hydration** — `syncEditorSelectionFromCurrentScene()` (`lib/scene.ts:251–332`)
3. **Zustand persist** hydrates UI/viewer/audio stores automatically on first subscriber
## What's NOT persisted
- Undo/redo history (`useScene.temporal` — in-memory only)
- Active tool state (`movingNode`, `editingHole`, `curvingWall`)
- Camera position/rotation
- Collections (stored in nodes array but not in the persist partialize)
- Three.js mesh/material cache
## Multi-scene support
- Single global key `pascal-editor-scene`. No scene id, name, thumbnail, version.
- `projectId` prop scopes UI **selection** (building/level/zone) but NOT scene data.
- No listing, no metadata, no per-project isolation of the scene itself.
## Gap to "MCP writes → user opens saved scene"
Needs:
1. Scene entity layer: id, name, projectId, created_at, thumbnail_url.
2. Backend table (or filesystem for local dev).
3. MCP tools for scene lifecycle (`save_scene`, `list_scenes`, `load_scene`, `delete_scene`).
4. Editor route `/scene/[id]` that reads scene by id on mount.
5. Host-app `onLoad(() => fetchScene(sceneId))`.
Foundation is solid — `SceneGraph` type + `applySceneGraphToEditor` are production-ready; only the entity layer is missing.