Files
tts-workshop/docs/bgm-loader-status.md
T

72 lines
5.9 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.
# bgm Loader — Status
> WIP. What's built, what works, what's missing, and the known issues.
> Spec: [`bgm-format.md`](./bgm-format.md).
## What's built
### `packages/bgm` — the loader core (new)
| File | Purpose |
| --- | --- |
| `src/types.ts` | Roles (`Package`, `Part`, `Surface`, `Setup`, `Route`, `Stacking`, `SurfaceMount`, …), `SerializedPackage` (the JSON the plugin emits), `BgmError`, `DefFile`, `ParsedDef` |
| `src/schemas.ts` | zod schemas + `validate*` for each role |
| `src/markdown.ts` | Virtual def files from markdown code blocks, via **`marked`**. `file=` naming + content-hash auto-naming (`./<hash>.yaml`); multiple blocks may share a `file=` name |
| `src/parse.ts` | yaml/json/toml → def objects (`yaml`, `smol-toml`); real-file walker (incl. `.csv`) |
| `src/variants.ts` | `$variants` expansion via **`typed-csv`** (`typed-csv/csv-loader`). Inline (newline) vs path; paths resolve against the virtual def map |
| `src/collect.ts` | `loadDefs` (real + virtual, virtual wins), `collectPackages` (package decl → `include` globs via **picomatch** → parts/surfaces/setups, `type#id` uniqueness, `$variants` on defs and route candidates). Sets each part's `baseUrl` to its source file's directory for resolving relative asset paths |
| `src/vite.ts` | The **vite plugin** (`bgm()`): resolves `virtual:bgm/packages` (all packages) and `virtual:bgm/package/<id>` (one package) imports to `export default <json>`, watches source files for reload. Serializes the package's `Map`s to objects (`SerializedPackage`); throws on unknown packages; re-collects per `load` (no stale cache). |
| `src/*.test.ts` | **23 tests, all passing** — markdown extractor, typed-csv parsing (incl. the spec's empty-array + crop tuple cases), full harbor collection, plugin unit tests (resolve/load/shape/watch), and a real `vite build` integration test covering two packages |
Deps: `marked`, `typed-csv`, `yaml`, `smol-toml`, `picomatch`, `zod`, `vite`, `@types/picomatch`.
### `games/harbor/harbor.md` — example game (new)
Exercises the format end-to-end: package decl, two `file=parts/tokens.yaml` blocks, a table surface with `mount`/`children` and `candidates: $variants` against a virtual csv block, a child player surface, and a setup declaring its enabled `surfaces`. Same content duplicated as the vitest fixture under `packages/bgm/src/__fixtures__/harbor/`.
### `games/poker/poker.md` — example game (new)
A real 52-card deck: a single `card` part expanded by `$variants` into 52 cards, each picking a cell from a `13×4` face sheet (`cards-13x4.jpg`) and a shared `4×1` back sheet (`back-4x1.png`). Assets are stored in Git LFS (`.gitattributes`).
### `packages/tabletop` — rendering library (new)
A standalone r3f library that renders bgm parts. `PartView`/`PartMesh` build a mesh from a `Part` definition via `@tts/mesh` (size/fillet, face/back sprite UVs, traced `shape` or rect fallback). Proxy calls (`/asset`, `/trace`) are injectable via `TabletopProvider`, so the host app supplies its own handlers. Plan: [`bgm-tabletop-plan.md`](./bgm-tabletop-plan.md).
### `apps/proxy` — local game assets (new)
The proxy serves local game assets from the `games` root: `GAMES_ROOT` (env or default) is set at startup (`config.ts`) and read by the `/asset` and `/trace` routes to serve relative paths (e.g. `poker/parts/assets/cards.png`) from disk, alongside the existing http(s) proxy path.
### `apps/web` — consumer (new)
- `vite.config.ts` — wired with `bgm({ root: <repo>/games })`, importing the plugin from `@tts/bgm`.
- `src/vite-env.d.ts` — ambient `declare module 'virtual:bgm/packages'` (all packages) and `'virtual:bgm/package/*'` (one package).
- `src/pages/BgmPage.tsx` — list page: imports `virtual:bgm/packages` and shows every discovered package. Routed at `/bgm`.
- `src/pages/BgmPackagePage.tsx` — detail page: looks up a package by id from `bgm` and renders its parts/surfaces/setups. Routed at `/bgm/:id`.
The vite plugin itself lives in `packages/bgm/src/vite.ts` (exported from `@tts/bgm`), not in the web app — so the loader's plugin is tested in isolation from the web project.
## Works
- `pnpm --filter @tts/bgm build` and `typecheck` pass.
- Root `pnpm test`: **191 pass**.
- `pnpm --filter @tts/web build` succeeds; config warnings fixed.
- `src/vite.test.ts` runs a **real `vite build`** against a self-contained fixture (`src/__fixtures__/vite-build/`) and asserts the bundled output contains the package data — the plugin is proven end-to-end without touching the web app.
- `pnpm --filter @tts/tabletop build` / `test` pass; `pnpm --filter @tts/proxy typecheck` passes.
## Known issues
1. ~~Plugin emits empty maps~~ — fixed: `load` serializes `Map`s via `Object.fromEntries`.
2. ~~Plugin `load` uses `this.error`~~ — fixed: throws instead.
3. ~~HMR cache not invalidated~~ — fixed: dropped the closure cache; re-collects per `load`.
4. ~~`tinyglobby` leftover dep~~ — removed.
5. ~~Package-level test script finds no files~~ — added `packages/bgm/vitest.config.ts`.
## Not yet done
- ~~No consumer yet~~ — `apps/web/src/pages/BgmPage.tsx` lists packages from `virtual:bgm/packages`; `BgmPackagePage.tsx` shows one at `/bgm/:id`.
- **`$variants` URL paths** — spec mentions file/URL; URLs deferred.
- **zod `SerializedPackage` shape for the emitted JSON** — the plugin emits `SerializedPackage` objects; a zod schema for the emitted module would give runtime validation beyond the ambient `declare module`.
- **`setup` value expansion** — `type` without `id` → all parts of that type is documented but not implemented in the loader (it's a game-state init concern; noted as future).
- **Surface mounting is validated but not resolved** — `mount`/`children`/`surfaces` are parsed and validated, but the loader doesn't resolve child→parent relationships or enforce that a setup's `surfaces`/a surface's `children` reference existing surfaces. That's a game-state/rendering concern (see `docs/bgm-tabletop.md`).
- Docs for the loader itself (this file is the start).