AgentStack
SKILL verified MIT Self-run

Comic Asset Ref Generator

skill-wanshuiyin-aris-movie-director-comic-asset-ref-generator · by wanshuiyin

Phase-1 (S4) of a comic movie — PRODUCE the canonical reusable references the whole spiral conditions on. Per asset it bakes ONE canonical 1:1 white-bg identity ref via codex gpt-image-2 (conditioned, never hand-pasted) OR, for a deterministic motif (clock/chart/stamp/star-map), emits a single-source parametric SVG from a python generator (asset_lib.py). Hashes + base64-encodes the bake into the…

No reviews yet
0 installs
9 views
0.0% view→install

Install

$ agentstack add skill-wanshuiyin-aris-movie-director-comic-asset-ref-generator

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Comic Asset Ref Generator? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

comic-asset-ref-generator — the Reference Producer (Phase 1 · S4)

The missing Layer-2 of comic-author: take the storyboard's consolidated ASSET_REQUESTS and produce, for every declared asset, the one canonical artifact that every downstream panel bake will condition on — so the film never grows two visual dialects and every panel of the same character/prop/motif reads as the same thing. This is precisely the producer of comic.json's identity_refs (e.g. duo_canonical_ref_v001.png + per-character locks like executor.hoodie #1D4684 / reviewer.beard true) that the proven comic created by hand. It is the upstream sibling of [comic-blueprint-author](../comic-blueprint-author/SKILL.md) (which authors per-panel content-SVGs) and feeds [comic-asset-review-loop](../comic-asset-review-loop/SKILL.md) and the [comic-director](../comic-director/SKILL.md) spiral.

Two asset classes, two production routes — this is the load-bearing fork:

storyboard.consolidated_asset_requests
   ├── identity / scene / prop  ──▶  RASTER ref:  codex gpt-image-2, CONDITIONED on a labeled white-bg
   │      (a face, a hoodie,           condition + real identity refs → 1:1 (or 16:9 scene) PNG
   │       an empty room)              → output_ref{file_path,data_url,sha256,width,height,mime}  (ALL 6)
   │
   └── deterministic motif      ──▶  SVG SOURCE:  ONE parametric builder in asset_lib.py
          (clock / chart / stamp        (ddl_chip / stamp / mug / curve_panel / tokyo_chip / starmap …)
           / mug / star-map)            the "ref" IS the single-source SVG — NOT an image bake
                                        → records generator_script, owner_script, file_sha256

   both routes → review_status:"pending"  (NEVER "locked" here)  → collision gate → asset-review-loop

The battle lesson, landed as the fork above: a clock, a chart, a verdict stamp, a star-map is deterministic content — you do NOT bake it as a fuzzy image and hope the digits land; you build it once from a python generator (asset_lib.py) so all 18 instances of the DDL timeline, all 7 verdict stamps, both the labeled and the wordless star-map render from the same coordinates and never diverge. An identity (a face, a costume) is not deterministic — that you bake once via gpt-image-2, conditioned on a labeled white-bg reference and the real identity refs, never a free prompt, never a hand-paste.

Constants

  • GENERATOR (raster route) = mcp__codex__codex, model: "gpt-5.5", model_reasoning_effort: "high",

sandbox: "workspace-write", approval-policy: "never", config{ include_image_gen_tool: true }. This exact shape is the empirical v3.5 lesson: without workspace-write + approval=never + include_image_gen_tool=true, Codex falls back to writing descriptive text (or an SVG renderer) instead of firing image_gen. image_gen is incompatible with minimal effort; high is the upper bound. Codex must reply exactly one JSON line: {"ok":true,"path":...,"model":"gpt-image-2","width":...,"height":...,"bytes":...} or {"ok":false,"error":...}.

  • SVG SOURCE (deterministic route) = a pure-python parametric builder living in gen/asset_lib.py, emitted

by a thin gen/gen_core_assets.py writer. The palette is pinned to comic.json ui_tokens — never re-typed per asset. This route calls no image model and spends zero credits.

  • MAXGENRETRIES = 2 (3 attempts total) — on ok:false OR a missing / zero-byte / invalid PNG

(file check). Append "[retry {n}: previous failure was: {reason}]" to the prompt each retry.

  • VERSIONING = monotonic 3-digit _v{NNN} (duo_canonical_ref_v001.png, ddl_widget_template_v1.svg).

Version only grows; the prior artifact stays on disk for the audit cascade; a supersedes self-edge links the new version to the old (record prev_sha256: + prev_version:N in tags).

  • SUBDIR by asset_kind: characters | scenes | props | text_panels (raster) under /; SVG sources

under gen/ + assets/.

  • NEVER LOCKreview_status is left "pending" (node statusunder_review). The executor that

produces an asset is forbidden from approving it; locking belongs to the cross-model comic-asset-review-loop (a different model family). Setting review_status:"locked" here is a contract violation.

  • ONE RUNNER PER PROJECT — each raster bake writes its own explicit out_path via the

.bakereq.json/.bakestatus.json sidecar seam, so there is no global-dir cross-pollination between concurrent bakes. There is no /tmp/aris_imagegen.lock in agent mode — the agent wrapper itself serializes the mcp__codex__codex calls. The real race surface is two runners on the same project colliding on the per-asset .bakereq.json/.bakestatus.json sidecars + the shared out_path, so keep one runner per project. (The global generated-images dir + newest-after-marker pickup that could cross-pollinate is a hazard of the legacy exec path ONLY, retired for real bakes.)

Input contract (3 modes)

This skill never invents an asset id. If the outline/storyboard did not declare it, the operator adds it at the outline layer (comic-outline-creator) — not here.

  1. single asset_id matching ^asset:[a-z0-9_-]+$ — produce one asset, await its verdict.
  2. --batch-from-outline — read the outline's `characterassetids[] + sceneassetids[] +

propassetids[] ∪ the storyboard's consolidatedassetrequests, keep **only** review_status=="pending"`, process serially (raster bakes never overlap), fire the review loop once at the end.

  1. --regenerate --reason "" — force a re-render even if approved/rejected; prefix the

generation prompt with "[regen reason: ...]", bump _v{NNN}, write a supersedes self-edge.

What it reads / what it writes (wiki nodes & edges)

Per [schemas/node_schema.json](../../schemas/node_schema.json) (node/comic/3.0):

  • READS storyboard_spec (payload.consolidated_asset_requests, payload.global_policies) and

outline_spec (payload.character_asset_ids / scene_asset_ids / prop_asset_ids, payload.global_style_bible).

  • WRITES / MUTATES the asset node (node_id: ^asset:[a-z0-9_-]+$, node_type:"asset"). Required

payload fields (schema oneOf → asset): asset_kind, name, visual_description, identity_lock, ref_requirements, review_status, version. This skill additionally writes the produced ref onto the node (see the two contracts below) and leaves review_status:"pending", node status:"under_review".

  • EDGES ([schemas/edge_schema.json](../../schemas/edge_schema.json), src/dst/type): on a regenerate,

emit a supersedes true self-edge with the bare node_id on BOTH endpoints (the node_id pattern ^(...|asset|...):[a-z0-9_-]+$ forbids @/{/}, and there is ONE asset: node per asset — no per-version node files — so any @v{N} endpoint would dangle and fail cli/validate_wiki.py line 154-156): {src: asset:, dst: asset:, type:"supersedes", evidence:"regen v{N}->v{N+1}: ; prev_sha256:; prev_version:N"}. The cross-version lineage lives in the artifact filename _v{NNN} + prev_sha256/prev_version in tags (per [output-versioning](../../protocols/output-versioning.md)) — NOT in the edge endpoints. (Only if you truly need a versioned snapshot node, encode the version IN the slug — asset:_v002, which matches the pattern — AND actually write that second node file so both endpoints resolve.)

  • FAILURE — on retry exhaustion write a failure_mode node (node_id: fail:, root status:"active"

— the runtime canon validatewiki.py enforces for failuremode; payload has all 3 PAYLOADREQUIRED fields layer:"asset_ref", affected_shot_ids:[] (empty — this is the UPSTREAM asset gate, no shots yet; or the downstream panel/asset ids if known), active:true; plus repair_pattern:"", tags:["image_gen_unavailable"]) so the spiral routes around it, and exit non-zero. Mirror the live shape [examples/comic_m3_audit/wiki/nodes/fail_s09_a01.json](../../examples/comicm3audit/wiki/nodes/fails09_a01.json). Do not trigger the review loop on an empty file.

The two fail-closed engine contracts (honor these or the director refuses to run)

These are the same fail-closed invariants the spiral enforces — produce assets so they cannot violate them:

  1. Every panel needs a content_svg. Every deterministic motif a panel will use MUST be produced as a

single-source SVG in asset_lib.py, so the panel's blueprint can name a real content_svg. If a recurring motif has no parametric source here, the downstream blueprint has nothing to bake-condition on and the director's render step fails closed. One parametric builder per recurring motif — no exceptions.

  1. A baked figure-panel needs expected_literals. Any motif carrying gated text (a chart with 0.71→0.66,

a stamp reading REJECT, a DDL chip reading T-16:05) must render those literals deterministically so the panel can declare ascii-tokenizable expected_literals for the blind token-diff gate. Conversely, a zero-text asset (the wordless constellation) must contain zero glyphs — assert it at build time (assert "/{subdir}/{name}_v{NNN}.png); size = 1024x1024 (1:1 default) or 1280x720 (scene 16:9), background opaque/fully white, n:1.

  1. Orchestrator writes .bakereq.json =

{prompt_text, content_png, identity_ref, out_path:OUTPUT_PATH, model:"gpt-5.5", config:{model_reasoning_effort:"xhigh", include_image_gen_tool:true}, sandbox:"workspace-write", cwd, created_at, min_bytes:500000, aspect, request_id:""} (atomic .tmp → mv), pre-deleting any stale out_path + status so a prior bake can't be silently reused. request_id is a per-bake uuid4-hex nonce the orchestrator mints (see step 3).

  1. Agent calls mcp__codex__codex with exactly that request (the reference + output paths are LITERAL in

prompt_text — the mcp__codex__codex schema has no -i image param); codex writes the native PNG to OUTPUT_PATH. The config MUST carry both model_reasoning_effort:"xhigh" and include_image_gen_tool:true, else the wrapper won't hand codex the native image tool and no bake fires.

  1. Agent writes .bakestatus.json =

{status:"ok"|"fail", failure_kind, mcp_output:"", request_id:""}. mcp_output is MANDATORY on BOTH ok and fail (the HARD-VETO scans it for import struct/zlib.compress/ `/matplotlib/… traces of a hand-drawn fallback); request_id is copied **VERBATIM** from the .bakereq.json` (a missing/mismatched id is a stale/foreign bake and fail-closes).

  1. Orchestrator verifies the EXPLICIT OUTPUT_PATH (only after reading status:"ok") via

`` python3 /scripts/pickup_image.py --out-existing --out OUTPUT_PATH \ --min-bytes 500000 --aspect --created-at \ --request-id --transcript .bakestatus.json ` which checks PNG sig + IHDR dims + size **strictly > minbytes** + mtime >= createdat + a non-empty mcpoutput, fail-closes on a requestid mismatch, and **HARD-VETOES** struct/zlib/PIL// matplotlib markers in the transcript (a clean PNG sig NEVER overrides a fallback marker). **There is no newest-pickup** — pickup verifies the one explicit OUTPUT_PATH` this bake wrote.

RETRY per MAX_GEN_RETRIES. After exhaustion: keep the best valid PNG if any, else write the failure_mode node + exit non-zero (do not call the review loop on an empty file). Never patch a failed bake by hand-pasting the missing trait — re-condition and re-bake.

> Grid guard. A 2×2 / contact-sheet / variation-grid output is a failed attempt → retry (the > "single coherent image, not a grid" line is the primary mitigation; a PIL aspect-vs-canvas check + an optional > codex "is this a grid?" sanity reply is the backstop).

P3r · RASTER route — hash, encode, update (atomic), honor the 6-field contract

  • SHA256 = shasum -a 256 ; (W,H) via PIL; DATA_URL = "data:image/png;base64,$(base64 -b 0 || base64 -w 0 )"

(macOS -b / GNU -w, cross-platform). data_url is a v4 invariant — Layer-3 multi-ref composition reads it directly; a missing data_url silently breaks downstream.

  • Mutate the node output_ref with ALL SIX fields {file_path, data_url, sha256, width, height, mime}.

A partial write is a schema violation — reject it. Write .tmp then mv (atomic; the wiki must validate even if interrupted). Leave review_status:"pending", node status:"under_review". Append a log.md line.

P1s–P3s · SVG-SOURCE route — one parametric builder per motif

  1. Add / reuse one builder in gen/asset_lib.py for the motif (ddl_chip, stamp, mug, curve_panel,

tokyo_chip, mini_stamp_glyph, verdict_card, the star-map coord tables). Palette pinned to comic.json ui_tokens at the top of the file. Encode every cross-panel reuse contract into the docstring (e.g. S11 REJECT ↔ S16 ACCEPT instantiate the SAME verdict_card — mirror pair; the star-map JSON is the single coordinate truth for S16b labeled + S22 wordless).

  1. Emit the canonical sheet via gen/gen_core_assets.py — a thin w(name, content) writer that imports

only from asset_lib. Its docstring maps each output filename → the storyboard ASSET_REQUEST #. Enforce single-source inline: if a specialized generator (e.g. gen_b06) takes ownership of a richer variant, delete the generic duplicate here (don't keep two).

  1. Coordinate-truth motifs (the star-map): write the JSON (wiki_starmap_nodes_v1.json) as the only

truth source; both the labeled SVG (S16b) and the wordless SVG (S22) derive from it programmatically禁目测 / never re-layout by eye. The zero-text twin asserts assert " **Why no numeric approve here:** the executor that *produced* the asset is not allowed to *judge* it > (cross-model independence). This gate only proves the artifact is *well-formed and single-source*; whether it > is *good* (identity fidelity, on-bible look) is decided by comic-asset-review-loop` with a different model > family.

STYLE-BIBLE / banned-vocab filter (mandatory before any raster bake)

The aris_movie source bans camera/lens vocab that conflicts with downstream synth and silently regresses fidelity (8K, 4K, photorealistic, cinematic, 50mm, dolly, push-in, bokeh, rim light, masterpiece, trending on artstation, close-up, wide shot, …). For the comic, this filter reads ART_BIBLE.md and additionally enforces the bible's own terms: the two-world warm-real / dark-cyber palette (warm = Edison/wood/window; digital-ARIS = dark_navy_void #0A0E27), the voxel ban (禁止 voxel 立体块 — pixel-flat only), and the per-character hex/feature locks (executor blue hoodie #1D4684 + brown hair + NO beard; reviewer green hoodie #30582D + near-black hair + beard). A surviving banned/off-bible term ⟹ refuse to call image_gen. Identity is BRING-YOUR-OWN: swap these locks for whatever the project's ART_BIBLE.md + identity_lock declare; the ARIS chibi duo is only the worked example.

Worked example (copy this exact pattern)

The proven comic is [examples/comic_m3_audit/](../../examples/comicm3audit/). Copy its shape:

  • The single-source builder library

[examples/comic_m3_audit/gen/asset_lib.py](../../examples/comicm3audit/gen/assetlib.py): one parameterized builder per recurring tokenddl_chip(x,y,t,state,skin,…) (the sole renderer for the whole 18-instance DDL timeline, 3 skins × {amber,red,green} + a SUBMITTED variant), the STAMPS table + stamp(...) (DUP / SURVIVES / REJECT / ACCEPT / WARNcorrected / SUBMITTED / AUDIT — one stamp di

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.