Compare commits
2
Commits
cf8ca07850
...
211c151971
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
211c151971 | ||
|
|
345832e389 |
@@ -14,8 +14,9 @@ analyze their contents. A lightweight, client-only pnpm monorepo.
|
|||||||
| `packages/mesh` | 2D shapes + extrusion into 3D mesh geometry | Isomorphic |
|
| `packages/mesh` | 2D shapes + extrusion into 3D mesh geometry | Isomorphic |
|
||||||
| `packages/shared` | Shared types + zod schemas | Isomorphic |
|
| `packages/shared` | Shared types + zod schemas | Isomorphic |
|
||||||
|
|
||||||
See [`docs/architecture.md`](docs/architecture.md) for the architecture and
|
See [`docs/overview.md`](docs/overview.md) for the docs index,
|
||||||
[`docs/implementation-plan.md`](docs/implementation-plan.md) for the plan.
|
[`docs/architecture.md`](docs/architecture.md) for the architecture, and
|
||||||
|
[`docs/status/implementation-plan.md`](docs/status/implementation-plan.md) for the plan.
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export function tintedColor(base: THREE.Color, tint: THREE.Color): THREE.Color {
|
|||||||
* the same image.
|
* the same image.
|
||||||
*
|
*
|
||||||
* These caches live for the session (like drei's global texture cache) and are
|
* These caches live for the session (like drei's global texture cache) and are
|
||||||
* not disposed on unmount; see `docs/full-setup-view.md`.
|
* not disposed on unmount; see `docs/status/full-setup-view.md`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const geometryCache = new Map<string, THREE.BufferGeometry>();
|
const geometryCache = new Map<string, THREE.BufferGeometry>();
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
> **Scope:** The system's architecture and dependency graph. For implementation
|
> **Scope:** The system's architecture and dependency graph. For implementation
|
||||||
> details (files, endpoints, build order), see
|
> details (files, endpoints, build order), see
|
||||||
> [`implementation-plan.md`](./implementation-plan.md). For the rationale behind
|
> [`status/implementation-plan.md`](./status/implementation-plan.md). For the
|
||||||
> key decisions, see [`decisions.md`](./decisions.md).
|
> rationale behind key decisions, see [`decisions.md`](./decisions.md).
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
# bgm-commands
|
# bgm-commands
|
||||||
|
|
||||||
Command execution for [bgm](./bgm-format.md) board games, built into
|
Command execution for [bgm](./format.md) board games, built into
|
||||||
[`@tts/tabletop`](./bgm-tabletop.md). A command is a unit of scripted
|
[`@tts/tabletop`](./tabletop.md). A command is a unit of scripted
|
||||||
interaction — focus the camera, wait for a tap, move a part, show a caption —
|
interaction — focus the camera, wait for a tap, move a part, show a caption —
|
||||||
that runs against the tabletop state store and render layer.
|
that runs against the tabletop state store and render layer.
|
||||||
|
|
||||||
This doc covers **command execution**: the async lifecycle, run contexts, and
|
This doc covers **command execution**: the async lifecycle, run contexts, and
|
||||||
tap interaction. The message layer above this — how commands are *declared*
|
tap interaction. The message layer above this — how commands are *declared*
|
||||||
and *fired* (triggers, orchestrators, the message queue) — is specified in
|
and *fired* (triggers, orchestrators, the message queue) — is specified in
|
||||||
[`bgm-engine.md`](./bgm-engine.md). Commands are async functions registered
|
[`engine.md`](./engine.md). Commands are async functions registered
|
||||||
with the engine's handler registry; `@tts/tabletop` provides the concrete
|
with the engine's handler registry; `@tts/tabletop` provides the concrete
|
||||||
commands that mutate the tabletop store and render layer.
|
commands that mutate the tabletop store and render layer.
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ commands that mutate the tabletop store and render layer.
|
|||||||
|
|
||||||
A command is an async function that returns a result. Every command ends in
|
A command is an async function that returns a result. Every command ends in
|
||||||
one of three states, emitted as a message discriminated on the type suffix
|
one of three states, emitted as a message discriminated on the type suffix
|
||||||
(see `bgm-engine.md` §3):
|
(see `engine.md` §3):
|
||||||
|
|
||||||
- `:done` — completed normally.
|
- `:done` — completed normally.
|
||||||
- `:cancel` — interrupted (a newer command superseded it, the user skipped,
|
- `:cancel` — interrupted (a newer command superseded it, the user skipped,
|
||||||
@@ -124,7 +124,7 @@ cancel, so a cancelled `wait: tap` never leaks a handler.
|
|||||||
## 5. run context
|
## 5. run context
|
||||||
|
|
||||||
The context a command receives is the handle to everything it can affect. The
|
The context a command receives is the handle to everything it can affect. The
|
||||||
engine defines the base `RunContext` (see `bgm-engine.md` §5): `signal`
|
engine defines the base `RunContext` (see `engine.md` §5): `signal`
|
||||||
(cancellation), `emit`, `wait`, and `enableTrigger`/`disableTrigger`. Tabletop
|
(cancellation), `emit`, `wait`, and `enableTrigger`/`disableTrigger`. Tabletop
|
||||||
extends it with the handles commands need to mutate the board:
|
extends it with the handles commands need to mutate the board:
|
||||||
|
|
||||||
@@ -142,12 +142,12 @@ interface TabletopRunContext extends RunContext {
|
|||||||
The tap detector reads trigger points from a runtime map keyed by part id; it
|
The tap detector reads trigger points from a runtime map keyed by part id; it
|
||||||
does not care where they are declared. Declaration (on the part definition, in
|
does not care where they are declared. Declaration (on the part definition, in
|
||||||
a setup, or in a script) is the deferred "how to declare" half and lives in
|
a setup, or in a script) is the deferred "how to declare" half and lives in
|
||||||
`bgm-format.md`.
|
`format.md`.
|
||||||
|
|
||||||
## Open decisions
|
## Open decisions
|
||||||
|
|
||||||
- **Where commands are declared** — the `script` role and its schema
|
- **Where commands are declared** — the `script` role and its schema
|
||||||
(`bgm-format.md`), deferred.
|
(`format.md`), deferred.
|
||||||
- **Animation** — a general "ease toward target placement" layer (preferred)
|
- **Animation** — a general "ease toward target placement" layer (preferred)
|
||||||
vs explicit per-move tweens.
|
vs explicit per-move tweens.
|
||||||
- **Camera** — `CameraControls` (drei) vs hand-rolled.
|
- **Camera** — `CameraControls` (drei) vs hand-rolled.
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# bgm-engine
|
# bgm-engine
|
||||||
|
|
||||||
The message layer that drives [bgm](./bgm-format.md) board games, built into
|
The message layer that drives [bgm](./format.md) board games, built into
|
||||||
[`@tts/engine`](./architecture.md). It unifies the two halves of scripted
|
[`@tts/engine`](../architecture.md). It unifies the two halves of scripted
|
||||||
interaction — *declaring* what should happen and *executing* it — into a single
|
interaction — *declaring* what should happen and *executing* it — into a single
|
||||||
reactive loop: **messages** flow through a **queue**, and **handlers** react to
|
reactive loop: **messages** flow through a **queue**, and **handlers** react to
|
||||||
them.
|
them.
|
||||||
@@ -9,7 +9,7 @@ them.
|
|||||||
This doc covers the message model (what flows), the queue and its tick (how it
|
This doc covers the message model (what flows), the queue and its tick (how it
|
||||||
flows), and the handlers (who reacts). Command *execution* — the async
|
flows), and the handlers (who reacts). Command *execution* — the async
|
||||||
lifecycle, run contexts, and tap interaction — is specified in
|
lifecycle, run contexts, and tap interaction — is specified in
|
||||||
[`bgm-commands.md`](./bgm-commands.md); this doc is the layer above it.
|
[`commands.md`](./commands.md); this doc is the layer above it.
|
||||||
|
|
||||||
## package split
|
## package split
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ is node-testable in isolation (mirroring `@tts/extract`'s isomorphic, zero-dep
|
|||||||
style). It defines the contract — `Message`, the handler registry, `Trigger`,
|
style). It defines the contract — `Message`, the handler registry, `Trigger`,
|
||||||
`Orchestrator`, and `RunContext`.
|
`Orchestrator`, and `RunContext`.
|
||||||
|
|
||||||
[`@tts/tabletop`](./bgm-tabletop.md) is one consumer of that contract: it
|
[`@tts/tabletop`](./tabletop.md) is one consumer of that contract: it
|
||||||
registers the built-in commands (`move`, `focus`, `caption`, `enableSurface`,
|
registers the built-in commands (`move`, `focus`, `caption`, `enableSurface`,
|
||||||
...) that mutate the tabletop store and drive the render layer. The engine
|
...) that mutate the tabletop store and drive the render layer. The engine
|
||||||
never imports tabletop; tabletop depends on the engine for the message types
|
never imports tabletop; tabletop depends on the engine for the message types
|
||||||
@@ -94,7 +94,7 @@ it cannot re-enter itself.
|
|||||||
### interaction messages
|
### interaction messages
|
||||||
|
|
||||||
Interaction is the player's input, reported to the engine as messages. Only
|
Interaction is the player's input, reported to the engine as messages. Only
|
||||||
tap interaction is supported (see `bgm-commands.md` §4).
|
tap interaction is supported (see `commands.md` §4).
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
interface TapMessage {
|
interface TapMessage {
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
# bgm State Model
|
||||||
|
|
||||||
|
The format's model of what a board game *is*, and the shape of the states it can
|
||||||
|
be in. This is the organizing model behind the concrete specs:
|
||||||
|
[`format.md`](./format.md) (the manifest), [`tabletop.md`](./tabletop.md) (the
|
||||||
|
render library), and [`engine.md`](./engine.md) / [`commands.md`](./commands.md)
|
||||||
|
(scripted interaction).
|
||||||
|
|
||||||
|
> **Status:** Design. The loader and render layer implement components and a
|
||||||
|
> static setup today; the state-shape framing, zone-facing, and the anchoring
|
||||||
|
> scope cut below are proposals to guide the next phase.
|
||||||
|
|
||||||
|
## 1. Components are constants; setup is the shape of states
|
||||||
|
|
||||||
|
A bgm game is authored two ways, and they answer different questions:
|
||||||
|
|
||||||
|
- **Components** (`part`, `surface`) describe the **constants** — the physical
|
||||||
|
pieces and the board geometry that do not change during play. A tile is a
|
||||||
|
45×45 mm square with a meadow/road/city face; the play board has a draw pile
|
||||||
|
and an 11×11 grid. These are timeless facts about the game, not state.
|
||||||
|
- **setup** describes the **shape of the game's states** — which parts can be
|
||||||
|
where, how many, and with what facing. It is a *schema* over the state space,
|
||||||
|
not a concrete snapshot of one run.
|
||||||
|
|
||||||
|
The runtime store is then an **instance** of the setup's shape: the current
|
||||||
|
state of play, a point in the state space the setup describes. This buys three
|
||||||
|
things:
|
||||||
|
|
||||||
|
- **Validation** — a state is legal iff it matches the setup's shape (on the
|
||||||
|
right paths, right counts, right facing).
|
||||||
|
- **A contract for the rule engine** — legal play is a *transition between
|
||||||
|
shapes*; the rule layer (layer 4 in the layering vision) reasons over them.
|
||||||
|
- **A clean boundary** — components are timeless; setup is the state space; the
|
||||||
|
store is the current point.
|
||||||
|
|
||||||
|
### Open: does setup carry the initial state?
|
||||||
|
|
||||||
|
A game needs a concrete starting position, not just a schema. The default is
|
||||||
|
that a `setup` is **shape + initial instance** — one role that both describes
|
||||||
|
the legal state space and seeds the store. The alternative (schema-only, with
|
||||||
|
the initial state derived from the shape) is explored but not preferred.
|
||||||
|
|
||||||
|
## 2. The state: path → stack × facing
|
||||||
|
|
||||||
|
The state space is made of two axes.
|
||||||
|
|
||||||
|
### Path → stack
|
||||||
|
|
||||||
|
Every part lives on a **path** (a URL-style key like `/grid/5/5` or `/draw`),
|
||||||
|
and multiple parts on a path form an ordered **stack** (a deck, a pile of meeples,
|
||||||
|
a tile with a meeple on it). Placement is one axis. This is already in use.
|
||||||
|
|
||||||
|
### facing — part affordance × zone restriction
|
||||||
|
|
||||||
|
Facing is the second axis, and it has two distinct sources of constraint:
|
||||||
|
|
||||||
|
- **The part** declares the **physical affordance** — the facings the piece
|
||||||
|
physically supports. A card supports face/back/standing; a tile supports
|
||||||
|
face/back but not "tapped".
|
||||||
|
- **The path (zone)** declares the **legal facing** — what's allowed on that
|
||||||
|
zone. An MTG discard pile requires face-up; a play area allows tapped; a
|
||||||
|
facedown deck requires face-down. The same card is face-up in the discard,
|
||||||
|
tapped in play, face-up in exile — the piece's affordance doesn't change, only
|
||||||
|
the zone's rule does.
|
||||||
|
|
||||||
|
A state's facing is legal iff it is **both physically possible (part) and
|
||||||
|
zone-legal (path)** — the effective set is the intersection.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
role: part
|
||||||
|
type: card
|
||||||
|
id: basic
|
||||||
|
facing: [face, back, standing] # physical affordance
|
||||||
|
|
||||||
|
role: surface
|
||||||
|
type: board
|
||||||
|
id: main
|
||||||
|
layout:
|
||||||
|
- route: /discard
|
||||||
|
facing: [face] # zone restriction
|
||||||
|
- route: /play
|
||||||
|
facing: [face, tap] # zone restriction
|
||||||
|
```
|
||||||
|
|
||||||
|
Deck / the current facing lives in the store and must be in the intersection.
|
||||||
|
|
||||||
|
### Open questions
|
||||||
|
|
||||||
|
- **Default when a path declares no `facing`** — unrestricted (only the part's
|
||||||
|
affordance bounds it), or a sensible default like `face`? Lean unrestricted.
|
||||||
|
- **Is "tapped" a facing or a rotation?** In MTG it's a 90° in-plane rotation.
|
||||||
|
Default: fold common rotations into the facing enum (`face` / `back` /
|
||||||
|
`standing` / `tap`) for schema simplicity; arbitrary rotation is a later
|
||||||
|
extension.
|
||||||
|
- **Naming** — the part-side and path-side are different constraints wearing the
|
||||||
|
same word. Worth distinct terms (capability/typ) so they don't collide.
|
||||||
|
|
||||||
|
## 3. Anchoring scope: stacks-on-paths, not part-to-part networks
|
||||||
|
|
||||||
|
Real TTS mods anchor components to each other — a meeple on a tile, a fanned
|
||||||
|
hand, tokens scattered on a board. We are **not** modeling part-aligned-to-part
|
||||||
|
relative placement networks. Instead:
|
||||||
|
|
||||||
|
- **Stacks absorb part-on-part.** "Meeple on tile" is a stack `[tile, meeple]`
|
||||||
|
on a path. Much of TTS's anchoring collapses into the path→stack model.
|
||||||
|
- **Free relative placement is out of scope** — a meeple at an offset on a tile,
|
||||||
|
a fanned hand, arbitrary token scatter are not modeled.
|
||||||
|
|
||||||
|
This is a deliberate scope cut. It keeps the state model closed and simple, but
|
||||||
|
it is a **fidelity loss for converted games** and part of the "with some fixing"
|
||||||
|
cost of the TTS→bgm conversion. Components (layer 1), not the state model, are
|
||||||
|
the place to extend later if needed.
|
||||||
|
|
||||||
|
### The grid compromise
|
||||||
|
|
||||||
|
Because we don't model parts-aligned-to-parts, common layouts are expressed
|
||||||
|
explicitly — and grid layouts become verbose (the Carcassonne board is 121
|
||||||
|
hand-written row coordinates in `grid.csv`). The mitigations:
|
||||||
|
|
||||||
|
- **Grid shorthand** — a declarative `grid` (cols/rows, cell size, origin) that
|
||||||
|
expands to routes, instead of authored coordinates.
|
||||||
|
- **Free-placement shorthand** — a `free`/scatter mode for loose collections,
|
||||||
|
when the exact positions don't matter to play.
|
||||||
|
|
||||||
|
But there is **no general part-to-part network** on the roadmap. If a converted
|
||||||
|
game needs it, that is a format extension to design deliberately, not an
|
||||||
|
implicit assumption.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
| Concept | Role | Where |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Components | Constants — the physical pieces & board geometry | `part`, `surface` |
|
||||||
|
| Setup | The shape of the state space (+ initial instance) | `setup` |
|
||||||
|
| Store | The current state, an instance of the setup | `@tts/tabletop` |
|
||||||
|
| Facing | Part affordance × zone restriction | part + path/zone restriction |
|
||||||
|
| Anchoring | Stacks-on-paths only; no part networks | — |
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# bgm-tabletop
|
# bgm-tabletop
|
||||||
|
|
||||||
a r3f based interactive component library to work with [bgm](./bgm-format.md) board games. will be used somewhere in the `web` app's bgm inspector routes.
|
a r3f based interactive component library to work with [bgm](./format.md) board games. will be used somewhere in the `web` app's bgm inspector routes.
|
||||||
|
|
||||||
## 1. stack
|
## 1. stack
|
||||||
|
|
||||||
@@ -47,14 +47,14 @@ the render map is per enabled surface: a piece may appear on more than one enabl
|
|||||||
|
|
||||||
## 4. stacking
|
## 4. stacking
|
||||||
|
|
||||||
the format's stacking strategy (`curve` / `limit` / `align` / `steps` / `tilt` / `zStart` / `zEnd`, see `bgm-format.md` §4) is implemented as a hook, e.g. `useStacking(route.stacking, index, stackSize)`, returning the offset/rotation to apply to a piece: `{ x, y, rotation, z, tilt }`. `x`/`y`/`rotation` come from the `curve`; `z` is the surface-normal height ramped from `zStart` to `zEnd`; `tilt` is the rotation about the card's local Y (long) axis, applied to every part. `PartPlacement` consumes it.
|
the format's stacking strategy (`curve` / `limit` / `align` / `steps` / `tilt` / `zStart` / `zEnd`, see `format.md` §4) is implemented as a hook, e.g. `useStacking(route.stacking, index, stackSize)`, returning the offset/rotation to apply to a piece: `{ x, y, rotation, z, tilt }`. `x`/`y`/`rotation` come from the `curve`; `z` is the surface-normal height ramped from `zStart` to `zEnd`; `tilt` is the rotation about the card's local Y (long) axis, applied to every part. `PartPlacement` consumes it.
|
||||||
|
|
||||||
## 5. commands
|
## 5. commands
|
||||||
|
|
||||||
Scripted interaction — focus, tap-to-advance, move, caption — is built on an
|
Scripted interaction — focus, tap-to-advance, move, caption — is built on an
|
||||||
async command layer. See [`bgm-commands.md`](./bgm-commands.md) for command
|
async command layer. See [`commands.md`](./commands.md) for command
|
||||||
execution (lifecycle, run contexts, tap interaction), and
|
execution (lifecycle, run contexts, tap interaction), and
|
||||||
[`bgm-engine.md`](./bgm-engine.md) for the message layer above it (the queue,
|
[`engine.md`](./engine.md) for the message layer above it (the queue,
|
||||||
triggers, and orchestrators that declare and fire commands).
|
triggers, and orchestrators that declare and fire commands).
|
||||||
|
|
||||||
## 6. usage
|
## 6. usage
|
||||||
+2
-2
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
> **Scope:** The rationale behind key design decisions. For the system's
|
> **Scope:** The rationale behind key design decisions. For the system's
|
||||||
> architecture, see [`architecture.md`](./architecture.md). For the concrete
|
> architecture, see [`architecture.md`](./architecture.md). For the concrete
|
||||||
> build plan, see [`implementation-plan.md`](./implementation-plan.md).
|
> build plan, see [`status/implementation-plan.md`](./status/implementation-plan.md).
|
||||||
>
|
>
|
||||||
> Each entry records the decision, the context, and the alternatives considered.
|
> Each entry records the decision, the context, and the alternatives considered.
|
||||||
> New entries are appended; existing entries are updated only to correct facts,
|
> New entries are appended; existing entries are updated only to correct facts,
|
||||||
@@ -275,7 +275,7 @@ group starts (e.g. a `camera` group so a second focus cancels the first).
|
|||||||
**Context:** The user wants to script interaction sequences — focus, caption,
|
**Context:** The user wants to script interaction sequences — focus, caption,
|
||||||
title, highlight, tap-to-advance, move, camera away. The state store and
|
title, highlight, tap-to-advance, move, camera away. The state store and
|
||||||
render layer already exist; what's missing is a way to drive them over time
|
render layer already exist; what's missing is a way to drive them over time
|
||||||
and react to input. Design: [`bgm-commands.md`](./bgm-commands.md).
|
and react to input. Design: [`bgm/commands.md`](./bgm/commands.md).
|
||||||
|
|
||||||
**Alternatives considered:** A single monolithic script interpreter. Rejected
|
**Alternatives considered:** A single monolithic script interpreter. Rejected
|
||||||
— commands as self-contained async units are testable in isolation and let
|
— commands as self-contained async units are testable in isolation and let
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Docs
|
||||||
|
|
||||||
|
The documentation is split into the living specs, which describe how the
|
||||||
|
system works today, and the status/plans, which track development iterations
|
||||||
|
and go stale as work lands.
|
||||||
|
|
||||||
|
## Specs — how the system works
|
||||||
|
|
||||||
|
| Doc | Covers |
|
||||||
|
| --- | --- |
|
||||||
|
| [`architecture.md`](./architecture.md) | System architecture and the package dependency graph |
|
||||||
|
| [`decisions.md`](./decisions.md) | Key design decisions and the rationale behind them |
|
||||||
|
| [`bgm/format.md`](./bgm/format.md) | The board game manifest (bgm) format spec |
|
||||||
|
| [`bgm/engine.md`](./bgm/engine.md) | The bgm message layer: queue, triggers, orchestrators |
|
||||||
|
| [`bgm/commands.md`](./bgm/commands.md) | bgm command execution: lifecycle, run contexts, tap interaction |
|
||||||
|
| [`bgm/tabletop.md`](./bgm/tabletop.md) | The r3f tabletop component library |
|
||||||
|
| [`bgm/state-model.md`](./bgm/state-model.md) | The format's state model: components vs setup, facing, anchoring scope |
|
||||||
|
|
||||||
|
## Status & plans (dev logs)
|
||||||
|
|
||||||
|
| Doc | Covers |
|
||||||
|
| --- | --- |
|
||||||
|
| [`status/implementation-plan.md`](./status/implementation-plan.md) | Original build plan |
|
||||||
|
| [`status/bgm-loader.md`](./status/bgm-loader.md) | bgm loader — what's built, works, missing |
|
||||||
|
| [`status/bgm-tabletop.md`](./status/bgm-tabletop.md) | bgm tabletop — implementation plan / status |
|
||||||
|
| [`status/full-setup-view.md`](./status/full-setup-view.md) | Full-setup view plan |
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# bgm Loader — Status
|
# bgm Loader — Status
|
||||||
|
|
||||||
> WIP. What's built, what works, what's missing, and the known issues.
|
> WIP. What's built, what works, what's missing, and the known issues.
|
||||||
> Spec: [`bgm-format.md`](./bgm-format.md).
|
> Spec: [`../bgm/format.md`](../bgm/format.md).
|
||||||
|
|
||||||
## What's built
|
## What's built
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ A real 52-card deck: a single `card` part expanded by `$variants` into 52 cards,
|
|||||||
|
|
||||||
### `packages/tabletop` — rendering library (new)
|
### `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`) default to `@tts/http` handlers and are overridable via `TabletopProvider`. Plan: [`bgm-tabletop-plan.md`](./bgm-tabletop-plan.md).
|
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`) default to `@tts/http` handlers and are overridable via `TabletopProvider`. Plan: [`bgm-tabletop.md`](./bgm-tabletop.md).
|
||||||
|
|
||||||
### `packages/http` — shared proxy HTTP (new)
|
### `packages/http` — shared proxy HTTP (new)
|
||||||
|
|
||||||
@@ -71,5 +71,5 @@ The vite plugin itself lives in `packages/bgm/src/vite.ts` (exported from `@tts/
|
|||||||
- **`$variants` URL paths** — spec mentions file/URL; URLs deferred.
|
- **`$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`.
|
- **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).
|
- **`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`).
|
- **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 `../bgm/tabletop.md`).
|
||||||
- Docs for the loader itself (this file is the start).
|
- Docs for the loader itself (this file is the start).
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
# bgm-tabletop — Implementation Plan / Status
|
# bgm-tabletop — Implementation Plan / Status
|
||||||
|
|
||||||
> **Scope:** A standalone r3f component library that renders [bgm](./bgm-format.md)
|
> **Scope:** A standalone r3f component library that renders
|
||||||
> board games: a state store, surface mounting, part placement with stacking,
|
> [bgm](../bgm/format.md) board games: a state store, surface mounting, part
|
||||||
> and per-part meshes. Design: [`bgm-tabletop.md`](./bgm-tabletop.md).
|
> placement with stacking, and per-part meshes. Design:
|
||||||
|
> [`../bgm/tabletop.md`](../bgm/tabletop.md).
|
||||||
> **Status:** items 1–8 implemented and the full tabletop scene is wired into
|
> **Status:** items 1–8 implemented and the full tabletop scene is wired into
|
||||||
> the web app's setup detail route (`/bgm/:id/setups/:type/:setup`). The
|
> the web app's setup detail route (`/bgm/:id/setups/:type/:setup`). The
|
||||||
> part-inspection route renders `PartView` from the library.
|
> part-inspection route renders `PartView` from the library.
|
||||||
@@ -75,7 +76,7 @@ useful slice and unblocks the web app's part inspection route immediately.
|
|||||||
|
|
||||||
### 3. State store (`state.ts`) ✅
|
### 3. State store (`state.ts`) ✅
|
||||||
|
|
||||||
Source-of-truth game state per `bgm-tabletop.md` §2:
|
Source-of-truth game state per `../bgm/tabletop.md` §2:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
interface GameState {
|
interface GameState {
|
||||||
@@ -96,7 +97,7 @@ interface PartState {
|
|||||||
Computed with a selector/memo so the render list is stable. A path's ordered
|
Computed with a selector/memo so the render list is stable. A path's ordered
|
||||||
children (for stacking) are derived from the parts map by sorting on `index`.
|
children (for stacking) are derived from the parts map by sorting on `index`.
|
||||||
- **Assumption**: each piece id is unique on the board (documented in
|
- **Assumption**: each piece id is unique on the board (documented in
|
||||||
`bgm-tabletop.md`); the render map is keyed by piece id.
|
`../bgm/tabletop.md`); the render map is keyed by piece id.
|
||||||
|
|
||||||
### 4. Setup seeding (`setup.ts`) ✅
|
### 4. Setup seeding (`setup.ts`) ✅
|
||||||
|
|
||||||
@@ -104,7 +105,7 @@ interface PartState {
|
|||||||
`Setup` — enables its `surfaces` (or all when omitted) and applies its
|
`Setup` — enables its `surfaces` (or all when omitted) and applies its
|
||||||
ordered `setup` placements (each moves its `parts` to a `path`).
|
ordered `setup` placements (each moves its `parts` to a `path`).
|
||||||
- `setup` value expansion: a bare `type` (no id) expands to all parts of that
|
- `setup` value expansion: a bare `type` (no id) expands to all parts of that
|
||||||
type (documented in `bgm-format.md` §3; the loader doesn't do this — it's a
|
type (documented in `../bgm/format.md` §3; the loader doesn't do this — it's a
|
||||||
game-state init concern, so it lives here).
|
game-state init concern, so it lives here).
|
||||||
|
|
||||||
### 5. Surface mounting (`mount.ts`) ✅
|
### 5. Surface mounting (`mount.ts`) ✅
|
||||||
@@ -126,7 +127,7 @@ interface PartState {
|
|||||||
### 7. Stacking (`stacking.ts`) ✅
|
### 7. Stacking (`stacking.ts`) ✅
|
||||||
|
|
||||||
- `useStacking(route.stacking, index, stackSize)` → `{ x, y, rotation, z, tilt }`.
|
- `useStacking(route.stacking, index, stackSize)` → `{ x, y, rotation, z, tilt }`.
|
||||||
- Implements the format's positioning process (`bgm-format.md` §4): step
|
- Implements the format's positioning process (`../bgm/format.md` §4): step
|
||||||
length from curve length / `max(steps, count-1)`, alignment (`start`/`end`/
|
length from curve length / `max(steps, count-1)`, alignment (`start`/`end`/
|
||||||
`center`), and `limit` (`0` all, `n` first n, `-n` last n).
|
`center`), and `limit` (`0` all, `n` first n, `-n` last n).
|
||||||
- `z` ramps linearly from `zStart` to `zEnd` across the curve's span; `tilt`
|
- `z` ramps linearly from `zStart` to `zEnd` across the curve's span; `tilt`
|
||||||
@@ -174,7 +175,7 @@ consumers share them (see Open decisions).
|
|||||||
|
|
||||||
## Commands (not yet implemented)
|
## Commands (not yet implemented)
|
||||||
|
|
||||||
Scripted interaction is designed in [`bgm-commands.md`](./bgm-commands.md):
|
Scripted interaction is designed in [`../bgm/commands.md`](../bgm/commands.md):
|
||||||
async commands with `ok`/`cancel`/`error` results, per-invocation run
|
async commands with `ok`/`cancel`/`error` results, per-invocation run
|
||||||
contexts, fire-and-forget vs self-managed waiting, and tap interaction with
|
contexts, fire-and-forget vs self-managed waiting, and tap interaction with
|
||||||
part-local trigger points. Implementation order: types + run-context manager,
|
part-local trigger points. Implementation order: types + run-context manager,
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
> **Scope:** The concrete build plan — files, endpoints, dependencies, build
|
> **Scope:** The concrete build plan — files, endpoints, dependencies, build
|
||||||
> order. For the system's architecture and dependency graph, see
|
> order. For the system's architecture and dependency graph, see
|
||||||
> [`architecture.md`](./architecture.md). For the rationale behind key decisions,
|
> [`../architecture.md`](../architecture.md). For the rationale behind key decisions,
|
||||||
> see [`decisions.md`](./decisions.md).
|
> see [`../decisions.md`](../decisions.md).
|
||||||
|
|
||||||
A lightweight, client-only pnpm monorepo for searching the Tabletop Simulator
|
A lightweight, client-only pnpm monorepo for searching the Tabletop Simulator
|
||||||
Steam Workshop, fetching full TTS save files, and analyzing their contents.
|
Steam Workshop, fetching full TTS save files, and analyzing their contents.
|
||||||
@@ -55,7 +55,16 @@ tts-workshop/
|
|||||||
├── .npmrc
|
├── .npmrc
|
||||||
├── .env.example # STEAM_API_KEY, PORT
|
├── .env.example # STEAM_API_KEY, PORT
|
||||||
├── docs/
|
├── docs/
|
||||||
│ └── implementation-plan.md # this file
|
│ ├── overview.md
|
||||||
|
│ ├── architecture.md
|
||||||
|
│ ├── decisions.md
|
||||||
|
│ ├── bgm/
|
||||||
|
│ │ ├── format.md
|
||||||
|
│ │ ├── engine.md
|
||||||
|
│ │ ├── commands.md
|
||||||
|
│ │ └── tabletop.md
|
||||||
|
│ └── status/
|
||||||
|
│ └── implementation-plan.md # this file
|
||||||
├── apps/
|
├── apps/
|
||||||
│ ├── proxy/
|
│ ├── proxy/
|
||||||
│ │ ├── package.json
|
│ │ ├── package.json
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
* their `include` patterns, and assembles the package's parts, surfaces,
|
* their `include` patterns, and assembles the package's parts, surfaces,
|
||||||
* and setups.
|
* and setups.
|
||||||
*
|
*
|
||||||
* See docs/bgm-format.md for the format's concrete behavior.
|
* See docs/bgm/format.md for the format's concrete behavior.
|
||||||
*/
|
*/
|
||||||
import * as path from 'node:path';
|
import * as path from 'node:path';
|
||||||
import picomatch from 'picomatch';
|
import picomatch from 'picomatch';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Parse raw definition files (yaml/json/toml text) into JSON objects.
|
* Parse raw definition files (yaml/json/toml text) into JSON objects.
|
||||||
*
|
*
|
||||||
* A def file's document can be either a single JSON object (the root) or a
|
* A def file's document can be either a single JSON object (the root) or a
|
||||||
* list of objects; both are handled per docs/bgm-format.md §3. In list mode,
|
* list of objects; both are handled per docs/bgm/format.md §3. In list mode,
|
||||||
* each object is a separate definition.
|
* each object is a separate definition.
|
||||||
*/
|
*/
|
||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* These validate the raw definition objects (after `$variants` expansion)
|
* These validate the raw definition objects (after `$variants` expansion)
|
||||||
* and produce the typed `Part` / `Surface` / `Setup` / `PackageDef` values.
|
* and produce the typed `Part` / `Surface` / `Setup` / `PackageDef` values.
|
||||||
* See docs/bgm-format.md for the format's concrete behavior.
|
* See docs/bgm/format.md for the format's concrete behavior.
|
||||||
*/
|
*/
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import type { PackageDef, Part, Setup, Surface } from './types.js';
|
import type { PackageDef, Part, Setup, Surface } from './types.js';
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* discovered as JSON objects from yaml/json/toml files and from markdown
|
* discovered as JSON objects from yaml/json/toml files and from markdown
|
||||||
* code blocks, then assembled into a `Package` (see `collect.ts` / `emit.ts`).
|
* code blocks, then assembled into a `Package` (see `collect.ts` / `emit.ts`).
|
||||||
*
|
*
|
||||||
* The concrete behavior of the format is described in `docs/bgm-format.md`.
|
* The concrete behavior of the format is described in `docs/bgm/format.md`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Part value types. */
|
/** Part value types. */
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* The `$variants` directive: parse a CSV into a typed object array and
|
* The `$variants` directive: parse a CSV into a typed object array and
|
||||||
* extend the original object with each row.
|
* extend the original object with each row.
|
||||||
*
|
*
|
||||||
* Per docs/bgm-format.md §1:
|
* Per docs/bgm/format.md §1:
|
||||||
* - The CSV's first row is the header, the second row is the type declaration
|
* - The CSV's first row is the header, the second row is the type declaration
|
||||||
* (`string`, `number`, `string[]`, `[number;number;number;number]`, ...),
|
* (`string`, `number`, `string[]`, `[number;number;number;number]`, ...),
|
||||||
* the remaining rows are data.
|
* the remaining rows are data.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Stacking — the format's positioning process (`bgm-format.md` §4).
|
* Stacking — the format's positioning process (`docs/bgm/format.md` §4).
|
||||||
*
|
*
|
||||||
* Given a route's `stacking` strategy and a piece's position in its path's
|
* Given a route's `stacking` strategy and a piece's position in its path's
|
||||||
* stack, compute the offset/rotation to apply. Parts are spread along an SVG
|
* stack, compute the offset/rotation to apply. Parts are spread along an SVG
|
||||||
|
|||||||
Reference in New Issue
Block a user