@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
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { Theme } from "../emit/kit.js";
|
|
2
2
|
import type { Runner } from "../plan/codex.js";
|
|
3
|
+
import type { DepthInfo } from "./depth.js";
|
|
3
4
|
import type { UnitBox } from "./inspect.js";
|
|
4
5
|
/** Bump with any change to the art prompt: it is part of every art key, and so of every scene key. */
|
|
5
|
-
export declare const ART_VERSION = "art-
|
|
6
|
+
export declare const ART_VERSION = "art-4";
|
|
6
7
|
/** A picture bigger than this is not one the tool made for a slide. */
|
|
7
8
|
export declare const MAX_ART_BYTES: number;
|
|
8
9
|
/** Effort for the art call: MEASURED 2026-10-09, low drew the pictures above in 36-49s. */
|
|
@@ -23,12 +24,75 @@ export interface ArtRef {
|
|
|
23
24
|
png?: string;
|
|
24
25
|
/** The PNG with its subjects boxed and numbered, for the draft call (src/bespoke/sheet.ts). */
|
|
25
26
|
boxed?: string;
|
|
27
|
+
/** The backdrop with the subjects over it as the box shows them: what the draft call sees first. */
|
|
28
|
+
composite?: string;
|
|
26
29
|
/** The subjects, left to right, as shares of the picture (src/bespoke/inspect.ts). */
|
|
27
30
|
subjects?: UnitBox[];
|
|
28
31
|
/** What the inspection measured, for the report. */
|
|
29
32
|
check?: ArtCheck;
|
|
30
33
|
/** The deck's copy carries its own feathered edges (alpha): the shell adds no CSS mask. */
|
|
31
34
|
feathered?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* ROUND 5: the subjects are drawn on a transparent ground (`cutout`) in
|
|
37
|
+
* front of a BACKDROP of their setting, drawn in the same call: the scene is
|
|
38
|
+
* a full environment, and the two layers move at different rates (parallax).
|
|
39
|
+
*/
|
|
40
|
+
cutout?: boolean;
|
|
41
|
+
plate?: PlateRef;
|
|
42
|
+
/** The subjects, as the illustrator names them (the deck's repetition check reads these). */
|
|
43
|
+
motifs?: string[];
|
|
44
|
+
/** The setting, in the illustrator's words. */
|
|
45
|
+
setting?: string;
|
|
46
|
+
/** Vision's feature print of the subjects over the pack's ground (src/bespoke/inspect.ts). */
|
|
47
|
+
print?: number[];
|
|
48
|
+
/** ROUND 6: the picture as depth planes the shell's camera moves through (src/bespoke/depth.ts). */
|
|
49
|
+
depth?: DepthRef;
|
|
50
|
+
}
|
|
51
|
+
/** One backdrop plane: frame-shaped, at distance `z` (the subjects' plane is 1). */
|
|
52
|
+
export interface PlaneRef {
|
|
53
|
+
name: string;
|
|
54
|
+
file: string;
|
|
55
|
+
z: number;
|
|
56
|
+
/** Its out-of-focus twin (rack focus cross-fades to it; src/bespoke/sheet.ts `SOFT_PX`). */
|
|
57
|
+
soft: {
|
|
58
|
+
name: string;
|
|
59
|
+
file: string;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** One subject cut out on its own plane: its box in frame px, 1-based `subject`. */
|
|
63
|
+
export interface SubjectPlaneRef extends PlaneRef {
|
|
64
|
+
subject: number;
|
|
65
|
+
box: {
|
|
66
|
+
x: number;
|
|
67
|
+
y: number;
|
|
68
|
+
w: number;
|
|
69
|
+
h: number;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** A picture's depth planes (round 6), for the frame they were cut for. */
|
|
73
|
+
export interface DepthRef {
|
|
74
|
+
/** The frame the planes cover, px: a picture is re-cut for another. */
|
|
75
|
+
frame: {
|
|
76
|
+
width: number;
|
|
77
|
+
height: number;
|
|
78
|
+
};
|
|
79
|
+
/** The picture's own pixels per frame px at rest (after any upscale), at most `PLANE_SCALE`. */
|
|
80
|
+
scale: number;
|
|
81
|
+
/** Backdrop planes, far to near. */
|
|
82
|
+
planes: PlaneRef[];
|
|
83
|
+
subjects: SubjectPlaneRef[];
|
|
84
|
+
info: DepthInfo;
|
|
85
|
+
}
|
|
86
|
+
/** A picture's backdrop: its own files beside the subjects'. */
|
|
87
|
+
export interface PlateRef {
|
|
88
|
+
/** The file name under the deck's `assets/bespoke/`. */
|
|
89
|
+
name: string;
|
|
90
|
+
/** Where the deck's bytes are (the cache). */
|
|
91
|
+
file: string;
|
|
92
|
+
/** The PNG as drawn. */
|
|
93
|
+
png: string;
|
|
94
|
+
width: number;
|
|
95
|
+
height: number;
|
|
32
96
|
}
|
|
33
97
|
/** What the inspection said about the picture kept, and how many draws it took. */
|
|
34
98
|
export interface ArtCheck {
|
|
@@ -53,12 +117,19 @@ export interface ArtBrief {
|
|
|
53
117
|
context: string;
|
|
54
118
|
theme: Theme;
|
|
55
119
|
pack: string;
|
|
120
|
+
/** The scene's visual device (`assignDevices`): the picture shows what that device acts on. */
|
|
121
|
+
device?: string;
|
|
122
|
+
/** The deck plan's setting and subjects for this picture (`assignDevices`, round 5). */
|
|
123
|
+
setting?: string;
|
|
124
|
+
subjects?: readonly string[];
|
|
125
|
+
/** A data beat (round 6: illustrated too): the subjects are the quantities. */
|
|
126
|
+
data?: boolean;
|
|
56
127
|
}
|
|
57
128
|
/** The illustrator's reply. `--output-schema` holds it to this. */
|
|
58
129
|
export declare const ART_SCHEMA: {
|
|
59
130
|
readonly type: "object";
|
|
60
131
|
readonly additionalProperties: false;
|
|
61
|
-
readonly required: readonly ["ok", "file", "reason", "depicts"];
|
|
132
|
+
readonly required: readonly ["ok", "file", "plate", "reason", "depicts", "setting", "subjects"];
|
|
62
133
|
readonly properties: {
|
|
63
134
|
readonly ok: {
|
|
64
135
|
readonly type: "boolean";
|
|
@@ -70,6 +141,13 @@ export declare const ART_SCHEMA: {
|
|
|
70
141
|
readonly type: "null";
|
|
71
142
|
}];
|
|
72
143
|
};
|
|
144
|
+
readonly plate: {
|
|
145
|
+
readonly anyOf: readonly [{
|
|
146
|
+
readonly type: "string";
|
|
147
|
+
}, {
|
|
148
|
+
readonly type: "null";
|
|
149
|
+
}];
|
|
150
|
+
};
|
|
73
151
|
readonly reason: {
|
|
74
152
|
readonly anyOf: readonly [{
|
|
75
153
|
readonly type: "string";
|
|
@@ -80,6 +158,15 @@ export declare const ART_SCHEMA: {
|
|
|
80
158
|
readonly depicts: {
|
|
81
159
|
readonly type: "string";
|
|
82
160
|
};
|
|
161
|
+
readonly setting: {
|
|
162
|
+
readonly type: "string";
|
|
163
|
+
};
|
|
164
|
+
readonly subjects: {
|
|
165
|
+
readonly type: "array";
|
|
166
|
+
readonly items: {
|
|
167
|
+
readonly type: "string";
|
|
168
|
+
};
|
|
169
|
+
};
|
|
83
170
|
};
|
|
84
171
|
};
|
|
85
172
|
/** The art key: everything the picture is drawn from. */
|
|
@@ -93,7 +180,18 @@ export declare function artKey(brief: ArtBrief, model: string): string;
|
|
|
93
180
|
* a picture turns into a render.
|
|
94
181
|
*/
|
|
95
182
|
export declare const ART_STYLE = "STYLE \u2014 FLAT 2D VECTOR, strictly. The look of a modern explainer channel's flat illustration (Kurzgesagt-like flat design) or a vector editorial infographic: every shape is ONE solid, uniform colour with crisp hard edges, like cut paper; simple geometric forms with rounded corners; a darker flat shape of the same hue may mark a side or a fold (a hard-edged shape, never a blend). Characters and objects are simplified and iconic, drawn front-on or in clean side view. FORBIDDEN, every one: gradients of any kind, airbrushed or soft shading, ambient occlusion, glossy or specular highlights, reflections, rim light, soft or drop shadows (not even under the subjects), glow, blur, depth of field, texture, grain, noise, 3D rendering, clay, plastic, vinyl-toy or Pixar-style characters, isometric 3D, photorealism, outlines thinner than the shapes they bound. If in doubt, flatter.";
|
|
96
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Subjects the illustrator reaches for when an idea is abstract, and which
|
|
185
|
+
* then turn up in every picture of a deck: round 4's pictures were a friendly
|
|
186
|
+
* robot in 34 of 38 (MEASURED 2026-10-10, both runs of four decks). Forbidden
|
|
187
|
+
* unless the beat itself is about one (`stockAllowed`).
|
|
188
|
+
*/
|
|
189
|
+
export declare const STOCK_MOTIFS: readonly ["robot", "android", "cyborg", "mascot", "humanoid", "brain", "light bulb", "lightbulb", "gear", "cog", "computer monitor", "laptop", "magnifying glass"];
|
|
190
|
+
/** The stock motifs this beat's own words name, which it may therefore draw. */
|
|
191
|
+
export declare function stockAllowed(b: Pick<ArtBrief, "headline" | "intent" | "claim" | "narration" | "context">): string[];
|
|
192
|
+
export declare function artPrompt(b: ArtBrief, retry?: string, avoid?: readonly string[]): string;
|
|
193
|
+
/** Whether a pack's ground is dark (relative luminance under 0.2): its backdrops must be lit. */
|
|
194
|
+
export declare function darkGround(hex: string): boolean;
|
|
97
195
|
/** Width and height from a PNG's IHDR, or undefined when the bytes are not a PNG. */
|
|
98
196
|
export declare function pngSize(bytes: Buffer): {
|
|
99
197
|
width: number;
|
|
@@ -112,6 +210,51 @@ interface ArtMeta {
|
|
|
112
210
|
subjects?: UnitBox[];
|
|
113
211
|
check?: ArtCheck;
|
|
114
212
|
feathered?: boolean;
|
|
213
|
+
cutout?: boolean;
|
|
214
|
+
plate?: {
|
|
215
|
+
width: number;
|
|
216
|
+
height: number;
|
|
217
|
+
};
|
|
218
|
+
motifs?: string[];
|
|
219
|
+
setting?: string;
|
|
220
|
+
print?: number[];
|
|
221
|
+
depth?: {
|
|
222
|
+
frame: {
|
|
223
|
+
width: number;
|
|
224
|
+
height: number;
|
|
225
|
+
};
|
|
226
|
+
scale: number;
|
|
227
|
+
planes: Array<{
|
|
228
|
+
z: number;
|
|
229
|
+
}>;
|
|
230
|
+
subjects: Array<{
|
|
231
|
+
z: number;
|
|
232
|
+
subject: number;
|
|
233
|
+
box: SubjectPlaneRef["box"];
|
|
234
|
+
}>;
|
|
235
|
+
info: DepthInfo;
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
/** What `ArtCache.putDepth` stores: the planes' bytes with their distances. */
|
|
239
|
+
export interface DepthCopies {
|
|
240
|
+
frame: {
|
|
241
|
+
width: number;
|
|
242
|
+
height: number;
|
|
243
|
+
};
|
|
244
|
+
scale: number;
|
|
245
|
+
planes: Array<{
|
|
246
|
+
webp: Buffer;
|
|
247
|
+
soft: Buffer;
|
|
248
|
+
z: number;
|
|
249
|
+
}>;
|
|
250
|
+
subjects: Array<{
|
|
251
|
+
webp: Buffer;
|
|
252
|
+
soft: Buffer;
|
|
253
|
+
z: number;
|
|
254
|
+
subject: number;
|
|
255
|
+
box: SubjectPlaneRef["box"];
|
|
256
|
+
}>;
|
|
257
|
+
info: DepthInfo;
|
|
115
258
|
}
|
|
116
259
|
/** Copies a picture may have beside its PNG: the deck's WebP, the draft call's boxed PNG. */
|
|
117
260
|
export interface ArtCopies {
|
|
@@ -119,6 +262,10 @@ export interface ArtCopies {
|
|
|
119
262
|
boxed?: Buffer;
|
|
120
263
|
/** The WebP's edges are feathered into transparency for the beat's box. */
|
|
121
264
|
feathered?: boolean;
|
|
265
|
+
/** The backdrop's deck copy (feathered WebP), when there is a backdrop. */
|
|
266
|
+
plateWebp?: Buffer;
|
|
267
|
+
/** What the draft call is shown: the backdrop with the subjects over it, as the box shows them. */
|
|
268
|
+
composite?: Buffer;
|
|
122
269
|
}
|
|
123
270
|
/**
|
|
124
271
|
* Pictures beside the scene cache, under `art/`: `<key>.png` (as drawn),
|
|
@@ -129,8 +276,12 @@ export declare class ArtCache {
|
|
|
129
276
|
readonly dir: string;
|
|
130
277
|
constructor(dir: string);
|
|
131
278
|
private ref;
|
|
279
|
+
private depthRef;
|
|
280
|
+
/** Store a picture's depth planes (round 6) beside it, and return the picture with them. */
|
|
281
|
+
putDepth(key: string, d: DepthCopies): Promise<ArtRef | undefined>;
|
|
282
|
+
private write;
|
|
132
283
|
get(key: string): Promise<ArtRef | undefined>;
|
|
133
|
-
put(key: string, bytes: Buffer, meta: Omit<ArtMeta, "version" | "key">, copies?: ArtCopies): Promise<ArtRef>;
|
|
284
|
+
put(key: string, bytes: Buffer, meta: Omit<ArtMeta, "version" | "key">, copies?: ArtCopies, plate?: Buffer): Promise<ArtRef>;
|
|
134
285
|
}
|
|
135
286
|
export interface DrawArtOptions {
|
|
136
287
|
run: Runner;
|
|
@@ -147,17 +298,28 @@ export interface DrawArtOptions {
|
|
|
147
298
|
home?: string;
|
|
148
299
|
/** Why the previous picture of this beat was rejected, for the second attempt. */
|
|
149
300
|
retry?: string;
|
|
301
|
+
/** What the deck's other pictures show, so this one shows something else. */
|
|
302
|
+
avoid?: readonly string[];
|
|
150
303
|
}
|
|
151
304
|
/**
|
|
152
305
|
* One art call. Resolves to the picture's bytes and what it depicts, or throws
|
|
153
306
|
* with the reason — which the pass reports, and then draws the beat without.
|
|
154
307
|
*/
|
|
155
|
-
|
|
308
|
+
/** What one art call drew: the subjects, and the backdrop when the tool drew one. */
|
|
309
|
+
export interface Drawn {
|
|
156
310
|
bytes: Buffer;
|
|
157
311
|
width: number;
|
|
158
312
|
height: number;
|
|
159
313
|
depicts: string;
|
|
160
|
-
|
|
314
|
+
setting: string;
|
|
315
|
+
motifs: string[];
|
|
316
|
+
plate?: {
|
|
317
|
+
bytes: Buffer;
|
|
318
|
+
width: number;
|
|
319
|
+
height: number;
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
export declare function drawArt(brief: ArtBrief, opts: DrawArtOptions): Promise<Drawn>;
|
|
161
323
|
/**
|
|
162
324
|
* The picture at `path`, if it is one the image tool saved: inside
|
|
163
325
|
* `<home>/generated_images/`, after symlinks; a PNG by its magic bytes; under
|
|
@@ -170,4 +332,8 @@ export declare function copyArt(entries: Iterable<{
|
|
|
170
332
|
}>, out: string): Promise<string[]>;
|
|
171
333
|
/** Where a deck's page finds an illustration. */
|
|
172
334
|
export declare function artHref(art: ArtRef): string;
|
|
335
|
+
/** Where a deck's page finds one of a picture's depth planes. */
|
|
336
|
+
export declare function planeHref(p: {
|
|
337
|
+
name: string;
|
|
338
|
+
}): string;
|
|
173
339
|
export {};
|
|
@@ -34,6 +34,16 @@ export interface KeyInput {
|
|
|
34
34
|
pack: unknown;
|
|
35
35
|
/** The illustration's art key (src/bespoke/art.ts), when the scene was drawn around one. */
|
|
36
36
|
art?: string;
|
|
37
|
+
/**
|
|
38
|
+
* The scene's visual device and its idea (`assignDevices`): both are in its
|
|
39
|
+
* prompt. The beat's own only — no other beat's device is in a scene's
|
|
40
|
+
* prompt, so editing one beat does not re-key the scenes after it.
|
|
41
|
+
*/
|
|
42
|
+
device?: string;
|
|
43
|
+
idea?: string;
|
|
44
|
+
/** The camera grammar and the data build (round 5): both shape the prompt and the scene. */
|
|
45
|
+
grammar?: string;
|
|
46
|
+
build?: string;
|
|
37
47
|
}
|
|
38
48
|
export interface CacheEntry {
|
|
39
49
|
version: number;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate `card_row`: a generated scene whose main visual is the template the
|
|
3
|
+
* bespoke pass exists to replace — a row of cards, a column of panels, a grid
|
|
4
|
+
* of tiles. Round 2 and round 4 both recorded scenes that "still speak the
|
|
5
|
+
* language of labelled cards and connectors"; the prompt forbids it, and this
|
|
6
|
+
* is the cheap check that it was obeyed.
|
|
7
|
+
*
|
|
8
|
+
* STATIC, from the markup alone: every `<rect>` with literal geometry, moved by
|
|
9
|
+
* the `translate`/`scale` (and the `rotate(0)` or axis-aligned `matrix`) of the
|
|
10
|
+
* `<g>`s around it and by the `x`/`y`/`viewBox` of a nested `<svg>`, outside
|
|
11
|
+
* `<defs>`, clip paths, masks, patterns and symbols (a reveal's clip rect is not
|
|
12
|
+
* a card); and every `<div>` placed by `left`/`top`/`width`/`height` in px, in
|
|
13
|
+
* its inline style or in a `#id` rule of the scene's css. A card is a
|
|
14
|
+
* rect at least `MIN_SIDE` of the box on each side and under `MAX_W`/`MAX_H` of
|
|
15
|
+
* it (a ground or a band is not one). Cards are "alike" when both sides agree
|
|
16
|
+
* within `ALIKE`. The scene is flagged when three or more alike cards share a
|
|
17
|
+
* row (centres within half a card's height) or a column, or four make a grid —
|
|
18
|
+
* and together they cover at least `MIN_AREA` of the box, so a legend's swatches
|
|
19
|
+
* or a counter's plate never trip it.
|
|
20
|
+
*
|
|
21
|
+
* What it cannot see: cards drawn as `<path>`, positioned only by the script,
|
|
22
|
+
* placed by a `<use>`, rotated, or laid out by flex/grid/class rules rather than
|
|
23
|
+
* px boxes. It is a heuristic for the commonest case, not proof of a good scene
|
|
24
|
+
* — the critique round and a person judge the rest.
|
|
25
|
+
*
|
|
26
|
+
* A DATA beat is never asked (src/bespoke/pipeline.ts): its prompt asks for
|
|
27
|
+
* bars, and four bars of close values (PSNR 35.4 against 36.2) are alike
|
|
28
|
+
* rectangles in a row by every measure here.
|
|
29
|
+
*/
|
|
30
|
+
/** A card's sides, as shares of the body box. */
|
|
31
|
+
export declare const MIN_SIDE = 0.08;
|
|
32
|
+
export declare const MAX_W = 0.6;
|
|
33
|
+
export declare const MAX_H = 0.8;
|
|
34
|
+
/** Two cards are alike when each side is within this share of the other's. */
|
|
35
|
+
export declare const ALIKE = 0.2;
|
|
36
|
+
/** The cards of a row must cover this share of the box between them. */
|
|
37
|
+
export declare const MIN_AREA = 0.12;
|
|
38
|
+
/**
|
|
39
|
+
* Bump with any change to what `cardRow` flags. Part of the gate stamp a cached
|
|
40
|
+
* rejection carries (src/bespoke/pipeline.ts `GATE_STAMP`), so loosening this
|
|
41
|
+
* check releases the scenes it refused instead of keeping them archetypes.
|
|
42
|
+
*/
|
|
43
|
+
export declare const CARDS_VERSION = "cards-2:0.08/0.6/0.8/0.2/0.12";
|
|
44
|
+
interface Rect {
|
|
45
|
+
x: number;
|
|
46
|
+
y: number;
|
|
47
|
+
w: number;
|
|
48
|
+
h: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The cards the markup draws, in box px. `css` is the scene's stylesheet: a
|
|
52
|
+
* `<div>` placed and sized by its `#id` rule is read like one placed inline.
|
|
53
|
+
*/
|
|
54
|
+
export declare function cardsOf(markup: string, box: {
|
|
55
|
+
width: number;
|
|
56
|
+
height: number;
|
|
57
|
+
}, css?: string): Rect[];
|
|
58
|
+
/**
|
|
59
|
+
* Why the scene's main visual is a card row or a tile grid, or undefined when
|
|
60
|
+
* it is not. The message names what was found, for the critique round.
|
|
61
|
+
*/
|
|
62
|
+
export declare function cardRow(markup: string, box: {
|
|
63
|
+
width: number;
|
|
64
|
+
height: number;
|
|
65
|
+
}, css?: string): string | undefined;
|
|
66
|
+
export {};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type Label } from "./callouts.js";
|
|
2
1
|
import type { Shot } from "./shots.js";
|
|
3
2
|
/** What a model hands back for one beat. Token form: ids are `SCENEID-…`. */
|
|
4
3
|
export interface Fragment {
|
|
@@ -10,11 +9,6 @@ export interface Fragment {
|
|
|
10
9
|
* camera frames on which cue (src/bespoke/shots.ts). Absent on any other scene.
|
|
11
10
|
*/
|
|
12
11
|
shots?: Shot[];
|
|
13
|
-
/**
|
|
14
|
-
* An illustrated scene's subject labels, which the shell draws ON their
|
|
15
|
-
* subjects (src/bespoke/callouts.ts). Absent on any other scene.
|
|
16
|
-
*/
|
|
17
|
-
labels?: Label[];
|
|
18
12
|
}
|
|
19
13
|
/** One reason a fragment may not be used. */
|
|
20
14
|
export interface StaticFinding {
|
|
@@ -40,8 +34,6 @@ export interface FragmentContext {
|
|
|
40
34
|
subjects?: number;
|
|
41
35
|
/** How many narration cues the scene has, for its shot list. */
|
|
42
36
|
cues?: number;
|
|
43
|
-
/** Whether a label's text fits its subject's zone (src/bespoke/callouts.ts `fitLabel`). */
|
|
44
|
-
labelFits?: (text: string, subject: number) => boolean;
|
|
45
37
|
}
|
|
46
38
|
export declare function checkMarkup(markup: string, ctx?: FragmentContext): StaticFinding[];
|
|
47
39
|
export declare function checkCss(css: string): StaticFinding[];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DATA BUILDS: how a data beat's chart comes on, chosen per beat so no two
|
|
3
|
+
* data beats of a deck build alike.
|
|
4
|
+
*
|
|
5
|
+
* WHY. Round 4 drew data beats as clean charts that build — and every one of
|
|
6
|
+
* them built the same way: bars grow from zero while their counters count up,
|
|
7
|
+
* no camera. An explainer varies the verb with the point: a ranking RACES, a
|
|
8
|
+
* trend is TRACED with a callout on the moment that matters, a gap is the
|
|
9
|
+
* DELTA highlighted, several series side by side are SMALL MULTIPLES lit one
|
|
10
|
+
* after another. And the camera works on a chart as on a picture: it pushes
|
|
11
|
+
* in on the value the voice names and pulls back for the whole.
|
|
12
|
+
*
|
|
13
|
+
* Each build is checked statically (`checkBuild`): the scene declares it on
|
|
14
|
+
* its root group (`data-build`) and carries the marks the build is made of
|
|
15
|
+
* (round 6: the camera is the scene's choice, no longer required — r1's smoke
|
|
16
|
+
* deck lost a data beat to that rule alone); the shell stamps it on the scene (`data-ds-build`) so the
|
|
17
|
+
* deck gate (`verify`) refuses two data beats that build alike.
|
|
18
|
+
*
|
|
19
|
+
* ROUND 6 dropped the bar race: bars growing from zero and sliding to their
|
|
20
|
+
* rank are the animated UI the founder called old-fashioned, and `ui_motion`
|
|
21
|
+
* refuses them. A chart's marks stand at their size and come on by drawing or
|
|
22
|
+
* fading; the camera and the voice carry the comparison.
|
|
23
|
+
*/
|
|
24
|
+
/** A data beat's build. */
|
|
25
|
+
export type DataBuild = "line-callout" | "delta" | "small-multiples";
|
|
26
|
+
export declare const BUILDS: readonly DataBuild[];
|
|
27
|
+
/**
|
|
28
|
+
* The build for a data beat of `archetype`, given the builds of the data beats
|
|
29
|
+
* before it in deck order: the best fit the deck has not used; past three data
|
|
30
|
+
* beats, the best fit that is not the previous one.
|
|
31
|
+
*/
|
|
32
|
+
export declare function chooseBuild(archetype: string, prior: readonly DataBuild[]): DataBuild;
|
|
33
|
+
/** What each build is, as the prompt says it. */
|
|
34
|
+
export declare const BUILD_NOTES: Readonly<Record<DataBuild, string>>;
|
|
35
|
+
/** One reason a data scene does not build as asked. */
|
|
36
|
+
export interface BuildFinding {
|
|
37
|
+
rule: "data_build";
|
|
38
|
+
message: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Whether a data scene builds as `build` asks: it declares the build on a
|
|
42
|
+
* group, carries the marks the build is made of, animates them the build's
|
|
43
|
+
* way. Markup and script are the fragment's (token form).
|
|
44
|
+
*/
|
|
45
|
+
export declare function checkBuild(f: {
|
|
46
|
+
markup: string;
|
|
47
|
+
script: string;
|
|
48
|
+
}, build: DataBuild): BuildFinding[];
|
|
49
|
+
/** The data builds of a deck's kept data scenes, in deck order, and which repeat. */
|
|
50
|
+
export declare function buildRepeats(seq: readonly string[]): string[];
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { DepthCopies } from "./art.js";
|
|
2
|
+
/** The Core ML package's directory name. */
|
|
3
|
+
export declare const DEPTH_MODEL_NAME = "DepthAnythingV2SmallF16.mlpackage";
|
|
4
|
+
/** The ncnn model the upscaler is run with (x2). */
|
|
5
|
+
export declare const UPSCALE_MODEL = "realesr-animevideov3";
|
|
6
|
+
/** How the planes of one picture were made, for the report. */
|
|
7
|
+
export interface DepthInfo {
|
|
8
|
+
/** "depth-anything-v2-small" when the model ran; "flat" when it did not. */
|
|
9
|
+
model: "depth-anything-v2-small" | "flat";
|
|
10
|
+
/** Why it is flat. */
|
|
11
|
+
reason?: string;
|
|
12
|
+
/** 2 when the picture was upscaled before slicing; 1 when it was not (and why). */
|
|
13
|
+
upscale: number;
|
|
14
|
+
upscaleReason?: string;
|
|
15
|
+
}
|
|
16
|
+
/** `~/.cache/decksmith`, where the optional models live. */
|
|
17
|
+
export declare function decksmithCache(env?: NodeJS.ProcessEnv): string;
|
|
18
|
+
/** The depth model's path, or the reason there is none. */
|
|
19
|
+
export declare function depthModel(env?: NodeJS.ProcessEnv, platform?: string): Promise<{
|
|
20
|
+
path: string;
|
|
21
|
+
} | {
|
|
22
|
+
reason: string;
|
|
23
|
+
}>;
|
|
24
|
+
/** The upscaler's binary and its models folder, or the reason there is none. */
|
|
25
|
+
export declare function upscaler(env?: NodeJS.ProcessEnv): Promise<{
|
|
26
|
+
bin: string;
|
|
27
|
+
models: string;
|
|
28
|
+
} | {
|
|
29
|
+
reason: string;
|
|
30
|
+
}>;
|
|
31
|
+
/**
|
|
32
|
+
* The Swift helper: `depth <model> <in.png> <out.png>`. The package is compiled
|
|
33
|
+
* on first use and the compiled model kept beside the helper, so later pictures
|
|
34
|
+
* skip the compile. CPU only: the answer is cached per picture, and the CPU's
|
|
35
|
+
* is the one that does not change with what else the GPU is doing.
|
|
36
|
+
*/
|
|
37
|
+
export declare const DEPTH_SWIFT = "import Foundation\nimport CoreML\nimport CoreImage\nimport ImageIO\nimport Vision\n\nlet a = CommandLine.arguments\nfunc fail(_ m: String) -> Never { FileHandle.standardError.write((m + \"\\n\").data(using: .utf8)!); exit(1) }\nguard a.count == 5 else { fail(\"usage: depth <model.mlpackage> <compiled dir> <in.png> <out.png>\") }\nlet pkg = URL(fileURLWithPath: a[1])\nlet compiled = URL(fileURLWithPath: a[2])\ndo {\n if !FileManager.default.fileExists(atPath: compiled.path) {\n let tmp = try MLModel.compileModel(at: pkg)\n try? FileManager.default.createDirectory(at: compiled.deletingLastPathComponent(), withIntermediateDirectories: true)\n let staged = compiled.deletingLastPathComponent().appendingPathComponent(UUID().uuidString + \".mlmodelc\")\n try FileManager.default.moveItem(at: tmp, to: staged)\n if (try? FileManager.default.moveItem(at: staged, to: compiled)) == nil { try? FileManager.default.removeItem(at: staged) }\n }\n let cfg = MLModelConfiguration()\n cfg.computeUnits = .cpuOnly\n let model = try MLModel(contentsOf: compiled, configuration: cfg)\n guard let (inName, inDesc) = model.modelDescription.inputDescriptionsByName.first,\n let c = inDesc.imageConstraint,\n let outName = model.modelDescription.outputDescriptionsByName.keys.first else { fail(\"not an image model\") }\n guard let src = CGImageSourceCreateWithURL(URL(fileURLWithPath: a[3]) as CFURL, nil),\n let img = CGImageSourceCreateImageAtIndex(src, 0, nil) else { fail(\"cannot read the picture\") }\n let fv = try MLFeatureValue(cgImage: img, constraint: c, options: [.cropAndScale: VNImageCropAndScaleOption.scaleFill.rawValue])\n let out = try model.prediction(from: MLDictionaryFeatureProvider(dictionary: [inName: fv]))\n guard let pb = out.featureValue(for: outName)?.imageBufferValue else { fail(\"no depth image\") }\n try CIContext().writePNGRepresentation(of: CIImage(cvPixelBuffer: pb), to: URL(fileURLWithPath: a[4]), format: .RGBA8, colorSpace: CGColorSpace(name: CGColorSpace.sRGB)!)\n print(\"{\\\"width\\\":\\(CVPixelBufferGetWidth(pb)),\\\"height\\\":\\(CVPixelBufferGetHeight(pb))}\")\n} catch { fail(\"\\(error)\") }\n";
|
|
38
|
+
/**
|
|
39
|
+
* The backdrop's depth as a grey RGBA PNG (Depth Anything's relative inverse
|
|
40
|
+
* depth: brighter is nearer; RGBA because the repository's PNG reader takes
|
|
41
|
+
* no greyscale), at the model's own 518x392. Rejects with why.
|
|
42
|
+
*/
|
|
43
|
+
export declare function estimateDepth(png: string, out: string, toolDir: string, model: string): Promise<void>;
|
|
44
|
+
/** `in.png` upscaled 2x into `out.png`, alpha kept. Rejects with why. */
|
|
45
|
+
export declare function upscale2x(png: string, out: string, up: {
|
|
46
|
+
bin: string;
|
|
47
|
+
models: string;
|
|
48
|
+
}): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Where to cut the backdrop into planes: depth quantiles of its pixels (a far
|
|
51
|
+
* plane for the farther half, a middle and a near one), merged where two
|
|
52
|
+
* planes would sit closer than `MIN_SEPARATION` in depth — a plane that moves
|
|
53
|
+
* like its neighbour is bytes for nothing. `values` is the depth map's pixels
|
|
54
|
+
* (0..255). Returns the cut points (0..1, ascending) — none for a flat picture.
|
|
55
|
+
*/
|
|
56
|
+
export declare const CUT_QUANTILES: readonly [0.5, 0.82];
|
|
57
|
+
export declare const MIN_SEPARATION = 0.12;
|
|
58
|
+
export declare function depthCuts(values: ArrayLike<number>): number[];
|
|
59
|
+
/**
|
|
60
|
+
* The nearest and farthest a plane may be put, in subject-plane units. A plane
|
|
61
|
+
* at z zooms by z / (z - (1 - 1/s)) when the camera pushes to s: MEASURED
|
|
62
|
+
* 2026-10-10 on the first r6 deck, a foreground plane at 0.6 swung to 2.7x on a
|
|
63
|
+
* 1.6x push and filled half the frame with a blurred wall. At 0.8 it is 1.9x.
|
|
64
|
+
*/
|
|
65
|
+
export declare const Z_NEAR = 0.8;
|
|
66
|
+
export declare const Z_FAR = 3;
|
|
67
|
+
/** Subjects stay within this range of the reference plane: their boxes are the camera's targets. */
|
|
68
|
+
export declare const SUBJECT_Z: readonly [number, number];
|
|
69
|
+
/**
|
|
70
|
+
* A plane's distance from the camera, from its relative inverse depth `u`
|
|
71
|
+
* (0 far .. 1 near), with the subjects' typical `u` at distance 1 — the plane
|
|
72
|
+
* the shell's camera frames (`#sid-cam`). Depth Anything's output is affine-
|
|
73
|
+
* invariant disparity, so `0.35` stands in for its unknown shift: a far wall
|
|
74
|
+
* at u≈0.1 lands at ~2x the subjects' distance, a near floor at ~0.75x.
|
|
75
|
+
*/
|
|
76
|
+
export declare function zOf(u: number, uRef: number): number;
|
|
77
|
+
/** A subject's distance: where it stands on the backdrop, held near the reference plane. */
|
|
78
|
+
export declare function subjectZ(uFoot: number, uRef: number): number;
|
|
79
|
+
/**
|
|
80
|
+
* The depth under each subject's foot (the bottom centre of its box, a little
|
|
81
|
+
* inside), read from the backdrop's depth map. Boxes are shares of the
|
|
82
|
+
* picture; `depth` is the map, row-major, `w` x `h`.
|
|
83
|
+
*/
|
|
84
|
+
export declare function footDepths(depth: ArrayLike<number>, w: number, h: number, boxes: ReadonlyArray<readonly [number, number, number, number]>): number[];
|
|
85
|
+
/** What `cutPicture` is given: a drawn picture, and where to work. */
|
|
86
|
+
export interface CutInput {
|
|
87
|
+
/** The subjects' picture (transparent ground), or the whole picture when there is no backdrop. */
|
|
88
|
+
subjects: Buffer;
|
|
89
|
+
/** The backdrop, when the illustrator drew one. */
|
|
90
|
+
plate?: Buffer;
|
|
91
|
+
/** The subjects' boxes, shares of the subjects' picture (src/bespoke/inspect.ts). */
|
|
92
|
+
boxes: ReadonlyArray<readonly [number, number, number, number]>;
|
|
93
|
+
/** The frame the planes must cover, px. */
|
|
94
|
+
frame: {
|
|
95
|
+
width: number;
|
|
96
|
+
height: number;
|
|
97
|
+
};
|
|
98
|
+
/** Scratch for the intermediate PNGs. */
|
|
99
|
+
work: string;
|
|
100
|
+
tag: string;
|
|
101
|
+
/** Where the compiled helpers live (the inspection's). */
|
|
102
|
+
toolDir: string;
|
|
103
|
+
env?: NodeJS.ProcessEnv;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* A drawn picture cut into depth planes for the shell's camera: upscaled 2x
|
|
107
|
+
* when the upscaler is there, its backdrop's depth estimated when the model is
|
|
108
|
+
* there, sliced (sheet.ts `depthPlanes`), and every plane and subject given a
|
|
109
|
+
* distance. Each optional step that cannot run is recorded in `info` and the
|
|
110
|
+
* cut goes on without it; only a Chrome that cannot draw the planes throws.
|
|
111
|
+
*/
|
|
112
|
+
export declare function cutPicture(i: CutInput): Promise<DepthCopies>;
|
|
113
|
+
/** A flat picture's backdrop distance: it moves at half the subjects' zoom, as round 5's did. */
|
|
114
|
+
export declare const FLAT_Z = 2;
|
|
115
|
+
/** The subjects' depth is at least this much nearer than the backdrop's farthest band (relative inverse depth). */
|
|
116
|
+
export declare const REF_BEHIND = 0.15;
|
|
117
|
+
/**
|
|
118
|
+
* The depth the camera's plane (distance 1) is put at: the subjects' median
|
|
119
|
+
* foot, held IN the scene — at least `REF_BEHIND` nearer than the backdrop's
|
|
120
|
+
* farthest band and no nearer than its nearest — whatever the feet read (a
|
|
121
|
+
* subject drawn high in its picture can land on the far wall of the
|
|
122
|
+
* backdrop's map). MEASURED 2026-10-10: one picture's feet read farther than
|
|
123
|
+
* every backdrop band, every plane landed nearer than the subjects, and the
|
|
124
|
+
* backdrop zoomed MORE than they did (shot_variety: "no parallax").
|
|
125
|
+
* `bands` are the planes' mean depths, far to near.
|
|
126
|
+
*/
|
|
127
|
+
export declare function referenceDepth(feet: readonly number[], bands: readonly number[]): number;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SHOT GRAMMARS: how the shell's camera tells one illustrated scene, chosen per
|
|
3
|
+
* beat by what the narration is doing, and never the same on two scenes in a row.
|
|
4
|
+
*
|
|
5
|
+
* WHY. Round 4 staged every illustrated scene in one grammar — the whole
|
|
6
|
+
* picture, a push in on each subject the voice names, the whole again. That is
|
|
7
|
+
* how an explainer cuts one shot, and also, scene after scene, the "same
|
|
8
|
+
* animation every card" the founder dislikes, one level up. An explainer
|
|
9
|
+
* editor picks the move by the sentence: two things weighed against each other
|
|
10
|
+
* get a rack between them; a process gets a camera that travels along it; a
|
|
11
|
+
* "turns out" gets a close detail that pulls back to show where it sits; a
|
|
12
|
+
* number gets a hard cut to the thing measured. So does this file:
|
|
13
|
+
*
|
|
14
|
+
* tour establish → push in on each named subject → reveal (round 4's)
|
|
15
|
+
* follow establish → push in on the first subject → TRACK along the
|
|
16
|
+
* others at one scale, slow and continuous (a process, a pipeline)
|
|
17
|
+
* rack establish → A → whip to B → back to A → a two-shot of both →
|
|
18
|
+
* reveal (a comparison, a cause and its effect)
|
|
19
|
+
* zoom-out OPENS CLOSE on the key detail, pulls back to a two-subject
|
|
20
|
+
* frame, then to the whole (a reveal of context)
|
|
21
|
+
* wipe the picture is wiped on subject by subject as the voice names
|
|
22
|
+
* each, the camera wide and creeping (a reveal, a sequence)
|
|
23
|
+
* cutaway wide, and HARD CUTS to a close insert of what is measured, then
|
|
24
|
+
* back (a number, a detail)
|
|
25
|
+
* parallax a slow lateral truck across the scene at a medium scale, the
|
|
26
|
+
* backdrop sliding slower than the subjects (a setting, a definition)
|
|
27
|
+
*
|
|
28
|
+
* The role is read from the beat deterministically (archetype, then the
|
|
29
|
+
* narration's own words in en/ko/zh/ja); the grammar is the role's best fit
|
|
30
|
+
* that the deck has not just used. `chooseGrammar` is a pure function of the
|
|
31
|
+
* role and the grammars before it, so it slots into the up-front, deck-order
|
|
32
|
+
* device pass (`assignDevices`) as one more field beside a beat's device.
|
|
33
|
+
*/
|
|
34
|
+
/** What the narration of a beat is doing, rhetorically. */
|
|
35
|
+
export type Role = "compare" | "cause" | "process" | "reveal" | "quantify" | "define";
|
|
36
|
+
export declare const ROLES: readonly Role[];
|
|
37
|
+
/** How the shell's camera tells an illustrated scene. */
|
|
38
|
+
export type Grammar = "tour" | "follow" | "rack" | "zoom-out" | "wipe" | "cutaway" | "parallax";
|
|
39
|
+
export declare const GRAMMARS: readonly Grammar[];
|
|
40
|
+
/** Each role's grammars, best fit first. Every grammar appears for every role, so a choice always exists. */
|
|
41
|
+
export declare const FIT: Readonly<Record<Role, readonly Grammar[]>>;
|
|
42
|
+
/**
|
|
43
|
+
* The role a beat plays: its archetype's prior (two, or one for a generic
|
|
44
|
+
* layout) against the narration's own signals (each match one, at most three
|
|
45
|
+
* per role). Ties go to the more specific role.
|
|
46
|
+
*/
|
|
47
|
+
export declare function roleOf(beat: {
|
|
48
|
+
archetype: string;
|
|
49
|
+
intent?: string;
|
|
50
|
+
claim?: string;
|
|
51
|
+
narration?: string;
|
|
52
|
+
}): Role;
|
|
53
|
+
/**
|
|
54
|
+
* The grammar for a beat of role `role`, given the grammars of the illustrated
|
|
55
|
+
* beats before it in deck order: best fit first, one the deck has not used,
|
|
56
|
+
* else one not used by the last two — so never the previous one.
|
|
57
|
+
* Deterministic.
|
|
58
|
+
*/
|
|
59
|
+
export declare function chooseGrammar(role: Role, prior: readonly Grammar[]): Grammar;
|
|
60
|
+
/** `chooseGrammar` over a deck's beats in order. */
|
|
61
|
+
export declare function assignGrammars(roles: readonly Role[]): Grammar[];
|
|
62
|
+
/**
|
|
63
|
+
* A deck's grammars as the gate reads them: how many distinct ones, and which
|
|
64
|
+
* consecutive pairs repeat. `seq` is the deck's illustrated scenes in order.
|
|
65
|
+
*/
|
|
66
|
+
export declare function grammarRepeats(seq: readonly string[]): {
|
|
67
|
+
distinct: number;
|
|
68
|
+
adjacent: Array<[number, string]>;
|
|
69
|
+
};
|
|
70
|
+
/** The wanted diversity of `n` illustrated scenes: all different up to four, then at least four. */
|
|
71
|
+
export declare function diversityWanted(n: number): number;
|
|
72
|
+
/** What the prompt tells a scene its grammar does, so its shot list and its own motion fit it. */
|
|
73
|
+
export declare const GRAMMAR_NOTES: Readonly<Record<Grammar, string>>;
|