@jokerized/decksmith 0.9.3 → 0.9.4
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/README.md +449 -90
- package/dist/animate/LICENSE +21 -0
- package/dist/animate/NOTICE +32 -0
- package/dist/animate/core.js +530 -0
- package/dist/animate/cut-paper.js +206 -0
- package/dist/animate/morph.js +131 -0
- package/dist/cli.js +13368 -8864
- package/dist/ds-animate.js +1 -0
- package/dist/index.js +13182 -8678
- package/dist/mcp.js +9805 -7587
- package/dist/types/bespoke/art.d.ts +172 -6
- package/dist/types/bespoke/cache.d.ts +10 -0
- package/dist/types/bespoke/cards.d.ts +66 -0
- package/dist/types/bespoke/contract.d.ts +0 -8
- package/dist/types/bespoke/databuild.d.ts +50 -0
- package/dist/types/bespoke/depth.d.ts +127 -0
- package/dist/types/bespoke/grammar.d.ts +73 -0
- package/dist/types/bespoke/inspect.d.ts +40 -1
- package/dist/types/bespoke/pipeline.d.ts +195 -11
- package/dist/types/bespoke/probe.d.ts +2 -2
- package/dist/types/bespoke/prompt.d.ts +110 -34
- package/dist/types/bespoke/references.d.ts +13 -14
- package/dist/types/bespoke/repair.d.ts +23 -29
- package/dist/types/bespoke/scene.d.ts +55 -10
- package/dist/types/bespoke/select.d.ts +28 -21
- package/dist/types/bespoke/sheet.d.ts +66 -1
- package/dist/types/bespoke/shots.d.ts +225 -22
- package/dist/types/build/files.d.ts +7 -0
- package/dist/types/build/piece.d.ts +8 -0
- package/dist/types/emit/animate-runtime.d.ts +149 -0
- package/dist/types/emit/archetypes/claim-figure.d.ts +84 -1
- package/dist/types/emit/archetypes/equation-walk.d.ts +2 -2
- package/dist/types/emit/archetypes/hero-number.d.ts +21 -0
- package/dist/types/emit/archetypes/index.d.ts +2 -2
- package/dist/types/emit/archetypes/kinetic.d.ts +2 -0
- package/dist/types/emit/archetypes/pipeline.d.ts +14 -2
- package/dist/types/emit/archetypes/stage.d.ts +57 -0
- package/dist/types/emit/backdrop.d.ts +114 -0
- package/dist/types/emit/kit.d.ts +8 -0
- package/dist/types/emit/look.d.ts +14 -0
- package/dist/types/emit/motion.d.ts +78 -46
- package/dist/types/emit/type.d.ts +48 -5
- package/dist/types/images/providers.d.ts +6 -0
- package/dist/types/plan/codex.d.ts +4 -2
- package/dist/types/plan/direct.d.ts +1 -1
- package/dist/types/plan/duration.d.ts +1 -1
- package/dist/types/plan/prompt.d.ts +1 -1
- package/dist/types/plan/refs.d.ts +2 -2
- package/dist/types/plan/variety.d.ts +74 -0
- package/dist/types/prefs.d.ts +20 -1
- package/dist/types/render/captions.d.ts +4 -5
- package/dist/types/render/capture.d.ts +7 -0
- package/dist/types/types.d.ts +680 -4
- package/dist/types/verify/drift.d.ts +5 -0
- package/dist/types/verify/fidelity.d.ts +15 -1
- package/dist/types/verify/index.d.ts +17 -0
- package/dist/types/verify/scenes.d.ts +185 -5
- package/package.json +1 -1
- package/dist/types/bespoke/callouts.d.ts +0 -76
|
@@ -26,15 +26,14 @@
|
|
|
26
26
|
* this module) all still agree. Emphasis lives strictly inside a hold window
|
|
27
27
|
* and is back at rest before the window closes, so every frame a gate
|
|
28
28
|
* captures at a hold is the frame v0.8.0 would have captured there.
|
|
29
|
-
* 4.
|
|
30
|
-
*
|
|
31
|
-
* pass at a size it is not drawn at.
|
|
29
|
+
* 4. Nothing is scaled. Emphasis is light (`glow`), so the type floor's declared
|
|
30
|
+
* sizes are the drawn ones at every hold.
|
|
32
31
|
*
|
|
33
32
|
* INTERFACE, for the other v2 tracks (player, fit, style, layout):
|
|
34
33
|
*
|
|
35
|
-
* - `planMotion(seed, beats)` → which entrance verb each scene uses
|
|
36
|
-
* joins each pair, and the order emphasis kinds are tried in. A
|
|
37
|
-
* that wants to bias the grammar should filter `
|
|
34
|
+
* - `planMotion(seed, beats)` → which entrance verb each scene uses (a fade),
|
|
35
|
+
* which seam joins each pair, and the order emphasis kinds are tried in. A
|
|
36
|
+
* style pack that wants to bias the grammar should filter `SEAMS` before
|
|
38
37
|
* calling it rather than post-edit its answer, so the no-repeat rules still
|
|
39
38
|
* hold.
|
|
40
39
|
* - `restyleEntrance(scene, sid, verb)` rewrites an emitted scene's own
|
|
@@ -50,26 +49,20 @@
|
|
|
50
49
|
import type { Archetype, BeatRole } from "../types.js";
|
|
51
50
|
import { type Scene, type Tween } from "./kit.js";
|
|
52
51
|
/**
|
|
53
|
-
* How a scene's parts arrive
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
* to HTML elements this module can SEE are HTML (an id whose tag it read in the
|
|
68
|
-
* scene's markup). An SVG part or a class selector gets the verb's transform
|
|
69
|
-
* fallback instead, because clip-path on an SVG child clips against a reference
|
|
70
|
-
* box nobody measured.
|
|
71
|
-
*/
|
|
72
|
-
export declare const ENTRANCES: readonly ["rise", "slide", "snap", "focus", "wipe", "mask"];
|
|
52
|
+
* How a scene's parts arrive: ONE verb, a quiet opacity fade, in place.
|
|
53
|
+
*
|
|
54
|
+
* There were six — rise, slide, snap (a pop from 0.9 with overshoot), focus
|
|
55
|
+
* (out of a blur), wipe and mask (clip-path sweeps) — hashed per scene so no
|
|
56
|
+
* two adjacent scenes arrived alike. The founder's verdict on the result
|
|
57
|
+
* (2026-10-10): "graphic animation by animated UI elements is old-fashioned".
|
|
58
|
+
* Plates, chips, cards and labels sliding, popping or being swept in WERE the
|
|
59
|
+
* motion, and that is the thing he named. So a v2 archetype's parts now simply
|
|
60
|
+
* appear, and what moves is the picture: the backdrop's drift and the camera
|
|
61
|
+
* (src/emit/backdrop.ts, src/emit/camera.ts), the seams between scenes, and
|
|
62
|
+
* things inside a figure that are its content (a probe travelling a curve, a
|
|
63
|
+
* pulse travelling a pipeline). Those are not entrances and are never touched.
|
|
64
|
+
*/
|
|
65
|
+
export declare const ENTRANCES: readonly ["fade"];
|
|
73
66
|
export type Entrance = (typeof ENTRANCES)[number];
|
|
74
67
|
/**
|
|
75
68
|
* How one scene hands off to the next. `dive` is the existing camera move and is
|
|
@@ -80,20 +73,34 @@ export type Entrance = (typeof ENTRANCES)[number];
|
|
|
80
73
|
* | dissolve | opacity → 0, power2.in (v0.8.0) | — |
|
|
81
74
|
* | push | xPercent 0 → −4, opacity → 0 | xPercent 4 → 0 |
|
|
82
75
|
* | lift | yPercent 0 → −4, opacity → 0 | yPercent 4 → 0 |
|
|
83
|
-
* | wipe | clip-path closes left to right | — |
|
|
84
76
|
* | zoom | scale 1 → 1.04, opacity → 0 | scale 0.96 → 1 |
|
|
85
77
|
*
|
|
78
|
+
* There was a fifth, `wipe`: a clip-path closing left to right. It was cut
|
|
79
|
+
* (2026-10-10) because a hard edge sweeping a whole slide is a graphic, not a
|
|
80
|
+
* picture: at 4fps the r3 deck showed it as half a robot and a lone chip on an
|
|
81
|
+
* empty slide (s4→s5), a bare blue rectangle (s8→s9). Every seam left is a
|
|
82
|
+
* fade the eye reads as a cut or a camera move.
|
|
83
|
+
*
|
|
84
|
+
* Each seam also clears the outgoing scene's TYPE first (`chromeOut`), so two
|
|
85
|
+
* headlines are never on screen together.
|
|
86
|
+
*
|
|
86
87
|
* 4% is under the scene's own padding at every format (110px of 1920 is 5.7%,
|
|
87
88
|
* 84px of 1080 is 7.8%), so a mid-seam frame never puts content off the canvas
|
|
88
89
|
* for the layout gate's grid samples to find.
|
|
89
90
|
*/
|
|
90
|
-
export declare const SEAMS: readonly ["dissolve", "push", "lift", "
|
|
91
|
+
export declare const SEAMS: readonly ["dissolve", "push", "lift", "zoom"];
|
|
91
92
|
export type Seam = (typeof SEAMS)[number] | "dive";
|
|
92
|
-
/**
|
|
93
|
-
|
|
93
|
+
/**
|
|
94
|
+
* What moves while the narrator talks about a part: light, and only light. A
|
|
95
|
+
* `pulse` (the part scaled up and back) and an `underline` (a rule faded in
|
|
96
|
+
* under it) were the other two, and both are a UI element doing a move — the
|
|
97
|
+
* thing the founder called old-fashioned (2026-10-10). A glow is the part being
|
|
98
|
+
* lit, which is something a picture does.
|
|
99
|
+
*/
|
|
100
|
+
export declare const EMPHASES: readonly ["glow"];
|
|
94
101
|
export type Emphasis = (typeof EMPHASES)[number];
|
|
95
102
|
/** Every ease this module writes. A test pins that nothing else appears. */
|
|
96
|
-
export declare const MOTION_EASES: readonly ["power3.out", "expo.out", "
|
|
103
|
+
export declare const MOTION_EASES: readonly ["power3.out", "expo.out", "power2.in", "power2.inOut", "sine.out", "sine.inOut"];
|
|
97
104
|
/**
|
|
98
105
|
* FNV-1a, 32-bit. The seeded choice every v2 decision is made with: stable
|
|
99
106
|
* across platforms and Node versions, which a `Math.random` with a seed is not.
|
|
@@ -116,23 +123,16 @@ export interface MotionPlan {
|
|
|
116
123
|
/** Per beat, the order emphasis kinds are tried in (the first that fits wins). */
|
|
117
124
|
emphases: Emphasis[][];
|
|
118
125
|
}
|
|
119
|
-
/**
|
|
120
|
-
* At most this share of a deck's scenes open with `rise`, the one verb that
|
|
121
|
-
* reads as v0.8.0's stock fade-up. The plan's target is "modal entrance ≤ 40%".
|
|
122
|
-
*/
|
|
123
|
-
export declare const RISE_SHARE = 0.25;
|
|
124
126
|
/**
|
|
125
127
|
* The deck's motion, decided once for the whole storyboard.
|
|
126
128
|
*
|
|
127
|
-
* ENTRANCES:
|
|
128
|
-
*
|
|
129
|
-
* rather than a rotation so two decks with the same archetype sequence still
|
|
130
|
-
* move differently, which is the cross-deck sameness the critic flagged.
|
|
129
|
+
* ENTRANCES: every beat fades (`ENTRANCES`). Variety between scenes is the
|
|
130
|
+
* seams' and the pictures' job now, not the parts'.
|
|
131
131
|
*
|
|
132
132
|
* SEAMS are chosen by the RELATION between the two beats first, then varied:
|
|
133
133
|
* same family (two quantity beats) → `push`, a lateral continuation; a role
|
|
134
134
|
* boundary (`background` → `limitations`) → `zoom`, a chapter break; into or
|
|
135
|
-
* out of a title → `lift`; any other family change → `
|
|
135
|
+
* out of a title → `lift`; any other family change → `zoom` or `dissolve`; into the closing
|
|
136
136
|
* beat → `dissolve`. A seam that would repeat the previous one is replaced by a
|
|
137
137
|
* hashed pick from the rest. Then, for a deck of 10+ beats with fewer than three
|
|
138
138
|
* kinds, the earliest replaceable seams are rotated through the missing kinds.
|
|
@@ -147,18 +147,29 @@ export declare function planMotion(seed: string, beats: readonly MotionBeat[]):
|
|
|
147
147
|
export declare function ensureSeamKinds(seams: Seam[], want: number): void;
|
|
148
148
|
/**
|
|
149
149
|
* A tween this module may restyle: an opacity 0 → 1 reveal whose `from` only
|
|
150
|
-
* moves opacity and position/scale,
|
|
151
|
-
*
|
|
152
|
-
*
|
|
150
|
+
* moves opacity and position/scale. Dims, restores, draw-ons and colour turns
|
|
151
|
+
* are someone else's and stay exactly as emitted.
|
|
152
|
+
*
|
|
153
|
+
* `immediateRender: false` reveals COUNT. They used to be skipped as "someone
|
|
154
|
+
* else's", and they are mostly a panel's lines or a card's words staggering in
|
|
155
|
+
* after their card — the same sliding-in the founder objected to, one level
|
|
156
|
+
* down. A fade only removes keys, so it cannot become a second writer of
|
|
157
|
+
* anything the tween did not already write.
|
|
153
158
|
*/
|
|
154
159
|
export declare function isEntrance(t: Tween): boolean;
|
|
155
|
-
/** The tag of the element an `#id` selector names in this markup, if it is one. */
|
|
156
|
-
export declare function tagOf(html: string, target: string): string | undefined;
|
|
157
160
|
/**
|
|
158
161
|
* One scene's entrances, re-voiced in `verb`. Positions and durations are
|
|
159
162
|
* untouched (rule 3 at the top), so this cannot move a hold or the voice.
|
|
160
163
|
*/
|
|
161
164
|
export declare function restyleEntrance(scene: Scene, sid: string, verb: Entrance): Scene;
|
|
165
|
+
/**
|
|
166
|
+
* `restyleEntrance` for the CHROME alone: the eyebrow and headline the shell
|
|
167
|
+
* draws around a bespoke scene with the stock `chromeIn` (src/bespoke/scene.ts).
|
|
168
|
+
* The scene's own tweens are its author's and are left exactly as written; the
|
|
169
|
+
* chrome is ours, and unrestyled it slid up from y:14/22 starting at 0.15s,
|
|
170
|
+
* straight over the outgoing scene's headline (r3, s13→s14).
|
|
171
|
+
*/
|
|
172
|
+
export declare function restyleChrome(scene: Scene, sid: string, verb: Entrance): Scene;
|
|
162
173
|
/**
|
|
163
174
|
* When the incoming chrome may start, in unpaced seconds: once the outgoing
|
|
164
175
|
* scene's handoff (`HANDOFF_SECONDS`, 0.4) has taken it below half opacity,
|
|
@@ -180,6 +191,27 @@ export declare const SEAM_CLEAR = 0.3;
|
|
|
180
191
|
* tween, so a v2 deck whose plan says dissolve hands off as v0.8.0 did.
|
|
181
192
|
*/
|
|
182
193
|
export declare function seamOut(kind: Exclude<Seam, "dive">, sid: string, at: number, over: number): Tween[];
|
|
194
|
+
/**
|
|
195
|
+
* The share of a handoff the outgoing scene's TYPE takes to fade out. Its
|
|
196
|
+
* eyebrow and headline are gone by `CHROME_OUT * over` (0.16s of 0.4), well
|
|
197
|
+
* before the incoming chrome may start at `SEAM_CLEAR` (0.3), so the two
|
|
198
|
+
* headlines never share a frame. The picture keeps the whole `over` to
|
|
199
|
+
* dissolve under the next scene.
|
|
200
|
+
*
|
|
201
|
+
* WHY. The root fade alone left the outgoing headline at 23-75% while the
|
|
202
|
+
* incoming one came up at the same place: r3's s12→s13 and s13→s14 seams
|
|
203
|
+
* showed both headlines and both eyebrows overprinted for about two frames at
|
|
204
|
+
* 4fps. `power2.in` on the root holds the old type high exactly when the new
|
|
205
|
+
* type arrives, so no ease on the root alone can fix it.
|
|
206
|
+
*/
|
|
207
|
+
export declare const CHROME_OUT = 0.4;
|
|
208
|
+
/**
|
|
209
|
+
* The outgoing half of a seam for the scene's own type: `#sid-e` and
|
|
210
|
+
* `#sid-h`, whichever of them `html` draws (a title-less scene draws no
|
|
211
|
+
* eyebrow, and a tween on an absent id is a GSAP warning). `immediateRender:
|
|
212
|
+
* false`, so it never paints at build time over the chrome's own entrance.
|
|
213
|
+
*/
|
|
214
|
+
export declare function chromeOut(sid: string, html: string, at: number, over: number): Tween[];
|
|
183
215
|
/**
|
|
184
216
|
* The INCOMING half, on the next scene's own timeline from its 0. Settles by
|
|
185
217
|
* `firstHold - 0.05`, so the frame at the first stop is the frame v0.8.0 drew
|
|
@@ -71,6 +71,46 @@ export declare function familyOf(face: LatinFace): string;
|
|
|
71
71
|
* draws a glyph; it is there so (body, display) pairs give distinct stacks.
|
|
72
72
|
*/
|
|
73
73
|
export declare function stackFor(body: LatinFace, display: LatinFace): string;
|
|
74
|
+
/**
|
|
75
|
+
* THE V2 TYPE SCALE in px at 1920x1080 — the founder's, confirmed 2026-10-10,
|
|
76
|
+
* after "the fonts are too large": a 56px headline, 40-44px body and labels, a
|
|
77
|
+
* 40px kicker. No 160-560px hero numeral and no 64px+ kinetic type; the
|
|
78
|
+
* narration and its subtitles carry the words, so what is ON the slide is
|
|
79
|
+
* minimal and quiet.
|
|
80
|
+
*
|
|
81
|
+
* One table, read by every v2 emitter (the chrome through `TYPES` below, each
|
|
82
|
+
* archetype through `v2Text`), by src/bespoke's prompt, labels and gates, and —
|
|
83
|
+
* restated, because that file may import nothing from here — by the burned
|
|
84
|
+
* caption in src/types.ts, so a size cannot be lowered in one place and left
|
|
85
|
+
* large in another. Never under `floor`: AGENTS.md invariant 5. Classic never
|
|
86
|
+
* reads it — `--design classic` is still the complete rollback.
|
|
87
|
+
*/
|
|
88
|
+
export declare const TYPE_SCALE: {
|
|
89
|
+
/** The line that says the slide: headline, title slide, a hero statement. */
|
|
90
|
+
readonly headline: 56;
|
|
91
|
+
/** Body copy and the largest a label is set: labels run `label`..`body`. */
|
|
92
|
+
readonly body: 44;
|
|
93
|
+
/** The smallest a label is set; with `body`, the 40-44px label band. */
|
|
94
|
+
readonly label: 40;
|
|
95
|
+
/** Eyebrow / kicker. */
|
|
96
|
+
readonly kicker: 40;
|
|
97
|
+
/** A burned subtitle (src/types.ts `captionFontSize` restates it). */
|
|
98
|
+
readonly caption: 40;
|
|
99
|
+
/** Never under this (invariant 5). */
|
|
100
|
+
readonly floor: 40;
|
|
101
|
+
/**
|
|
102
|
+
* The largest a display equation is asked at. Not the headline's 56: KaTeX
|
|
103
|
+
* sets a sub- or superscript at 0.7em, and at 64 that is 44.8px — on the body
|
|
104
|
+
* scale, clear of the floor. Classic asked up to 108; v2 grew it to 140.
|
|
105
|
+
*/
|
|
106
|
+
readonly math: 64;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* A text size as v2 sets it: `px` held inside `[floor, cap]`. Classic passes
|
|
110
|
+
* through untouched. `cap` defaults to body/label size; a role that IS the
|
|
111
|
+
* headline passes `TYPE_SCALE.headline`.
|
|
112
|
+
*/
|
|
113
|
+
export declare function v2Text(v2: boolean, px: number, cap?: number): number;
|
|
74
114
|
/** Today's chrome, exactly. `title.ts` exported these numbers before specs existed. */
|
|
75
115
|
export declare const CLASSIC_TYPE: TypeSpec;
|
|
76
116
|
/**
|
|
@@ -84,11 +124,14 @@ export declare const CLASSIC_TYPE: TypeSpec;
|
|
|
84
124
|
* - `grotesk-plex`: Space Grotesk headline over a Plex body.
|
|
85
125
|
* - `plex-serif`: a Plex headline over a serif body, the inverse of `serif-inter`.
|
|
86
126
|
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
127
|
+
* SIZE IS NOT A VOICE ANY MORE. Every spec sets the eyebrow at `TYPE_SCALE.kicker`
|
|
128
|
+
* and the headline — the title slide's included — at `TYPE_SCALE.headline`; the
|
|
129
|
+
* pairs differ in face, weight, tracking, case and leading. They used to differ
|
|
130
|
+
* in size too (60-70px headlines, 144-168px titles), and the founder's verdict
|
|
131
|
+
* on those was "the fonts are too large".
|
|
132
|
+
*
|
|
133
|
+
* HEIGHT. A one-line eyebrow plus a one-line headline costs well under classic's
|
|
134
|
+
* 146px in every spec, so nothing here takes room from the body.
|
|
92
135
|
*
|
|
93
136
|
* FLOORS. Every eyebrow is at least 40px (invariant 5). Title tracking is never
|
|
94
137
|
* positive: `fitText` measures untracked, so only a tightening is free.
|
|
@@ -7,6 +7,12 @@ export interface ImageRequest {
|
|
|
7
7
|
/** `images.style`, folded into every prompt. */
|
|
8
8
|
style: string;
|
|
9
9
|
aspect: ImageAspect;
|
|
10
|
+
/**
|
|
11
|
+
* The picture covers the frame — a stage or a backdrop — rather than sitting
|
|
12
|
+
* on a plate. Absent means a plate, which is every request made before this
|
|
13
|
+
* existed, so their prompts and cache keys do not move.
|
|
14
|
+
*/
|
|
15
|
+
bleed?: boolean;
|
|
10
16
|
/**
|
|
11
17
|
* `images.model`, for the separate backend only; the Codex and tool rungs
|
|
12
18
|
* ignore it. Carried on the request rather than baked into the provider
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Prefs } from "../prefs.js";
|
|
2
2
|
import { type Source, type Storyboard } from "../types.js";
|
|
3
3
|
/** The schema for one run. `role` is present only when the paper arc was asked for. */
|
|
4
|
-
export declare function schemaFor(prefs: Pick<Prefs, "genre">): unknown;
|
|
4
|
+
export declare function schemaFor(prefs: Pick<Prefs, "genre" | "bespoke" | "design">): unknown;
|
|
5
5
|
/**
|
|
6
6
|
* The default-preferences schema, unchanged and still exported: `general` hides
|
|
7
7
|
* `role`, so these bytes are what they have always been.
|
|
@@ -18,6 +18,8 @@ export interface CodexOptions {
|
|
|
18
18
|
prefs?: Prefs;
|
|
19
19
|
/** Swappable so a test can drive the real parse path without spawning anything. */
|
|
20
20
|
run?: Runner;
|
|
21
|
+
/** Told what the first plan broke, before the one repair round is asked for. */
|
|
22
|
+
onRepair?: (broken: readonly string[]) => void;
|
|
21
23
|
}
|
|
22
24
|
export interface RunnerArgs {
|
|
23
25
|
prompt: string;
|
|
@@ -42,7 +42,7 @@ export interface Direction {
|
|
|
42
42
|
export interface LookSummary {
|
|
43
43
|
beats: number;
|
|
44
44
|
distinct: number;
|
|
45
|
-
/** Share of beats whose chrome sits on top of the slide (title excluded from the numerator). */
|
|
45
|
+
/** Share of beats whose chrome sits on top of the slide (title and chromeless beats excluded from the numerator). */
|
|
46
46
|
modalChrome: number;
|
|
47
47
|
/** Adjacent pairs with the same signature. */
|
|
48
48
|
adjacentRepeats: number;
|
|
@@ -6,8 +6,8 @@ export interface PendingIllustration {
|
|
|
6
6
|
where: string;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
|
-
* Every pending slot, in beat order. A claim-figure without a
|
|
10
|
-
* pending by construction — the schema insists on one of the two — and a
|
|
9
|
+
* Every pending slot, in beat order. A claim-figure or stage without a
|
|
10
|
+
* `figureId` is pending by construction — the schema insists on one of the two — and a
|
|
11
11
|
* split-compare side is pending only when it carries a brief, because a side
|
|
12
12
|
* with neither is a list.
|
|
13
13
|
*/
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VARIETY: the plan-level rule that a deck must not be one layout repeated.
|
|
3
|
+
*
|
|
4
|
+
* The measured failure this answers (2026-10-09, a 14-beat Korean paper deck,
|
|
5
|
+
* no figures, planned with `--images`): 5 split-compare, 5 pipeline, 2 callout,
|
|
6
|
+
* 1 title, 1 bar-compare, ZERO illustrations — and beats 2 to 12 alternated
|
|
7
|
+
* split-compare / pipeline / split-compare / pipeline for nine slides running.
|
|
8
|
+
* RULE 1's "not the same archetype twice in a row" held at every pair, and the
|
|
9
|
+
* deck still read, slide after slide, as the same two cards on a pale ground.
|
|
10
|
+
* The prompt said a stage MAY carry an illustration; the planner never did.
|
|
11
|
+
*
|
|
12
|
+
* So the rule is a minimum, not an invitation, and it is CHECKED: the prompt
|
|
13
|
+
* (src/plan/prompt.ts) states these numbers by importing them from here, and
|
|
14
|
+
* `codexPlanner` (src/plan/codex.ts) runs `varietyFindings` on what comes back,
|
|
15
|
+
* asks once for a repair, and refuses a plan that still breaks it. One table,
|
|
16
|
+
* read by both, so the sentence the model is given and the check it is held to
|
|
17
|
+
* cannot drift apart.
|
|
18
|
+
*
|
|
19
|
+
* WHAT IT DELIBERATELY DOES NOT DO. It never rewrites a beat. Turning a pipeline
|
|
20
|
+
* into a stage needs a picture brief only the planner can write honestly, and
|
|
21
|
+
* reordering beats breaks the narration's argument. A plan that breaks the rule
|
|
22
|
+
* goes back to the planner with the reasons, which is the only repair that
|
|
23
|
+
* keeps the deck's content the planner's.
|
|
24
|
+
*/
|
|
25
|
+
import type { Prefs } from "../prefs.js";
|
|
26
|
+
import type { Archetype, Beat, Design, Storyboard } from "../types.js";
|
|
27
|
+
/** A deck this long must carry stage beats. Below it there is no room to spend one. */
|
|
28
|
+
export declare const STAGE_MIN_BEATS = 8;
|
|
29
|
+
/** At least one stage per this many beats, when the deck may ask for pictures. */
|
|
30
|
+
export declare const STAGE_EVERY = 4;
|
|
31
|
+
/** Longest A/B/A/B run allowed: three beats (A, B, A) is a return; four is a rut. */
|
|
32
|
+
export declare const MAX_ALTERNATION = 3;
|
|
33
|
+
/**
|
|
34
|
+
* At least this share of a deck's beats are SCENES — a picture owns or backs
|
|
35
|
+
* them — when the deck may ask for pictures. Three stages in fourteen still left
|
|
36
|
+
* nine beats of cards on the pack's pale ground in the 2026-10-09 ko e2e; a
|
|
37
|
+
* diagram with a `backdrop` is drawn over a picture, so "most beats are scenes"
|
|
38
|
+
* no longer costs the diagram.
|
|
39
|
+
*/
|
|
40
|
+
export declare const SCENE_SHARE = 0.6;
|
|
41
|
+
/**
|
|
42
|
+
* The archetypes that draw boxes, cards or rows of them — what the founder
|
|
43
|
+
* means by slideware. A backdrop puts them in a scene but they are still
|
|
44
|
+
* panels: round 1 of the 2026-10-09 ko e2e had ten of fourteen beats as
|
|
45
|
+
* scenes, and nine of fourteen were still panels over pictures.
|
|
46
|
+
*/
|
|
47
|
+
export declare const PANEL_ARCHETYPES: ReadonlySet<Archetype>;
|
|
48
|
+
/** At most this share of a picture deck's beats are panels: five of fourteen. */
|
|
49
|
+
export declare const PANEL_SHARE = 0.36;
|
|
50
|
+
/** How many panel beats a deck of `beats` may carry, given whether it may ask for pictures. */
|
|
51
|
+
export declare function panelsAllowed(beats: number, images: Prefs["images"]): number;
|
|
52
|
+
/** How many stage beats a deck of `beats` must carry, given the picture cap. */
|
|
53
|
+
export declare function stagesRequired(beats: number, images: Prefs["images"]): number;
|
|
54
|
+
/** How many beats of a deck of `beats` must be scenes (`SCENE_SHARE`), given the picture cap. */
|
|
55
|
+
export declare function scenesRequired(beats: number, images: Prefs["images"]): number;
|
|
56
|
+
/**
|
|
57
|
+
* Whether a picture owns or backs this beat: a stage, a split-compare side
|
|
58
|
+
* with a picture, or a diagram over a `backdrop`. A brief counts as a figure
|
|
59
|
+
* does — it is a picture by the time anyone sees the deck. A hero number and a
|
|
60
|
+
* kinetic claim are scenes with or without one: with none they fill the frame
|
|
61
|
+
* with a field of colour, never the pale ground — and so, in v2, is a
|
|
62
|
+
* bar-compare.
|
|
63
|
+
*
|
|
64
|
+
* NOT a claim-figure or an annotated-figure: both draw their figure as a card
|
|
65
|
+
* on the pack's pale ground (neither goes through `overBackdrop` or
|
|
66
|
+
* `overField`), so counting them let a plan meet `SCENE_SHARE` with exactly
|
|
67
|
+
* the cards-on-paper the share exists to refuse.
|
|
68
|
+
*/
|
|
69
|
+
export declare function isScene(beat: Beat, design?: Design): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Every way `storyboard` breaks the variety rule, as sentences the planner can
|
|
72
|
+
* act on. Empty is a pass.
|
|
73
|
+
*/
|
|
74
|
+
export declare function varietyFindings(storyboard: Storyboard, images: Prefs["images"], design?: Design): string[];
|
package/dist/types/prefs.d.ts
CHANGED
|
@@ -44,6 +44,16 @@ export declare function prefsFromFlags(flags: PrefFlags): PrefsPatch;
|
|
|
44
44
|
* storyboard planned under v2.
|
|
45
45
|
*/
|
|
46
46
|
export declare function designFor(prefs: Pick<Prefs, "design">, recorded?: Design): Design;
|
|
47
|
+
/**
|
|
48
|
+
* The bespoke pass a build runs, with every default filled in, or undefined.
|
|
49
|
+
* ON BY DEFAULT UNDER V2: every beat is drawn by a generated scene and the
|
|
50
|
+
* archetype is only its fallback. `--no-bespoke` (`"bespoke": {"enabled":
|
|
51
|
+
* false}`) turns it off; classic never runs it, so a classic deck keeps its
|
|
52
|
+
* bytes.
|
|
53
|
+
*/
|
|
54
|
+
export declare function bespokeFor(prefs: Pick<Prefs, "bespoke">, design: Design): {
|
|
55
|
+
prefs: NonNullable<Prefs["bespoke"]>;
|
|
56
|
+
} | undefined;
|
|
47
57
|
/** The flag surface the CLI exposes. Every one optional: absent means unstated. */
|
|
48
58
|
export interface PrefFlags {
|
|
49
59
|
slides?: string | number;
|
|
@@ -71,7 +81,7 @@ export interface PrefFlags {
|
|
|
71
81
|
imageModel?: string;
|
|
72
82
|
imageStyle?: string;
|
|
73
83
|
imageMax?: string | number;
|
|
74
|
-
/** `--bespoke`: generated scenes for
|
|
84
|
+
/** `--bespoke` / `--no-bespoke`: generated scenes for every beat (v2 only; on by default there). */
|
|
75
85
|
bespoke?: boolean;
|
|
76
86
|
bespokeCalls?: string | number;
|
|
77
87
|
bespokeSeconds?: string | number;
|
|
@@ -80,3 +90,12 @@ export interface PrefFlags {
|
|
|
80
90
|
bespokeCache?: string;
|
|
81
91
|
bespokeArt?: string | number;
|
|
82
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Commander gives a plain `--flag` `undefined` until it is passed, which is
|
|
95
|
+
* exactly the "unstated" that `prefsFromFlags` needs — except for `--no-x`,
|
|
96
|
+
* which defaults to `true` and would therefore outrank the config file on every
|
|
97
|
+
* run. So the negation is read as a negation and nothing else. `--images` is
|
|
98
|
+
* the other one read by hand: it is a boolean, and the loop below only knows
|
|
99
|
+
* strings.
|
|
100
|
+
*/
|
|
101
|
+
export declare function flagsFromOptions(o: Record<string, unknown>): PrefFlags;
|
|
@@ -27,11 +27,10 @@ export interface CaptionBand {
|
|
|
27
27
|
* cues. Hidden by default and revealed one at a time, so what is measured is
|
|
28
28
|
* exactly what is captured.
|
|
29
29
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* floating in it.
|
|
30
|
+
* There is no scrim (2026-10-10): the founder asked for a quiet lower third,
|
|
31
|
+
* not a box, so each line is white type with a close dark halo. The span keeps
|
|
32
|
+
* `box-decoration-break: clone` and its padding so every line's halo lies
|
|
33
|
+
* inside the rectangle `measure` reports and the band is captured with it.
|
|
35
34
|
*
|
|
36
35
|
* `line-height` is set from a measurement, not from a ratio. The inline box is
|
|
37
36
|
* as tall as the font's content area plus the padding, and that is a number only
|
|
@@ -103,6 +103,13 @@ export interface DeckPage {
|
|
|
103
103
|
shoot(): Promise<Buffer>;
|
|
104
104
|
/** For callers that need to read the DOM at a stop, as `fidelity` does. */
|
|
105
105
|
page: Page;
|
|
106
|
+
/**
|
|
107
|
+
* Every uncaught error the page has raised since it opened, in order. The
|
|
108
|
+
* runtime swallows a throw inside a seek, so this is the only place an
|
|
109
|
+
* animate piece's drawing error (`reportError`) surfaces: without it a seek
|
|
110
|
+
* resolves over a stale or half-painted canvas.
|
|
111
|
+
*/
|
|
112
|
+
errors: string[];
|
|
106
113
|
close(): Promise<void>;
|
|
107
114
|
}
|
|
108
115
|
export interface OpenOptions {
|