docs: design command execution for tabletop scripts
Add bgm-commands.md covering async commands with ok/cancel/error results, per-invocation run contexts, fire-and-forget vs self-managed waiting, and tap interaction with part-local trigger points. Link it from the tabletop design and plan docs, and record the decisions in decisions.md.
This commit is contained in:
+41
-1
@@ -259,4 +259,44 @@ boundary.
|
||||
**Alternatives considered:** A polling `CameraFit` that waited for non-empty
|
||||
bounds each frame; hand-rolled camera math. Rejected — Suspense already
|
||||
signals content readiness, so `Bounds` inside the boundary fits the loaded
|
||||
geometry directly.
|
||||
geometry directly.
|
||||
|
||||
## D19 — Commands are async with ok/cancel/error results
|
||||
|
||||
**Decision:** Scripted interaction is built on async commands. Each command
|
||||
returns `ok`, `cancel` (interrupted — superseded, skipped, surface disabled),
|
||||
or `error` (genuinely failed). Each invocation gets its own run context — the
|
||||
unit of cancellation and the carrier of command state. Commands are either
|
||||
fire-and-forget (the runtime doesn't await them) or self-managed waiting (they
|
||||
resolve their own promise when a condition is met); both get a run context and
|
||||
cancel path. Supersede groups cancel a running command when another in the
|
||||
group starts (e.g. a `camera` group so a second focus cancels the first).
|
||||
|
||||
**Context:** The user wants to script interaction sequences — focus, caption,
|
||||
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
|
||||
and react to input. Design: [`bgm-commands.md`](./bgm-commands.md).
|
||||
|
||||
**Alternatives considered:** A single monolithic script interpreter. Rejected
|
||||
— commands as self-contained async units are testable in isolation and let
|
||||
the runtime stay a thin orchestrator.
|
||||
|
||||
## D20 — Tap interaction reports every tap with the nearest trigger point
|
||||
|
||||
**Decision:** Only tap interaction is supported. A tap on a part is reported
|
||||
to the command layer as a `TapEvent` carrying the part, the tap position in
|
||||
the part's local frame, and the nearest trigger point within its `radius` (or
|
||||
`null` on a miss). Trigger points are authored in the part's local frame with
|
||||
mm radius; distance is measured in the part's plane; ties go to the first
|
||||
declared. The command decides how to react to a miss — resolve, reject, or
|
||||
ignore.
|
||||
|
||||
**Context:** Commands need to wait on player input (`wait: tap`). Reporting
|
||||
every tap with the nearest trigger point keeps the runtime dumb and lets the
|
||||
command own the UX (e.g. a "wrong spot" shake). Authoring trigger points in
|
||||
the part's local frame keeps them valid as the part moves, rotates, and
|
||||
flips.
|
||||
|
||||
**Alternatives considered:** Reporting only a hit and silently dropping
|
||||
misses. Rejected — a command that needs to react to a wrong tap has no way to
|
||||
do so. World-space trigger points. Rejected — they break when the part moves.
|
||||
Reference in New Issue
Block a user