@jokerized/decksmith 0.9.0 → 0.9.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 +212 -0
- package/dist/cli.js +20183 -14325
- package/dist/deck-player-element.js +1 -1
- package/dist/deck-player.js +1 -1
- package/dist/index.js +10605 -4957
- package/dist/mcp.js +1558 -319
- package/dist/types/bespoke/art.d.ts +173 -0
- package/dist/types/bespoke/cache.d.ts +69 -0
- package/dist/types/bespoke/callouts.d.ts +76 -0
- package/dist/types/bespoke/contract.d.ts +57 -0
- package/dist/types/bespoke/inspect.d.ts +69 -0
- package/dist/types/bespoke/pipeline.d.ts +207 -0
- package/dist/types/bespoke/probe.d.ts +34 -0
- package/dist/types/bespoke/prompt.d.ts +182 -0
- package/dist/types/bespoke/references.d.ts +73 -0
- package/dist/types/bespoke/repair.d.ts +121 -0
- package/dist/types/bespoke/scene.d.ts +97 -0
- package/dist/types/bespoke/select.d.ts +52 -0
- package/dist/types/bespoke/sheet.d.ts +26 -0
- package/dist/types/bespoke/shots.d.ts +128 -0
- package/dist/types/bespoke/untangle.d.ts +5 -0
- package/dist/types/emit/archetypes/index.d.ts +0 -7
- package/dist/types/emit/composition.d.ts +37 -2
- package/dist/types/emit/kit.d.ts +17 -0
- package/dist/types/emit/themes/pick.d.ts +6 -3
- package/dist/types/index.d.ts +17 -0
- package/dist/types/plan/codex.d.ts +36 -0
- package/dist/types/prefs.d.ts +10 -1
- package/dist/types/render/capture.d.ts +6 -0
- package/dist/types/render/timing.d.ts +3 -0
- package/dist/types/types.d.ts +71 -0
- package/dist/types/verify/check.d.ts +1 -1
- package/dist/types/verify/index.d.ts +14 -0
- package/dist/types/verify/scenes.d.ts +325 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -924,6 +924,218 @@ already built) and, while a stop's audio plays, seeks the scene through that sto
|
|
|
924
924
|
stretch on the audio clock so the emphasis lands on the same word as in the video. Both
|
|
925
925
|
are off under `prefers-reduced-motion`.
|
|
926
926
|
|
|
927
|
+
## v2 bespoke scenes (`--bespoke`)
|
|
928
|
+
|
|
929
|
+
The archetypes finish building in about five seconds and then hold still while the voice
|
|
930
|
+
keeps talking. `build --design v2 --bespoke` hands four to six beats per deck to Codex
|
|
931
|
+
instead: for each, a GSAP + SVG scene written for that beat, keyed to its narration cues,
|
|
932
|
+
that keeps explaining for as long as the sentence runs. Everything else stays v2. It is off
|
|
933
|
+
unless asked for; v2 without it, and classic, emit the bytes they did.
|
|
934
|
+
|
|
935
|
+
```bash
|
|
936
|
+
decksmith build storyboard.json --source source.json -o deck --design v2 --bespoke
|
|
937
|
+
# bespoke: b03-action-loop.draft in 121s …
|
|
938
|
+
# bespoke: b05-backbone — every gate passed and the rubric probe is clean; no critique call
|
|
939
|
+
# bespoke: 4 of 5 beats drawn bespoke, 7 Codex call(s), 190985 tokens, 343s
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
**Which beats.** A deterministic rule (`src/bespoke/select.ts`): mechanism archetypes
|
|
943
|
+
(pipeline, equation-walk/-morph, line-chart, stack, grid, split-/bar-compare, and figures
|
|
944
|
+
last), mechanism words in en/ko/ja/zh, a cited equation, and the beat's weight; ties
|
|
945
|
+
broken by a hash. Never a title, callout or table, a beat with no narration, or a beat a
|
|
946
|
+
camera dives through. `plan --bespoke` lets the planner mark beats `bespoke: true|false`;
|
|
947
|
+
`false` is obeyed, `true` is a strong hint.
|
|
948
|
+
|
|
949
|
+
**Per beat:** illustration → draft → static contract → probe deck (a real build with every
|
|
950
|
+
`verify` gate plus the motion gates, photographed at every cue) → the rubric probe → at most
|
|
951
|
+
one critique-and-fix call with the contact sheet and the measures attached (`codex exec -i`)
|
|
952
|
+
→ static contract → probe again → repair rounds. A draft that passed every gate and is clean
|
|
953
|
+
by the rubric probe is kept without the critique call; one that fails only on what the
|
|
954
|
+
repair fixes, and is otherwise clean, is repaired instead of critiqued. A beat that does not
|
|
955
|
+
pass keeps its archetype — the deck is never failed. If the fix round breaks a draft that
|
|
956
|
+
passed, the draft is kept.
|
|
957
|
+
|
|
958
|
+
**The illustration** (`src/bespoke/art.ts`, `src/bespoke/inspect.ts`). Every bespoke beat
|
|
959
|
+
but a data beat gets ONE picture from the image tool of the same Codex account
|
|
960
|
+
(`codex exec` with every tool off but `image_generation`; no API key — the account's own
|
|
961
|
+
login, as for the scenes), all of a deck's pictures asked for at once before the drafts
|
|
962
|
+
queue for their lanes. The illustrator is given the beat (fenced, untrusted), the pack's
|
|
963
|
+
colours and one fixed style paragraph — flat 2D vector, solid fills with hard edges; no
|
|
964
|
+
gradients, shading, shadows, gloss, 3D, clay or toy renders, by name — and asked for three
|
|
965
|
+
or four subjects doing the method, big, left to right, with empty ground between them and
|
|
966
|
+
NO text. Each picture is then inspected locally, for free: its subjects are the connected
|
|
967
|
+
regions that are not its flat ground (boxed, left to right); its flatness is how much of
|
|
968
|
+
it sits in its 16 commonest colours minus how much of it is soft shading (`FLAT_MIN`,
|
|
969
|
+
calibrated on round 3's 21 renders against 12 flat pictures); and its writing is read by
|
|
970
|
+
macOS Vision, once per script (en, ko, ja, zh), through a small Swift helper compiled once
|
|
971
|
+
into `~/.cache/decksmith/tools`. A picture with writing, a shaded render or one whose
|
|
972
|
+
subjects touch is redrawn ONCE with the reason; of two refused pictures the one without
|
|
973
|
+
writing and the flatter is kept, and one with writing never is. Off macOS the text check
|
|
974
|
+
reports `unchecked` in `bespoke.json` rather than passing. The deck gets a WebP with its
|
|
975
|
+
edges feathered into transparency for its box (~30-75 KB against 1.3 MB of PNG; a CSS mask
|
|
976
|
+
on the picture cost ~0.7s a probe frame); the draft call is shown the PNG and a copy with
|
|
977
|
+
the subjects boxed and numbered (`-i`). The shell places it: `<image data-art="1">` with no
|
|
978
|
+
href gets the href and a fixed placement covering the body box (`slice`), so the subjects'
|
|
979
|
+
boxes are known in box px before the scene is written. It is read only from
|
|
980
|
+
`$CODEX_HOME/generated_images/` (after symlinks), only as a PNG by its magic bytes, under
|
|
981
|
+
12 MB. `--bespoke-art <n>` (default 6; `bespoke.art`) caps pictures per deck, counted apart
|
|
982
|
+
from `--bespoke-calls`; a beat whose picture cannot be had is drawn without one.
|
|
983
|
+
|
|
984
|
+
**Data beats** (line-chart, bar-compare, data-table) get no picture: their scene is asked
|
|
985
|
+
for the chart that builds with the voice — axes draw, bars grow with their counters, the
|
|
986
|
+
line traces, the named value lights — from the beat's own numbers, never a table painted
|
|
987
|
+
over an illustration (`data_over_picture`).
|
|
988
|
+
|
|
989
|
+
**The camera** of an illustrated scene is the shell's, staged in one grammar
|
|
990
|
+
(`src/bespoke/shots.ts`). The scene names its `shots` — on which cue, how far into it, which
|
|
991
|
+
subject — and the shell compiles them: an ESTABLISHING shot of the whole picture for at
|
|
992
|
+
least 1.6s, a PUSH IN (1.1s, power3.inOut) that frames the named subject and its label at
|
|
993
|
+
1.6-2.2x, a move straight to the next subject, a 3% creep while a shot is held, and a
|
|
994
|
+
REVEAL back to the whole picture at the last cue; shots closer than 1.6s are dropped. Every
|
|
995
|
+
camera tween is a `fromTo` with explicit from-values, and no two touch. The scene's own
|
|
996
|
+
script may not move `#sN-cam` (`script_camera`). A scene without a picture still moves the
|
|
997
|
+
wrapper itself (`scale`/`x`/`y`, arithmetic in the prompt). A scene with a moving camera is
|
|
998
|
+
clipped to its box and marked `data-ds-clip`, so `verify` does not count what a push-in
|
|
999
|
+
carries past the canvas edge as off-canvas.
|
|
1000
|
+
|
|
1001
|
+
**The labels** of an illustrated scene are the shell's too (`src/bespoke/callouts.ts`). The
|
|
1002
|
+
scene says what each subject is called (`labels`); the shell gives each subject a zone just
|
|
1003
|
+
above it (or across its top when there is no room), as wide as half the gap to each
|
|
1004
|
+
neighbour, and sets the name there on a plate — 56px, shrinking to 44, then two lines —
|
|
1005
|
+
with a leader line to a dot on the subject, entering as the camera first arrives on it (or
|
|
1006
|
+
at the reveal). The zones are in the draft prompt, which tells the scene to keep its own
|
|
1007
|
+
drawing out of them; a name that does not fit even on two lines at 44px is refused
|
|
1008
|
+
statically (`labels`). Round 4's first run, with the scene placing its own labels on the
|
|
1009
|
+
subjects, put them there and then failed four scenes in five on their own plates and
|
|
1010
|
+
leader lines crossing their text.
|
|
1011
|
+
|
|
1012
|
+
**Repair** (`src/bespoke/repair.ts`), no model call. On `text_overlap`,
|
|
1013
|
+
`graphic_crosses_text` or `svg_text_overprint`, each colliding label's unit (the text, or
|
|
1014
|
+
the smallest `<g>` holding it and its plate) gets one constant offset — the smallest, in
|
|
1015
|
+
8px rings over sixteen directions in a fixed order — that clears every other label by 16px,
|
|
1016
|
+
every visible stroke sample by 10px and every shape painted over it, inside the box, at
|
|
1017
|
+
every frame the probe measured, camera scale included; it is written as a wrapping
|
|
1018
|
+
`<g transform="translate()">`. A label never moves farther than 0.8 of its own height
|
|
1019
|
+
(at least 32px): a collision that needs more is left to the critique round. On
|
|
1020
|
+
`end_dimmed`, the elements dimming parts the scene had lit are tweened back to full
|
|
1021
|
+
strength just before the end; on `camera_end`, the camera is tweened home. On `seek_order`,
|
|
1022
|
+
two tweens on one target animating one property over overlapping time — which a timeline
|
|
1023
|
+
resolves one way seeking forward and the other seeking back — are untangled in favour of
|
|
1024
|
+
the later one (the earlier is shortened to end where it starts, or loses that target or
|
|
1025
|
+
property when both start together; `src/bespoke/untangle.ts`). A repaired scene goes
|
|
1026
|
+
through the static contract and is gated again (at most two repair rounds).
|
|
1027
|
+
|
|
1028
|
+
**What the model is shown** (`src/bespoke/prompt.ts`): the beat, its cues, the paper's
|
|
1029
|
+
excerpts (fenced, untrusted), the contract, motion-design rules with numbers (one focal
|
|
1030
|
+
element per cue at 88-120px, the rest dimmed but kept; fill the box; paint it with filled
|
|
1031
|
+
shapes; at least three kinds of motion, one of flow, camera, counter or morph; the end
|
|
1032
|
+
frame a summary), text widths measured in the pack's own font, and two of four hand-made
|
|
1033
|
+
reference scenes (`src/bespoke/references.ts`: a routing mechanism with particle flow and
|
|
1034
|
+
a counter, a camera zoom into one block, a traced curve whose gap morphs into the headline
|
|
1035
|
+
number, a scatter whose dots travel into a bell, and — first, for a beat with an
|
|
1036
|
+
illustration — a scene built on its picture), picked for the beat's archetype and painted
|
|
1037
|
+
in the pack's colours. `test/bespoke-references.test.ts` runs each reference
|
|
1038
|
+
through every gate and the rubric probe in a real deck, so a reference that stops passing
|
|
1039
|
+
stops being one. Parts a cue introduces are `<g data-cue="N">` groups (semantic grouping,
|
|
1040
|
+
after Vector Prism, arXiv 2512.14336). MorphSVG is registered for a deck only when one of
|
|
1041
|
+
its scenes morphs.
|
|
1042
|
+
|
|
1043
|
+
**The rubric probe** (`rubricProbe`, free: it reads what the probe measured) sends a
|
|
1044
|
+
passing draft to the critique round when any of these is off: the drawing paints under 12%
|
|
1045
|
+
of its box at the end (round 1's scenes painted 4-16%), more than half its parts are still
|
|
1046
|
+
dimmed at the end, no label reaches 88px (not asked of an illustrated scene, whose picture
|
|
1047
|
+
is its focus and whose names are the shell's), fewer than three kinds of motion or none of
|
|
1048
|
+
flow/camera/counter/morph, an illustrated scene that holds fewer than two push-ins, does not
|
|
1049
|
+
open wide, or names fewer than two subjects on them, a cue whose picture changes by under
|
|
1050
|
+
0.5% of the frame, or a warning about the scene. The critique round scores the frames against a six-line rubric
|
|
1051
|
+
(fills the stage, one focus per cue, motion explains, legible hierarchy, the pack, sync),
|
|
1052
|
+
is told the measures and every finding with the colliding labels' coordinates, and returns
|
|
1053
|
+
the fixed scene.
|
|
1054
|
+
|
|
1055
|
+
**Caps**, checked before every call: `--bespoke-calls` (default 12; two per beat) and
|
|
1056
|
+
`--bespoke-seconds` (default 1800). A quota or rate-limit answer stops every further call.
|
|
1057
|
+
Codex runs only through the account's own CLI (`--bespoke-cli`, `--bespoke-model`), never
|
|
1058
|
+
an API key, five calls in flight (`bespoke.concurrency` in the config file), at
|
|
1059
|
+
`bespoke.effort` reasoning (default `medium`; `default` keeps the account's), from the
|
|
1060
|
+
scratch directory, and with its tools off: shell, apps, plugins, browser, image
|
|
1061
|
+
generation (the illustration call alone keeps it), web search and every MCP server the
|
|
1062
|
+
account configured. A bespoke call is a
|
|
1063
|
+
text transform; with tools on, the agent spent its first turns reading the account's own
|
|
1064
|
+
instruction files and skills (measured: 56,679 input tokens over several turns and
|
|
1065
|
+
135-488s for a draft that tool-less took one turn of 18,247 and 166s). A paced deck (`--speed`/`--duration` other than 1×) and non-16:9 formats are
|
|
1066
|
+
skipped, with a line saying so.
|
|
1067
|
+
|
|
1068
|
+
**Cache.** Keyed by everything a scene is drawn from — the beat's words and params, the
|
|
1069
|
+
quoted excerpts, the cue windows, the stops, the box, the pack, the prompt and contract
|
|
1070
|
+
versions, the model, the illustration's key — under `~/.cache/decksmith/bespoke`
|
|
1071
|
+
(`--bespoke-cache`); pictures under its `art/`, keyed by the beat's words, the pack's
|
|
1072
|
+
colours, the art prompt's version and the model. A rebuild costs no calls. A beat the gates rejected after its critique round is cached as rejected;
|
|
1073
|
+
a fallback the beat did not earn (cap, quota, timeout) is not.
|
|
1074
|
+
|
|
1075
|
+
**What a generated scene may run.** Three layers. (1) A static walk before anything is
|
|
1076
|
+
built or opened (`src/bespoke/contract.ts`, acorn): GSAP timeline calls with literal vars
|
|
1077
|
+
at explicit seconds, `gsap.set`, scoped `root.querySelector`, `Math` minus `random`, local
|
|
1078
|
+
code; `window`, `document`, `fetch`, `eval`, timers, storage, navigation, callbacks and
|
|
1079
|
+
function-valued tween vars are refused by name; CSS must be scoped to the scene with no
|
|
1080
|
+
at-rules, `url()` or animation; markup is SVG and inline HTML with no handlers, SMIL or
|
|
1081
|
+
external references, and `<image>` only as the beat's illustration (`data-art="1"`, no
|
|
1082
|
+
href — the shell writes it); path data must be numbers and commands (a word in a `d`
|
|
1083
|
+
attribute is a console error that used to fail every scene probed with it). (2) A CSP `<meta>` in every composition that carries one —
|
|
1084
|
+
`connect-src 'none'`, no `unsafe-eval`, local files only — and a probe that fails a scene
|
|
1085
|
+
on any page error, request or navigation (an error that names no scene fails every scene
|
|
1086
|
+
probed with it, unless the value it quotes is in exactly one candidate, which is then the
|
|
1087
|
+
one failed). (3) The player's frame is sandboxed
|
|
1088
|
+
(`allow-scripts allow-same-origin allow-downloads`). The paper's text reaches the model
|
|
1089
|
+
fenced as untrusted data. The static walk is not a proof against obfuscation — a
|
|
1090
|
+
property name assembled from parts at run time gets past it — which is what (2) and (3)
|
|
1091
|
+
are for; and (3) isolates only when decks are served from another origin than the host.
|
|
1092
|
+
|
|
1093
|
+
**The motion gates** (`src/verify/scenes.ts`) run on every scene `bespoke.json` lists, as
|
|
1094
|
+
errors: `static_hold` (the picture must change during every cue), `graphic_crosses_text`
|
|
1095
|
+
(a visible stroke through a label — a curve whose bounding box contains a label is not
|
|
1096
|
+
its plate — or a shape painted over one), `seek_order` (the frame must not depend on what
|
|
1097
|
+
was seeked before it, beyond 1500px of rasterising noise — counted on changed AREAS: a pixel
|
|
1098
|
+
counts when it and its 8 neighbours changed, so a picture re-rasterised a hair differently
|
|
1099
|
+
on its first paint, an outline round every subject, 12,698px raw, counts 309), `stage_fill` (the settled
|
|
1100
|
+
drawing's bounding box covers 80% of its box), `type_hierarchy` (one label of 64px or
|
|
1101
|
+
more at the end; not asked of an illustrated scene), `stray_marker` (an SVG marker painted where its line is not drawn),
|
|
1102
|
+
`early_reveal` (a `data-cue="N"` group showing more than 0.5s before cue N),
|
|
1103
|
+
`shot_variety` (an illustrated scene opens on the whole picture and the camera — sampled
|
|
1104
|
+
every 0.5s, no screenshot — HOLDS push-ins at 1.5x or closer on at least two different
|
|
1105
|
+
subjects; round 3's 1.1-1.4x pans are not push-ins), `label_anchor` (a label that names a
|
|
1106
|
+
subject sits within 96px of its box and covers no other subject by more than a quarter of
|
|
1107
|
+
itself, and at the end at least two subjects are named that way), `data_over_picture`
|
|
1108
|
+
(five or more numbers on the illustration),
|
|
1109
|
+
`cue_groups` (no such groups, or one naming a cue the scene does not have), `end_dimmed`
|
|
1110
|
+
(at the settled frame, more than 10% of the parts the scene had shown lit are left under
|
|
1111
|
+
0.6 opacity — a part drawn translucent from the start is not counted) and `camera_end` (the
|
|
1112
|
+
camera, or a viewBox, not home at the settled frame). Content
|
|
1113
|
+
outside a clipping `<svg>` — a camera zoomed in — is neither off the frame nor crossing
|
|
1114
|
+
anything. Overlap and crossing findings carry the labels' boxes in the body box's px.
|
|
1115
|
+
`seek_order` also runs on every other scene of a v2 deck, as a warning; it is what found
|
|
1116
|
+
the equation-walk bug fixed alongside this (22,037px before, 0 after). Below the tolerance
|
|
1117
|
+
and not traced: v2's equation-walk on the narrated demo differs by 529px on one KaTeX
|
|
1118
|
+
glyph when reached from past the scene's end.
|
|
1119
|
+
|
|
1120
|
+
`build` writes `bespoke.json` beside the deck: what was drawn and from where (cache,
|
|
1121
|
+
draft, critique), why each fallback, calls, tokens, seconds, the stages' wall clock, each
|
|
1122
|
+
picture's inspection (subjects, flatness, writing, draws) and each scene's staging
|
|
1123
|
+
measures. The full motion probe that `verify` would run again on a generated scene is
|
|
1124
|
+
skipped by `build` when the pass already ran it on the same bytes at the same scene id
|
|
1125
|
+
(`gatedAt`); `build` still seeks it with the deck's other scenes. `decksmith verify <dir>`
|
|
1126
|
+
always runs it. Set
|
|
1127
|
+
`DECKSMITH_BESPOKE_WORK=<dir>` to keep the prompts, replies and contact sheets.
|
|
1128
|
+
|
|
1129
|
+
**Costs** (measured on four HypePaper decks, twice each, see
|
|
1130
|
+
[`.planning/2026-10-09-v2-bespoke-round4.md`](.planning/2026-10-09-v2-bespoke-round4.md)):
|
|
1131
|
+
an illustration takes 60-120s, a draft 90-220s and a critique 70-120s; a deck's pass took
|
|
1132
|
+
380-730s for 5-8 scene calls plus 3-7 pictures (redraws included) and 153-227k tokens, and
|
|
1133
|
+
the whole `build` 466-812s on a Mac with 9-23% memory free — three builds of eight under ten
|
|
1134
|
+
minutes. The pictures add 128-348 KB of WebP to a deck (round 3: 6-7 MB of PNG). Round 3
|
|
1135
|
+
took 593-742s and 214-325k tokens; round 1 13-31 minutes and 540-705k. A rebuild from the
|
|
1136
|
+
cache makes 0 calls. None of that fits a 300-second build timeout: a host running this has
|
|
1137
|
+
to give `build` that long, or run it off the request path.
|
|
1138
|
+
|
|
927
1139
|
## Themes
|
|
928
1140
|
|
|
929
1141
|
Three, each a position rather than a hue.
|