@patterkit/runtime 0.4.5 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -25,6 +25,18 @@ version number always means the same runtime behaviour. This package is versione
25
25
 
26
26
  ## [Unreleased]
27
27
 
28
+ ## [0.5.0] - 2026-08-21
29
+
30
+ ### Added
31
+
32
+ - **Cast lists you can query at runtime.** Three static reads answer "who is in this?": the cast the
33
+ project declares, the speakers of a scene, and the speakers of one block. Scene and block refs take
34
+ an internal id or a gameId address. The result is the character token a line beat carries, deduped
35
+ and ordered by first appearance, and it is derived from the AUTHORED structure, so a speaker behind a
36
+ condition, inside a group, or voicing a choice prompt is included: it answers who *can* speak, not
37
+ who a given playthrough heard. Held across all four runtimes by the conformance corpus.
38
+ `engine.getCast()`, `engine.castForScene(sceneRef)`, `engine.castForBlock(sceneRef, blockRef)`.
39
+
28
40
  ## [0.4.5] - 2026-08-20
29
41
 
30
42
  ### Changed
package/dist/index.cjs CHANGED
@@ -360,6 +360,42 @@ var Engine = class _Engine {
360
360
  const id = this.resolveBlockRef(sceneId, blockRef);
361
361
  return (id != null ? this.host.tagIndex.get(id) : void 0) ?? [];
362
362
  }
363
+ /**
364
+ * Every cast member the PROJECT declares, in authored order - the same list `describeBundle` counts.
365
+ * A superset of any scene's cast: the validator holds a beat's `character` to a declared member, so
366
+ * {@link castForScene} and {@link castForBlock} only ever return names that appear here.
367
+ */
368
+ getCast() {
369
+ const names = [];
370
+ for (const c of this.host.bundle.cast ?? []) if (c?.name) names.push(c.name);
371
+ return names;
372
+ }
373
+ /**
374
+ * A scene's cast: the `character` token of every speaker with a line anywhere in it, deduped, in
375
+ * first-appearance order. Static, like {@link getOutline}: it walks the authored structure, so a
376
+ * speaker behind a condition, inside any group, or voicing a choice prompt counts - this is who CAN
377
+ * speak in the scene, not who a given playthrough heard. Empty for an unknown ref, or a scene with no
378
+ * dialogue. Tokens, not display names: resolve those through the delivered step (`characterName`),
379
+ * which is what follows `setLocale`.
380
+ */
381
+ castForScene(sceneRef) {
382
+ const id = this.resolveSceneRef(sceneRef);
383
+ const scene = id != null ? this.host.bundle.scenes[id] : void 0;
384
+ if (!scene) return [];
385
+ const out = /* @__PURE__ */ new Set();
386
+ for (const block of scene.blocks) collectCast(block.children, out);
387
+ return [...out];
388
+ }
389
+ /** One block's cast, by scene + block ref (id or gameId). {@link castForScene} scoped to a block. */
390
+ castForBlock(sceneRef, blockRef) {
391
+ const sceneId = this.resolveSceneRef(sceneRef);
392
+ const id = this.resolveBlockRef(sceneId, blockRef);
393
+ const block = id != null ? this.host.blockById.get(id) : void 0;
394
+ if (!block) return [];
395
+ const out = /* @__PURE__ */ new Set();
396
+ collectCast(block.children, out);
397
+ return [...out];
398
+ }
363
399
  /**
364
400
  * The authored structure as a nested tree: scenes -> blocks -> children (groups + snippets, groups
365
401
  * preserved) -> a snippet's beats. Static (no flow / play state); per-beat data is read at the source
@@ -1353,6 +1389,15 @@ var Flow = class {
1353
1389
  }
1354
1390
  }
1355
1391
  };
1392
+ function collectCast(nodes, out) {
1393
+ (0, import_model.walkNodes)(nodes, (n) => {
1394
+ if (n.type === "group") {
1395
+ if (n.prompt?.kind === "line" && n.prompt.character) out.add(n.prompt.character);
1396
+ return;
1397
+ }
1398
+ for (const beat of n.beats ?? []) if (beat.kind === "line" && beat.character) out.add(beat.character);
1399
+ });
1400
+ }
1356
1401
  function serialiseSelectors(map) {
1357
1402
  const out = {};
1358
1403
  for (const [id, st] of map) {