@plaintake/scenario 1.9.0 → 1.10.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/dist/index.js CHANGED
@@ -543,6 +543,7 @@ var SpeechSchema = z5.object({
543
543
  message: "engine must be recorded whenever any clip was synthesised",
544
544
  path: ["engine"]
545
545
  });
546
+ var ThemeSchema = z5.object({ accentColor: HEX_COLOUR });
546
547
  var RENDER_PLAN_SCHEMA = "agent-demo.render/v1";
547
548
  var RenderPlanSchema = z5.object({
548
549
  schema: z5.literal(RENDER_PLAN_SCHEMA),
@@ -730,6 +731,31 @@ var RenderPlanSchema = z5.object({
730
731
  camera: CameraSchema.optional(),
731
732
  highlight: HighlightSchema.optional(),
732
733
  speech: SpeechSchema.optional(),
734
+ /**
735
+ * The branding decision, resolved once from the licence and configuration at run time
736
+ * and frozen whole — the accent the cursor's fill, its click-ripple ring and the
737
+ * highlight label's text all draw. See `ThemeSchema`.
738
+ *
739
+ * Optional and **never defaulted**. The plan's own JSON is a weaker claim than the
740
+ * render — the schema doc above records how a Zod `.default()` materialises on parse,
741
+ * so `stableStringify` writes the field into `render/render-plan.json` and diverges the
742
+ * committed golden plan, which is what `style`'s defaults already did once. A default
743
+ * here would do it again on every parse; absent means off, and the object appears only
744
+ * when a theme was actually resolved.
745
+ *
746
+ * Top-level — a sibling of `intro`/`outro`/`cursor`/`highlight`, not a key inside one
747
+ * of them — so `recutPlan`'s `{...plan}` spread carries it through `--aspect` re-cuts
748
+ * unchanged; a nested key would need explicit handling there.
749
+ *
750
+ * The plan is not `.strict()`, so an older binary strips a `theme` it has never heard
751
+ * of — but a plain re-render is unaffected by that: `renderBundle` executes the frozen
752
+ * themed `cursor.ass`/`highlight.ass` verbatim and never regenerates them, exactly as
753
+ * an older build ignoring `speech` still muxes the frozen WAV. The hardcoded colours
754
+ * return only where derived files are *redrawn* — a fresh freeze, or a `render
755
+ * --aspect` re-cut, whose `writeCaptions(recut)` regenerates the tracks from a plan the
756
+ * older binary's own re-parse has stripped `theme` out of.
757
+ */
758
+ theme: ThemeSchema.optional(),
733
759
  /**
734
760
  * The capture timeline cut into windows — of a genuine multi-actor cast, of an implicit
735
761
  * single actor pausing for explain cut-aways, or both at once. `segments` is the one
@@ -296,9 +296,11 @@ export declare const TRANSITION_CARD_DEFAULT_MS = 3000;
296
296
  * to be a pure function of the plan, so the rect a step measured has to survive plan freeze
297
297
  * as a rect, not merely as a decision to draw one.
298
298
  *
299
- * `startMs`/`endMs` bound the whole step, not a retimed lead/rest/glide the way a cursor
300
- * point is — a spotlight has no motion to choreograph, so unlike `CursorPointSchema` there is
301
- * nothing here to pull earlier or hold open.
299
+ * `startMs`/`endMs` carry a window the derivation already retimed, the way a cursor point's
300
+ * do: a click's brackets the press — opening when the pointer parks and closing as the click
301
+ * ripple ends — while a continuous action's spans its whole step. The times are frozen as
302
+ * computed, so unlike `CursorPointSchema` (whose `rippleMs` the emitter re-derives fades
303
+ * around) there is no further choreography left for the render to do.
302
304
  *
303
305
  * `label` is the optional callout text a scenario may attach (`highlight: { label: '...' }`).
304
306
  * Absent means the spotlight alone, exactly what `highlight: true` (no object) asks for.
@@ -457,6 +459,54 @@ export type IntroInput = Omit<Intro, 'assPath'>;
457
459
  * position in the array against the schema's own `captions/turn-[0-9]+\.ass` family.
458
460
  */
459
461
  export type TransitionCardInput = Omit<TransitionCard, 'assPath'>;
462
+ /**
463
+ * The brand accent: one colour shared by the cursor's fill, its click-ripple ring and the
464
+ * highlight label's text. One field rather than one per consumer, because the cursor and
465
+ * the highlight should never disagree about the brand — the same "one block, one decision"
466
+ * shape as every other optional capability on the plan.
467
+ *
468
+ * Present only when a theme actually resolved — Pro tier, branding enabled, at least one
469
+ * colour named. Absent means every hardcoded colour the emitters already draw, so
470
+ * an unbranded run's `cursor.ass`/`highlight.ass` are exactly what they always were.
471
+ * Caption colours deliberately do not live here: `RenderPlanSchema.style` already carries
472
+ * `textColor`/`outlineColor`/`boxColor` as the single source of `captions/captions.ass`,
473
+ * and theming captions is a change to what gets frozen into those, not a second place a
474
+ * colour can hide.
475
+ *
476
+ * `accentColor` is `HEX_COLOUR` for the reason every plan colour is: the value reaches
477
+ * `assColour` and from there an ASS override tag, and `#RRGGBB` admits no ASS
478
+ * metacharacter. It is stored in the form the author wrote and converted to `&HAABBGGRR`
479
+ * only at emission, so the bundle shows the colour, not its encoding.
480
+ *
481
+ * Like the inputs above, this is the decision as the application layer supplies it — but
482
+ * it is the narrow end of a wider input: `buildRenderPlan` takes the four-field
483
+ * `ThemeInput` below and freezes only the accent here, because the caption colours have
484
+ * somewhere else to go.
485
+ */
486
+ export declare const ThemeSchema: z.ZodObject<{
487
+ accentColor: z.ZodString;
488
+ }, z.core.$strip>;
489
+ export type Theme = z.infer<typeof ThemeSchema>;
490
+ /**
491
+ * The theme decision as the application layer supplies it — all four colours a licence can
492
+ * resolve, in the same shape `@plaintake/license`'s `resolveTheme` returns, exactly as
493
+ * `OutroInput`/`IntroInput` are the shapes its other resolvers return. Only the fields the
494
+ * user actually configured appear; each absent field keeps the hardcoded default at the
495
+ * freeze, so recolouring `accentColor` alone is a complete theme.
496
+ *
497
+ * Wider than `ThemeSchema` on purpose. The plan-level block carries only `accentColor`
498
+ * because the three caption colours freeze into `RenderPlanSchema.style` — the single
499
+ * source `captions.ass` already reads — while the accent has no style field to freeze
500
+ * into and needs the plan key. A theme with no accent therefore freezes no `theme` key at
501
+ * all: the schema requires one, and defaulting it would recolour cursor surfaces the
502
+ * author never asked about.
503
+ */
504
+ export type ThemeInput = {
505
+ accentColor?: string | undefined;
506
+ captionTextColor?: string | undefined;
507
+ captionOutlineColor?: string | undefined;
508
+ captionBoxColor?: string | undefined;
509
+ };
460
510
  /**
461
511
  * The one value a plan's `schema` field ever holds.
462
512
  *
@@ -663,6 +713,9 @@ export declare const RenderPlanSchema: z.ZodObject<{
663
713
  voice: z.ZodString;
664
714
  }, z.core.$strip>>;
665
715
  }, z.core.$strip>>;
716
+ theme: z.ZodOptional<z.ZodObject<{
717
+ accentColor: z.ZodString;
718
+ }, z.core.$strip>>;
666
719
  actors: z.ZodOptional<z.ZodArray<z.ZodObject<{
667
720
  id: z.ZodString;
668
721
  label: z.ZodString;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plaintake/scenario",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "Authoring SDK for PlainTake demo scenarios: defineDemo and the scenario DSL types. Install for editor autocomplete; the PlainTake binary ships a runtime fallback.",
5
5
  "license": "MIT",
6
6
  "type": "module",