Files
dwg-dxf-viewer-sample/apps/viewer-3d/CLAUDE.md
T

6.0 KiB

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 — what work remains, who owns what, task breakdown.
  2. 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: use Vite hashed assets generated from the installed Three.js loader imports. Stage only single-thread web-ifc.wasm under public/web-ifc. Pin decoder version to the Three.js version in use.
  • Local file: createObjectURL + revoke after load. For repeat/cached loads, FileReaderArrayBufferGLTFLoader.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/
  web-ifc/                 # single-thread IFC decoder WASM
  samples/                 # 배포 demo model
  previews/                # pre-rendered WebP/WebM placeholders
dist/assets/               # Vite hashed Draco/Basis decoder assets
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).