@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
@@ -153,6 +153,10 @@ import { type FillRow } from "./fill.js";
153
153
  */
154
154
  export declare const INK_FLOOR = 0.0015;
155
155
  /** One declared stop: which scene, and where on the deck timeline. */
156
+ /** The scene's final state is measured this long before it ends: settled, before the handoff. */
157
+ export declare const FINAL_LEAD = 1;
158
+ /** A final state is measured only this long after the last hold; nearer, the hold is it. */
159
+ export declare const FINAL_GAP = 2;
156
160
  export interface Stop {
157
161
  /** Composition id — `s1`, `s2`. */
158
162
  sid: string;
@@ -216,8 +220,9 @@ export declare function readReserve(timingText: string | null): number;
216
220
  export interface FidelityReport {
217
221
  stops: Measured[];
218
222
  /**
219
- * Main-axis fill at each scene's last hold — measured on every deck, graded
220
- * only on a v2 one (`fit.json` present). See `./fill.ts`.
223
+ * Fill at each hold: every hold on a v2 deck (`fit.json` present), each with
224
+ * its content `area`, which is graded; each scene's last hold on a classic
225
+ * deck, measured and never graded. See `./fill.ts`.
221
226
  */
222
227
  fills: FillRow[];
223
228
  /**
@@ -42,22 +42,49 @@
42
42
  * is ink but not detail. Both are placement-independent: they do not move when
43
43
  * a look redefines where its body region is.
44
44
  *
45
+ * AND THE GRADED MEASURE, `area`: the bounding box of the body's REAL CONTENT
46
+ * over the region's area, at EVERY hold. Real content is what is left once the
47
+ * page's containers are made transparent (`stripContainers`): a card's wash and
48
+ * border, a figure's plate, a plot's panel. A row of three thin cards in a 170px
49
+ * band read as a full region on a wash that spanned it, and a column of bullets
50
+ * in a full-height panel read full by the panel (founder, 2026-10-12: "content
51
+ * sits small in the top-left with two thirds of the frame empty"). An extent is
52
+ * one axis; content in the top-left third is a third of BOTH axes, a ninth of
53
+ * the area, and only an area can say so.
54
+ *
45
55
  * GRADED ONLY ON A V2 DECK, i.e. one whose build wrote `fit.json`. A classic deck
46
56
  * is measured (so the eval can compare the two designs on the same storyboard)
47
- * but never gets a finding: v0.8.0's verdicts do not move. Both findings are
48
- * WARNINGS, as the plan's M1 sets them — a new gate starts by reporting:
57
+ * but never gets a finding: v0.8.0's verdicts do not move.
49
58
  *
50
- * hollow_at_hold measured fill under 0.70, the EMPTY band
51
- * fill_model_disagrees |predicted − measured| over 0.20 — the build-time
52
- * arithmetic and the browser disagree, which is a bug
53
- * in the model, not a matter of taste
59
+ * hollow_at_hold ERROR: at a hold, the content's box covers under 70%
60
+ * of the region's area. Every scene with a body, every
61
+ * hold — the title, kinetic and hero-number slides
62
+ * have no body under a title band (their words or
63
+ * number are the slide) and are not graded
64
+ * fill_model_disagrees WARNING: |predicted − measured| main-axis fill over
65
+ * 0.20 at the last hold — the build-time arithmetic and
66
+ * the browser disagree, which is a bug in the model
54
67
  */
55
- import { type FitManifest } from "../emit/fit.js";
68
+ import type { FitManifest } from "../emit/fit.js";
56
69
  import type { Finding } from "../types.js";
57
70
  /** A row counts as painted from this many off-background pixels: one is a stray fringe. */
58
71
  export declare const MIN_ROW_INK = 2;
59
72
  /** Predicted and measured fill may differ by this much before the model is called wrong. */
60
73
  export declare const FILL_TOLERANCE = 0.2;
74
+ /** A hold's content box must cover at least this share of its region's area. */
75
+ export declare const CONTENT_AREA_MIN = 0.7;
76
+ /**
77
+ * How far (max channel, times alpha) a fill must stand from the page's ground
78
+ * to be a tile rather than a wash. The deck themes' panel colours sit 10–25
79
+ * from their ground; a tone at a quarter strength sits past 40.
80
+ */
81
+ export declare const TILE_DELTA = 36;
82
+ /**
83
+ * Archetypes with no body under a title band: their words are the slide (a
84
+ * title, a kinetic statement, a hero number set at 200px or more), so there is
85
+ * no region to fill.
86
+ */
87
+ export declare const NO_BODY: Set<string>;
61
88
  /** Device px, in the frame's own coordinates. */
62
89
  export interface Box {
63
90
  left: number;
@@ -155,7 +182,24 @@ export declare function fillInk(region: FillRegion | null, modal: readonly [numb
155
182
  * writes `visibility:visible` on descendants and would show through.
156
183
  */
157
184
  export declare function hideScenes(on: boolean): void;
158
- /** One scene's last hold, measured. */
185
+ /**
186
+ * Run IN THE PAGE: make every CONTAINER in a scene transparent (`on`), or put
187
+ * it back. What is left is the content `area` measures.
188
+ *
189
+ * A container is an element whose box encloses the centre of a piece of
190
+ * content (a run of text, a picture, an SVG mark): an HTML one loses its
191
+ * background, border and shadow (what it holds stays), and an SVG `rect` is
192
+ * hidden. That is a card's wash, a figure's plate, a plot's panel, and a
193
+ * full-frame backdrop behind a lone number. What encloses nothing is content: a
194
+ * filled shape (a dot, a tile, a bar), a picture, a glyph — except an HTML leaf
195
+ * with a border and no fill, an empty box, which draws nothing. A container
196
+ * whose fill stands out from the ground (`TILE_DELTA`: a coloured cell, a chip)
197
+ * is a tile and stays. Classes
198
+ * and one style element, removed on `false`, so GSAP's inline styles are never
199
+ * touched.
200
+ */
201
+ export declare function stripContainers(sid: string, on: boolean): void;
202
+ /** One scene's hold, measured. */
159
203
  export interface FillRow {
160
204
  sid: string;
161
205
  t: number;
@@ -170,6 +214,11 @@ export interface FillRow {
170
214
  /** Share of the frame's cells holding ink, and of cells whose pixels vary. See `occupancy`. */
171
215
  cells: number;
172
216
  detail: number;
217
+ /**
218
+ * The content box's share of the region's AREA, measured on the frame with its
219
+ * containers stripped (`stripContainers`). Absent when that frame was not taken.
220
+ */
221
+ area?: number;
173
222
  }
174
223
  /**
175
224
  * How much of the frame carries content, by area. Pure.
@@ -193,6 +242,12 @@ export declare function measureFill(frame: FrameLike, test: InkTest, region: Fil
193
242
  sid: string;
194
243
  t: number;
195
244
  }): FillRow;
245
+ /**
246
+ * The content box's share of the region's area: the extent of ink in the region
247
+ * (down to `scanBottom` or the frame's edge) on a frame whose containers were
248
+ * stripped, each side capped at the region's. Pure. 0 with no region or no ink.
249
+ */
250
+ export declare function contentArea(frame: FrameLike, test: InkTest, region: FillRegion | null): number;
196
251
  /** The last declared stop of each scene: the final hold the fill is judged at. */
197
252
  export declare function finalStops<S extends {
198
253
  sid: string;
@@ -200,6 +255,12 @@ export declare function finalStops<S extends {
200
255
  }>(stops: readonly S[]): S[];
201
256
  /** Parse `fit.json`. Null when the deck has none — a classic build — or it does not parse. */
202
257
  export declare function readFitManifest(text: string | null): FitManifest | null;
203
- /** Findings for a v2 deck's measured fills. Nothing at all for a classic deck. */
258
+ /**
259
+ * Findings for a v2 deck's measured fills. Nothing at all for a classic deck.
260
+ *
261
+ * `rows` is every hold: `hollow_at_hold` is judged at each one that carries an
262
+ * `area`, one finding per scene naming its emptiest hold, and the model check at
263
+ * each scene's last hold (`finalStops`).
264
+ */
204
265
  export declare function gradeFill(rows: readonly FillRow[], manifest: FitManifest | null): Finding[];
205
266
  export {};
@@ -131,3 +131,49 @@ export interface Overprinted {
131
131
  * three example pairs because a repair needs to know WHICH labels.
132
132
  */
133
133
  export declare function gradeOverprint(rows: readonly Overprinted[]): Finding[];
134
+ /**
135
+ * The marks a word may not lie on, in device px: points (an SVG circle, by its
136
+ * centre and radius) and lines (an SVG line, polyline or open path, sampled
137
+ * every ~6px along its length). Visible ones only: a mark under a clip — a
138
+ * wipe that has not reached it, the camera's frame — is cut to the clip's box,
139
+ * so a series not yet drawn is not a series a label lies on.
140
+ */
141
+ export interface Marks {
142
+ points: Array<{
143
+ x: number;
144
+ y: number;
145
+ r: number;
146
+ }>;
147
+ lines: Array<{
148
+ x: number;
149
+ y: number;
150
+ }>;
151
+ }
152
+ /**
153
+ * Serialised into the page: every visible point and line inside this scene's
154
+ * SVGs. Closed shapes (rects, polygons) are not marks: a word on a panel or a
155
+ * chip is meant to be there.
156
+ */
157
+ export declare function collectSvgMarks(sid: string): Marks;
158
+ /** A word lying on a mark. */
159
+ export interface WordOnMark {
160
+ word: string;
161
+ on: "point" | "line";
162
+ /** Where the mark meets the word, device px, rounded: the place to look. */
163
+ at: [number, number];
164
+ }
165
+ /**
166
+ * Every run of text that lies on a point or a line: a line sample inside the
167
+ * run's box shrunk by `MIN_OVERLAP / 2` a side (a fifth of its height top and
168
+ * bottom, the leading), or a point whose disc reaches that far into it. A word INSIDE its own dot (a key's number) is not on it:
169
+ * the dot holds the whole run. Pure, for the same reason `overprints` is.
170
+ */
171
+ export declare function wordsOnMarks(runs: readonly TextRun[], marks: Marks): WordOnMark[];
172
+ /** One scene's words on marks at one stop. */
173
+ export interface MarkedStop {
174
+ sid: string;
175
+ t: number;
176
+ hits: WordOnMark[];
177
+ }
178
+ /** Findings for the scenes that print a word on a point or a line: one per scene, its worst stop. */
179
+ export declare function gradeWordsOnMarks(rows: readonly MarkedStop[]): Finding[];
@@ -56,7 +56,7 @@ export declare const PIXEL_DELTA = 24;
56
56
  */
57
57
  export declare const SEEK_TOLERANCE_PX = 1500;
58
58
  /** Bump whenever a gate's verdict can change: cached rejections from another version are retried. */
59
- export declare const GATES_VERSION = "gates-7";
59
+ export declare const GATES_VERSION = "gates-8";
60
60
  /**
61
61
  * A cue whose picture changes by less than this share of the frame held still:
62
62
  * about 310 px at 1080p. A frame that does not move renders to the same bytes,
@@ -84,6 +84,8 @@ export interface SceneWindow {
84
84
  start: number;
85
85
  duration: number;
86
86
  cues: SceneCue[];
87
+ /** Scene-relative holds, from timing.json: where the scene's reveals settle. */
88
+ holds?: number[];
87
89
  }
88
90
  export interface CueChange {
89
91
  sid: string;
@@ -93,6 +95,63 @@ export interface CueChange {
93
95
  changed: number;
94
96
  total: number;
95
97
  }
98
+ /**
99
+ * The longest a scene may show one unchanged picture, in seconds. The brief's
100
+ * rule is "no 6-9s stretches where nothing moves"; r1 of the literal verbs run
101
+ * had runs of up to 18.9s, all of them archetype scenes that passed every gate,
102
+ * because `static_hold` only ever probed generated scenes.
103
+ */
104
+ export declare const DEAD_SECONDS = 6;
105
+ export interface DeadSpan {
106
+ sid: string;
107
+ t0: number;
108
+ t1: number;
109
+ changed: number;
110
+ total: number;
111
+ }
112
+ /**
113
+ * The stretches of a scene that no reveal can be moving in: hold to the next
114
+ * reveal (which runs in the second before its hold), and the last hold to the
115
+ * settled end. Only those at least `DEAD_SECONDS` long, which are the only ones
116
+ * worth photographing.
117
+ *
118
+ * And each run of TWO such stretches, across the hold between them: a hold
119
+ * with nothing to reveal joins its neighbours into one still run that neither
120
+ * half shows. r2's OneVL deck had a lengths scene still for 12s over its last
121
+ * two holds, each window under 6s, and the gate passed it. The three frames
122
+ * of a two-stretch window still see a reveal at the hold between.
123
+ */
124
+ export declare function deadCandidates(w: SceneWindow, min?: number): Array<[number, number]>;
125
+ /**
126
+ * A step of a long stretch moved when this share of its pixels changed across
127
+ * `DEAD_STEP` seconds, compared at 480×270 (`pooled`). Not `MIN_CHANGE`'s "anything at all": a literal scene's
128
+ * lean — a 1.5% scale breathing over a still slide — changes edge pixels on
129
+ * every frame and passed r2's runs of 6–10s that a viewer saw as stills.
130
+ */
131
+ export declare const DEAD_MIN_CHANGE = 0.01;
132
+ /** The side `pooled` averages a frame down by: 1920×1080 to 480×270. */
133
+ export declare const DEAD_POOL = 4;
134
+ /** A frame averaged down `k`×`k` per pixel: what a viewer sees move, not antialiasing. */
135
+ export declare function pooled(f: Frame, k?: number): Frame;
136
+ /** Seconds between the two frames a step of motion is judged across. */
137
+ export declare const DEAD_STEP = 2;
138
+ /**
139
+ * The longest still run across frames at `times` (a second apart), given the
140
+ * changed pixels between each frame and the one `DEAD_STEP` seconds before it
141
+ * (`changed[k]` for frame k against frame k − DEAD_STEP; undefined for the
142
+ * first). A second of the stretch moved when a two-second step that spans it
143
+ * changed `min` of the pixels or more; the run is the longest stretch of
144
+ * seconds none of which moved. A slow lean — a slide breathing 1.5% across 8s —
145
+ * accumulates past 1% of the stretch's first frame and so read as motion to a
146
+ * comparison against the run's start; r3 had a line chart under 1% between every
147
+ * pair of frames two seconds apart for 14s, and the gate passed it.
148
+ */
149
+ export declare function stillRun(times: readonly number[], changed: ReadonlyArray<number | undefined>, total: number, min?: number): {
150
+ a: number;
151
+ b: number;
152
+ peak: number;
153
+ };
154
+ export declare function gradeDeadSpans(rows: readonly DeadSpan[], min?: number): Finding[];
96
155
  export declare function gradeStillCues(rows: readonly CueChange[], min?: number): Finding[];
97
156
  /**
98
157
  * The settled frame's drawing must span this share of the body box (the
@@ -473,7 +532,7 @@ export interface Probe {
473
532
  }
474
533
  export interface ProbeOptions {
475
534
  /** Which gates. Default all three. `seek` alone is what `verify` runs on plain v2 scenes. */
476
- gates?: ReadonlyArray<"motion" | "layout" | "seek">;
535
+ gates?: ReadonlyArray<"motion" | "layout" | "seek" | "dead" | "clip">;
477
536
  /** `seek_order` severity; `verify` passes `warning` for scenes nobody generated. */
478
537
  seekSeverity?: Finding["severity"];
479
538
  /** Keep the PNGs (the critique round needs them). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jokerized/decksmith",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "Turn a source document into an animated explanation deck.",
5
5
  "type": "module",
6
6
  "license": "MIT",