docs: unify commands and orchestrators in bgm-engine
Messages are a discriminated union with generic command/result types; the command host is dropped for a handler registry; commands and orchestrators are the same async shape taking a cancellable RunContext.
This commit is contained in:
+27
-20
@@ -8,18 +8,20 @@ that runs against the tabletop state store and render layer.
|
||||
This doc covers **command execution**: the async lifecycle, run contexts, and
|
||||
tap interaction. The message layer above this — how commands are *declared*
|
||||
and *fired* (triggers, orchestrators, the message queue) — is specified in
|
||||
[`bgm-engine.md`](./bgm-engine.md). The command host is the `@tts/tabletop`
|
||||
implementation of the engine's `CommandHost` contract.
|
||||
[`bgm-engine.md`](./bgm-engine.md). Commands are async functions registered
|
||||
with the engine's handler registry; `@tts/tabletop` provides the concrete
|
||||
commands that mutate the tabletop store and render layer.
|
||||
|
||||
## 1. async commands
|
||||
|
||||
A command is an async function that returns a result. Every command ends in
|
||||
one of three states:
|
||||
one of three states, emitted as a message discriminated on the type suffix
|
||||
(see `bgm-engine.md` §3):
|
||||
|
||||
- `ok` — completed normally.
|
||||
- `cancel` — interrupted (a newer command superseded it, the user skipped, the
|
||||
surface was disabled). **Not a failure.**
|
||||
- `error` — genuinely failed (asset missing, bad path, a thrown exception).
|
||||
- `:done` — completed normally.
|
||||
- `:cancel` — interrupted (a newer command superseded it, the user skipped,
|
||||
the surface was disabled). **Not a failure.**
|
||||
- `:error` — genuinely failed (asset missing, bad path, a thrown exception).
|
||||
|
||||
`cancel` is distinct from `error`: a superseded or skipped command stops
|
||||
cleanly, while a broken command surfaces loudly. The runtime treats them
|
||||
@@ -27,10 +29,10 @@ differently — a script that is superseded unwinds without alarming the player,
|
||||
but an `error` is reported.
|
||||
|
||||
```ts
|
||||
type CommandResult =
|
||||
| { status: 'ok' }
|
||||
| { status: 'cancel' }
|
||||
| { status: 'error'; error: Error };
|
||||
type CommandResult<Name extends string, R = void> =
|
||||
| { type: `${Name}:done`; data: R }
|
||||
| { type: `${Name}:cancel` }
|
||||
| { type: `${Name}:error`; error: Error };
|
||||
```
|
||||
|
||||
## 2. run contexts
|
||||
@@ -71,16 +73,18 @@ lifecycle.
|
||||
|
||||
**Supersede groups** cancel a running command when another in the same group
|
||||
starts. A `focus` command belongs to a `camera` group, so a second `focus`
|
||||
cancels the first.
|
||||
cancels the first. A superseded command's `signal` is aborted, and it emits
|
||||
`:cancel`.
|
||||
|
||||
A command is an async function taking the `RunContext` (with its `args`):
|
||||
|
||||
```ts
|
||||
interface Command {
|
||||
id: string;
|
||||
supersede?: string; // group; starting one cancels others in it
|
||||
execute(ctx: CommandContext): Promise<CommandResult>;
|
||||
}
|
||||
type Command<Args, Result> = (ctx: RunContext & { args: Args }) => Promise<Result>;
|
||||
```
|
||||
|
||||
The engine wraps it: it builds the context from the message, runs the function,
|
||||
and emits `:done` on resolve, `:cancel` on abort, `:error` on throw.
|
||||
|
||||
## 4. tap interaction
|
||||
|
||||
Only tap interaction is supported. A tap on a part is detected and reported to
|
||||
@@ -117,12 +121,15 @@ Rules:
|
||||
Commands subscribe to the tap stream via the context and unsubscribe on
|
||||
cancel, so a cancelled `wait: tap` never leaks a handler.
|
||||
|
||||
## 5. command context
|
||||
## 5. run context
|
||||
|
||||
The context a command receives is the handle to everything it can affect:
|
||||
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`
|
||||
(cancellation), `emit`, `wait`, and `enableTrigger`/`disableTrigger`. Tabletop
|
||||
extends it with the handles commands need to mutate the board:
|
||||
|
||||
```ts
|
||||
interface CommandContext {
|
||||
interface TabletopRunContext extends RunContext {
|
||||
pkg: Package;
|
||||
store: TabletopStore; // movePart, setPart, enableSurface, ...
|
||||
onTap(handler: (e: TapEvent) => void): () => void; // returns unsubscribe
|
||||
|
||||
Reference in New Issue
Block a user