@jokerized/decksmith 0.9.4 → 0.9.6

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.
Files changed (50) hide show
  1. package/dist/cli.js +20775 -10046
  2. package/dist/deck-runtime.js +2 -2
  3. package/dist/index.js +11549 -1433
  4. package/dist/mcp.js +10824 -1086
  5. package/dist/types/bespoke/pipeline.d.ts +1 -1
  6. package/dist/types/bespoke/scene.d.ts +18 -2
  7. package/dist/types/emit/archetypes/index.d.ts +15 -0
  8. package/dist/types/emit/composition.d.ts +16 -1
  9. package/dist/types/emit/kit.d.ts +33 -0
  10. package/dist/types/emit/svg.d.ts +19 -0
  11. package/dist/types/emit/tex.d.ts +13 -0
  12. package/dist/types/literal/check.d.ts +45 -0
  13. package/dist/types/literal/formula.d.ts +78 -0
  14. package/dist/types/literal/index.d.ts +133 -0
  15. package/dist/types/literal/kind.d.ts +121 -0
  16. package/dist/types/literal/kinds/common.d.ts +280 -0
  17. package/dist/types/literal/kinds/evolve.d.ts +58 -0
  18. package/dist/types/literal/kinds/flow.d.ts +13 -0
  19. package/dist/types/literal/kinds/operate.d.ts +27 -0
  20. package/dist/types/literal/kinds/place-combos.d.ts +33 -0
  21. package/dist/types/literal/kinds/place-lengths.d.ts +36 -0
  22. package/dist/types/literal/kinds/place-margins.d.ts +44 -0
  23. package/dist/types/literal/kinds/place-sets.d.ts +31 -0
  24. package/dist/types/literal/kinds/place.d.ts +69 -0
  25. package/dist/types/literal/kinds/prior-work.d.ts +29 -0
  26. package/dist/types/literal/kinds/read.d.ts +33 -0
  27. package/dist/types/literal/kinds/recap.d.ts +16 -0
  28. package/dist/types/literal/kinds/region.d.ts +56 -0
  29. package/dist/types/literal/kinds/stage.d.ts +108 -0
  30. package/dist/types/literal/kinds/svg.d.ts +65 -0
  31. package/dist/types/literal/kinds/table.d.ts +19 -0
  32. package/dist/types/literal/kinds/tex.d.ts +6 -0
  33. package/dist/types/literal/kinds-shared.d.ts +15 -0
  34. package/dist/types/literal/kit.d.ts +86 -0
  35. package/dist/types/literal/ops.d.ts +56 -0
  36. package/dist/types/literal/registry.d.ts +20 -0
  37. package/dist/types/plan/codex.d.ts +28 -5
  38. package/dist/types/plan/coverage.d.ts +179 -0
  39. package/dist/types/plan/duration.d.ts +2 -0
  40. package/dist/types/plan/locate.d.ts +46 -0
  41. package/dist/types/plan/prompt.d.ts +14 -1
  42. package/dist/types/plan/variety.d.ts +23 -0
  43. package/dist/types/render/timing.d.ts +7 -1
  44. package/dist/types/source/harvest.d.ts +1 -0
  45. package/dist/types/types.d.ts +21451 -933
  46. package/dist/types/verify/fidelity.d.ts +7 -2
  47. package/dist/types/verify/fill.d.ts +70 -9
  48. package/dist/types/verify/overprint.d.ts +46 -0
  49. package/dist/types/verify/scenes.d.ts +61 -2
  50. package/package.json +1 -1
@@ -201,7 +201,7 @@ export interface BespokeResult {
201
201
  * What a cached verdict was reached under: the browser's gates and the static
202
202
  * `card_row`. A rejection stamped otherwise is asked about again.
203
203
  */
204
- export declare const GATE_STAMP = "gates-7+cards-2:0.08/0.6/0.8/0.2/0.12";
204
+ export declare const GATE_STAMP = "gates-8+cards-2:0.08/0.6/0.8/0.2/0.12";
205
205
  /** A second critique starts only with this much of the wall-time cap left, seconds. */
206
206
  export declare const SECOND_SECONDS = 420;
207
207
  /** Repair rounds after the final gates, each one probe build of the repaired scenes only. */
@@ -13,6 +13,12 @@ export interface BespokeEntry {
13
13
  holds: number[];
14
14
  /** The beat's illustration, when it has one: `<image data-art="1">` shows it (src/bespoke/art.ts). */
15
15
  art?: ArtRef;
16
+ /**
17
+ * The section name above the headline when the beat's archetype has no
18
+ * `eyebrow` of its own (a stage, a kinetic beat): a literal scene's `eyebrow`
19
+ * slot. The archetype's own eyebrow wins.
20
+ */
21
+ eyebrow?: string;
16
22
  /**
17
23
  * The narration cues on the scene's clock and its length, from the same
18
24
  * timing the cue windows came from: what the shell's camera is timed to
@@ -29,6 +35,12 @@ export interface BespokeEntry {
29
35
  grammar?: Grammar;
30
36
  /** A data scene's build (src/bespoke/databuild.ts), stamped on the scene for the deck gate. */
31
37
  build?: DataBuild;
38
+ /**
39
+ * Clip the body to its box, as a camera scene is. A literal scene (src/literal/) sets it:
40
+ * its pictures move inside their own clipped panels (a push-in on a detail), and the
41
+ * clip is what tells the layout gate that what they carry past a panel is not painted.
42
+ */
43
+ clip?: true;
32
44
  }
33
45
  /** The file `build` writes beside a deck with the bespoke pass's account of itself. */
34
46
  export declare const BESPOKE_FILE = "bespoke.json";
@@ -36,8 +48,12 @@ export declare const BESPOKE_FILE = "bespoke.json";
36
48
  export type BespokeMap = Readonly<Record<string, BespokeEntry>>;
37
49
  /** Space the body box leaves under the chrome — the same 34px `bodyBudget` charges by default. */
38
50
  export declare const BODY_TOP = 34;
39
- /** The box the generated drawing gets, in reference px. The prompt quotes it. */
40
- export declare function bespokeRegion(beat: Beat, ctx: Pick<EmitContext, "format" | "theme">): {
51
+ /**
52
+ * The box the generated drawing gets, in reference px. The prompt quotes it.
53
+ * `eyebrow` is the scene's own section name when the archetype has none
54
+ * (`BespokeEntry.eyebrow`): it takes a line of the chrome too.
55
+ */
56
+ export declare function bespokeRegion(beat: Beat, ctx: Pick<EmitContext, "format" | "theme">, eyebrow?: string): {
41
57
  width: number;
42
58
  height: number;
43
59
  };
@@ -10,3 +10,18 @@ export declare const emitters: {
10
10
  * every archetype has exactly one emitter of the right shape.
11
11
  */
12
12
  export declare function emitScene(beat: Beat, ctx: EmitContext): Scene;
13
+ /**
14
+ * v2: every PART of a scene stands at `PREVIEW` from the open instead of
15
+ * arriving from nothing, and comes to full when its tween runs — so every hold
16
+ * shows the whole layout (the fill gate measures the content's box at each one,
17
+ * src/verify/fill.ts) and the reveal still says which part is being spoken to.
18
+ *
19
+ * A part is an element addressed by id alone whose FIRST tween fades it in
20
+ * from 0, and which no later tween fades out again: a transient (a packet, a
21
+ * morph's intermediate, a highlight that comes and goes) or a part shown in
22
+ * place of another would read as a ghost, so it keeps its own entrance. The
23
+ * chrome and class-addressed words are left alone. The entrance's offset and
24
+ * scale (`x`, `y`, `scale…`) are dropped: a previewed part stands where and as
25
+ * large as it lands, so its words are never drawn under their declared size.
26
+ */
27
+ export declare function previewParts(scene: Scene, sid: string): Scene;
@@ -241,10 +241,25 @@ export declare function openSeconds(scene: Scene): number;
241
241
  * divergence between them is invisible. Sharing the code is the only thing that
242
242
  * makes them the same answer.
243
243
  */
244
- export declare function stageScene(scene: Scene, speed: number): {
244
+ export declare function stageScene(scene: Scene, speed: number,
245
+ /** The beat's sentences, for an ARCHETYPE scene: see `onSentences`. */
246
+ segments?: readonly Segment[]): {
245
247
  scene: Scene;
246
248
  open: number;
247
249
  };
250
+ /**
251
+ * An archetype scene with a slow lean through each still stretch of its speech.
252
+ *
253
+ * `onSentences` lands each reveal on its sentence, but one sentence is often 7-9s
254
+ * and an archetype reveals once per sentence, so the rest of it stood still: r2 of
255
+ * the literal verbs run had ten `dead_stretch` failures, every one an archetype (a
256
+ * title held 8.9s, a callout panel 8.5s). Literal scenes already lean their camera
257
+ * over what is left of a sentence (`drift` in src/literal/kind.ts); this is the same
258
+ * move on the scene box: in and back out between a reveal's hold and the next
259
+ * reveal (or the scene's end), so every hold — where the layout gates photograph —
260
+ * sees the scene at rest, and the exit's own `scale: 1` from-state does not jump.
261
+ */
262
+ export declare function leanThroughSentences(scene: Scene, sid: string, seconds: number): Scene;
248
263
  /**
249
264
  * When each sentence of a beat is spoken, on one continuous clock.
250
265
  *
@@ -195,6 +195,12 @@ export interface EmitContext {
195
195
  source: Source;
196
196
  format: Format;
197
197
  theme: Theme;
198
+ /**
199
+ * The deck's language (the storyboard's BCP-47 `lang`). A figure's own caption
200
+ * is printed only when it is written in it (`inLanguage`). Absent: printed as
201
+ * before.
202
+ */
203
+ lang?: string;
198
204
  /**
199
205
  * This scene's root element id, e.g. `"s3"`. Every GSAP selector must be
200
206
  * scoped with it — an unscoped class selector reaches into other scenes and
@@ -503,6 +509,25 @@ export declare function js(s: string): string;
503
509
  * `-h` or `-e` to a spotlight.
504
510
  */
505
511
  export declare const DIM = 0.62;
512
+ /**
513
+ * Where a v2 part not yet spoken stands, from the scene's open: the whole
514
+ * layout is on screen at every hold — the fill gate measures the content's box
515
+ * at each one (src/verify/fill.ts) — and a part comes to full when it is spoken.
516
+ * Below `DIM` on purpose: it reads as "coming", not as "said".
517
+ */
518
+ export declare const PREVIEW = 0.32;
519
+ /**
520
+ * When the preview fades up, scene seconds: after the seam into the scene (the
521
+ * outgoing slide is gone by then, so nothing previewed overlaps its words) and
522
+ * before the first hold.
523
+ */
524
+ export declare const PREVIEW_AT = 0.5;
525
+ /**
526
+ * A v2 part's two tweens: up to `PREVIEW` as the scene opens, then to `to` at
527
+ * `at`, from where the preview left it. A part revealed during the opening
528
+ * keeps its plain entrance, since its preview would not be seen.
529
+ */
530
+ export declare function previewed(target: string, from: Vars, to: Vars, at: number): Tween[];
506
531
  /**
507
532
  * How much bigger the part under discussion stands than its neighbours.
508
533
  *
@@ -624,3 +649,11 @@ export declare function wordAtoms(text: string): {
624
649
  text: string;
625
650
  spaced: boolean;
626
651
  }[];
652
+ /**
653
+ * Whether `text` is written in the script of `lang`: Hangul for Korean, kana or
654
+ * Han for Japanese, Han for Chinese, and no CJK at all for any other language.
655
+ * A heuristic on script, which is what an untranslated caption gets wrong.
656
+ */
657
+ export declare function inLanguage(text: string, lang: string): boolean;
658
+ /** The caption a figure prints: the plan's own, else the source's when it is in the deck's language, else none. */
659
+ export declare function figureCaption(planned: string | undefined, source: string, lang: string | undefined): string;
@@ -189,6 +189,25 @@ export declare function textWidth(text: string, fontSize: number, weight?: numbe
189
189
  * one unbroken "word".
190
190
  */
191
191
  export declare function wrap(text: string, fontSize: number, maxWidth: number, weight?: number, tracking?: number, face?: Face): string[];
192
+ /**
193
+ * A run with no spaces as the units a line may break between: a number or a
194
+ * Latin name whole ("88.84", "OneVL", "T5-XXL"), any other character alone, and
195
+ * closing punctuation kept on the unit before it so no line starts with ":".
196
+ */
197
+ export declare function atomsOf(word: string): string[];
198
+ /**
199
+ * A figure's caption as a slide sets it, in at most `lines` lines of `width`.
200
+ *
201
+ * Its first sentence — the "Figure 5: A simplified trace diagram…" title the
202
+ * authors wrote — and, where even that is too long, cut at a word (a character,
203
+ * in a script with no spaces) with the ellipsis typed into the text. A caption
204
+ * is provenance; a paper's own runs to 600 characters ("Figure 1: Our technique
205
+ * illustrated…" from arXiv), which beside a claim took the whole column and
206
+ * left the figure a 30px plate, and under an annotated figure was clamped by
207
+ * CSS, which the layout gate rightly calls clipped text. The full caption stays
208
+ * the image's alt.
209
+ */
210
+ export declare function captionFit(caption: string, fontSize: number, width: number, lines: number, face?: Face, weight?: number): string;
192
211
  /**
193
212
  * Whether `wrap` would have to cut a word letter by letter to set `text` at
194
213
  * this size and width — "Rectified-flo" / "w". `wrap` does that as a last
@@ -6,6 +6,19 @@
6
6
  export declare const UNFIT_ATTR = "data-ds-unfit";
7
7
  /** KaTeX's message for `tex`, or null when it parses. Same options the deck uses. */
8
8
  export declare function texError(tex: string, display: boolean): string | null;
9
+ /**
10
+ * A command whose backslash was doubled on the way in, or null.
11
+ *
12
+ * `\\frac{p}{q}` PARSES — KaTeX reads a line break, then the letters f r a c —
13
+ * so `texError` passes it and the slide says "fracpq". Doubling is what a
14
+ * markdown escape does to TeX (measured on arXiv 2211.17192, every inline
15
+ * equation of it). Outside an environment a line break directly before a
16
+ * letter is not something a formula is written with, so it is refused rather
17
+ * than guessed at: the fix belongs where the TeX was read, not here.
18
+ */
19
+ export declare function escapedCommand(tex: string): string | null;
20
+ /** The sentence a build fails with for `escapedCommand`'s finding. */
21
+ export declare function escapedCommandError(where: string, id: string, tex: string): string | null;
9
22
  export interface Repaired {
10
23
  /** The TeX to render: the input when it parsed, otherwise the repaired form. */
11
24
  tex: string;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * PLAN-TIME CHECKS: every literal scene drawn as the build draws it, at the
3
+ * region and in the face the build lays it out with, without its material — a
4
+ * verb on placeholder material (its own run), a word form or a cross-cutting
5
+ * kind by its fragment on placeholder layers and no cues. What it refuses (a
6
+ * step label with no room, a lane with nothing to show, rings that do not fit,
7
+ * a parameter an op does not take) is sent back to the planner for repair
8
+ * instead of failing `build --literal`.
9
+ */
10
+ import type { Theme } from "../emit/kit.js";
11
+ import type { Literal } from "../types.js";
12
+ /** What stops a literal scene being drawn at `region`, or nothing. */
13
+ export declare function drawProblems(lit: Literal, region_: {
14
+ width: number;
15
+ height: number;
16
+ }, theme: Theme): string[];
17
+ /**
18
+ * When each part of a literal scene's script is first SHOWN — a fade from 0 or a
19
+ * wipe from width 0 — and when that reveal ends, scene seconds, in order. Read
20
+ * off the emitted script (`Tl` writes JSON), so it judges what ships. A part
21
+ * hidden only by its parent is not seen here.
22
+ */
23
+ export declare function firstShown(script: string): Array<{
24
+ id: string;
25
+ at: number;
26
+ end: number;
27
+ }>;
28
+ /** A part must stand whole on screen at least this long before its scene cuts away. */
29
+ export declare const SEEN_WHOLE_S = 1;
30
+ /**
31
+ * The parts of a literal scene that arrive too late to be seen: first shown
32
+ * less than `SEEN_WHOLE_S` before the scene ends (`duration`, scene seconds),
33
+ * or still arriving when it does. r2's scope lit its last item so late that
34
+ * the 2s frames never caught it before the cut.
35
+ *
36
+ * A step after the last hold is the stage's business, not this check's: the
37
+ * holds are the starts of the narration's STOPS, and the stage
38
+ * (src/literal/kinds/stage.ts) puts a scene's last step no later than the
39
+ * sentence that opens its last stop, then tours the finished picture.
40
+ */
41
+ export declare function lateReveals(script: string, duration: number): Array<{
42
+ id: string;
43
+ at: number;
44
+ end: number;
45
+ }>;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * A TINY FORMULA GRAMMAR for the expressions a source prints: numbers, names
3
+ * (Greek letters, subscripts: α, γ, x0, C_v), + − × ÷ ^, parentheses, and
4
+ * min max abs exp log sqrt clip. Parsed once, evaluated on numbers (the build)
5
+ * or on INTERVALS (the truth gate).
6
+ *
7
+ * Why intervals: a source prints rounded numbers. "α = 0.6, γ = 2 → 1.96X" is
8
+ * three rounded values, and a correct formula evaluated at the printed 0.6 can
9
+ * miss the printed 1.96 at the last digit. So a check is passed when the
10
+ * formula, over every input's printed-precision interval, reaches the output's
11
+ * own interval: a correct formula always passes, a wrong one almost never does
12
+ * across a table's rows. A decimal input carries half a unit of its last digit;
13
+ * an integer input is taken as exact (a count, not a measurement).
14
+ *
15
+ * No variable has a default and nothing is evaluated that the expression does
16
+ * not name. Pure.
17
+ */
18
+ export type Ast = {
19
+ t: "num";
20
+ v: number;
21
+ } | {
22
+ t: "var";
23
+ name: string;
24
+ } | {
25
+ t: "neg";
26
+ a: Ast;
27
+ } | {
28
+ t: "bin";
29
+ op: "+" | "-" | "*" | "/" | "^";
30
+ a: Ast;
31
+ b: Ast;
32
+ } | {
33
+ t: "call";
34
+ fn: string;
35
+ args: Ast[];
36
+ };
37
+ /** Unicode operators and TeX spacing written as the plain grammar. */
38
+ export declare function normalizeExpr(s: string): string;
39
+ export declare const GREEK: Readonly<Record<string, string>>;
40
+ /** Parse an expression; throws with the expression on anything it cannot read. */
41
+ export declare function parseFormula(src: string): Ast;
42
+ /** The variable names an expression reads. */
43
+ export declare function variablesOf(ast: Ast): string[];
44
+ /** Evaluate on numbers; a name with no value throws. */
45
+ export declare function evaluate(ast: Ast, env: Readonly<Record<string, number>>): number;
46
+ export type Iv = readonly [number, number];
47
+ /** Evaluate on intervals: the result holds every value the expression takes over the inputs' boxes. */
48
+ export declare function evaluateIv(ast: Ast, env: Readonly<Record<string, Iv>>): Iv;
49
+ /**
50
+ * A printed number as the interval it stands for: "0.6" is [0.55, 0.65], "2"
51
+ * is exactly 2 for an input (`exact`), [1.5, 2.5] for an output. Undefined
52
+ * when the text is not one plain number.
53
+ */
54
+ export declare function printed(value: string, exact?: boolean): Iv | undefined;
55
+ export interface FormulaCheck {
56
+ inputs: ReadonlyArray<{
57
+ name: string;
58
+ value: string;
59
+ }>;
60
+ output: string;
61
+ }
62
+ /**
63
+ * Whether one check passes: the formula over its inputs' printed intervals
64
+ * (with `fixed` ones added) reaches the printed output's interval. Returns the
65
+ * reason when it does not.
66
+ */
67
+ export declare function checkPasses(ast: Ast, check: FormulaCheck, fixed?: Readonly<Record<string, Iv>>): {
68
+ ok: true;
69
+ } | {
70
+ ok: false;
71
+ why: string;
72
+ };
73
+ /**
74
+ * The expression over every piece of its inputs' boxes, each cut into `k`. Only the
75
+ * variables it reads are cut, and `k` shrinks so there are at most 4096 pieces (k^n
76
+ * grows fast; a coarser cut is still an enclosure, only a wider one).
77
+ */
78
+ export declare function evaluateSplit(ast: Ast, env: Readonly<Record<string, Iv>>, k0: number): Iv[];
@@ -0,0 +1,133 @@
1
+ import { z } from "zod";
2
+ import type { Fragment } from "../bespoke/contract.js";
3
+ import { type BespokeMap } from "../bespoke/scene.js";
4
+ import { type DeckNarration } from "../emit/composition.js";
5
+ import type { Theme } from "../emit/kit.js";
6
+ import { type Timing } from "../render/timing.js";
7
+ import { type Beat, type Format, type LiteralKind, type Source, type Storyboard } from "../types.js";
8
+ import { type Cue, type Layers } from "./kit.js";
9
+ declare const specSchema: z.ZodObject<{
10
+ kind: z.ZodEnum<{
11
+ table: "table";
12
+ "prior-work": "prior-work";
13
+ operate: "operate";
14
+ evolve: "evolve";
15
+ flow: "flow";
16
+ place: "place";
17
+ region: "region";
18
+ recap: "recap";
19
+ }>;
20
+ takeaway: z.ZodString;
21
+ labels: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
22
+ image: z.ZodOptional<z.ZodString>;
23
+ data: z.ZodOptional<z.ZodUnknown>;
24
+ assets: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
25
+ headline: z.ZodOptional<z.ZodString>;
26
+ }, z.core.$strip>;
27
+ export type LiteralSpec = z.infer<typeof specSchema> & {
28
+ kind: LiteralKind;
29
+ };
30
+ /**
31
+ * What the pass draws, by beat. Built from the storyboard's own `literal` beats
32
+ * (`literalPlanOf`), or read from a prototype side file of this shape.
33
+ */
34
+ export declare const literalPlanSchema: z.ZodObject<{
35
+ image: z.ZodOptional<z.ZodString>;
36
+ beats: z.ZodRecord<z.ZodString, z.ZodObject<{
37
+ kind: z.ZodEnum<{
38
+ table: "table";
39
+ "prior-work": "prior-work";
40
+ operate: "operate";
41
+ evolve: "evolve";
42
+ flow: "flow";
43
+ place: "place";
44
+ region: "region";
45
+ recap: "recap";
46
+ }>;
47
+ takeaway: z.ZodString;
48
+ labels: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
49
+ image: z.ZodOptional<z.ZodString>;
50
+ data: z.ZodOptional<z.ZodUnknown>;
51
+ assets: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
52
+ headline: z.ZodOptional<z.ZodString>;
53
+ }, z.core.$strip>>;
54
+ }, z.core.$strip>;
55
+ export type LiteralPlan = z.infer<typeof literalPlanSchema>;
56
+ /** The figure a beat shows: its own, a split-compare side's, or its backdrop's. */
57
+ export declare function figureOf(beat: Beat): string | undefined;
58
+ /**
59
+ * The plan the storyboard carries: every beat with a `literal`, its takeaway,
60
+ * its labels, and the file its `picture` beat's figure lives in (under
61
+ * `assetsDir`, the source's `assets/`). Fails loudly on a picture that does
62
+ * not resolve: a scene computed from no picture is no scene.
63
+ */
64
+ export declare function literalPlanOf(storyboard: Storyboard, source: Source, assetsDir: string): LiteralPlan;
65
+ /**
66
+ * Each of the source's own figures, cut into panels as the build cuts it for a
67
+ * `region` or a figure trace (`panel`). A figure whose file
68
+ * is missing or unreadable is left out: the build names it.
69
+ */
70
+ export declare function figurePanelCounts(source: Source, assetsDir: string): Promise<Record<string, number>>;
71
+ /** Where the computed layers live in a deck. */
72
+ export declare const LITERAL_DIR = "assets/literal";
73
+ /** One literal scene's fragment, in token form, from its computed layers. */
74
+ export declare function literalFragment(kind: LiteralKind, layers: Layers, region: {
75
+ width: number;
76
+ height: number;
77
+ }, cues: readonly Cue[], spec: LiteralSpec, theme: Theme): Fragment;
78
+ /**
79
+ * A scene's script with a slow lean of the whole scene through each still stretch
80
+ * of a sentence: back, and forward to rest before the next sentence starts or the
81
+ * next tween runs, so every hold (a sentence's start) sees the layout as drawn.
82
+ *
83
+ * A kind times its steps on the sentences, but a step is one reveal and a sentence
84
+ * runs 7-9s: r2's results table stood 6.4s after each row lit, and a lengths scene
85
+ * with two groups over four sentences stood 12s across its last two. The kinds
86
+ * that lean their own camera (`drift`) leave no stretch for this to find.
87
+ *
88
+ * Reads the script it is given — every line is `Tl`'s `tl.fromTo(..., {to}, at);`
89
+ * with a JSON `to` — and a line it cannot read counts as busy for 1s, so an
90
+ * unfamiliar line can only make the lean shorter, never overlap a tween.
91
+ */
92
+ export declare function leanThroughStill(script: string, cues: readonly Cue[]): string;
93
+ /**
94
+ * A scene's narration as its SENTENCES — one cue per sentence spoken, from its
95
+ * first subtitle line to its last — on the scene's clock. Not the subtitle
96
+ * lines: the voice splits a long sentence into two lines, and a scene timed on
97
+ * lines took one causal step per half-sentence (r1, b17: the second row lit in
98
+ * the middle of the first row's sentence). Not the stops either: a stage beat
99
+ * speaks several sentences in one stop, and each is still a step.
100
+ */
101
+ export declare function sentenceCues(timing: Pick<Timing, "scenes" | "segments">, sid: string): Cue[];
102
+ export interface LiteralInput {
103
+ storyboard: Storyboard;
104
+ source: Source;
105
+ format: Format;
106
+ narration: DeckNarration;
107
+ theme: string;
108
+ plan: LiteralPlan;
109
+ /** Directory the plan's `image` is relative to. */
110
+ planDir: string;
111
+ /** The deck directory: layers go under `<out>/assets/literal/`. */
112
+ out: string;
113
+ onStep?: (m: string) => void;
114
+ }
115
+ export interface LiteralReport {
116
+ version: 1;
117
+ scenes: Array<{
118
+ beat: string;
119
+ kind: LiteralKind;
120
+ takeaway: string;
121
+ layers: string[];
122
+ cues: Cue[];
123
+ }>;
124
+ }
125
+ /**
126
+ * Compute every literal beat's layers and fragment. A beat not in the plan, or
127
+ * one the cut dropped, keeps its archetype.
128
+ */
129
+ export declare function literalPass(input: LiteralInput): Promise<{
130
+ map: BespokeMap;
131
+ report: LiteralReport;
132
+ }>;
133
+ export {};
@@ -0,0 +1,121 @@
1
+ /**
2
+ * THE KIND CONTRACT: what a literal kind is given and what it returns, plus
3
+ * the drawing helpers every kind shares (slot text, step timing, panels, word
4
+ * wrap). A kind is one module in `src/literal/kinds/` exporting a `KindImpl`,
5
+ * listed once in `src/literal/registry.ts`.
6
+ *
7
+ * EVERY WORD ON SCREEN IS A SLOT (src/types.ts `LITERAL_KIND_DOCS`), with no
8
+ * default: a kind has no paper's facts and no language built in.
9
+ */
10
+ import type { Fragment } from "../bespoke/contract.js";
11
+ import type { Theme } from "../emit/kit.js";
12
+ import type { LiteralKind } from "../types.js";
13
+ import { type Cue, type Layers, type Tl } from "./kit.js";
14
+ /** What a kind is given: its picture (picture kinds), its data (data kinds), the earlier scenes (recap). */
15
+ export interface KindInput {
16
+ beatId: string;
17
+ /** Absolute path of the picture, for a picture kind. */
18
+ image?: string;
19
+ /** Where the layers are written. */
20
+ dir: string;
21
+ region: {
22
+ width: number;
23
+ height: number;
24
+ };
25
+ spec: KindSpec;
26
+ /**
27
+ * The deck's theme: a kind that lays out words at build time measures them in
28
+ * the deck's own face (`widthOf`). Required, so a caller cannot drop it silently.
29
+ */
30
+ theme: Theme;
31
+ /** Earlier literal scenes of this deck, by beat id, in deck order. */
32
+ earlier: ReadonlyMap<string, {
33
+ kind: string;
34
+ layers: Layers;
35
+ labels: Record<string, string>;
36
+ }>;
37
+ }
38
+ export interface KindSpec {
39
+ labels: Record<string, string>;
40
+ /** The storyboard's `literal` object. */
41
+ data?: unknown;
42
+ /**
43
+ * The beat's headline, the words on screen above the scene: an item or a row it
44
+ * NAMES is the scene's subject and is emphasised from the first frame (`namedIn`).
45
+ */
46
+ headline?: string;
47
+ /** The source's own figures a scene may show, by id → absolute file. */
48
+ assets?: Record<string, string>;
49
+ }
50
+ export interface KindImpl {
51
+ /** Whether the kind computes from the deck's picture. */
52
+ picture: boolean;
53
+ layers(input: KindInput): Promise<Layers>;
54
+ fragment(L: Layers, region: {
55
+ width: number;
56
+ height: number;
57
+ }, cues: readonly Cue[], spec: KindSpec, theme: Theme, href: (f: string) => string): Fragment;
58
+ }
59
+ /** A slot's text (src/types.ts `LITERAL_KIND_DOCS`): no defaults, so no paper's facts and no language are built in. */
60
+ export declare const lab: (kind: LiteralKind, spec: KindSpec, slot: string, vars?: Readonly<Record<string, string | number>>) => string;
61
+ export declare const LAB_H = 60;
62
+ /**
63
+ * Whether `text` (a headline) names `name` (an item, a row, a group): the name,
64
+ * without a parenthetical ("Model (variant)" is named by "Model"),
65
+ * as a whole word — so "Net" does not name "Res Net+Head" and "Head" does not
66
+ * name "Res Head". Case and width folded (NFKC). A name of one character names
67
+ * nothing.
68
+ */
69
+ export declare function namedIn(text: string | undefined, name: string): boolean;
70
+ /**
71
+ * The indexes of `names` the headline names — the scene's subject. Empty when it
72
+ * names none, or every one (then nothing stands out from anything).
73
+ */
74
+ export declare function subjectOf(text: string | undefined, names: readonly string[]): Set<number>;
75
+ export declare const even: (n: number) => number;
76
+ /**
77
+ * When `n` causal steps start: on the narration's cues when there are enough,
78
+ * else spread evenly over the narrated span (one step per cue is the rule;
79
+ * this is only for a beat narrated in fewer sentences than it has steps).
80
+ */
81
+ export declare function stepStarts(cues: readonly Cue[], n: number): number[];
82
+ /**
83
+ * A slow move across a real picture (or a computed layer) between two times:
84
+ * the picture's own motion — a push-in on a detail, a pan along it — so a long
85
+ * sentence does not play over a frozen frame. Never a decoration: the element
86
+ * moved is the material the scene computed. `from` is where the previous move
87
+ * of the same element left it.
88
+ */
89
+ export interface Pose {
90
+ x: number;
91
+ y: number;
92
+ scale: number;
93
+ }
94
+ export declare const REST: Pose;
95
+ export declare function drift(tl: Tl, id: string, t0: number, t1: number, to: Pose, from?: Pose, origin?: string): void;
96
+ /**
97
+ * When `n` sub-steps of one step start, spread over the step's own sentence
98
+ * (from `t0` to `t1`, leaving `tail` seconds at the end), never closer than
99
+ * `min` nor further apart than `max`: a step's parts arrive while it is spoken,
100
+ * not in the first second and then nothing.
101
+ */
102
+ export declare function spread(t0: number, t1: number, n: number, min?: number, max?: number, tail?: number): number[];
103
+ export declare function img(id: string, src: string, x: number, y: number, w: number, h: number, extra?: string): string;
104
+ export declare function panel(id: string, x: number, y: number, w: number, h: number, inner: string, cls?: string): string;
105
+ /** Rendered width of a label, px, in the deck's face. */
106
+ export declare function widthOf(text: string, size: number, theme: Theme, weight?: number): number;
107
+ /** Greedy wrap to `maxW` px in the deck's face (`wrapBy`); a unit wider than the line keeps its own line. */
108
+ export declare function wrap(text: string, size: number, maxW: number, theme: Theme, weight?: number): string[];
109
+ /**
110
+ * A label on a picture that wraps to the picture's width instead of running past its
111
+ * edge (a panel clips it: "…적용한 장면 0" in r3 of the pure-planner deck). One element, so
112
+ * a tween of `id` still moves all of it; the browser wraps where `wrap` does — at spaces
113
+ * (keep-all keeps a Korean word whole), and between Han or kana characters, which
114
+ * keep-all would forbid — and `fromBottom` grows it upward from `y` by the lines `wrap`
115
+ * measures.
116
+ */
117
+ export declare function tag(id: string, text: string, x: number, y: number, maxW: number, size: number, color: string, theme: Theme, extra?: string, fromBottom?: boolean): string;
118
+ export declare function std(v: ArrayLike<number>): number;
119
+ export declare function mean(v: ArrayLike<number>): number;
120
+ /** A deterministic sequence in [0, 1): a 32-bit LCG, seeded. Build time only (invariant 4 is render time). */
121
+ export declare function lcg(seed: number): () => number;