Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/docs/command-bus.md is written in an unsupported language. File is not indexed.

0001 # Command Bus
0002 
0003 Firebird actions that arrive from outside the UI — URL deep links, server
0004 startup configuration, batch scripts — all travel as **commands**: small
0005 serializable objects with a `type` and arguments. One dispatcher executes them;
0006 handlers are registered per command type. This page is for developers who want
0007 to script the display or add their own commands.
0008 
0009 For the end-user view of URL parameters, see
0010 [Deep Links](/deep-links).
0011 
0012 The bus, the startup queue and the URL parsing come from the generic
0013 [`@dexvis/app-features`](https://github.com/dexvis/app-features-ng) package;
0014 `@dexvis/firebird-ng` re-exports what extension authors use, so the imports on
0015 this page stay `@dexvis/firebird-ng`.
0016 
0017 ## Command anatomy
0018 
0019 ```ts
0020 interface FbCommand {
0021   type: string;                 // selects the handler, e.g. 'open-dex'
0022   source?: 'url' | 'server' | 'batch' | 'ui' | 'code';
0023   [key: string]: unknown;       // handler-specific arguments
0024 }
0025 ```
0026 
0027 `FbCommand` is the same type as `AppCommand` from `@dexvis/app-features`;
0028 use either name.
0029 
0030 The same command can be written as a URL-grammar string: `type:argument`.
0031 Multiple commands join with `;`. The argument is everything after the FIRST
0032 colon, so URLs with colons survive: `open-dex:https://host/file.zip`.
0033 
0034 ## Built-in commands
0035 
0036 | Type            | Arguments            | URL grammar                    | Action |
0037 |-----------------|----------------------|--------------------------------|--------|
0038 | `open-geometry` | `url`                | `open-geometry:<url>`          | Load detector geometry. The loader is chosen from the registered geometry loaders by file extension / URL scheme. |
0039 | `open-dex`      | `url`                | `open-dex:<url>`               | Load event data. DEX json/zip and `.root` (server conversion) are chosen the same registry-driven way. |
0040 | `show-event`    | `index` (number)     | `show-event:2`                 | Select event by index. Waits up to 30 s for events to finish loading first. |
0041 | `set-config`    | `key`, `value`       | `set-config:key=value`         | Set a configuration value. From `url`/`server`/`batch` sources the value is session-scoped (not persisted); from `ui`/`code` it is saved normally, converted to the key's type (`'7'` becomes `7` for a numeric key). A key that no code declared yet keeps the value until the declaration arrives, which then sets the key's default and type. |
0042 | `camera-preset` | `name`               | `camera-preset:top`            | Move the camera to a named preset (`withCameraPreset()`). Face views `front`, `back`, `left`, `right`, `top`, `bottom` keep the current orbit target and distance; `home` is the start view (the top view framing the geometry, or the view a pack pinned). The flagship's ePIC pack adds the fixed poses `center` and `farforward`. |
0043 | `animate-collision` | none             | `animate-collision`            | Play the collision intro (`withCollisionIntro()`), then the event's time animation from the start. Without an intro, the time animation starts at once. |
0044 
0045 The URL shorthands `?dex=`, `?geometry=`, `?event=` expand to `open-dex`,
0046 `open-geometry`, `show-event`: `?dex=X` queues the same command as
0047 `?cmd=open-dex:X`, built by the handler's `fromUrlArg()`. Unlike a `?cmd=`
0048 item, a shorthand value may contain `;`.
0049 
0050 Face presets follow the accelerator (HENP) axis convention: the beam runs
0051 along Z (pointing right on screen in the front view), Y is up, and X points
0052 toward the accelerator center. The top and bottom views keep Z horizontal on
0053 screen. The same views are reachable interactively through the navigation
0054 cube in the display's top-right corner.
0055 
0056 ## Where commands come from
0057 
0058 Commands queue at application startup and run once the 3D scene is
0059 initialized, in this order:
0060 
0061 1. **Server**: the `startupCommands` array in `config.jsonc` (or injected by
0062    pyrobird — see below). Entries are command objects or grammar strings.
0063 2. **URL**: the shorthands and `?cmd=...` from the page address.
0064 
0065 Server commands queue first, so a URL deep link can follow up on or override
0066 what the server started. Execution is sequential — each command awaits the
0067 previous one, which is why `show-event` after `open-dex` works reliably.
0068 When startup commands carry data-loading commands, the corresponding
0069 config-driven auto-load is skipped (no double loading).
0070 
0071 ### Server configuration
0072 
0073 ```jsonc
0074 // config.jsonc
0075 {
0076   "startupCommands": [
0077     "open-dex:mydata.firebird.zip;show-event:2",
0078     { "type": "camera-preset", "name": "farforward" }
0079   ]
0080 }
0081 ```
0082 
0083 With pyrobird, pass commands from the CLI instead of editing files:
0084 
0085 ```bash
0086 pyrobird serve --startup-commands "open-dex:mydata.firebird.zip;show-event:2"
0087 pyrobird screenshot --commands "open-dex:mydata.firebird.zip;show-event:2;camera-preset:farforward"
0088 ```
0089 
0090 ## Readiness flags for batch tools
0091 
0092 The display publishes its state to `window.firebird` so headless drivers know
0093 when it is safe to capture:
0094 
0095 ```js
0096 window.firebird = {
0097   geometryReady: true,        // geometry finished loading (or none pending)
0098   startupCommandsDone: true,  // the startup queue ran to completion
0099   pendingLoads: 0,            // in-flight geometry/event loads
0100   ready: true,                // all of the above - safe to screenshot
0101   errors: [],                 // messages of failed loads and startup commands
0102 }
0103 ```
0104 
0105 A load counts from the moment it is requested, including a ROOT file that the
0106 browser converts first. A load that a newer one replaced stops counting. A
0107 load that fails still settles, so `ready` turns true; its message lands in
0108 `errors` and on screen. `errors` also lists every startup command that threw.
0109 
0110 `pyrobird screenshot` waits for `ready === true` or the first error, saves
0111 the screenshot either way, and reports the outcome in its exit code: 0 ready
0112 without errors, 1 server, browser or capture failure, 2 never ready within
0113 `--ready-timeout`, 3 non-empty `errors`. Custom Playwright/Puppeteer scripts
0114 should wait the same way and check `errors`:
0115 
0116 ```js
0117 await page.waitForFunction("window.firebird && window.firebird.ready === true");
0118 const errors = await page.evaluate(() => window.firebird.errors);
0119 ```
0120 
0121 The object exists only on the display route, after the display page
0122 initializes.
0123 
0124 ## Adding your own command
0125 
0126 A command handler is a class registered through the extension system (see
0127 [Extension System](/extensions)):
0128 
0129 ```ts
0130 import { Injectable } from '@angular/core';
0131 import { CommandHandler, FbCommand } from '@dexvis/firebird-ng';
0132 
0133 @Injectable()
0134 export class FocusDetectorCommandHandler implements CommandHandler {
0135   readonly type = 'focus-detector';
0136 
0137   // optional: how '?cmd=focus-detector:DIRC' maps to the command object
0138   fromUrlArg(arg: string): FbCommand {
0139     return { type: this.type, detectorName: arg };
0140   }
0141 
0142   async execute(command: FbCommand): Promise<void> {
0143     const name = command['detectorName'] as string;
0144     // ... find the detector node, move the camera
0145   }
0146 }
0147 ```
0148 
0149 ```ts
0150 // app.config.ts
0151 provideFirebird(
0152   withCommandHandler(FocusDetectorCommandHandler),
0153 )
0154 ```
0155 
0156 The handler class is instantiated through dependency injection, so `inject()`
0157 works in it. One handler per type; registering an existing type replaces the
0158 built-in — that is allowed and deliberate. After registration the command
0159 works from every source: `?cmd=focus-detector:DIRC` in a link,
0160 `startupCommands` on a server, `--commands` in batch.
0161 
0162 Not implemented on purpose (yet): undo/rewind and command journaling. The
0163 `source` field exists so a journal can be added later without changing
0164 dispatch call sites.