Communitygithub.com

TortoisewithBlackFrameGlasses/iconloom

Claude Code & Codex sidebar skill - extract every icon in your project into a live SVG workbench, restyle to one spec, write back to source. iOS/Android/Web/mini-program/React Native.

iconloom 是什麼?

iconloom is a Claude Code agent skill that claude Code & Codex sidebar skill - extract every icon in your project into a live SVG workbench, restyle to one spec, write back to source. iOS/Android/Web/mini-program/React Native.

相容平台Claude CodeCodex CLI~Cursor
npx skills add TortoisewithBlackFrameGlasses/iconloom

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

SVG self-check

Pipeline (the whole workflow in order — each step links its section below)

  1. Intent → spec + route — translate the ask into a graded spec, classify the shape, pick which rules run → ## Step 0 — Intent → spec + ## Route — classify the shape & pick which rules run.
  2. Geometry (library-first) — decide construction BEFORE drawing (library / boolean-primitives / spine+symmetry / clip-by-default) → ## Geometry / shape construction.
  3. Draw — emit few-anchor extrema beziers, one stroke per <path>, per the loop → ## The loop.
  4. Render + ZOOM — rsvg render, then zoom every seam/join and read the crops → ## The loop + ## After every edit.
  5. QA gate (fail-closed) — full render + handle overlay + crops + alignment checklist; end with an edit-link → ## Deliverable QA gate + ## Alignment checklist + ## EDIT-LINK delivery gate. 4b. Taste preflight (standing) — for any colored / multi-element SVG, tick the three taste axes (color / composition / style) and emit the TASTE: machine line, so the director judges only the residue, not raw taste → taste-preflight.md. 4c. Rules-used ledger — with the finished SVG, emit a RULES-USED block: one line per skill rule that actually DROVE a concrete choice this draw (naming the coord / hex / shape it forced), plus any considered-but-N/A → ## Rules-used ledger.
  6. Director loop — dispatch art-director on the full evidence kit (director-kit.sh prints the DISPATCH step for YOUR harness: Agent tool / --dispatch via codex exec / [self] role-play); loop until APPROVE → ## Designer-agent direction loop.
  7. Edit-link delivery — every finished SVG reply ends with the visual-editor link → ## EDIT-LINK delivery gate.

Editing an existing SVG rather than drawing one? Same discipline at smaller scope — reread the .spec.md, declare CTYPE·ROUTE for the changed REGION + the edit mechanism, scoped-edit, one-zoom → ## Editing an existing SVG. (Where a user correction should LIVE so it's used next time → ## Where a correction goes so it's USED next time.)

Setup nudge (one-time per session — know which distribution you are in)

The QA discipline below can be auto-enforced by two bundled Stop hooks (hooks/svg-qa-gate.py + hooks/svg-director-reminder.py), but the registration layer depends on the harness/distribution:

  • Codex plugin distribution: the plugin root ships hooks.json plus plugin-level agents/art-director.md and agents/stylist.md; there is no extra install.sh --sync-codex step for the downloader. Treat the hooks/agents as part of the installed plugin.
  • Bare skill copy in Codex: Codex does not load hooks/agents from skills/svg-selfcheck/ itself. Run bash install.sh --sync-codex once to refresh ~/.codex/{hooks,agents} and register ~/.codex/hooks.json.
  • Claude Code bare skill: hooks must be registered in a Claude settings.json; use install-hooks.sh / install.sh as below.

For Claude Code bare-skill installs, the FIRST time you act on this skill in a session, check ONCE whether the gate is loaded:

grep -ls svg-qa-gate.py ~/.claude/settings.json .claude/settings.json 2>/dev/null

If that prints a path, the hooks are already on — say nothing. If it prints nothing, tell the user once (don't repeat it every turn): "SVG QA-enforcement hooks aren't loaded — run bash <this-skill-dir>/install-hooks.sh to auto-block deliveries that skip QA (idempotent, --uninstall to remove), or skip it to keep QA manual." Do not run install-hooks.sh yourself without the user's go-ahead — it edits their settings.json.

Why this exists (the failure mode)

A model "sees" SVG only as a coarse rasterized snapshot, and reviews it at the gestalt level — "is this a swimming koi?" — which catches gross breakage (a fish that looks like a ghost) but misses fine edge-registration: a marking poking outside the body, a fin detached from the edge, an asymmetry, a label off its box. Colors never break (they're just hex); geometry drifts because control points are placed blind. So: never certify an SVG from a single full-image glance.

Step 0 — Intent → spec (translate the ask into a concrete, drawable target FIRST)

A vague request ("a filled book that opens", "a like animation") hides choices that decide WHAT you build. Jumping straight to geometry means you build YOUR guess, and guessing wrong burns whole build→verify→director rounds (a book "opened" three different wrong ways before the user's "at least open it from the FRONT" surfaced the real intent — an upfront intent pass would have caught it). So before any coordinates, translate the words into a spec (subject is an ICON / icon set, or motion is requested → run the expanded question set in intent-icons.md FIRST — 静态七问(词义/误读 kill-feature/显示语境/set 语法/…)+ 动效的 触发/结束语义必问 fork;the numbered骨架 below stays the source of truth for non-icon subjects):

  1. Name the subject and its REAL mechanism / behavior. Static icon → the load-bearing silhouette + metaphor. Animation → how does this thing actually move/change? (book → front cover hinges at the SPINE, pages fan from the binding; toggle → knob slides + track fills; like → heart pops + particle burst). This is the physics rule applied at design time.
  2. Pin the under-specified axes into concrete values. Icon: STYLE (面性/线性/duotone/flat), view/pose, grid + target size, palette, ONE metaphor. Animation: trigger, the discrete STATES (keyframes), the mechanism connecting them, the end/resting state, loop-vs-trigger-then-settle, duration band. Then classify the construction TYPE and ROUTE which rules apply — see the dedicated ## Route — classify the shape & pick which rules run section right below (the TYPE and the named applicable/skipped tables are required spec fields; a spec missing them is incomplete).
  3. Write the spec to <name>.spec.md by copying $skill_dir/spec-template.md — that template IS the graded contract + clean-restart file (契约 III + 落盘 IV + 重启锚 V + rubric VI in one). Fill its ≤6 checkable assertions (construction TYPE, squint@32, curve cleanliness, must-keep regions, delivery form, hidden fork) next to the target .svg; don't let the spec live only in context, where a lost session drops it and there's nothing to re-draw from or grade against. (Rough/one-off throwaways may skip it; finished deliverables must not.)
  4. Present concrete intent OPTIONS before acting when multiple readings are plausible. For any non-trivial SVG/animation request that could reasonably mean different mechanisms, visual styles, interaction states, or output formats, give the user 2–4 labeled options and wait for a choice. Each option must name the mechanism/style tradeoff ("emoji burst" vs "physically-plausible cone spray" vs "restrained UI microinteraction"), not vague color preferences. Only skip this when the user has already specified the exact mechanism/style, or the change is a narrow mechanical bug fix that has one correct interpretation. STYLE axis exception — options must be DRAWN, not described(标准选样机制). STYLE/variation 是 FORK ⇒ 一枚代表图标 × 2–4 版试样板(其余 knob 全锁、单变量对照)→ AskUserQuestion 按版号选; 完整流程(16px 缩样、Write 落盘可见性、探针非交付/EDIT-LINK 豁免):style.md §variation-是-FORK。
  5. Find the FORKS that need different geometry, and don't silently guess them. A fork = two readings that require a different shape or mechanism (open book = two-page lay-flat spread VS front-cover-flip → genuinely different rigs; "phone" = flat front vs 3/4 view). On those, a 10-second AskUserQuestion beats 3 rebuild rounds. Cosmetic-only choices (exact hue, corner radius) → just pick a sensible default and note it; don't ask.
  6. Anchor on a vetted reference shape — don't invent. Lucide / Material / Carbon for the base silhouette; svg-toolkit for libraries. (Hand-invented hearts/books/animals drift; vetted paths don't.)
  7. Restate the spec in one line — INCLUDING the construction method; for non-trivial work, confirm before building. e.g. "Filled book, Lucide silhouette, built via shapeforge boolean (two cover rrects ∪ spine − page-gap); opens by the front cover hinging at the left spine (single-page reveal, NOT a lay-flat spread); blue cover + cream page; ~400ms ease-out." If the one-liner doesn't name HOW it's constructed, the spec isn't done. The user corrects the WORDS for free; correcting the PIXELS costs a full loop.

Payoff: the expensive build → self-check → director loop runs ONCE on the right target, instead of N times discovering the target. Right intent first, then the geometry choices below.

Route — classify the shape & pick which rules run

Step 0 is not only "what to draw" — it SELECTS "which rules run." Classify the construction TYPE, then route the rule-tables on three axes; both the TYPE and the named applicable/skipped tables are required spec fields.

THREE-QUESTION ROUTE — ask these BEFORE the first coordinate; the three computed routes are CO-EQUAL, hand-bezier is the residue (铁律 B). Don't reach for <path d> until all three are answered "no":

askif yes → routetool
能布尔? decomposes into primitives (∪ / − / ∩)?① booleanshapeforge.py (ellipse/circle/rrect + boolean + cr_path)
能公式? any outline/feature writable as a formula/loop (repeats, spokes, texture, symmetry)?② parametrichachurize.py (striated fill), kappa arcs, code loops
能描图? have (or can render) a raster reference of an organic silhouette?③ trace→simplifytraceforge.py (potrace/vtracer → shapely.simplify → cr_path)
none of the above④ hand-bezier — the RESIDUEextrema anchors, axis-aligned tangents, kappa; should trend to ~zero

CONSTRUCTION-TYPE ROUTER — classify the shape into ONE of 4 BEFORE you learn-from-reference or draw (required spec field). The type picks the BUILD method, the way you REVERSE-ENGINEER a reference, AND which geometry rules apply. Using the wrong one (circle-decomposing an organic shape, or hand-authoring a boolean one) is the classic mistake.

  • ① PURE BOOLEAN / PRIMITIVE — silhouette = one primitive, or a union/difference of PRIMITIVES (circles/rects), no freehand. Includes the degenerate case: a round / oval / capsule / cone BODY is a single primitive (ellipse/circle/cone) — emit it as a primitive, do NOT hand-author a bezier teardrop (that drifts into a "weird oval" — the 洋葱 mistake). E.g. onion/tomato/eggplant = one ellipse; broccoli head / gear / donut / clove-bulb = boolean of circles. BUILD: shapeforge (ellipse/circle/rrect ± boolean) + cr_path. LEARN a ref by: max-inscribed-circle decomposition (distance-transform peaks, suppress, repeat) + overlay-verify → read the LAYOUT (count / position / size / overlap, e.g. "1 big + 2 medium asymmetric"); the exact coords are one-off, don't codify them.
  • ② BOOLEAN + ORGANIC (异型) — a decomposable boolean CORE + organic/parametric parts (guitar = boolean body + parametric strings/frets; most instruments). BUILD: boolean for the core, hand-bezier/parametric for the rest. LEARN: decompose the core (as ①); for the organic parts anchor on a vetted silhouette + operate the handles — DON'T force-fit circles to them.
  • ③ PURE ORGANIC (异型) — fully freehand organic silhouette that does NOT fit primitives (animals, mascots, leaves, blobs). BUILD: spine + primitives + symmetry, OR trace a ref (potrace/vtracer)→simplify, OR hand-bezier under geometry.md (anchors at extrema, no kinks, clip-by-default). LEARN: trace the silhouette / learn anatomy + proportions — do NOT run circle-decomposition on it (inscribed circles UNDERSIZE and mislead on organic shapes).
  • ④ NORMAL / GEOMETRIC ICON — UI/symbolic glyph (arrows, files, bell, toggle). BUILD: true-arc primitives (rect rx / A / kappa 0.5523) on the grid; keep 45°/90°. LEARN: keyline / grid / optical / stroke conventions.

A spec without a named construction TYPE is incomplete — do not start drawing. (What's safe to LEARN from any ref vs not: codify a CONVENTION only when cross-checked across ≥2–3 sets that agree; learn TECHNIQUE + ANATOMY; never copy verbatim paths, a single source's quirks/ defects, or style/grid choices that are that set's own system.)

ROUTE — from the TYPE, decide WHICH rule-tables apply (and which to SKIP); name them in the spec. Route on three axes:

  • Subject domain → load that domain module; each carries its own apply/skip table. No module → general geometry.md. Quick subject→module lookup:

    subjectmodule
    foodfood-icons.md
    instrumentinstruments.md
    animal / mascot / face / hand (吉祥物 / 头像 / 手)creatures.md
    potted plant / flowerpot (盆栽 / 多肉 / 花盆)plants.md
    box / framed / 3D-isobox-kit.md
    diagram / flowchart / chart / graph (流程图 / 图表 / 饼图 / 架构图)diagrams-charts.md
    (else)geometry.md
    icon(单枚/SET)的 Step-0 意图榨取 + 动效意图语义intent-icons.md
    + animating?icon-motion-principles.md
    + color / shadingcolor.md
    + style preset / controlstyle.md
    + liquid-glass finish → a self-contained .svg (refractive glass lens, 液态玻璃)liquidglass-style.md — run liquidglass.py
    + style FROM a reference (HTML/CSS/UI页/帧 — "画得像这个页面")style.md §Style FROM a reference — run style_extract.py
    + composition / layout / restraint (multi-element: hierarchy, negative space, "should this exist")composition.md
  • Nature: organic / mechanical / symbolic → sets construction method (above) AND which geometry rules apply. ORGANIC (food/animal/plant) SKIPS geometric-keyline-shapes, pixel-fitting, 45°/90°-angles, and mono/1-color (free curves + color=identity); SYMBOLIC/UI glyphs APPLY them.

  • Delivery: one-off illustration vs UI/SET icon (+ target sizes) → whether the ICON-SYSTEM checks run (optical-centering, 16px-survival / simplify-not-shrink, live-area + padding, set-consistency — see the delivery group in the alignment checklist). One-off art SKIPS them; a set/UI icon at target sizes RUNS them.

A spec that doesn't name its applicable tables (and the deliberately skipped ones) is incomplete.

The loop (mandatory for any non-trivial SVG)

  1. CLASSIFY BEFORE YOU DRAW — no coordinate before this line (铁律 A). Before writing ANY path, run the three-question route (## Route is the single source of truth — three CO-EQUAL computed routes, hand bezier is the RESIDUE trending to zero) and emit a machine-readable header in your reply: CTYPE: <①|②|③|④> · ROUTE: <boolean|param|trace|hand> · why:<≤10 words>. This line is a fail-closed gate: the Stop hook BLOCKS any turn that produced/changed a real .svg but shipped no CTYPE·ROUTE line, and soft-warns if you declare boolean/trace with no matching tool trace. Skipping it (jumping straight to <path d>) is exactly how a computable shape gets hand-typed and drifts. Classify first, then:
  2. Write the SVG to a file. 1b. EVERY CURVE IS A FEW-ANCHOR BEZIER — check it the moment you write, not when the Stop gate blocks you (this is the #1 repeat-miss). The raster is BLIND to anchor structure: a dense cr_path blob and a clean extrema bezier look identical rendered, so "the render looks smooth" is NOT proof the curve is clean. Anchor count is an INVISIBLE quantity you must check with a tool. So the instant any <path> exists, run node <skill-dir>/bezierlint.mjs file.svg; if anything is DENSE, fix it NOW (before step 2), don't ship and wait for the gate:
    • Generate few-anchor by DEFAULT, don't dense-then-simplify. Parametric/texture stroke (rib, vein, grain) → sample ~6–9 points and emit ONE open Catmull-Rom bezier per stroke, never a many-point polyline. Simple slab/lens/blob → hand-bezier with anchors at W/N/E/S extrema.
    • Only a genuinely complex BOOLEAN silhouette earns dense cr_path — and even then, first try shapely ring.simplify(tol)_cr_subpath so anchors land on the lobe extrema (30 beats 190).
    • Emit each stroke as its OWN <path> — never merge strokes into one M…M… path (the relative-m 2nd-subpath then breaks any later simplify, and clip-path hides the breakage from the raster). Reserve BEZIER-DENSE-ACK for the one case that's truly an irreducible boolean. The default is clean. A CIRCLES-ONLY union is NEVER that case — its boundary is exact circular arcs; emit it with shapeforge.circle_arc_path (anchors only at intersections, true A segments, no handles) and the lint passes natively. An ACK on a circle-union path is invalid — it means you resampled a perfect answer into an approximation (the broccoli-crown failure, caught by the user).
  3. Rasterize and look: rsvg-convert -w 760 file.svg -o /tmp/v.png then read /tmp/v.png. ⚠️ Render SVG→PNG with rsvg-convert ONLY. NEVER magick file.svg / convert file.svg — ImageMagick's built-in MSVG coder (it does NOT reliably use the rsvg delegate) silently DROPS whole <g> groups and mis-composites opacity/clip-path, so you QA a render that differs from what a browser shows (this once hid an entire root-whisker group + muddied the shading, sending a director on a wild-goose chase). magick is fine ONLY for manipulating an already-rsvg-rendered PNG (crop/append/diff). If rsvg-convert is truly missing, use qlmanage -t -s 760 or resvg, not magick. See README.md for tool requirements.
  4. Then ZOOM into every suspect region and read the crops — the full image is not enough. Render big with rsvg, then crop the joints/edges with magick (the PNG is already raster):
    rsvg-convert -w 1600 file.svg -o /tmp/big.png        # render: rsvg only
    magick /tmp/big.png -crop 460x460+820+200 /tmp/head.png   # crop the PNG: magick is fine here
    magick /tmp/big.png -crop 460x460+700+900 /tmp/tail.png   # tail/fin joins
    
    Suspect regions = wherever two shapes meet or one sits inside another (head, fin attachments, patch edges, corners, text-in-box).
  5. Inspect the render AND every crop yourself. If a crop is blank, off-target, too zoomed-out to judge, or misses the suspect region, the QA run fails: re-crop and re-run before evaluating the art.
  6. If any visible issue remains — even one you noticed yourself while writing the final answer — make a scoped edit, then re-render and re-zoom that exact region. Repeat until clean. Don't claim "done" before a clean zoom pass.

Editing an existing SVG (the edit branch — the flow that gets skipped on "改一下")

The pipeline above reads as "draw from scratch"; the #1 place discipline is dropped is a small EDIT ("把X改大" / "换个颜色" / "调这条缝"), where it's tempting to jump straight to Edit. The route / classification is NOT rewritten for edits — reuse the SAME 4 types + three-question route — you just apply it at a smaller scope and add one axis:

  1. Reread the contract first. If a sibling <name>.spec.md exists, Read it before touching geometry (it's the clean-restart anchor). The Stop hook nudges when you edit an SVG whose spec you never reread this turn.
  2. Declare the route for the REGION you change, not the whole image. Emit CTYPE · ROUTE for the touched part only ("把鱼鳍改大" → classify the fin, not the fish). The Stop hook BLOCKS any SVG-touching turn that ships no CTYPE·ROUTE line at all — that line is how "到底用没用布尔" becomes visible and checkable.
  3. Also declare the EDIT MECHANISM (edits have this axis, fresh draws don't): prefer structured node-ops (nodeops.mjs / the visual editor by anchor number) or re-run the generator (shapeforge / build_*.py) over hand-editing raw d — raw-d surgery is lossy and error-prone (see geometry.md + director loop §4), and it's the edit-time regression that drops BOTH the boolean construction AND the clean-bezier principle at once. The Stop hook soft-nudges (non-blocking) when you Edit a path's d= by hand with no nodeops / regen trace that turn. If you declare ROUTE: boolean on an edit, the hook expects a boolean tool trace THIS turn; if you're reusing prior geometry unchanged, declare ROUTE: hand · why: 复用/局部 instead (the hook soft-warns "said boolean, no boolean trace").
  4. Scoped edit + one-zoom. Change ONLY the geometry that causes the issue — do NOT drift color / opacity / curve as a side effect (see Don'ts) — then render → zoom the EXACT region you touched. One edit → one zoom.
  5. Same output gates apply. QA evidence · bezierlint · frame · motion/reduced-motion · edit-link all fire on edits exactly as on fresh draws (the Stop gate keys off "an .svg was touched this turn").

Where a correction goes so it's USED next time (durability ladder)

A correction changes future behavior only if it lands in a layer future turns actually see. Three layers, weakest → strongest:

  • 提示词 (this SKILL.md / a command / a memory file) — advisory; may be skipped, and on an EDIT the skill may not even load. Fine for one-off taste.
  • 每轮注入 (a UserPromptSubmit hook / the recalled MEMORY.md) — guaranteed IN CONTEXT every turn, but still soft. Use for a must-do that needs JUDGMENT (can't be machine-checked).
  • (Stop / PreToolUse hook) — enforced; the turn can't end / the tool can't run. Use for any must-do that is MECHANICALLY CHECKABLE.

Rule: a checkable correction → make it a GATE the same session (don't leave it in memory); a judgment correction that must fire every turn → injection; memory is the weakest layer, for one-offs only. Memory files are recalled as background and reflect what was true when written — they do NOT guarantee next-run compliance. (This skill's bezier / frame / motion gates all began as corrections promoted from prose → Stop gate for exactly this reason — the durability-ladder method above is the self-contained record.)

Deliverable QA gate (fail closed)

For any SVG that will be delivered as finished, and for any request about Bezier curves, organic shape, seams, joins, reference fidelity, or "why does this shape look wrong", treat QA as fail-closed:

  • A conclusion based only on the full PNG is a visual note, not approval.
  • Do not say APPROVE, done, or ship-quality until the evidence exists: full render + zoomed crops for touched/suspect regions + alignment checklist.
  • For Bezier/path-shape concerns, also produce a handle overlay with showhandles.py; without it, the review has not inspected the curve structure.
  • For reference-matching work, also run fidcheck.sh and/or viscompare.py.
  • Final delivery must report the evidence paths, e.g. render, handle overlay, crops, and reference overlay/diff if applicable. If any required artifact is missing, say exactly which gate was skipped and do not call the result approved.
  • Transparent background by default (抠背景). An icon / logo / UI asset ships on a transparent canvas — before delivery, inspect the root/top level and REMOVE any canvas-sized background rectangle or full-bleed color plate (<rect width="100%" height="100%">, a 0 0 W H rect, or a rectilinear <path> covering the viewBox). A scene / poster whose background IS the design is the exception: declare it in the spec or reply with the literal token BG: intended and say why. (The Stop gate soft-nudges a newly-drawn SVG that has a full-bleed opaque backdrop and no BG: intended; edits to an existing SVG are exempt — you didn't draw the plate.)

Resolve bundled tool paths relative to the directory containing this SKILL.md; never hard-code an absolute skills path (e.g. ~/.claude/skills/...), because a downloaded copy of this skill may live elsewhere. A typical portable pattern is:

skill_dir="/path/to/svg-selfcheck"  # directory containing this SKILL.md
python "$skill_dir/shapeqa.py" file.svg --out /tmp/svgqa --crop head:80,40,220,220
python "$skill_dir/showhandles.py" file.svg /tmp/handles.png 1200
bash "$skill_dir/fidcheck.sh" file.svg reference.png /tmp/svgqa

Use shapeqa.py as the default evidence rig when possible: it renders the full SVG, runs showhandles.py, and writes named crops in one command. It does not replace visual judgment; it prevents the agent from skipping the evidence step.

After every completed drawing or SVG edit, run QA once. At minimum, run shapeqa.py (or manually produce the same full render + handle overlay + crops) before showing the result. If the artifact is meant as a finished deliverable, feed those evidence paths into the director loop before final response. Do not wait for the user to ask for QA after seeing the image.

QA has three required outcomes: PASS (valid crops + no actionable defects), FIXED (defect found, edited, and QA re-run clean), or BLOCKED/REPORTED (only for unfixable issues or explicit rough-draft/no-QA requests). There is no "noticed a problem but shipped anyway" outcome.

EDIT-LINK delivery gate (fail-closed — the single most-DROPPED step) ⚠️

Every reply that delivers a finished SVG MUST END with the visual-editor edit-link. No exceptions. This is not a nicety or an optional flourish — it is a hard delivery GATE, exactly like the QA gate above, and it fails CLOSED. In practice this is the #1 most-frequently-forgotten delivery step: the SVG gets built, QA'd, director-approved… and then the reply ends WITHOUT the link. Treat a finished-SVG reply that has no edit-link as an incomplete delivery, the same as shipping without QA.

The gate (run as the LITERAL LAST action before you send a finished-SVG reply):

  1. Run python3 "$skill_dir/edit-link.py" <file.svg> on the machine where the .svg lives (this also auto-starts the local saveserver.py so 存回 writes back to the original path — see the module note below).
  2. Paste ITS PRINTED markdown link into the reply as the final line — the default prints a RELATIVE (svg-editor.html) link, and that is correct: relative FILE links open EMBEDDED in the sidebar preview. ⚠ HARD RULE: never swap it for an http://localhost:<port>/… URL as the chat entry — an http:// link in chat ALWAYS opens the system browser and can never reach the sidebar (that mode is --serve, only for a user who explicitly wants an external browser). If you delivered via the --sidebar + preview_start PANEL flow instead, the panel is ALREADY open — the final line is 「看预览面板」, no link at all.
  3. Only then send. If the reply would end without that link (or the panel pointer), the delivery is NOT done — go back to step 1.

Self-check before every finished-SVG send — ask literally: "Did I create or edit an .svg this turn, and does my reply END with an edit-link?" If the first is yes and the second is no, you have DROPPED the gate. Add the link before sending. (A Stop hook also nags on this, but do NOT rely on the hook — the hook is a backstop, the gate is your responsibility.)

Applies to EVERY finished SVG, not just /svg-draw. Any turn that hands the user a finished/edited .svg — a fresh drawing, a fix, a tweak, an animation — ends with the edit-link.

MULTI-ICON delivery(一次交付 ≥2 枚)⇒ 额外给一张「全套画板」编辑器页。 除了每枚的 per-file 编辑链接,还必须:python3 iconboard.py <set>_board.svg icon1.svg icon2.svg … 拼出全套画板 → edit-link.py <set>_board.svg --per-file → 把画板编辑器链接和 per-file 链接一起交付。分工: 画板页 = 一屏看全套/拖动对比/整体审阅;per-file 页 = 单枚修改并存回原文件(画板存回只写画板 文件本身,不回写成员——这句话必须随链接说给用户)。

ANIMATED-SVG caveat (SMIL / CSS <animate>): the node editor may DROP or GARBLE <animate> / <animateTransform> / SMIL timing on save (存回 round-trips the static geometry, not the animation rig). So for an animated SVG, do NOT silently point the user at a node-editor link that would eat their animation. Instead STILL provide a pointer, but point it at the right thing and name the caveat:

  • Point to the generator (the build_*.py / script that emits the animated SVG) and/or a static editable version for geometry tweaks, and tell the user plainly: "the node editor may strip <animate> on save — edit the animation in the generator, use the editor only for static geometry."
  • Never leave an animated SVG with no pointer at all. A pointer with a caveat beats a dropped gate.

Skip this gate ONLY when the SVG is an explicit intermediate / throwaway / rough-draft (say so), or the user explicitly declined the editor. Otherwise: finished SVG reply ⇒ ends with the edit-link. Period.

After every edit — the step that actually gets skipped

The skill fails in practice not because the rules are wrong but because they don't get run. So make it a hard habit: after EVERY change, before anything else, render and zoom the EXACT region you just touched (plus the seams it borders). One edit → one zoom. Never stack two edits without a zoom between them on a region that matters, and never say "looks good / done" without a fresh zoom of what changed:

  • changed a patch/marking size → zoom the patch↔body edge;
  • moved a whisker/eye → zoom that root;
  • reshaped the tail/fin → zoom that join. Most misses here happened because a change was made and only the whole image was re-glanced — the changed seam was never zoomed.

Alignment checklist (run every pass)

  • Inside the outline & no edge slivers: every fill / marking stays INSIDE its parent silhouette — AND never lands just barely inside the outline, which leaves thin white cracks along the edge. A marking must be either clearly inside (clean margin) or clipped FLUSH to the outline — never in-between.
  • Seams — attached, not floating: fins / limbs / tail / connectors / whiskers attach AT, or anchored slightly INTO, the parent edge — no gap, no float ahead, no detachment. (Anchor a barbel a few px inside the body, never ahead of the snout.)
  • No "barely touching": any two shapes/markings/lines are either clearly separated (a clean, even gap) or clearly overlapping/merged — never a tiny kissing tangent or a pinched hairline between them (reads as a seam/crack). This also kills decorative lines (scale hints, etc.) that run from the white ground into a colored fill — that "connects a little" and looks like a seam; drop them or keep them fully inside one region.
  • No unintended corners on organic forms: an animal / plant / mascot outline should read as smooth convex curves, not faceted — a visible sharp angle on a head, snout, body, or petal is almost always a bug. The usual cause is piecewise-LINEAR interpolation of a width/radius profile (the slope jumps at every control point → a kink in the outline, mirrored on both sides). Fix at the source: interpolate the profile with a C1-smooth scheme (Catmull-Rom / cardinal Hermite), and place control points so the curve stays convex at tips (slope should decelerate into a nose/snout, giving a rounded bulge, not a cone).
  • Pose-aware parts: are orientation-dependent bits (whiskers, eyes, highlights, arrow labels) derived from the shape's tangent/normal — NOT fixed screen offsets? (these break the moment the pose changes)
  • Symmetry: are mirrored elements actually symmetric (or intentionally not)?
  • Overlaps & z-order: only intended overlaps; nothing stray poking through; correct stacking.
  • ViewBox: nothing clipped off-frame unintentionally; content within bounds.
  • SQUINT / fresh-eye recognition (ALWAYS — EVERY object, illustration OR icon; NOT delivery-only). Render it SMALL (~32–48px) or blurred and name what it reads as with the goal HIDDEN from your mind. The semantic prior ("I know this is a salmon nigiri") rubber-stamps a detailed full render even when it's wrong — the squint strips the prior. If it reads as the nearest WRONG object (sushi→bread roll, broccoli→tree/cloud, onion→weird oval, the koi→ghost), it is REVISE no matter how clean every component/seam/bezier is. Component checks (slab thickness, marbling, fold, no-sliver, bezierlint) passing is NOT recognition — this is the gestalt gate they can't replace, and the #1 way an APPROVE goes wrong. (Distinct from the icon-SET 16px-survival below, which is about detail mushing at a target size; this recognition gate applies to one-off illustrations too. Learned: a Fluent salmon-nigiri passed all component checks but squinted as a bread roll because the rice was hidden and the salmon too loaf-like.)
  • Animating? verify the MOTION, and check what each group CONTAINS. A static render proves nothing about an animation — bake representative transforms at a few time points (or watch it in a foreground browser tab; background tabs throttle rAF so it looks frozen) and read those frames. And before animating a group, confirm what's inside it: animate the subject, not the whole scene. Translating/rotating a group that also holds the background or backdrop (water ripples, sky, frame) drags the scenery along with the subject — the fish and its "water" move as one block instead of the fish swimming through still water. Put the backdrop OUTSIDE the animated group.

DELIVERY group — run these ONLY when Step 0 routed this as a UI / SET icon at target sizes (skip for a one-off illustration; this is the "icon-system" half of the rules that the geometry checks above don't cover — the half that gets silently skipped unless Step 0 turns it on):

  • Optical centering (measure, don't eyeball): a heavy-top or asymmetric subject looks like it floats — its visual CENTROID, not its bbox, should sit at the frame centre. Measure (sample the rendered alpha, average the ink coords) and nudge the whole icon so the centroid lands on centre. Don't hand-compute this: run python3 <skill-dir>/centerfix.py <file.svg> (add --apply to write the translate correction; it targets the centroid ~3.5% ABOVE math centre per geometry.md, and is idempotent — re-running a centred icon is a no-op).
  • 16px survival / simplify-not-shrink: actually render at the smallest target size and READ it. If fine detail (split stems, crevices, thin florets, hairline strokes) mushes, ship a SIMPLIFIED variant for small sizes (solid 2-tone, single stem, fewer/bigger features) — don't scale the detailed art down. Widen apertures that close to mud.
  • Live area + padding: keep uniform padding inside the grid's live area, consistent across the set, so icons don't jump in size cell-to-cell.
  • Set consistency: the palette / stroke-vs-fill / corner style / detail level / perspective match the rest of the family (lock these in Step 0; the #1 cohesion bug is mixing them arbitrarily).

Geometry / shape construction → geometry.md

Decide geometry BEFORE drawing — library-first (check the svg-toolkit skill), parametric → code, organic → spine + primitives + symmetry, realistic → raster→vectorize, clip-by-default. Full detail (anchor/handle placement, smooth curves with no kinks, hachure texture, overlap-don't-abut, stroke-expansion — never buffer a polyline, grid/optical/pixel/metaphor) → geometry.md.

For the local PS1 low-resolution pixel-tile recipe, default to grid 15 / qbits 3 / Bayer dither 0. Keep each subject's own three-color ramp. Treat grid, quantization, or dither changes as deliberate variations, not silent defaults.

异形 / complex / concave / holed silhouette → DON'T hand-author the bezier. A hard organic outline (animal body, double-cutaway guitar, gear, bitten apple, keyhole, letter-with-hole) is the single hardest thing to place control points for by eye — build it from PRIMITIVES + BOOLEAN with the bundled shapeforge.py (the industry-standard "Pathfinder" method), then smooth: cr_path resamples at equal arc-length + Catmull-Rom so the boolean polygon isn't faceted. Import it from this skill's dir:

import sys, pathlib; sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent))  # or the dir holding SKILL.md
from shapeforge import ellipse, circle, rrect, boolean, round_join, cr_path, circle_arc_path
shape = round_join(boolean(ellipse(...), add=[circle(...)], sub=[ellipse(...)]), 2)
d = cr_path(shape)   # holes → render with fill-rule="evenodd"

Reserve hand-authored bezier for SIMPLE shapes / true arcs (rect rx, A, kappa 0.5523). See geometry.md.

Don'ts

  • Don't judge correctness from one whole-image render — zoom into the seams.
  • Don't place anchors mid-curve with arbitrary handle directions — anchors at extrema, handles axis-aligned.
  • Don't add extra anchor points to force a curve — anchors locate, handles curve. Pull/lengthen the handles instead of inserting points. At a smooth point the two handles move in tandem (collinear); only a deliberate corner breaks them.
  • Don't position pose-dependent features with hardcoded screen-space offsets.
  • Don't fix one defect by changing unrelated properties (scope discipline). When correcting a seam/overlap/alignment, change ONLY the geometry that causes it. Do NOT also alter the shape's color, opacity, or the curve/style of an edge as a side effect — those are separate aesthetic choices the user didn't ask for, and silently changing them reads as "you broke my drawing." Minimal diff: the result should be identical to before except where the defect was. (Learned when a tail-seam fix also turned the tail opaque and rounded its straight join — two unrequested changes.)
  • Don't say it's correct without doing the zoom + checklist pass.

Self-QA against a reference — don't outsource it to the user

When reproducing or tracing a reference image, BE YOUR OWN EYE. After every change, automatically: render the SVG → overlay it on the reference at ~50% → make a difference image → read both yourself, plus a diff% number. Iterate until it aligns. The user should see the result only once it matches — don't make them spot the deviation and report "变形太多" back to you round after round; that's your job.

  • Tool (bundled in this skill): resolve this skill's directory, then run bash "$skill_dir/fidcheck.sh" <svg> <ref-image> [out-dir] → prints diff% and writes /tmp/fc_overlay.png (svg 50% over original — shows misalignment / shrink) + /tmp/fc_diff.png (near-blank = aligned, dark blobs = where it deviates). Auto-samples the reference's corner as the comparison background, so it works for any reference, not just dark ones.
  • Measure against the ORIGINAL reference, not an intermediate. A subtle trap: if you compare to a processed stage (e.g. a potrace output that already smoothed/eroded the shape), you'll certify "1% off" while the user sees big deviation from the original. Diff against the source the user is looking at.
  • A whole-image diff% LIES — never trust the number alone. It's diluted by the matching background (a koi on a big dark field reads "2% off" even when clearly wrong), and an AREA metric is blind to LOST INTERNAL DETAIL — flattening striped/translucent fins to a solid color, or dropping shading/gradients, barely changes area yet looks "差得远." ALWAYS also eyeball a same-scale side-by-side (original | yours) and scan for missing texture, shading, and fine lines — not just outline alignment. If a diff% must be quoted, restrict it to the subject's region, not the whole canvas.

A live auto-refreshing localhost preview page is a bonus for the human, never a substitute for your own overlay-diff pass.

Designer-agent direction loop (critic ↔ executor)

For a non-trivial NEW-DRAWN SVG deliverable, run a director subagent (art-director, which can Read/Bash/Edit/Write) after your own render → zoom self-check and before final delivery. The loop is mandatory only when you new-draw / add new geometry / (batch-)redraw a whole image and deliver it as finished, or the user names a review (/svg-review): render → rig → director directs (or operates the handles itself) → execute → re-rig → repeat until APPROVE. Editing an existing SVG (coord shifts, param tweaks, data fixes, structured node-ops) does NOT trigger the director — your own render → zoom self-check closes it, and the user can still call /svg-review anytime. Do not claim "done" while the director verdict is REVISE; either fix the blocking issues and re-run QA, or explicitly report the remaining REVISE items. Only skip director QA when the user explicitly asks for a rough draft / quick sketch / no QA, and say that QA was skipped. Hard-won lessons on making the direction actually effective:

派遣经济学(先决定「这轮该不该派」,再决定怎么派)——2026-07-06 用 4 枚交付级图标实测校准: 5 轮全冷启动 ≈197k,按本节应为 2 轮 ≈80k,保住 ~90% 的 catch。

  • 必派:新几何首次交付(gestalt/squint + 品味是导演主场——同证据异判、反语义先验,是画手 结构性做不到的:铆钉疙瘩是画手放大看过判"干净"、导演同图读出问题的实例);用户点名要评审; 自己的 squint 结论存疑。
  • 攒批(仅限新绘过程中、终审前的增量迭代):新绘链条里的小改(重上色/参数微调/机制已被断言或 定帧数值证明的动效)不单独派——自跑对应 checklist + squint,回复里写 DIRECTOR-BATCHED(待审: <清单>)(director-reminder hook 认此 token 不再提醒),攒到下一次必派轮或交付前总审一并交卷。 不适用于编辑已有图——见下条。
  • 不派(编辑已有图):对已有 SVG 的坐标平移/参数微调/数据修复/结构化 node-ops——不派导演, 也不落 DIRECTOR-BATCHED 攒批义务;自己的 render→zoom 自检即收口,用户随时可显式 /svg-review
  • 不派:用户明说 草稿/快速/rough(既有豁免);纯机械事实(净空/咬合/loop seam)——断言与定帧 比导演便宜且更准,把它们的结果当"已证事实"写进 brief,别让导演重验。
  • 派的姿势:① 同一交付链续用同一位导演(SendMessage 续 agent,免冷启动重读规则证据,省 30–40%);② 让它判 DIFF 和 gestalt,不判你已数值证明的东西;③ 它给的坐标级处方一律 executor 验算再采(实测两次给错:半径比撞标签环 ink、通气孔环在 1.5 描边下几何不可行——lesson #3 双向成立)。

成本分档(按用户措辞路由):「快速画个/草稿/rough」→ 快速档:断言 + bezierlint + 32px squint 自证,免 spec 文件、免导演(既有豁免的正式命名),单枚 ~5–10k;默认/「交付级」→ 完整流程 + 上述派遣经济学。

Two agents, two lanes — execute vs judge; don't conflate them. art-director JUDGES (verdict + the subjective residue) and, when told, operates the pen on geometry. stylist is a SEPARATE agent that EXECUTES the skin only — recolor per color.md, enforce style.md family×variation, add material-depth / dark-mode tokens — on a GEOMETRY-FROZEN file it may never edit a d= (it proves it with a geometry-attr diff). Hand the skin to stylist when a colored/illustrative piece needs real color/style work (multi-color, brand palette, dark-mode, material depth); a mono icon whose style is locked in the spec doesn't need it. It emits the palette+style [self] fields of the TASTE: line (step 4b); composition stays with the geometry holder (it's geometry, not skin), and the "is-it-beautiful" residue stays with the director. It earns its keep most AFTER item ③ (svgaudit) gives the [auto] fields real teeth.

Director QA must use a delivery bar, not an exploration bar. Do not prompt the director with "acceptable as exploratory variants" when you plan to present files as finished; that rubber-stamps weak shapes. The director must judge against the named intent and output format ("ship this icon / illustration"), and APPROVE only when the piece is genuinely deliverable. If the result is just a rough option board, label it as rough options and do not call it QA-approved.

Dispatch it at FULL CAPACITY — use director-kit.sh, don't hand-spawn it with one PNG. The director is only as good as the eyes you give it; spawning art-director with a single shrunk render uses a fraction of what it can do (handle operation, reference overlay, the three animation gates, frame audit all stay dormant). So before spawning, build the full evidence kit in one command:

skill_dir="/path/to/svg-selfcheck"   # dir containing this SKILL.md
bash "$skill_dir/director-kit.sh" file.svg \
  --goal "<finished intent + must-keep features>" \
  [--ref reference.png] \
  [--crop join:x,y,w,h] [--crop face:x,y,w,h] \
  [--frames f0.svg f1.svg ...]      # animation: bake frames by the REAL mechanism first

It runs shapeqa.py (render + handle overlay + crops) always, adds fidcheck.sh overlay/diff% when --ref is given, and iconframes.py strip+audit when --frames are given, then prints a DIRECTOR BRIEF with every artifact path filled in, ending in a harness-aware DISPATCH step — follow it: Claude Code = spawn the art-director subagent on Opus with the brief pasted in; a harness with NO subagent mechanism (Codex etc.) = re-run director-kit.sh … --dispatch, which runs the director as an independent codex exec session (evidence pngs attached, verdict falls to <out>/director-verdict.md); no CLI at all = role-play agents/art-director.md yourself, verdict marked [self]. Whatever the lane: require the fixed verdict structure and loop until APPROVE. For fine geometry, tell it to HOLD THE PEN (Edit the exposed control points itself), not dictate coords.

Match the rig to the concern (what director-kit.sh assembles for you): The director must receive evidence artifact paths, not just prose. For Bezier QA, include a handle overlay from showhandles.py or shapeqa.py; for join/seam QA, include zoom crops of the exact regions; for reference QA, include overlay/diff outputs. If the director can identify a concrete path defect and has edit access, it should change the SVG path and re-run the evidence rig instead of only giving verbal advice.

  • exact bezier control points → showhandles.py <svg> — draws anchors (blue) + handles (red hollow + lines) on the faded art, so it can direct/operate specific handles.
  • shape vs a reference → viscompare.py <svg> <ref> <feat:x,y,w,h> … — same-zoom REF-over-MINE crops per feature + center-pixel samples.
  • fidelity vs the original → fidcheck.sh <svg> <ref> — overlay + diff% (measure vs the ORIGINAL, not an intermediate).
  • presence / color / position → pixel sampling (viscompare prints center colors; a number catches "this is background, not an eye" deterministically).
  • motion / animation → BAKE frames. A static render proves nothing about animation: apply the animated transforms at a few time points, render a filmstrip, read it. (And animate the subject, not the backdrop.)

What makes direction effective (each learned from a failure):

  1. Objective = perceptual match + named must-have features. NEVER optimize a single scalar. Goodhart: a director told to chase IoU closed an open honking beak because filling it raised the number. Make "the result looks like the target" the goal; name required features ("mouth stays open"); demote any metric to a sanity check.
  2. Describe the DIFFERENCE (this tile vs that tile), not "what it should be." The model's semantic prior overrides pixels — a director mis-read an open beak as a "wedge" twice, even with same-zoom crops, because it "knows" what a beak is.
  3. Executor verifies shape claims against GROUND TRUTH. The director can be confidently wrong; don't blindly obey (and don't blindly override — re-check the reference yourself).
  4. For fine geometry, let the director OPERATE THE HANDLES via STRUCTURED OPS, not dictate coordinates in prose AND not hand-edit raw d (both are lossy/slow/error-prone). Build the kit with director-kit.sh --nodes <pathIndex>: it renders a NUMBERED anchor/handle overlay (nodes.png) as the director's eyes, and the brief hands it the nodeops.mjs engine (the Node-verified node ops the visual editor uses) so it edits by anchor number — op … smooth <a>, move-anchor <a> <dx> <dy>, move-handle <a> in|out <x> <y> [symmetric|aligned|independent], retract <a> — instead of coordinate surgery. Then re-run the kit to re-审. (Plain showhandles.py overlay + raw Edit is the fallback when node ops don't apply, e.g. non-path shapes.)
  5. Direct TOP-DOWN: gestalt/silhouette → proportion → detail. Don't nitpick details on a wrong gestalt.
  6. Pick the right generation method; don't hand-author what a tool does. Clean flat art → potrace per-color + LSQ anchor-simplify (sample → RDP → least-squares bezier handles; reduces anchors with ~0 curve change). Photographic detail → vtracer multi-color. Organic character from scratch → expensive; set expectations.
  7. Know when to STOP. Fine organic curves have steep diminishing returns (one beak cost ~160k tokens of director iteration). Approve "ship-quality," not "pixel-identical."

Animation / motion → icon-motion-principles.md

Purpose-first, durations scaled by size, easing by direction, keyframe-first (every pausable frame is a valid icon), reduced-motion, and the iconframes.py rig. Verify motion by BAKED frames, never a still → icon-motion-principles.md. For the quick PASS/FAIL gate a reviewer/director actually runs on an animated delivery (the tickable A–F checklist), use motion-checklist.md.

Color & shading → color.md

Palette choice/QA, mono vs multi vs duotone allocation, limited-palette cohesion, and make-it-modern material depth (vertical gradient + inner-shadow + sheen) + dark-mode → color.md.

Style presets & control → style.md

Style = family × variation; define / switch / precisely control a set's look (variable axes, style-spec) — incl. the stroke-expansion / never-buffer-a-polyline rule — → style.md.

Composition & restraint → composition.md

The layout / hierarchy / negative-space / "should this shape exist" axis (geometry-correct ≠ well-composed; color.md governs hue, this governs arrangement). Subtract-before-add, chrome/container budget = 0, one focal via size+placement not just color, negative space as a designed shape, no tangents, optical > mathematical centering, quantized spacing rhythm, effects budget ≈ 0 — plus the squint / delete / silhouette-invert / frame checks that catch a flat or cluttered composition → composition.md. Load for any multi-element icon / scene / diagram / illustration; single mono glyphs only need its optical-centre + no-self-tangent + even-padding subset.

Rules-used ledger (delivery block)

Every finished SVG delivery emits a RULES-USED block — the standing "which rules actually fired" trace, next to CTYPE·ROUTE / SCORE / TASTE. It makes the skill's work auditable: on THIS specific draw you see which rules drove the art and which were skipped.

Format — one line per rule that DROVE A CONCRETE DECISION this draw:

RULES-USED (<name>, <canvas>):
· <rule> (<source file>) — <the exact coord / hex / shape / choice it forced>
· 考虑但未用: <rule> — <why it was N/A this time>

Honesty guard (or it degrades to checkbox theater — same trap as the [auto]/[self] labels):

  • List ONLY a rule that changed a concrete artifact — a coordinate, a colour, a structure, a gate outcome — and NAME that artifact on the line. A rule you merely "know" but didn't apply does NOT go in.
  • Mark 考虑但未用 for a rule you'd expect to fire but deliberately didn't (e.g. optical-centre skipped on a vertically-symmetric shape); don't fake a ✓ for it.
  • Don't pad to look thorough — 4–10 load-bearing lines is normal for one icon.

Enforcement: soft. hooks/svg-qa-gate.py nudges (systemMessage, never blocks) if a real .svg was drawn/edited this turn but the reply shipped no RULES-USED block. RULES-ACK opts out (trivial recolor / micro-edit).

The core above (failure mode · the loop · after-every-edit · alignment checklist · intent→spec · don'ts · self-QA · designer-agent loop) ALWAYS applies. Deep how-to lives in:

  • intent-icons.md — icon(单枚/套)+ 动效的 Step-0 展开问句集:静态八问(词义拆解、误读 kill-feature、显示语境折算、set 语法、重画任务的杀什么/保什么、交付元数据)+ 动效先问触发/结束语义再进 A–F
  • intent-lexicon.md — 品味译表:用户软词(手绘感/高级/灵动/Q弹/一直在动…)→ 专业术语 → 可执行参数,含「查表→回显确认→写成可勾断言」三步翻译协议;表里没有的软词按 §5 构造法新译并回填
  • geometry.md — shape construction + icon grid/optics/metaphor
  • color.md — palette, duotone, gradient/material-depth, dark-mode
  • style.md — style presets & precise style control, + style FROM a reference file (parse an HTML/CSS page or a UI/video frame into the STYLE-SPEC knobs so an icon MATCHES it — style_extract.py)
  • composition.md — layout / hierarchy / negative-space / restraint ("should this shape exist"); the arrangement-taste axis color.md doesn't cover — subtract-before-add, chrome budget=0, focal via size+placement, no tangents, optical centering, spacing rhythm, + squint/delete/silhouette checks. Load for multi-element work
  • taste-preflight.md — the STANDING delivery-side pass (step 4b) that forces all three taste files (color/composition/style) to be consulted every time and emits a machine-readable TASTE: line — the delivery mirror of the pre-draw CTYPE·ROUTE gate, so taste stops slipping to the last director round. Runs on every colored/multi-element delivery; does NOT consume a spec-contract slot
  • icon-motion-principles.md — animation / motion
  • motion-checklist.md — the distilled A–F PASS/FAIL checklist a reviewer/director actually RUNS on any animated SVG (the runnable companion to icon-motion-principles.md, which is the cited research report — numbers live there, the tickable gate lives here)
  • creatures.md — load when the subject is an animal / mascot / face / hand (动物 / 吉祥物 / 头像 / 手); the ③ PURE ORGANIC highest-drift subject class where silhouette + proportion + bilateral symmetry is 90% of the job — spine+primitives-or-trace build, per-subject apply/skip and failure modes
  • food-icons.md — load after the core workflow whenever the subject is food; contains only food-specific view/features/color/texture/style rules, not duplicated QA principles
  • instruments.md — load when the subject is a musical instrument; the cross-axis case (organic body via shapeforge boolean + mechanical repeats via parametric code), material programs, per-instrument cheat sheet, and the guitar-build failure modes
  • plants.md — load when the subject is a potted plant / flowerpot (盆栽 / 多肉 / 花盆); the locked flat-flowerpot recipe (light-rim + dark-body tapered trapezoid + flat soil ellipse, two-tone terracotta, no gradient) the user set as the default
  • box-kit.md + boxkit.py — reliably draw "方的" box icons (rounded rect / framed / 3D iso box) with a variation policy so they're not cookie-cutter
  • diagrams-charts.md — load when the subject is a diagram / flowchart / chart / graph (流程图 / 图表 / 饼图 / 架构图); the ④ GEOMETRIC + connectors case (axes/ticks/gridlines, chart-type→primitive mapping, flowchart node shapes, and connectors that ATTACH flush to node edges) — additive on the general geometric branches, which all apply here
  • spec-template.md — the Step 0 spec you copy to <name>.spec.md next to the target .svg: the graded contract (≤6 checkable assertions) + clean-restart file + art-director rubric (契约 III + 落盘 IV + 重启锚 V + rubric VI in one). Copy it, don't keep the spec only in context.
  • style-spec-template.md — 族级契约模板(≥2 枚的 SET):FAMILY/VARIATION/硬规格/MOTION/LOG 命名段,复制到图标族目录命名 STYLE-SPEC.md;单枚契约仍走 spec-template.md,两层别混
  • module-template.md — the standard header (§1 ROUTE bucket · §2 APPLY/SKIP table · §3 palette · §4 failure-modes) every NEW domain module must open with; copy it when authoring a new *.md module so it routes and exempts rules the same way food-icons.md/plants.md do
  • render.py — shared SVG→PNG render helper every script imports/shells to; tries rsvg-convertresvgcairosvgqlmanage in order and uses the first available, NEVER ImageMagick for SVG rasterizing (magick is crops/diffs only). from render import render or python3 render.py in.svg out.png [width].
  • easing.py — named + design-system-verified easing constants for motion generators to import instead of eyeballing a cubic-bezier: DECEL (入场) / ACCEL (出场) / STANDARD (屏内移动) / EMPHASIZED_* / LINEAR, each derived once as a tuple and emitted as both CSS cubic-bezier(...) and SMIL keySplines. from easing import DECEL, css, smil or python3 easing.py [css|smil] TOKEN.
  • shapeqa.py — one-command evidence rig for delivery QA: full render, handle overlay, and named crops
  • centerfix.py — optical-centering / 重心 helper: renders the SVG, computes the alpha-weighted INK CENTROID (not bbox), and reports/--applys the translate that lands it on the optical target (frame centre lifted ~3.5% per geometry.md). Idempotent. python3 centerfix.py <file.svg> [--apply] [--above N].
  • svgaudit.py — deterministic rule-checks (the measurable ones; not the eye/model-judgment gates): A STROKE (every stroke-width / linecap / linejoin used → flags non-uniform weight & mixed caps, geometry.md §stroke), B FRAME (ink-bbox padding per side, live-area %, off-frame clipping, ## Alignment checklist → DELIVERY group), C PALETTE (all colours, ΔE-merged, split dark/medium/light, color.md §palette). --all <dir> adds D SET-CONSISTENCY (flags icons whose weight/caps/colour-count/padding deviate from the set mode, ## Alignment checklist → DELIVERY group: set consistency). python3 svgaudit.py <file.svg> or --all <dir> [--no-render] [--de N].
  • style_extract.py / style_sample.py — style FROM a reference, two paths: A 有可解析源 (HTML/CSS/design-tokens/tailwind/组件源)→ style_extract.py(deterministic, stdlib;prints a STYLE-FROM-REF: line + writes style-spec.json, detects the page's icon library → draw in ITS spec);B 只有截图/视频帧 → style_sample.py(measures palette/theme/stroke, honest nulls for radius/fill-mode/font). 用法/字段/边界:style.md §Style FROM a reference。
  • stylepack_thumb.py — approved 光栅风格入编辑器时的缩略图门:从画板裁正方形 3×2,强制 恰好 6 枚不同语义 icon、隐藏全部 <text>、自动识别六格并压成 6px 间距的紧凑排版后写 WebP;可同时更新 svg-editor.html 对应 slug 的内联 thumb,记录 thumb_layout/thumb_count/thumb_subjects/thumb_text/thumb_compact,拒绝单枚截图、文字和标题留白。 具体入库规则见 icon-imagegen.md §Style-card preview gate。
  • bezierlint.mjs — DEFAULT-CLEAN-BEZIER gate (blacklist). Counts a path's anchors vs the extrema its silhouette needs and FLAGS dense cr_path/traced paths (the render-based self-check is BLIND to anchor structure — a dense blob looks smooth). The svg-qa-gate Stop hook runs it and BLOCKS delivery of any dense path unless you write BEZIER-DENSE-ACK (a genuine complex boolean). node bezierlint.mjs <file.svg>.
  • nodeops.mjs — structured bezier-NODE engine (the editor's Node-verified anchorList/moveAnchor/ dragHandle/smoothAnchor as a CLI). list/map (numbered anchor overlay)/op so the art-director edits geometry by anchor number instead of raw-d surgery. Wired into director-kit.sh --nodes <i>.
  • iconboard.py — assemble N icon SVGs onto ONE labeled grid artboard for side-by-side viewing (each cell inherits its icon's root presentation attrs, so mixed-style sets render faithfully). VIEW tool — editing a member icon still goes through its per-file edit link (saving the board back writes the BOARD file, not the members). python3 iconboard.py out.svg a.svg b.svg … [--cols N] [--tile 64] [--bg HEX] [--row-labels "组1,组2"] [--live]. STANDING delivery rule: any multi-icon (≥2) delivery ships the board's edit-link ALONGSIDE the per-file links — see the MULTI-ICON paragraph in the EDIT-LINK gate section above.
    • LIVE board / icon WORKBENCH + data-svgid write-back-to-origin + six-step whole-project pipeline(抽取→接线→查重→拼板→统一→回灌)→ icon-workbench.md; guided runner /icon-workbench <project-dir>. The two rules that bite if forgotten: rebuild a board with the SAME flags every time (--live --optical-fit --locked-dir …, display-only), and any generator/regen script MUST honor the .handedits.json sidecar (skip a listed file whose sha1 still matches — else editor changes vanish on regen). Tools: link-origins.py · icon_harvest.py · visdup.py · icon_normalize.py · icongallery.py — usage in the module.
    • IMAGE-GEN 概念探索 + 光栅生产道(step 5b)→ icon-imagegen.md: style-spec → prompt pack → 2–4 受控方向 → 用户选向。每枚 icon 判 MEDIUM: vector|raster — vector 走概念稿(选中图仅作视觉 参考,/svg-draw 确定性重建);raster 走生产道(raw 生成物不可直接应用,固定经过 rasterprep.py 去底/alpha finalization → rastercheck.py --strict → manifest-bound rasterwrap.py,saveserver 在写前再次 fail-closed 校验)后进六步流水线 step 6 回灌确认门 + origins 台账。默认语义源=text-only:先把用户文字+id/name/label 拆成带精确计数的完整 SEMANTIC-INVENTORY(复合名不得漏项,如 cloud-moon=云1+新月1),再重画;禁止读取或传入被替换 旧 icon 的像素/路径;风格参考必须标 style-only,只有用户当轮明确要求保形/按原图改/参考原图 才可 override。 内含 approved riso-face-coarseStylepack(矢量/光栅分道)、五段式 base-prompt recipe(数值优先)、批量一致性两法。
    • PULL ROUTING(轻 vs 重,先判再动手): 用户说「抽 icon / 拉图标 / 把项目图标弄进来 / 看看这项目有哪些图标」 → 默认走轻:/icon-pull <project-dir>(零决策门,一条 icon_harvest.py … --out ROOT/.icon-workbench/icons 直接进图库 + origins.json 轻回灌台账)。只有出现「统一 / 规范 / 去重 / 合并 / 整理全项目 / 批量回写」 这类意图才走重:/icon-workbench(六步三门 + data-svgid 锚定回写)。轻拉取后用户再要统一规范 → 升级到重,已拉取的 .icon-workbench/icons 直接复用不重抽。两种回灌的区别(别混): 轻 = 单枚编辑 ⌘S 存回 → saveserver 按 origins.json 自动回灌原文件,但仅安全通道 (v1 白名单:standalone 整文件替换 + inline 且源是 .html/.htm 块替换;源已变 / 定位不唯一 → 拒并提示, 不乱写;其余通道 writable:false 带 reason);重 = 全项目规范化后经锚定回写所有原文件(JSX/RN/sprite/ 动态属性全通道)。
    • iOS 项目回写后要看效果 → ios-refresh.py:改图标回灌到源 .svg / imageset 后,模拟器仍跑旧编译产物; python3 <skill-dir>/ios-refresh.py <项目或改动文件> 自动定位工程(.xcworkspace 优先)/ scheme / bundle / 模拟器,重编 + 重装 + 重启看效果(--dry-run 只打印计划;--screenshot 截图)。门控:macOS + Xcode 才跑, 非 Mac 优雅退出(exit 3、不崩);首次需模拟器 runtime(只提示不擅自下 8GB);只读项目源、绝不改源。 机制见 delivery-editing.md / icon-workbench.md
    • 不可编辑图标 → 只读锁定瓦(默认策略,别漏):项目自带但不可编辑的图标——SF Symbols(苹果系统 符号)、PNG 位图(无矢量源)、未装工具的 iconfont(缺 fontTools)——icon_harvest --out 默认作 只读锁定瓦纳入图库与画板(落 <out>/locked/ + locked.json,SF/iconfont 引用芯片、PNG 内嵌真实 像素),不参与选中 / 存回 / 回灌(origins.json 一律 writable:false,manifest 单列 locked 桶 不计 count)。要真正可编辑,须在源项目替换为矢量资产。--no-locked 关生成;拼板带 --locked-dir <out>/locked 一并上板(有 locked.json 自动按 category 多分区)。
  • svg-editor.html + edit-link.py — single-file visual editor (drag shapes, select a path
    • Enter for node mode, recolor, ⌘/Ctrl+S 存回). After finishing an SVG deliverable run python3 <skill-dir>/edit-link.py <file.svg> and paste ITS printed RELATIVE link as the LAST step (= the EDIT-LINK gate above; for ANIMATED SVGs point at the generator / a static editable version
    • name the " may be stripped on save" caveat). ⚠ After editing the svg-editor.html TEMPLATE, run edit-link.py --refresh-all — stale generated pages look like a cache bug, aren't. Delivery-mode mechanics(DEFAULT 侧边栏路径 / --serve / --sidebar+panel、port+root injection 与 /__root__ 验根、zombie-sync 清理、saveserver guarantees、零依赖降级阶梯)→ delivery-editing.md.

相關技能