git-subtree-dir: apps/viewer-3d git-subtree-mainline:5e10bb1be4git-subtree-split:a71790070d
104 lines
5.9 KiB
Markdown
104 lines
5.9 KiB
Markdown
# CLAUDE.md — hmwebviewer (Three.js 3D Viewer)
|
|
|
|
Hybrid SSR+CSR web 3D model viewer. Spec: `3d_viewer_architecture_spec.pdf`.
|
|
|
|
## ⚠️ First action on EVERY session / agent start
|
|
|
|
Read these two files before doing anything:
|
|
1. [`PLAN.md`](./PLAN.md) — what work remains, who owns what, task breakdown.
|
|
2. [`PROGRESS.md`](./PROGRESS.md) — what is done, current state, blockers, decisions log.
|
|
|
|
If either file is missing or empty, treat the project as not started and bootstrap from the spec.
|
|
|
|
## What we are building
|
|
|
|
A browser 3D model viewer with **two load paths**:
|
|
|
|
- **Path A — Server asset (SSR + CSR)**: server ships a pre-rendered 360° animated WebP/WebM placeholder + HTML/CSS skeleton. Three.js loads + decodes the real Draco/KTX2 model in the background. On ready, fade WebP → canvas (opacity 0.5s).
|
|
- **Path B — Local file (Drag & Drop, CSR only)**: user drops a `.glb`/`.gltf`. `URL.createObjectURL(file)` → `GLTFLoader.load` → decode → add to scene → `URL.revokeObjectURL`.
|
|
|
|
Target: perceived load < 3s, no frame drops, smooth GPU.
|
|
|
|
## Locked technical decisions
|
|
|
|
These are decided. Do not relitigate without explicit user approval.
|
|
|
|
- **Three.js** + `GLTFLoader` + `DRACOLoader` + `KTX2Loader` on ONE shared loader instance each (multiple DRACOLoader instances crash — three.js #22445).
|
|
- **Geometry**: Draco. **Textures**: KTX2 / Basis Universal. Both compatible on same loader.
|
|
- **Decoder hosting**: CDN by default; copy WASM to `public/draco` + `public/basis` if offline/CSP required. Pin decoder version to the three.js version in use.
|
|
- **Local file**: `createObjectURL` + revoke after load. For repeat/cached loads, `FileReader`→`ArrayBuffer`→`GLTFLoader.parse()`.
|
|
- **Build**: Vite. Draco worker spawns via BLOB URL — decoder files must be reachable at the configured path at runtime.
|
|
- **Asset pre-processing (offline)**: `gltf-transform` (Draco + KTX2) — preferred over `gltf-pipeline`. Meshopt is a viable Draco alternative.
|
|
- **Pre-render pipeline (offline)**: Blender headless CLI 360° turntable frames → assemble to animated WebP (alpha) / WebM VP9. OR Puppeteer + headless Three.js `page.screenshot({type:'webp'})` per rotation step.
|
|
- **Renderer**: WebGLRenderer (stable baseline). WebGPU renderer = future option, not now.
|
|
|
|
Full rationale in user memory: `~/.claude/projects/d--MYCLAUDE-PROJECT-hmwebviewer/memory/`.
|
|
|
|
## Architecture map (target)
|
|
|
|
```
|
|
src/
|
|
viewer/
|
|
ThreeDViewer.ts # core class: init, loadServerAsset, loadLocalFile, executeHydration, toggleUI
|
|
loaders.ts # singleton GLTFLoader + DRACOLoader + KTX2Loader setup
|
|
hydration.ts # WebP placeholder -> canvas fade coordination
|
|
dnd/
|
|
dropzone.ts # HTML5 drag&drop, file validation, createObjectURL/revoke
|
|
ui/
|
|
progress.ts # load progress bar
|
|
scenes/ # per-model scene configs
|
|
public/
|
|
draco/ # decoder WASM (if bundled)
|
|
basis/ # KTX2 decoder WASM (if bundled)
|
|
previews/ # pre-rendered WebP/WebM placeholders
|
|
tools/
|
|
preprocess.mjs # gltf-transform Draco+KTX2 pipeline
|
|
prerender/ # Blender/Puppeteer turntable -> WebP
|
|
```
|
|
|
|
## How to work here (rules)
|
|
|
|
- **Surgical changes.** Touch only what a task requires. Match existing style.
|
|
- **Simplicity first.** Minimum code that solves the task. No speculative features/config.
|
|
- **Verify before claiming done.** Run the relevant check (build / typecheck / load test) and quote real output.
|
|
- **Keep PLAN.md + PROGRESS.md current.** Update the task status when you start/finish a unit of work. Other agents depend on it.
|
|
- **Memory is durable; PLAN/PROGRESS are working state.** Stable decisions → memory (via the memory dir). Transient task state → PLAN/PROGRESS.
|
|
|
|
## Commands (see `.claude/commands/`)
|
|
|
|
- `/bootstrap` — scaffold project from spec (run once, when PLAN says not started).
|
|
- `/next-task` — read PLAN + PROGRESS, pick the next ready task, assign self.
|
|
- `/report` — append current status to PROGRESS.md.
|
|
- `/optimize-asset <file>` — run gltf-transform Draco+KTX2 on an asset.
|
|
- `/verify-viewer` — build + load smoke test.
|
|
|
|
## Agents (see `.claude/agents/`)
|
|
|
|
Specialized subagents for parallelizable work — `viewer-core`, `dnd-handler`, `asset-pipeline`, `hydration`, `reviewer`. Invoke via the Agent tool / Task delegation. Details in each agent file.
|
|
|
|
## Reinforced structure — agent ↔ skill ↔ command ↔ task map
|
|
|
|
| PLAN task(s) | Owning agent | Skill to load | Command |
|
|
|---|---|---|---|
|
|
| P0 | task-lead → setup | threejs-viewer | `/bootstrap` |
|
|
| P1-1..P1-4 | viewer-core | threejs-viewer | `/verify-viewer` |
|
|
| P2-1,P2-2 | dnd-handler | threejs-viewer | `/verify-viewer` |
|
|
| P3-1..P3-3 | hydration | threejs-viewer | `/verify-viewer` |
|
|
| P4-1..P4-3 | asset-pipeline | threejs-viewer | `/optimize-asset` |
|
|
| P5-* | reviewer | threejs-viewer | `/verify-viewer`, `/report` |
|
|
| (any) | task-lead | task-graph | `/next-task`, `/report` |
|
|
|
|
**Load the `threejs-viewer` skill** whenever touching runtime viewer/dnd/asset/hydration code — it holds the locked patterns (singleton loaders, Blob URL lifecycle, hydration gating). **Load `task-graph`** when picking up or dispatching work.
|
|
|
|
## Runbook — how a work session goes
|
|
|
|
1. SessionStart hook reminds you. Read `PLAN.md` + `PROGRESS.md`.
|
|
2. Run `/next-task` (or have `task-lead` agent do it) → get the next ready task + owning agent.
|
|
3. Dispatch the owning agent with task ID, scope, acceptance criteria. Dispatch independent agents in ONE message (parallel).
|
|
4. On completion: owning agent flips PLAN row → `done`, runs `/report` to append PROGRESS.md.
|
|
5. `reviewer` runs after functional waves; `/verify-viewer` gates release.
|
|
|
|
## Hooks
|
|
- `SessionStart` → `.claude/hooks/session-start.sh` prints the "read PLAN + PROGRESS" reminder.
|
|
- `progress-nudge.sh` exists under `.claude/hooks/` for PostToolUse nudge to update PROGRESS after runtime edits — add its `PostToolUse` entry to `settings.json` if desired (not auto-wired).
|