@jokerized/decksmith 0.2.0 → 0.3.1
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 +2 -1
- package/dist/cli.js +679 -132
- package/dist/ds-morph.js +1 -0
- package/dist/index.js +661 -130
- package/dist/mcp.js +374 -39
- package/dist/types/emit/archetypes/equation-morph.d.ts +2 -0
- package/dist/types/emit/archetypes/equation-walk.d.ts +63 -1
- package/dist/types/emit/archetypes/index.d.ts +1 -1
- package/dist/types/emit/archetypes/stack.d.ts +9 -0
- package/dist/types/emit/depth.d.ts +95 -0
- package/dist/types/emit/kit.d.ts +7 -0
- package/dist/types/emit/morph-runtime.d.ts +178 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/mcp/tools.d.ts +12 -0
- package/dist/types/plan/arc.d.ts +82 -0
- package/dist/types/plan/codex.d.ts +6 -0
- package/dist/types/prefs.d.ts +1 -0
- package/dist/types/render/ffmpeg.d.ts +0 -14
- package/dist/types/types.d.ts +412 -0
- package/dist/types/verify/apparent.d.ts +123 -0
- package/dist/types/verify/index.d.ts +64 -0
- package/dist/types/verify/typefloor.d.ts +3 -1
- package/package.json +1 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The type floor, measured on the rendered frame instead of read off the source.
|
|
3
|
+
*
|
|
4
|
+
* `typefloor.ts` scans declared sizes and says so plainly in its own header:
|
|
5
|
+
* "text shrunk by a `scale` below 1 at a hold reads as its unscaled size". That
|
|
6
|
+
* hole is not hypothetical and it is not only about `scale`. Measured in Chrome
|
|
7
|
+
* at `rotateX(30deg)` under `perspective: 1400px`, a run declaring 46px renders
|
|
8
|
+
* 31.4 apparent px near the top of the plane — invariant 5 broken by 8.6px, with
|
|
9
|
+
* `lint`, `check`, `drift` and the declared-size scan all green, because not one
|
|
10
|
+
* of them looks at how big the glyph actually came out.
|
|
11
|
+
*
|
|
12
|
+
* That matters now because Gap 2 wants depth, and every way of tilting a plane
|
|
13
|
+
* shrinks the type on the far half of it. A depth archetype built against a floor
|
|
14
|
+
* that cannot see projection would ship unreadable slides that pass. So the gate
|
|
15
|
+
* comes first and the archetype second.
|
|
16
|
+
*
|
|
17
|
+
* HOW APPARENT SIZE IS MEASURED. For an SVG text node, `getBBox()` is the
|
|
18
|
+
* untransformed box in user units and `getClientRects()` is the painted box in
|
|
19
|
+
* device px, so their ratio is the TOTAL scale between the two — the element's
|
|
20
|
+
* own transform, every ancestor transform, the 3D projection's per-point
|
|
21
|
+
* perspective divide, and the stage zoom, all of it, without having to know which
|
|
22
|
+
* of them applied. Measured against the three cases that matter:
|
|
23
|
+
*
|
|
24
|
+
* flat, declared 46 ratio 1.000 -> 46.0 apparent px
|
|
25
|
+
* tilted 30deg, near plane top 0.682 -> 31.4
|
|
26
|
+
* tilted 30deg, near plane bottom 1.126 -> 51.8 (magnified, not a fault)
|
|
27
|
+
* `scale(0.6)` at a hold 0.600 -> 27.6
|
|
28
|
+
*
|
|
29
|
+
* `getScreenCTM()` was tried first and rejected: it returns 0.673 for BOTH the
|
|
30
|
+
* top and bottom runs above, because it carries the affine part and drops the
|
|
31
|
+
* perspective divide that makes those two differ by 23 apparent px.
|
|
32
|
+
*
|
|
33
|
+
* WHY IT DIVIDES BY THE STAGE. A deck legitimately scales its whole stage —
|
|
34
|
+
* `zoomOf`/`REF_PULL` — and in portrait 40 reference px is SUPPOSED to land at 30
|
|
35
|
+
* canvas px, which `typefloor.ts` calls "the whole argument of REF_PULL and not a
|
|
36
|
+
* violation". Dividing the run's own ratio by the scene's gives apparent size
|
|
37
|
+
* back in REFERENCE px, so this gate agrees with the declared one on every deck
|
|
38
|
+
* that does nothing clever, and only diverges where something shrank one element
|
|
39
|
+
* relative to its own scene.
|
|
40
|
+
*/
|
|
41
|
+
import type { Finding } from "../types.js";
|
|
42
|
+
/** One text run, as the frame actually drew it. */
|
|
43
|
+
export interface ApparentRun {
|
|
44
|
+
/** First 40 characters, for the message. */
|
|
45
|
+
text: string;
|
|
46
|
+
/** `font-size` as declared, in px. */
|
|
47
|
+
declared: number;
|
|
48
|
+
/** Painted height over untransformed height, including the stage's own zoom. */
|
|
49
|
+
ratio: number;
|
|
50
|
+
/** Its own computed opacity, multiplied down the ancestors that carry one. */
|
|
51
|
+
opacity: number;
|
|
52
|
+
}
|
|
53
|
+
/** What `measureApparent` hands back for one instant. */
|
|
54
|
+
export interface ApparentStop {
|
|
55
|
+
sid: string;
|
|
56
|
+
t: number;
|
|
57
|
+
runs: ApparentRun[];
|
|
58
|
+
/** The scene's own painted-over-declared scale, the baseline runs divide by. */
|
|
59
|
+
stage: number;
|
|
60
|
+
/**
|
|
61
|
+
* True at a declared stop, where the frame has arrived and everything drawn is
|
|
62
|
+
* being read. False at a sampled midpoint, where a run may be part-way through
|
|
63
|
+
* its own entrance — see `SETTLED_OPACITY`.
|
|
64
|
+
*/
|
|
65
|
+
settled: boolean;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Serialised into the page: every visible SVG text run's apparent scale.
|
|
69
|
+
*
|
|
70
|
+
* Deliberately the same walk as `collectSvgTextRuns` in overprint.ts — same
|
|
71
|
+
* visibility rules, same "only inside an `<svg>`" restriction — because two gates
|
|
72
|
+
* that disagree about which text exists are two gates that cannot be reconciled
|
|
73
|
+
* when they disagree about a deck.
|
|
74
|
+
*/
|
|
75
|
+
export declare function collectApparent(sid: string): {
|
|
76
|
+
runs: ApparentRun[];
|
|
77
|
+
stage: number;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Apparent size in reference px: what the run declared, times how much the frame
|
|
81
|
+
* shrank or grew it relative to its own scene.
|
|
82
|
+
*/
|
|
83
|
+
export declare function apparentPx(run: ApparentRun, stage: number): number;
|
|
84
|
+
/**
|
|
85
|
+
* How opaque a run must be, at a sampled midpoint, to count as text being read.
|
|
86
|
+
*
|
|
87
|
+
* At a declared stop the frame has arrived and everything drawn counts. Between
|
|
88
|
+
* stops it has not: `annotated-figure` enters its labels from `scale: 0.97`, so
|
|
89
|
+
* a run caught half way through its own entrance is BOTH under the floor and
|
|
90
|
+
* fading in, and failing a build for it would be crying wolf about a frame no
|
|
91
|
+
* one reads. A run at 0.95 opacity is not entering any more; it has arrived.
|
|
92
|
+
*/
|
|
93
|
+
export declare const SETTLED_OPACITY = 0.95;
|
|
94
|
+
/**
|
|
95
|
+
* The times to sample BETWEEN the declared stops.
|
|
96
|
+
*
|
|
97
|
+
* `fidelity` measures at stops because that is where a frame has settled, and
|
|
98
|
+
* the apparent floor inherited that — which left exactly the hole it was built
|
|
99
|
+
* to close, one interval over: text scaled DOWN between two stops is invisible
|
|
100
|
+
* to a gate that only looks at the stops. A camera pulling back, or an exit that
|
|
101
|
+
* shrinks a label, would ship.
|
|
102
|
+
*
|
|
103
|
+
* Midway between consecutive stops of the SAME scene. Not across a scene
|
|
104
|
+
* boundary, where the midpoint lands in a cross-fade between two compositions
|
|
105
|
+
* and belongs to neither. Costs a seek and a DOM read each — no screenshot,
|
|
106
|
+
* which is what makes doubling the sample count affordable.
|
|
107
|
+
*/
|
|
108
|
+
export declare function midpoints(stops: readonly {
|
|
109
|
+
sid: string;
|
|
110
|
+
t: number;
|
|
111
|
+
}[]): {
|
|
112
|
+
sid: string;
|
|
113
|
+
t: number;
|
|
114
|
+
}[];
|
|
115
|
+
/**
|
|
116
|
+
* Runs the frame drew below the floor, whatever shrank them.
|
|
117
|
+
*
|
|
118
|
+
* An ERROR, not a warning, and for the same reason `typefloor` is: text the
|
|
119
|
+
* audience cannot read is not a matter of degree. The tolerance is a tenth of a
|
|
120
|
+
* pixel, which is rasteriser noise rather than a grace margin — a deck that wants
|
|
121
|
+
* 40px declares 40px and measures 40.0, as the flat control does exactly.
|
|
122
|
+
*/
|
|
123
|
+
export declare function gradeApparent(stops: readonly ApparentStop[], floor?: number): Finding[];
|
|
@@ -242,6 +242,70 @@ export declare function scanUnusedFigures(storyboard: Storyboard, source: Source
|
|
|
242
242
|
* decision cannot be made by accident.
|
|
243
243
|
*/
|
|
244
244
|
export declare function scanBeatCount(storyboard: Storyboard, prefs: Prefs): Finding[];
|
|
245
|
+
/**
|
|
246
|
+
* Where a paper-shaped deck missed the shape it was asked for.
|
|
247
|
+
*
|
|
248
|
+
* SILENT UNLESS THE ARC WAS DECLARED. `prefs.genre` defaults to `general`, so
|
|
249
|
+
* every deck built before this existed, and every deck whose author did not say
|
|
250
|
+
* `--genre paper`, gets exactly nothing from this scan. That is not timidity: a
|
|
251
|
+
* ten-role heading lexicon over all 351 markdown files in this repository found
|
|
252
|
+
* 345 with zero hits, so there is no honest way to infer the genre, and a scan
|
|
253
|
+
* that guessed would mislabel the Korean fixture and every hypepaper analysis
|
|
254
|
+
* the tool actually ingests.
|
|
255
|
+
*
|
|
256
|
+
* REPORTED, NEVER REPAIRED, and a WARNING. It joins the four scans that already
|
|
257
|
+
* take that shape, and `scanBeatCount`'s header settles the class: `build`
|
|
258
|
+
* prints every content loss and fails on none of them, because the alternative
|
|
259
|
+
* is re-asking, and the only possible second instruction — "return more" — is a
|
|
260
|
+
* padding request with extra steps. Promoting this one is a decision about all
|
|
261
|
+
* of them.
|
|
262
|
+
*
|
|
263
|
+
* WHAT IT CANNOT DO. It cannot tell whether a beat labelled `limitations` really
|
|
264
|
+
* discusses one; `role` is the plan's own declaration, and a declaration can be
|
|
265
|
+
* false. What it checks instead is the part that is mechanical and that no
|
|
266
|
+
* committed plan has ever got right on its own: that the roles exist, that they
|
|
267
|
+
* are unique, that the ending is in the right ORDER, and that the closing pair
|
|
268
|
+
* does not collapse into two of the same picture. A rule about wording would be
|
|
269
|
+
* met cosmetically, exactly as `scanHeadlines` records a sharpened rule being
|
|
270
|
+
* answered by swapping one verb.
|
|
271
|
+
*/
|
|
272
|
+
export declare function scanPaperArc(storyboard: Storyboard, prefs: Prefs): Finding[];
|
|
273
|
+
/**
|
|
274
|
+
* Narration that belongs to a different version of this storyboard.
|
|
275
|
+
*
|
|
276
|
+
* `narration.json` is keyed by BEAT ID and carries nothing that ties it to the
|
|
277
|
+
* plan it was made for, so an id that still exists is an id `build` will happily
|
|
278
|
+
* speak — even when the beat behind it has been replaced. Renumbering is the way
|
|
279
|
+
* in: inserting one beat and shifting the ids after it leaves every later id
|
|
280
|
+
* pointing at its neighbour's voice.
|
|
281
|
+
*
|
|
282
|
+
* FOUND IN THE SHIPPED DEMO, and it is the seventh green-gate case this project
|
|
283
|
+
* has recorded. A thirteenth beat was inserted at position six and the rest
|
|
284
|
+
* renumbered; the audio on disk predated it, so beats six through twelve each
|
|
285
|
+
* spoke the slide after them and the thirteenth spoke nothing. `build` reported
|
|
286
|
+
* `PASS — 0 error(s), 0 warning(s)`, because every id it looked for was present
|
|
287
|
+
* and nothing compared what was SAID against what the beat says it says.
|
|
288
|
+
*
|
|
289
|
+
* AN ERROR, NOT A WARNING, and it is the one member of this family that earns
|
|
290
|
+
* it. The other storyboard scans are editorial judgements only an author can
|
|
291
|
+
* settle; this is a string comparison between two authored fields that must
|
|
292
|
+
* agree, and the artifact it lets through is a video whose voice describes the
|
|
293
|
+
* wrong pictures. Missing narration audio is already an error here, and audio
|
|
294
|
+
* that is present and wrong is not the better failure.
|
|
295
|
+
*
|
|
296
|
+
* NARROW ON PURPOSE. It compares only beats that have BOTH a narration text and
|
|
297
|
+
* segments, so a deck narrated at a lower density — where some beats are
|
|
298
|
+
* deliberately silent — says nothing, and the existing missing-audio error keeps
|
|
299
|
+
* its own case. Whitespace is normalised because the splitter re-joins sentences
|
|
300
|
+
* at stop boundaries; on the demo's thirteen beats the concatenation reproduces
|
|
301
|
+
* the authored text exactly, which is what makes the comparison safe to make
|
|
302
|
+
* fatal.
|
|
303
|
+
*/
|
|
304
|
+
export declare function scanNarrationDrift(storyboard: Storyboard, narration: {
|
|
305
|
+
beats: Record<string, {
|
|
306
|
+
text: string;
|
|
307
|
+
}[]>;
|
|
308
|
+
}): Finding[];
|
|
245
309
|
/**
|
|
246
310
|
* How far a name may precede the thing it names before a viewer notices.
|
|
247
311
|
*
|
|
@@ -28,7 +28,9 @@
|
|
|
28
28
|
*
|
|
29
29
|
* WHAT IT DOES NOT SEE, stated because a gate that overclaims is the thing this
|
|
30
30
|
* file was written to stop. It reads declared sizes, so text shrunk by a
|
|
31
|
-
* `scale` below 1 at a hold reads as its unscaled size
|
|
31
|
+
* `scale` below 1 at a hold reads as its unscaled size — `apparent.ts` is the
|
|
32
|
+
* gate that closes exactly that, by measuring the painted glyph instead, and it
|
|
33
|
+
* catches a 3D projection the same way; and it says nothing about
|
|
32
34
|
* whether the text FITS — `container_overflow` and `text_occluded` in
|
|
33
35
|
* `hyperframes check` are the gates for that, and `check.ts` already grades them
|
|
34
36
|
* up to errors.
|