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>
This commit is contained in:
Adrian Perez
2026-04-18 18:47:36 +02:00
co-authored by Claude Opus 4.7
parent bdb47a6e5d
commit 42bd05db9c
11 changed files with 1463 additions and 0 deletions
@@ -0,0 +1,49 @@
# 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:104135` |
| Every UI state mutation | `pascal-editor-ui-preferences` | Zustand persist in `use-editor.tsx:372607` |
| Every viewer state mutation | `viewer-preferences` | Zustand persist in `use-viewer.ts:81220` |
| Every audio state mutation | `pascal-audio-settings` | `use-audio.tsx:2243` |
| On `beforeunload` | Final scene snapshot | `use-auto-save.ts:137147` |
## Read pathways
1. **Editor mount** (`editor/index.tsx:765796`):
- If host supplied `onLoad``await onLoad()`
- Else → `loadSceneFromLocalStorage()`
- Apply via `useScene.setScene(nodes, rootNodeIds)`
2. **Selection hydration**`syncEditorSelectionFromCurrentScene()` (`lib/scene.ts:251332`)
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.