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

4.3 KiB

bgm Loader — Status

WIP. What's built, what works, what's missing, and the known issues. Spec: bgm-format.md.

What's built

packages/bgm — the loader core (new)

File Purpose
src/types.ts Roles (Package, Part, Surface, Setup, Route, Stacking, …), 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)
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 Maps 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 surface with candidates: $variants against a virtual csv block, and a setup. Same content duplicated as the vitest fixture under packages/bgm/src/__fixtures__/harbor/.

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: 177 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.

Known issues

  1. Plugin emits empty maps — fixed: load serializes Maps 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 yetapps/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 expansiontype 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).
  • Docs for the loader itself (this file is the start).