{"slug":"comic-storyboard-creator","title":"comic-storyboard-creator","summary":"Phase-1 comic-author step — turn a LOCKED, user-approved outline into the page-first storyboard that IS the authoring source of truth: a fixed page order BEFORE any prose, the MOTIF STATE TABLE (the master per-panel continuity ledger), a fixed 9-field per-panel spec, and one dedu","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-09-06T17:21:26.760565Z","repo":{"url":"https://github.com/wanshuiyin/ARIS-Movie-Director","stars":62,"forks":4,"license":"MIT","updatedAt":"2026-09-09T05:40:53Z"},"bodyHtml":"<hr>\n<h2>name: comic-storyboard-creator\ndescription: Phase-1 comic-author step — turn a LOCKED, user-approved outline into the page-first storyboard that IS the authoring source of truth: a fixed page order BEFORE any prose, the MOTIF STATE TABLE (the master per-panel continuity ledger), a fixed 9-field per-panel spec, and one deduped canonical asset contract. Decompose beats→pages→panels, 抽卡 K page/panel-order lineages by feasibility, then fill every panel one unit at a time. Writes a storyboard_spec + a motif_ledger (read by comic-continuity-audit) + N panel_spec nodes. Use when the user says \"做分镜\", \"storyboard\", \"排页\", \"panel spec\", \"分镜稿\", or the outline layer is locked and approved and you need the per-panel authoring layer the thin comic-author SOP defers to. Two-stage under the N1 contract: a PROVISIONAL structural gate pass on draft assets now, the FINAL asset-resolution validation after the asset layer locks.</h2>\n<h1>comic-storyboard-creator — the Page-First Storyboard + Master Continuity Ledger (Phase 1, step 4; re-gated at step 6b)</h1>\n<p>The <strong>storyboard step of the <a href=\"../comic-author/SKILL.md\"><code>comic-author</code></a> suite</strong>: take a LOCKED, user-approved\n<a href=\"../comic-outline-creator/SKILL.md\"><code>outline_spec</code></a> and produce the artifact that IS the authoring source of\ntruth — a <strong>fixed page order authored as its own section BEFORE any per-panel prose</strong>, the <strong>MOTIF STATE\nTABLE</strong> (the master per-panel ledger that pins every continuity variable for all panels <em>before</em> any bake),\na <strong>fixed 9-field per-panel spec</strong>, and <strong>one deduped canonical asset contract</strong>. This is the deep\nlayer the thin <a href=\"../comic-author/SKILL.md\"><code>comic-author</code></a> orchestrator SOP defers to; it ports the rigor of aris_movie's\n<code>movie-storyboard-creator</code> (抽卡 lineages → score → gate) and <code>-v4</code> (locked-inputs precondition → beat→panel\nbudget → deterministic spec) onto stills, and it emits the <code>panel_spec</code> fields the downstream\n<a href=\"../comic-blueprint-author/SKILL.md\"><code>comic-blueprint-author</code></a> and <a href=\"../comic-director/SKILL.md\"><code>comic-director</code></a>\nconsume. The downstream baking spiral is <strong>not</strong> this skill's job — this is pure authoring + ledger.</p>\n<blockquote>\n<p><strong>Two-stage role (the N1 contract):</strong> this layer's gate runs TWICE. Right after the outline locks, this\nskill authors the storyboard and runs <code>--gate storyboard</code> as a <strong>PROVISIONAL structural pass</strong> — the\nstoryboard MAY reference <strong>draft</strong> (declared-but-unlocked) assets; <code>panel_assets_referenceable</code> is\nunscorable, is left <code>null</code>, and the fuser SKIPs it (no <code>locked</code> flip yet). Then, after the asset layer has\nlocked everything and OUTLINE_FINAL_LOCK has re-confirmed the outline, the <strong>FINAL asset-resolution\nvalidation</strong> re-runs <code>--gate storyboard</code> with all four dims scorable and flips the storyboard to <code>locked</code>.\nThe hard locked-asset barrier stays downstream, before blueprint authoring\n(<a href=\"../comic-author/SKILL.md\"><code>comic-author</code></a> steps 6a–7).</p>\n</blockquote>\n<blockquote>\n<p><strong>Cardinal lesson baked in as a gate, not prose:</strong> <em>decompose beats→pages→panels and 抽卡 K orderings by\nfeasibility, then fill ONE panel at a time — never batch-author-then-look.</em> The MOTIF STATE TABLE is the\nconcrete guard: it pre-commits a per-dimension-per-panel ground truth (mug heat / executor bounce /\nTok|yo evidence / DDL spine / exact_parse / claim_delta) with <strong>machine-checkable global invariants</strong>\n(DDL monotonic never-rewind; bounce S02 = the film's ONLY MAX; REJECT↔ACCEPT mirror), so the audit reads\nintent off a table instead of inferring it.</p>\n</blockquote>\n<pre><code>  locked+approved outline_spec ─▶ ① PRECONDITION (refuse if outline unlocked / unapproved; draft assets OK here)\n                                      ▼\n                                ② DECOMPOSE  beats → pages → panels  (beat→panel budget arithmetic)\n                                      ▼\n                                ③ 抽卡 K page/panel-ORDER lineages (Codex xhigh) → score(feasibility/fidelity/novelty) → keep\n                                      ▼\n                                ④ PAGE ORDER FIRST   (a fixed section, page-type + L/R world per page, BEFORE prose)\n                                      ▼\n                                ⑤ MOTIF STATE TABLE  (master ledger; monotonic DDL; bounce-uniqueness; mirror locks)\n                                      ▼\n                                ⑥ PER-PANEL 9-FIELD SPEC  (one unit at a time; DONE panels locked; baked-vs-gate contract)\n                                      ▼\n                                ⑦ CONSOLIDATE ASSET_REQUESTS  (one canonical owner per token; naming 铁律)\n                                      ▼\n                                ⑧ EMIT  storyboard_spec + motif_ledger + N panel_spec (+ continuity_constraint)\n                                      ▼\n                                ⑨ GATE ×2: PROVISIONAL structural pass now → (assets lock + OUTLINE_FINAL_LOCK)\n                                   → FINAL asset-resolution pass flips `locked`\n</code></pre>\n<h2>Constants</h2>\n<ul>\n<li><p><strong>抽卡 K (lineages of page/panel ordering)</strong> — <code>K_LITE=3</code>, <code>K_BALANCED=6</code> (default), <code>K_MAX=8</code>, <code>K_BEAST=12</code>\n(ported verbatim from <code>movie-storyboard-creator</code>). Effort tier governs <em>count of orderings</em>, not depth.</p>\n</li>\n<li><p><strong>FEASIBILITY_FLOOR = 5</strong> — a lineage scoring <code>feasibility &lt; 5/10</code> is dropped (e.g. it needs arbitrary\nun-gateable text rendering, exact UI replication, or face identity it can't anchor). If <code>&lt;2</code> survive,\nre-prompt <strong>once</strong> on the same Codex thread; still <code>&lt;2</code> → tell the user to lower <code>--effort</code> or relax the\nbanlist. <strong>Never fall back to a Claude-generated lineage</strong> (violates reviewer independence).</p>\n</li>\n<li><p><strong>REVIEWER</strong> = the Codex CLI at <code>model_reasoning_effort: xhigh</code> for the 抽卡 brainstorm + the cross-layer\ngate — it pins NO model (it follows the local codex config, currently <code>gpt-5.6-sol</code>); Gemini <code>auto-gemini-3</code>\nwhere a second family is needed. Never downgrade the effort tier (<a href=\"../../protocols/reviewer-routing.md\"><code>reviewer-routing</code></a>).</p>\n</li>\n<li><p><strong>PAGE_TYPES</strong> (authoring vocabulary) = <code>{cover, single, 2-up, vertical-3, grid2x2, big-frame, endcard}</code>.\nThese are NOT the compiled IR's page types — <code>schemas/comic.schema.json</code> <code>pages[].type</code> enum is\n<code>{cover, single, grid, grid2x2, feature, finale}</code> — so the compiler MUST project them (an unmapped token\nFAILS jsonschema):</p>\n<table>\n<thead>\n<tr>\n<th>storyboard token</th>\n<th>compiles to <code>pages[].type</code></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>cover</code> / <code>single</code> (incl. full-bleed) / <code>grid2x2</code></td>\n<td>same name</td>\n</tr>\n<tr>\n<td><code>2-up</code> / <code>vertical-3</code></td>\n<td><code>grid</code></td>\n</tr>\n<tr>\n<td><code>big-frame</code></td>\n<td><code>feature</code></td>\n</tr>\n<tr>\n<td><code>endcard</code></td>\n<td>the <strong>PRIOR page's <code>closing.image</code></strong> — the shipped-reference convention: comic_m3_audit compiles S22's endcard into <code>P_B12.closing.image</code> (18 pages ship, not a 19th endcard page). <code>finale</code> stays a legal enum value for a standalone end page, but <code>closing.image</code> is THE convention to copy.</td>\n</tr>\n</tbody>\n</table>\n</li>\n<li><p><strong>WORLDS</strong> = <code>{warm, dark-cyber, seam, starfield}</code> (human = warm, ARIS = dark-cyber, explicit <code>seam</code> at\nhand-off/payoff, <code>starfield</code> for the wiki/finale) — the two-world palette grammar inherited from the outline.</p>\n</li>\n<li><p><strong>MOTIF_TABLE_COLUMNS</strong> (per panel, verbatim) = <code>Panel | &lt;motif-A&gt; | DDL | &lt;motif-B&gt; | exact_parse | claim_delta | bounce</code>\n— for the worked example: <code>Panel | Mug | DDL | Tok|yo | exact_parse | claim_delta | bounce</code>. The two metric\ncolumns (<code>exact_parse</code>, <code>claim_delta</code>) <strong>never co-mingle</strong> (different metrics, different value sets).</p>\n</li>\n<li><p><strong>PANEL_TEMPLATE</strong> = the fixed 9 fields (+ title anchor): <code>text_mode</code> / <code>content_blueprint</code> /\n<code>expected_literals</code> / <code>scene</code> / <code>characters</code> / <code>bubbles{zh,en}</code> / <code>side_narration{zh,en,trait}</code> / <code>motifs</code> /\n<code>asset_requests</code>. No free prose outside these fields. (cover/finale panels add <code>safe_zones</code>/<code>endcard</code> fields.)</p>\n</li>\n<li><p><strong>OUTPUT</strong> = <code>story/STORYBOARD_DRAFT.md</code> (the human artifact) + wiki nodes (<code>storyboard:&lt;slug&gt;</code>, <code>motif:&lt;slug&gt;</code>,\n<code>panel:&lt;slug&gt;</code> × N, optional <code>cont:&lt;slug&gt;</code>). Versioned per <a href=\"../../protocols/output-versioning.md\"><code>output-versioning</code></a>.</p>\n</li>\n</ul>\n<h2>Input contract — locked + approved upstream (refuse otherwise)</h2>\n<p>This skill is <strong>pure authoring + ledger</strong>, and it operates ONLY on converged upstream (convergence is the\nupstream gates' job, per <a href=\"../../protocols/acceptance-gate.md\"><code>acceptance-gate</code></a>):</p>\n<ul>\n<li><strong>Refuse (HALT, point at the offending node) if</strong> the <code>outline_spec</code> is not <code>status: \"locked\"</code>, OR it lacks\nthe explicit user-approval stamp (the user-first gate — never proceed without a recorded\n<code>✅ APPROVED by user &lt;date&gt;</code>). Whitelisted assets may still be <strong>draft/declared</strong> at the PROVISIONAL pass —\nthat is the N1 two-stage contract; an unlocked asset only blocks the <strong>FINAL</strong> asset-resolution validation\n(and everything downstream of it).</li>\n<li><strong>Asset-id whitelist is SACRED.</strong> Every panel may reference asset names ONLY from the outline's\n<code>character_asset_ids</code> / <code>scene_asset_ids</code> / <code>prop_asset_ids</code> plus assets you newly request <em>as</em>\n<code>asset_requests</code>. <strong>Never free-describe an asset inline.</strong> If a panel needs an asset that doesn't exist yet,\nadd it to <code>asset_requests</code> (which reopens the asset layer) — do not invent it silently.</li>\n<li>Consumed outline fields: <code>narrative_beats[]</code>, <code>beat_table</code> (the 6-column table: Beat / Panels / layout /\nworld / content+台词 gist / ARIS-feature-as-story-cost), <code>motif_arcs</code> (the per-shot continuity values),\n<code>design_constraint</code> (the dual-identity), <code>title</code> / <code>logline</code> / <code>tagline</code>.</li>\n</ul>\n<h2>Procedure (followable, one unit at a time — never batch)</h2>\n<h3>① Precondition check</h3>\n<p>Load the <code>outline_spec</code>. Verify <code>status == \"locked\"</code> AND the user-approval stamp is present. (Whitelisted\nassets may still be draft — <code>locked</code> is the FINAL pass's demand, not an authoring precondition; N1 two-stage.)\nOn any failure → HALT with the precise offending node id so the orchestrator routes\nback to the outline layer. Record provenance in the header: source outline id, the prior\ncross-model verdict it survived (real example: codex critique returned <strong><code>REVISE</code></strong>; \"全部 fix 落地\"), and the\n<code>✅ APPROVED by user &lt;date&gt;</code> line.</p>\n<h3>② Decompose beats → pages → panels (budget arithmetic)</h3>\n<p>For each outline beat, read its <code>layout</code> token to set its page type and per-page panel count, then assign\nshot/panel ids. Compute the page budget: a beat tagged <code>vertical-3</code> owns 3 panels on one page; <code>2-up</code> owns 2;\n<code>grid2x2</code> owns a recap page; <code>single</code>/<code>full-bleed</code>/<code>endcard</code> own 1. The centerpiece beat may expand\n(real: B08 went 4 panels → <strong>5 single-read pages</strong>, adding a NEW <code>S12a</code> audit-entry panel, with the 2×2 kept\nONLY as a recap/hero page). Clamp the global total to the project's tier window; if oversize, collapse the\nlongest multi-panel beat first; if undersize, split the beat with the most slack. <strong>Every panel must land on\nexactly one page with a stable page id</strong> (<code>P00_cover</code>, <code>P01_b02</code>, …, <code>P03_end</code>).</p>\n<h3>③ 抽卡 K page/panel-order lineages (Codex xhigh), score, keep</h3>\n<p>Pass <strong>file paths only</strong> (the locked outline, the style bible, the wiki banlist of prior failed orderings) to\nthe Codex CLI at <code>xhigh</code> (no model pin — local codex config) — reviewer independence: Codex forms its own\nreading, never gets your summary. Demand\n<code>K</code> (= the tier constant) alternative <strong>page/panel orderings</strong> of the same beat set, each differing on ≥2 of:\n<em>page-rhythm axis</em> (cover/2-up/grid/vertical-3/big-frame mix) · <em>cast-presence axis</em> (which panels show the\nduo vs solo) · <em>world-alternation axis</em> (warm/dark/seam sequencing) · <em>reading-order axis</em>. Score each lineage\n0–10 on <strong>Feasibility</strong> (lower if it needs un-gateable arbitrary text / exact UI replication / face identity),\n<strong>Brief-fidelity</strong> (does it preserve the locked beat boundaries + the dual-identity), <strong>Novelty-vs-banlist</strong>\n(penalize ≥0.6 Jaccard overlap with a prior failed ordering). <strong>Drop any lineage with <code>feasibility &lt; 5</code>.</strong>\nPromote the top survivor to the active page order; keep the rest as candidate notes (failed orderings become\nbanlist memory so the next run never re-proposes them). The 抽卡 here is over <em>orderings</em>, not panel content —\npanel content is filled deterministically in ⑥.</p>\n<h3>④ PAGE ORDER FIRST (its own fixed section, before any prose)</h3>\n<p>Author the chosen ordering as a <strong>separate, fixed section that comes BEFORE per-panel prose</strong> (the\n<code>page_order</code> field of the <code>storyboard_spec</code>). Assign each panel to its stable page id + page TYPE + per-page\nL/R world. End with an explicit <code>TOTALS</code> line: panel count · page count · how many NEW bakes vs reused DONE\nimages. This section is the authority the compiler and the gate check the eventual <code>comic.json</code> against.</p>\n<h3>⑤ Author the MOTIF STATE TABLE (master ledger, before per-panel prose)</h3>\n<p>Author the <strong>MOTIF STATE TABLE</strong> as the single source of truth for the continuity dimensions across <strong>all</strong>\npanels, <em>before</em> writing any per-panel prose. One row per panel; the columns are <code>MOTIF_TABLE_COLUMNS</code>.\nEncode every machine-checkable invariant directly in the table + its conventions block:</p>\n<ul>\n<li><strong>A motif column that is a thermometer</strong> (the worked example's <code>Mug</code>): track ONLY the continuity-bearing\ninstance (the <code>ML RESEARCH</code> motif mug: <code>hot</code> two steam wisps = temperature origin → <code>fading</code> one thin wisp\n→ <code>cold</code> no steam + milk skin, a B01↔S20 bookend = \"the hardest continuity constraint\"). <strong>Disambiguate\nmotif-vs-env</strong>: any look-alike that is just an environment prop (the <code>&lt;/&gt;</code> mug) is tagged <code>env</code> and is NOT\ntracked — this is the <em>absence ≠ drift</em> / <em>design-aware gate</em> rule made concrete (a naive holistic gate\nwould false-flag it).</li>\n<li><strong>DDL = MONOTONIC, NEVER REWIND.</strong> The countdown is non-increasing across the ENTIRE film. Write the exact\nsequence in the conventions block (real: <code>T-24:00:00 → 19:42 → 19:42 → 18:55 → 18:40 → 18:30 → 17:46 → 17:02 → 16:21 → 16:05 → 05:12 → 02:58 → 02:41 → 01:57 → 00:42 → 00:27(submitted)</code>). Two consecutive equal\nvalues are allowed (a \"same-instant rhyme\"); an <em>increase</em> is a hard veto. If any draft value would rewind,\nfix it inline and annotate the fix (real: <code>S06 DDL T-15:27 → T-18:40</code> purely so <code>18:40 &gt; S07's 18:30</code>).</li>\n<li><strong>Two metric columns that NEVER co-mingle.</strong> <code>exact_parse</code> carries <code>{0.60, 0.71, 0.66, 0.78, 0.89}</code>;\n<code>claim_delta</code> carries <code>{+6.2, +1.4}</code>. They are different metrics; writing one into the other's column is a\nveto. (Real: S10 shows <code>exact_parse 0.71→0.66</code> while <code>claim_delta</code> stays <code>—</code>; S14 shows\n<code>claim_delta +6.2→+1.4</code> while <code>exact_parse</code> stays <code>—</code>.)</li>\n<li><strong>bounce = the wordless emotion thermometer with a UNIQUENESS invariant.</strong> <code>bounce = MAX</code> appears <strong>exactly\nonce</strong> (real: <code>S02 是全片唯一 MAX</code>). Every later high is annotated \"below S02\". After the fall, <strong>NO new peak\nis allowed</strong> — a post-fall celebration must be written as <em>arrested</em> (real: <code>S12a = attempted celebration, ARRESTED before becoming a jump</code>, the codex fix that removed an earlier \"MAX\" there). The arc closes at the\nsmallest bounce (real: <code>S21 = smallest bounce</code>, the mirror landing of S02).</li>\n<li><strong>MIRROR LOCKS</strong> (paired non-adjacent constraints the table also pins): <code>REJECT card ↔ ACCEPT card</code> =\nexact same diagonal stamp geometry/angle (real: S11 ↔ S16, both from the shared verdict-card geometry,\nthe audit hinge); <code>S02 unique-MAX bounce ↔ S21 smallest bounce</code>; a labeled wiki map ↔ its wordless twin\nshare node coordinates <strong>programmatically derived from one JSON</strong> (real: S16b ↔ S22 from\n<code>wiki_starmap_nodes_v1.json</code>, 禁目测 — no eyeballing).</li>\n</ul>\n<h3>⑥ Per-panel 9-field spec, in comic page order (ONE panel at a time)</h3>\n<p>Walk the page order and author each panel in the fixed template — <strong>finish one panel fully before starting the\nnext</strong> (this is the \"never batch-generate-then-look\" lesson at authoring time). Each panel carries:</p>\n<ol>\n<li><strong>title + beat + page-type + world</strong> (the header anchor).</li>\n<li><strong><code>text_mode</code></strong> ∈ <code>{baked, html}</code> — <code>baked</code> = the image model renders the in-frame text; <code>html</code> = the\npanel is a pure scene and ALL text lives in the HTML overlay (zero glyphs in the image).</li>\n<li><strong><code>content_blueprint</code></strong> — which canonical SVG asset is instantiated + the exact literal layout (e.g.\n\"from <code>assets/ddl_widget_template_v1.svg</code> instantiate <code>T-24:00:00</code>, amber on a navy widget, screen-corner\").</li>\n<li><strong><code>expected_literals</code></strong> — the blind-transcribable tokens that <strong>will be gated</strong> (see the contract below).</li>\n<li><strong><code>scene</code></strong> — the staged environment (density target, books/props, the warm/dark world rendered).</li>\n<li><strong><code>characters</code></strong> — who is present + their motif-table state (bounce, pose); note who is absent and why.</li>\n<li><strong><code>bubbles{zh,en}</code></strong> — speaker + style + bilingual line. <strong>Skill names NEVER appear in a bubble or in-frame</strong>\n(铁律) — they live only in <code>side_narration</code>.</li>\n<li><strong><code>side_narration{zh,en,trait}</code></strong> — first sentence = <em>what happened</em>; second = the ARIS capability <em>bound to\na story cost</em>; the <code>trait</code> tag names the bound skill. (The 侧栏讲解铁律 inherited from the outline.)</li>\n<li><strong><code>motifs</code></strong> — restate that panel's row of the MOTIF STATE TABLE (must agree with ⑤ exactly).</li>\n<li><strong><code>asset_requests</code></strong> — the canonical asset names this panel consumes (whitelist only).</li>\n</ol>\n<p><strong>In the human <code>STORYBOARD_DRAFT.md</code>, a DONE / reused panel's row carries ONLY <code>status</code> + <code>side_narration</code> +\n<code>motifs (as baked)</code></strong> — locked, never retro-edited (real: S12–S15, baked images promoted from a grid to single\npages; their square crops stay in the existing 2×2 recap; no regeneration). A DONE panel that is edited is a\nhard veto. <strong>The wiki <code>panel_spec</code> node is NOT reduced:</strong> <code>validate_wiki.py</code> <code>PAYLOAD_REQUIRED[\"panel_spec\"]</code>\nunconditionally requires all 13 fields for EVERY panel_spec (no DONE exemption), so a DONE/reused panel's\n<code>panel_spec.payload</code> must still carry every field, holding its prior locked values unchanged (never retro-edited).\nThe reduced 3-field form is a STORYBOARD_DRAFT.md convenience only.</p>\n<h3>⑦ Enforce the baked-vs-gate contract per panel</h3>\n<p><code>expected_literals</code> holds <strong>ONLY the salient, large, blind-transcribable tokens</strong>; everything visible-but-not-\ngated is <strong>explicitly excluded in writing</strong>:</p>\n<ul>\n<li>Sub-threshold chips out of contract — real: the S09 <code>Tok|yo</code> chip is sized ≤1.5% frame height, <em>\"below\nblind-review transcription threshold\"</em>, NOT in <code>expected_literals</code> (it is a deliberate foreshadow, no\ncallout, no arrow); it becomes hero/gated only at S10.</li>\n<li>Skill names NEVER in-frame (铁律) — they are side-narration only.</li>\n<li>ASCII-only gating — real: S20 gates <code>SUBMITTED</code>; the <code>✓</code> is decorative non-ASCII and is out of contract.</li>\n<li>A deliberately <em>sub-gate</em> token must never be smuggled into <code>expected_literals</code> (hard veto).</li>\n</ul>\n<h3>⑧ Consolidate ASSET_REQUESTS (one canonical owner per token; naming 铁律)</h3>\n<p>Collect every panel's <code>asset_requests</code> into ONE canonical, deduped, authoritative list. Apply the <strong>naming\n铁律</strong>: declare all draft-era name variants void and map them to the single canonical name; pin <strong>one\nparametric source per recurring motif</strong> (real: ONE <code>ddl_widget_template_v1.svg</code> is the sole render source for\nthe entire 18-instance countdown timeline; ONE <code>stamp_family_v1.svg</code> for ALL verdict stamps — no two stamp\nsets, and it must match the already-baked S12–S15 stamps; ONE <code>wiki_starmap_nodes_v1.json</code> is the single truth\nsource shared by the labeled map S16b and its wordless twin S22). Flag P0 blockers (real:\n<code>researcher_chibi_canonical_ref_v001.png</code> missing — only the duo had a canonical ref) and enumerate\nzero-new-work reuse (DONE panels, the existing recap page, S01's baked image reused as a set-continuity\ncondition ref for S20/S21 same-room/same-desk/same-camera).</p>\n<h3>⑨ Emit nodes, attach the review, THEN invoke the gate (two steps — never cold)</h3>\n<p>Write the wiki nodes (§ below) and append the author edges. The storyboard gate is a <strong>score-FUSER</strong>: it\nwalks <code>reviews</code> edges into the target, fuses the pre-existing <code>review:*</code> score-nodes, and <strong>HARD-FAILS if\nzero are attached</strong> (\"no reviews — gate is a score-fuser, not a reviewer\"). So before invoking it:</p>\n<ol start=\"0\">\n<li><strong>Which pass is this? (the N1 two-stage ordering).</strong> The <strong>PROVISIONAL pass</strong> runs right after authoring:\nevery panel asset ref must be <em>whitelisted or filed as a complete <code>asset_request</code></em> (DECLARED), but <code>locked</code>\nis NOT required — <code>panel_assets_referenceable</code> (<em>resolves AND locked</em>) is unscorable, is left <code>null</code>, and\nthe fuser SKIPs it (the provisional verdict rides on the other three structural dims; no <code>locked</code> flip\nyet). The <strong>FINAL pass</strong> runs only after the asset layer has driven every requested asset to <code>locked</code> AND\nOUTLINE_FINAL_LOCK has re-confirmed the outline (<a href=\"../comic-author/SKILL.md\"><code>comic-author</code></a> steps 5–6b):\nnow all four dims are scorable, an un-locked ref hard-vetoes on <code>_unresolved_asset_refs</code>, and an <code>approve</code>\nverdict flips the storyboard to <code>locked</code>.</li>\n<li><strong>Pre-gate review (fan-out → persist).</strong> The storyboard gate is <strong>structural, CC-only</strong> (no visual\nreviewer — no pixels exist yet), so the cross-model lens here is the structural validator run, not a\npanel of model families. Compute the structural facts (below; at the PROVISIONAL pass\n<code>panel_assets_referenceable</code> stays <code>null</code> — see ⑨.0) and persist them as a <code>review</code> node:\n<code>node_id: review:&lt;slug&gt;</code>, <code>payload {target_node_id: \"storyboard:&lt;slug&gt;\", reviewer, gate_kind: \"storyboard\", review_scores:{panel_assets_referenceable, global_policies_valid, panel_count_band_aligned, continuity_chain_well_formed}}</code>, with a <strong><code>reviews</code></strong> edge <code>review:&lt;slug&gt; → storyboard:&lt;slug&gt;</code>.</li>\n<li><strong>Invoke the fuser.</strong> <code>python3</code> / call <strong><a href=\"../comic-cross-layer-gate/SKILL.md\"><code>comic-cross-layer-gate</code></a>\n<code>&lt;storyboard:slug&gt; --gate storyboard</code></strong> to fuse + adjudicate against the EXACT predicate below. On an\n<code>approve</code> verdict (the gate's verdict set is <code>{approve, revise}</code>) <strong>at the FINAL pass</strong>, the gate flips\n<code>storyboard_spec.status</code> → <code>locked</code>; a PROVISIONAL-pass <code>approve</code> leaves it <code>under_review</code> (⑨.0), and\n<code>revise</code> sets/keeps <code>under_review</code> at either pass. (Canon ⑥ FLIP: <code>locked</code> is a STATUS reached by the\nadvance verdict, never a verdict name.) The gate (a different model\nfamily) — never this authoring agent — acquits (<a href=\"../../protocols/artifact-integrity.md\"><code>artifact-integrity</code></a>).\nReviewer routing for any model-family fan-out: Claude (one lens) ‖ Codex CLI <code>xhigh</code> (no model pin — local\ncodex config, currently <code>gpt-5.6-sol</code>) ‖ Gemini\n<code>auto-gemini-3</code>, file paths only (<a href=\"../../protocols/reviewer-routing.md\"><code>reviewer-routing</code></a>).</li>\n</ol>\n<h2>EXACT gate (<code>storyboard</code>) — quote <a href=\"../comic-cross-layer-gate/SKILL.md\"><code>comic-cross-layer-gate</code></a> <code>--gate storyboard</code></h2>\n<p>This is <strong>not</strong> this skill's rubric to define — <a href=\"../comic-cross-layer-gate/SKILL.md\"><code>comic-cross-layer-gate</code></a>\nis the SOLE gate authority, and <code>--gate storyboard</code> is <strong>STRUCTURAL, CC-only</strong> (no visual reviewer; no pixels\nyet). Verdict set <code>{approve, revise}</code>. Under the N1 contract it is invoked TWICE (provisional → final; the\nwhich-pass rules are ⑨.0). The text below is quoted verbatim from that gate so this skill authors\nto the real predicate — if the two ever diverge, the gate wins.</p>\n<p><strong>Scored dimensions = exactly FOUR; each scored <code>0–5</code>; ADVANCE (<code>APPROVE</code>) iff ALL FOUR ≥ 4.</strong> These four are\n<strong>file-system facts the gate computes</strong>, not reviewer opinion:</p>\n<ul>\n<li><strong><code>panel_assets_referenceable</code></strong> — every asset ref in each <em>panel</em> <strong>resolves AND is <code>status: locked</code></strong>.\nScored at the FINAL pass only; at the PROVISIONAL pass it is left <code>null</code>/SKIPped and the declared-check\n(whitelisted or complete <code>asset_request</code>) applies instead — see ⑨.0 for the two-stage ordering.</li>\n<li><strong><code>global_policies_valid</code></strong> — <code>global_policies</code> fields match expected (text-mode rules present; mirror-lock\npolicy present; page-order authority declared).</li>\n<li><strong><code>panel_count_band_aligned</code></strong> — panels-per-page in band per target tier <code>{mvp:(2,2), demo:(4,6), longform:(10,12)}</code> (in-range = 5, off-by-one = 3, further = ≤2), AND the <code>TOTALS</code> line reconciles (Σ\npanels-per-page == panel count; NEW + reused == total).</li>\n<li><strong><code>continuity_chain_well_formed</code></strong> — the MOTIF STATE TABLE has one row per panel; links have no\ndangling / out-of-order / cycle; every per-panel <code>motifs</code> field agrees with its table row.</li>\n</ul>\n<p><strong>STRUCTURAL HARD VETO</strong> (forces <code>revise</code> <strong>regardless of reviewer scores OR Codex</strong> — these are NOT scored\n≥4 dims, they are the gate's computed structural vetoes; \"structural failures cannot be voted-around\"):</p>\n<ol>\n<li>Any non-empty <code>_unresolved_asset_refs</code> (a referenced asset missing or not <code>locked</code>) — FINAL pass; at the\nprovisional pass declared-but-unlocked refs are expected, and only an UNDECLARED ref (no whitelist entry,\nno complete <code>asset_request</code>) vetoes.</li>\n<li>Any non-empty <code>_policy_violations</code> (a missing/inconsistent <code>global_policies</code> field, incl. no\npage-order-first section).</li>\n<li>Any non-empty <code>_continuity_breaks</code> (no MOTIF STATE TABLE; a row missing; a <code>motifs</code> field disagreeing).</li>\n<li>An out-of-band <code>_panel_count_band</code>.</li>\n<li><strong>DDL non-monotonic</strong> (any countdown value increases) — the never-rewind invariant.</li>\n<li><strong>bounce uniqueness broken</strong> (more than one <code>MAX</code>, or a post-fall peak).</li>\n<li><strong>The two metric columns co-mingle</strong> (a <code>claim_delta</code> value in the <code>exact_parse</code> column or vice-versa).</li>\n<li><strong>A DONE/reused panel was retro-edited</strong> (the DONE-lock).</li>\n<li><strong>The storyboard page order disagrees with the compiled <code>comic.json</code> page order</strong> (the orphan-panel class) —\nthe storyboard's page order is the authority; the compiler must conform, not the reverse.</li>\n</ol>\n<p>Author-time obligations the structural facts above encode (this skill is responsible for them BEFORE the gate\nruns, so the four dims pass and no veto fires): the page-order-first section, the 9-field-per-panel\ncompleteness (DONE panels in the reduced locked form), <code>expected_literals</code> = salient blind-transcribable ASCII\nonly with the deliberate exclusions written out (a sub-gate chip smuggled in is a <code>baked_vs_gate_contract</code>\nbreak), the consolidated one-canonical-owner-per-token asset list (no un-normalized alias), the text-mode/\nblueprint match (a <code>baked</code> panel with no <code>content_blueprint</code>, or an <code>html</code> panel carrying in-frame literals,\nis invalid), and the <code>✅ APPROVED by user &lt;date&gt;</code> provenance stamp from the outline layer.</p>\n<h2>Two engine contracts to author to (fail-closed)</h2>\n<p>Author every <code>panel_spec</code> so the downstream blueprint + spiral never refuse it. <strong>Mind the payload-vs-runtime\npath split</strong> (do NOT conflate them — see <code>schemas/node_schema.json</code>):</p>\n<ul>\n<li><code>panel_spec.payload.content_blueprint</code> — what THIS skill writes: a deterministic description of which\ncanonical SVG asset is instantiated + the exact literal layout (NOT a raw SVG, and <strong>never</strong> a\n<code>condition.content_svg</code> key — that prefix exists only on comic.json).</li>\n<li><code>blueprint.payload.content_svg</code> — the actual SVG, authored later by\n<a href=\"../comic-blueprint-author/SKILL.md\"><code>comic-blueprint-author</code></a> from this panel's <code>content_blueprint</code>.</li>\n<li><code>comic.json</code> panel <code>condition.content_svg</code> (+ <code>condition.expected_literals</code>) — the RUNTIME fields the spiral\nengine reads (<code>spiral_engine.js</code> at <code>.condition.content_svg</code>); the compiler maps the blueprint into these.</li>\n</ul>\n<p>Author to that chain so the downstream never refuses the panel:</p>\n<ol>\n<li><strong>Every panel needs a <code>content_blueprint</code></strong> (a resolvable blueprint description) so the blueprint author can\nproduce a non-empty <code>blueprint.payload.content_svg</code> → the engine's <code>condition.content_svg</code>. Do NOT plan a\npanel with no blueprint; the engine rejects a null <code>condition.content_svg</code> at runtime.</li>\n<li><strong>A <code>baked</code> figure-panel MUST declare <code>expected_literals</code></strong> (exact numbers/keys, verbatim) in the panel_spec\n— these become the comic.json <code>condition.expected_literals</code> the engine fail-closes on. A scene panel with no\naudited numbers → <code>text_mode: \"html\"</code> (and its text moves to the HTML overlay).</li>\n</ol>\n<h2>Node it reads / writes (<code>schemas/node_schema.json</code>)</h2>\n<p><strong>Reads</strong> — one <code>outline_spec</code> (<code>node_id</code> <code>outline:&lt;slug&gt;</code>, must be <code>status: \"locked\"</code>): its\n<code>narrative_beats</code>, <code>beat_table</code>, <code>motif_arcs</code>, <code>design_constraint</code>, <code>title</code>/<code>logline</code>/<code>tagline</code>, and the\n<code>*_asset_ids</code> whitelists. Also reads the wiki banlist of prior failed orderings (for the 抽卡 novelty score).</p>\n<p><strong>Writes</strong> (status <code>under_review</code> → <code>locked</code> after the gate):</p>\n<ul>\n<li><strong><code>storyboard_spec</code></strong> (<code>node_id</code> <code>storyboard:&lt;slug&gt;</code>) — payload required:\n<code>source_outline_id, page_order, page_ids, panel_ids, global_policies, motif_ledger_id, consolidated_asset_requests</code>. This is the envelope; <code>page_order</code> is the fixed authoritative ordering.</li>\n<li><strong><code>motif_ledger</code></strong> (<code>node_id</code> <code>motif:&lt;slug&gt;</code>) — payload required: <code>source_storyboard_id, columns, rows, invariants, mirror_locks</code>. <code>columns</code> = the <code>MOTIF_TABLE_COLUMNS</code>; <code>rows</code> = one object per panel;\n<code>invariants</code> = the declarative predicates (<code>ddl_monotonic_non_increasing</code>, <code>bounce_single_max</code>,\n<code>metric_columns_disjoint</code>, <code>motif_vs_env_disambiguation</code>); <code>mirror_locks</code> = the paired constraints.\n<strong>This node is READ by <a href=\"../comic-continuity-audit/SKILL.md\"><code>comic-continuity-audit</code></a></strong> — the table is the\nper-panel ground-truth checklist that turns its cross-model audit from \"infer the intent\" into \"verify\nagainst the row\" (and makes <em>absence ≠ drift</em> design-aware).</li>\n<li><strong><code>panel_spec</code></strong> × N (<code>node_id</code> <code>panel:&lt;slug&gt;</code>) — payload required: <code>source_storyboard_id, page_id, panel_id, sequence_index, page_type, world, asset_ids, text_mode, expected_literals, content_blueprint, bubbles, side_narration, motifs</code>. (cover/finale panels additionally carry <code>safe_zones</code> + the endcard\nfields.) Every <code>panel_spec</code> — including DONE/reused — carries ALL the required payload fields above (the\nreduced 3-field form is the <code>STORYBOARD_DRAFT.md</code> convenience only, never the wiki node).</li>\n<li><em>(optional)</em> <strong><code>continuity_constraint</code></strong> × M (<code>node_id</code> <code>cont:&lt;slug&gt;</code>) — payload required: <code>family, constraint_text, applies_to_panel_ids, source_node_id, active</code> — for a constraint the gate should check\nper-panel as a standalone predicate (e.g. one per mirror lock).</li>\n</ul>\n<p>Author edges (every <code>type</code> MUST be in <code>validate_wiki.py</code> <code>EDGE_TYPES</code> or the wiki hard-fails — there is no\n<code>contains</code> / <code>generated_from</code> / <code>references_asset</code> in that set):</p>\n<ul>\n<li><strong><code>derived_from</code></strong> (storyboard_spec → outline_spec) — \"this storyboard was authored from that outline\".</li>\n<li><strong><code>uses_motif_ledger</code></strong> (storyboard_spec → motif_ledger) — the ledger this storyboard owns.</li>\n<li><strong><code>uses_asset</code></strong> (panel_spec → each whitelisted <em>locked</em> asset it consumes); for a <em>newly-requested</em> asset\n(one filed via <code>asset_requests</code>, not yet built) emit <strong><code>plans_asset</code></strong> (panel_spec → asset) instead.</li>\n<li><strong>No storyboard→panel containment edge</strong> — there is none in the vocab. Membership is already carried by the\n<code>storyboard_spec.payload.panel_ids</code> / <code>motif_ledger_id</code> fields and each <code>panel_spec.payload.source_storyboard_id</code>.</li>\n</ul>\n<p>All verdict-bearing runtime edges (<code>attempt_of</code>/<code>reviews</code>/<code>decides</code>/<code>rollback_of</code>) belong to Phase 2/3, not\nhere. Trace every gate round to <code>trace.jsonl</code> (<a href=\"../../protocols/review-tracing.md\"><code>review-tracing</code></a>).</p>\n<h2>Worked example</h2>\n<p>The canonical exhibit is <strong><a href=\"../../examples/comic_m3_audit/story/STORYBOARD_DRAFT.md\"><code>examples/comic_m3_audit/story/STORYBOARD_DRAFT.md</code></a></strong>\n— the full real artifact: a <strong>24-panel / 19-page</strong> pixel-art comic of \"ARIS handed over 24 hours\". Copy its\nexact shape:</p>\n<ul>\n<li><strong>Header / provenance + gate state</strong> (lines 1–2): <code>storyboard layer draft v1 — revised per codex cross-model critique (verdict REVISE applied); ✅ APPROVED by user 2026-06-10 (\"批了\") — asset-library build started</code>. The user-first gate is honored before any asset work.</li>\n<li><strong>PAGE ORDER FIRST</strong> (lines 3–6), the real 19-page layout verbatim:\n<code>P00_cover[S01·full-bleed] → P01_b02[S02·single·seam-split] → P02_b03[2-up S03(L warm)|S04(R dark)] → P03_b04[S05] → P04_b05[S06] → P05_b06[vertical-3 S07/S08/S09 big] → P06_b07[2-up mirror S10(L)|S11(R)] → P_B08_0[S12a NEW] → P_B08_1..4[S12–S15 reuse] → P02_b08[grid2x2 recap S12–S15 kept] → P_B09[S16 mirror-of-S11] → P_B09_5[S16b big-frame star-map] → P_B10[S17] → P_B11[2-up seam S18(L)|S19(R)] → P_B12[2-up S20(L)|S21(R seam)] → P03_end[S22 endcard]</code>. <strong>TOTALS: 24 panels · 19 pages · 20 NEW bakes +\n4 reused DONE (S12–S15).</strong> (19 pages is the AUTHORED plan — the compiler folds the <code>endcard</code> into\n<code>P_B12.closing.image</code>, so the compiled <code>comic.json</code> ships <strong>18</strong> pages; see §Constants PAGE_TYPES mapping.)</li>\n<li><strong>The CORRECTED MOTIF STATE TABLE</strong> (lines 14–39) — the load-bearing artifact. Columns\n<code>Panel | Mug | DDL | Tok|yo | exact_parse | claim_delta | bounce</code>. Patterns to copy: the monotonic-DDL fix\n(<code>S06 T-18:40</code> so it stays <code>&gt; S07's 18:30</code>); split metric columns (<code>S10 exact_parse 0.71→0.66</code> with\n<code>claim_delta —</code>; <code>S14 claim_delta +6.2→+1.4</code> with <code>exact_parse —</code>); bounce uniqueness (<code>S02 是全片唯一 MAX</code>;\n<code>S12a = attempted celebration, ARRESTED before becoming a jump</code>; <code>S21 = smallest bounce</code>); motif-vs-env\n(the <code>&lt;/&gt;</code> mug tagged <code>env</code>, never tracked).</li>\n<li><strong>Per-panel 9-field specs</strong> (e.g. S01 at lines 45–57, S02 at 59–73) — the exact template to fill, including\n<code>expected_literals: [\"DDL\", \"T-24:00:00\"]</code>, the side_narration <code>trait</code> tag, and the <code>motifs</code> line restating\nthe table row.</li>\n<li><strong>DONE-panel reduced form</strong> (S12–S15, lines 221–247) — only <code>status</code> + <code>side_narration</code> + <code>motifs (as baked)</code>.</li>\n<li><strong>Consolidated ASSET_REQUESTS</strong> (lines 369–383) — the 10-entry canonical list + the naming 铁律 (draft\nvariants declared void) + the single-source pins + P0 blocker + zero-new-work reuse.</li>\n</ul>\n<h2>Hard do / don't (earned lessons)</h2>\n<ul>\n<li><strong>DO</strong> require a LOCKED, user-approved outline before authoring; HALT with the offending node id otherwise.\n(Draft assets are fine at the PROVISIONAL pass; locked assets are the FINAL pass's demand — N1 two-stage.)\nConvergence is the upstream gate's job, not yours.</li>\n<li><strong>DO</strong> author the <strong>page order as its own section BEFORE any prose</strong>, and the <strong>MOTIF STATE TABLE before\nany per-panel prose</strong> — both are sources of truth the gate and compiler check against.</li>\n<li><strong>DO</strong> fill <strong>one panel at a time</strong>, fully, in page order. NEVER batch-author all panels then look — the\nledger + per-unit spec is precisely the guard against that failure.</li>\n<li><strong>DO</strong> keep <code>expected_literals</code> to salient blind-transcribable ASCII only, and write out the deliberate\nexclusions (sub-threshold chips, decorative non-ASCII, skill names).</li>\n<li><strong>DO</strong> consolidate assets to one canonical owner per token and map every draft alias to it.</li>\n<li><strong>DON'T</strong> let a panel free-describe an asset — reference the whitelist or file an <code>asset_request</code>.</li>\n<li><strong>DON'T</strong> ever rewind the DDL, emit a second <code>MAX</code> bounce, add a post-fall peak, or co-mingle the two metric\ncolumns — each is a hard veto.</li>\n<li><strong>DON'T</strong> retro-edit a DONE/reused panel.</li>\n<li><strong>DON'T</strong> put a skill name in a bubble or in-frame; it lives in <code>side_narration</code> only.</li>\n<li><strong>DON'T</strong> self-acquit. The cross-layer gate (a different model family) decides; the loop drives, it can't\nacquit.</li>\n</ul>\n<h2>Protocols (governance contracts this skill honors)</h2>\n<ul>\n<li><a href=\"../../protocols/reviewer-independence.md\"><code>reviewer-independence</code></a> — the 抽卡 Codex call and the cross-layer gate get <strong>file paths only</strong> (the locked outline, style bible, banlist) behind an <code>=== EXTERNAL CONTEXT (advisory) ===</code> fence, never this agent's interpretation; the brainstorm family ≠ the gate family.</li>\n<li><a href=\"../../protocols/acceptance-gate.md\"><code>acceptance-gate</code></a> — the loop can DRIVE but can't ACQUIT; user approval of the outline is the hard precondition gate (never proceed without it); the storyboard gate (different model family) acquits the layer.</li>\n<li><a href=\"../../protocols/reviewer-routing.md\"><code>reviewer-routing</code></a> — Codex at <code>xhigh</code> (NO model pin — follows the local codex config, currently <code>gpt-5.6-sol</code>); Gemini <code>auto-gemini-3</code>; never downgrade the effort tier (effort never lowers reviewer quality).</li>\n<li><a href=\"../../protocols/artifact-integrity.md\"><code>artifact-integrity</code></a> — the agent that authors the storyboard does not judge its own correctness; the MOTIF STATE TABLE is the ground-truth spec a fresh reviewer verifies, never the author.</li>\n<li><a href=\"../../protocols/review-tracing.md\"><code>review-tracing</code></a> — every 抽卡 round + gate round is logged to <code>trace.jsonl</code> so each verdict (and each dropped lineage) is auditable.</li>\n</ul>\n","files":[{"path":"SKILL.md","sizeBytes":36411,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-09-06T17:21:58.945694Z","sha256":"210A9A34C4C5094A41BCE73AA59C2AE241B70D2650D7464E97877164D827659B","sizeBytes":14449},"review":null,"source":{"repositoryUrl":"https://github.com/wanshuiyin/ARIS-Movie-Director","path":"skills/comic-storyboard-creator","license":"MIT","commit":"a1e7319f8a0af18511c300462e24b06091b4c927","subtreeSha":"EC41EF3D37D51383896238F085A35783B2CA33D3B87EC08D323DFAAA48225DE0","lastSyncedAt":"2026-09-23T13:50:40.850809Z"},"reviewedAt":"2026-09-06T17:22:43.096385Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/wanshuiyin/ARIS-Movie-Director/tree/main/skills/comic-storyboard-creator"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install wanshuiyin-aris-movie-director@llmmart"},{"target":"git","command":"git clone https://github.com/wanshuiyin/ARIS-Movie-Director.git"}]}