docs: reorganize docs into bgm and status folders
Group the bgm spec cluster under docs/bgm and move dev logs and plans under docs/status, add an overview index, and update cross-references in the docs, README, and source comments.
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
# Full Setup View — Plan
|
||||
|
||||
> **Scope:** A new page that renders every loadable object in a save into a
|
||||
> single shared 3D scene, sharing materials and geometry where possible. This
|
||||
> complements the existing per-object inspection on the mod page.
|
||||
|
||||
## Motivation
|
||||
|
||||
The mod page (`apps/web/src/pages/ModPage.tsx`) inspects one object at a time
|
||||
inside a shared `Scene`. A "full setup" view renders the whole save at once —
|
||||
every tile, token, card, and custom model laid out on a virtual table — so a
|
||||
user can see the entire scene at a glance.
|
||||
|
||||
## Current architecture (relevant pieces)
|
||||
|
||||
- Each viewer owns its own `<Scene>` wrapper (`components/viewers/Scene.tsx`),
|
||||
which provides the camera, lights, orbit controls, contact shadows, and
|
||||
post-processing. The mesh content lives inside each viewer:
|
||||
- `TileViewer` → `<TileMesh>` (extruded tile, textured top face)
|
||||
- `TokenViewer` → `<TokenMesh>` (alpha-traced extruded token)
|
||||
- `CardViewer` → `<CardMesh>` (rounded-rect card, sprite UVs)
|
||||
- `CustomModelViewer` → `<Model>` (GLTF/OBJ/FBX via `FlexibleModelLoader`)
|
||||
- `@tts/extract` provides `flattenObjects(mod)` / `traverseMod` to enumerate
|
||||
every object in a save.
|
||||
- `@tts/mesh` provides the shape + extrusion helpers used by the viewers.
|
||||
- Every object in a save carries a `Transform` (position/rotation/scale in TTS
|
||||
world units), which the proxy passes through in the raw BSON. The shared
|
||||
type now models it as `TTSObjectTransform`.
|
||||
|
||||
## Plan
|
||||
|
||||
### 1. Refactor viewers to expose their mesh content (no `Scene`)
|
||||
|
||||
Each viewer currently wraps its mesh in `<Scene>`. To compose everything into
|
||||
one scene, extract and export the inner mesh components, keeping the existing
|
||||
viewers as thin wrappers:
|
||||
|
||||
- `TileViewer` → export `TileObjectMesh` (accepts a `TTSObject`)
|
||||
- `TokenViewer` → export `TokenObjectMesh`
|
||||
- `CardViewer` → export `CardObjectMesh`
|
||||
- `CustomModelViewer` → export `CustomModelMesh` (the `<Model>` + fallback box)
|
||||
|
||||
Each viewer now renders `<Scene><XxxObjectMesh object={…} /></Scene>`, so the
|
||||
object-facing wrapper is the single source of truth for both the per-object
|
||||
view and the full-setup view.
|
||||
|
||||
### 2. New page `FullSetupPage.tsx` at `/mod/:id/setup`
|
||||
|
||||
- Reuse `useModStore` (same load path as `ModPage`).
|
||||
- `flattenObjects(mod)` → filter to renderable classes (those registered in
|
||||
`components/viewers/register.ts`: `Tile`, `Custom_Tile`, `Custom_Token`,
|
||||
`Card`, `CardCustom`, `Deck`, `DeckCustom`, `Custom_Deck`, `Custom_Model*`).
|
||||
- Render **one** `<Scene>` containing all renderable objects as
|
||||
`<group position={…}>` entries, dispatching to the right `*Mesh` by `Name`.
|
||||
- Show a summary header (total objects, rendered count, skipped count) and
|
||||
loading/error states matching `ModPage`.
|
||||
|
||||
### 3. Layout
|
||||
|
||||
- Place each object at its real position from the save's `Transform` instead of
|
||||
a generated grid.
|
||||
- `components/viewers/transform.ts` converts a TTS transform to three.js:
|
||||
TTS is left-handed (Y up, +Z toward the player), three.js is right-handed,
|
||||
so Z is reflected in position and rotation. Each class also gets a base-size
|
||||
correction (our viewer meshes are authored for inspection, in arbitrary
|
||||
units) and a "lay flat" rotation for the extruded tile/token/card meshes.
|
||||
- `Scene`'s `Bounds fit` auto-fits the camera to the full layout, so no camera
|
||||
work is needed.
|
||||
- Non-renderable objects (bags, dice, boards without assets) are skipped and
|
||||
counted, not dropped silently.
|
||||
|
||||
### 4. Share materials & geometry
|
||||
|
||||
- **Geometry cache (module-level `Map<string, BufferGeometry>`):** key by a
|
||||
canonical string — `card:{w}:{h}:{t}`, `tile:{type}:{aspect}:{t}`,
|
||||
`token:{url}:{t}`, `model:{meshUrl}`. All cards of the same size, or tiles
|
||||
of the same type/size, reuse one geometry instead of rebuilding per object.
|
||||
Token geometry is keyed by the source image URL (the trace is cached per
|
||||
URL, so the silhouette is deterministic).
|
||||
- **Material cache (module-level `Map<string, Material>`):** key by
|
||||
`textureUrl + color + roughness`. drei already caches textures by URL
|
||||
globally, so sharing the material on top avoids per-object material
|
||||
allocation for tiles/tokens with the same image.
|
||||
- **Cards:** the face/back textures are shared (drei caches them by URL) and
|
||||
the sprite cell is selected via a per-material UV transform injected into the
|
||||
shader (`cardMaterial.ts`), so cards share texture, shader, and geometry —
|
||||
only the material uniforms differ. Materials are cached per card id + tint.
|
||||
- Dispose shared resources on page unmount, or accept a module-level cache for
|
||||
the session (see Open decisions).
|
||||
|
||||
### 5. Routing & navigation
|
||||
|
||||
- Add `<Route path="/mod/:id/setup" element={<FullSetupPage />} />` in
|
||||
`apps/web/src/App.tsx`.
|
||||
- Add a "Full setup" link/button on `ModPage` next to the download button.
|
||||
|
||||
### 6. Edge cases
|
||||
|
||||
- Objects with no asset (no `ImageURL`/`MeshURL`) render as neutral-colored
|
||||
placeholders (matching the current viewers' fallback behavior).
|
||||
- Token tracing suspends per URL (already cached in `TokenViewer`); the shared
|
||||
`Scene` Suspense boundary handles it.
|
||||
- Large saves: the grid + shared geometry keeps it performant, but cap or warn
|
||||
on very large object counts if needed.
|
||||
|
||||
## Files touched
|
||||
|
||||
- `apps/web/src/components/viewers/{Tile,Token,Card,CustomModel}Viewer.tsx` —
|
||||
export object-facing mesh wrappers
|
||||
- `apps/web/src/components/viewers/sharedResources.ts` — new geometry/material
|
||||
caches
|
||||
- `apps/web/src/components/viewers/transform.ts` — new TTS→three.js placement
|
||||
conversion
|
||||
- `apps/web/src/components/viewers/sharedResources.ts` — `objectTint`/
|
||||
`tintedColor` helpers for the per-object `ColorDiffuse` tint
|
||||
- `packages/shared/src/types.ts` — add `TTSObjectTransform` and `ColorDiffuse`
|
||||
- `apps/web/src/pages/FullSetupPage.tsx` — new
|
||||
- `apps/web/src/App.tsx` — route
|
||||
- `apps/web/src/pages/ModPage.tsx` — nav link
|
||||
- Possibly a small `geometryCache`/`materialCache` helper under
|
||||
`components/viewers/`
|
||||
|
||||
## Open decisions (defaults in bold)
|
||||
|
||||
- **Layout style** — **real `Transform` placement** (was a grouped grid before
|
||||
the transform data was wired in).
|
||||
- **Geometry/material cache lifetime** — **session-level module cache**
|
||||
(simplest, consistent with drei's global texture cache) vs dispose-on-unmount.
|
||||
Reference in New Issue
Block a user