← Back to skills
extension
Category: Development & EngineeringAPI key requirement unconfirmed

Agent-ready-Material-Generation

帮助设计师生成Agent-ready 的设计材料。把品牌、风格和组件范围等关键设计决策,转化为可复用的Figma 设计系统和可供 Agent 执行的 Markdown 设计契约。

personAuthor: WenjiaWanghubModelScope

Agent-ready Material Generation Skill

Derive the design-system definition; delegate Figma mutation to the official execution skills. Optimize for 10% high-leverage user decisions and 90% traceable system derivation.

Stage -1 — Required host and Figma MCP gate

Before user input collection, derivation, inspection, or generation, follow agent-environment.md. This prerequisite applies to every user-facing mode, including Markdown-only output. Reuse a verified official Figma connection; if missing, install it through the active host, complete OAuth/reload, and verify use_figma plus the other required tools. Stop and explain missing capabilities or an unsupported host. A configured server or successful whoami alone is not READY.

Use the actual host's skill loader and namespaced skill names. Resolve all bundled script/reference paths from this skill's directory, not the user's working directory. If companion skills are not separately discovered, load their SKILL.md under this bundle's skills/ directory. Install missing official Figma execution skills through the host's supported route before any Figma execution.

Non-negotiable boundary

Treat this skill as the decision, grammar, derivation, and validation layer.

  • Do not reimplement Figma Plugin API mechanics, node-ID handling, state ledgers, idempotency, cleanup, metadata inspection, screenshots, or error recovery.

  • Load and obey $figma-generate-library before planning or building the library in Figma.

  • Load and obey $figma-use before every use_figma call. Never call use_figma without it.

  • Load $figma-create-new-file before creating a Figma file when no target file exists.

  • Load $design-system-contract-gen only when the user requests the L0–L7 Markdown contract, either beside a generated Figma library or from an existing read-only Figma source. In a Figma-only run, preserve every existing Figma workflow artifact and gate, but do not add Contract IR, the L0–L7 package, or a Markdown acceptance gate.

  • Resolve conflicting instructions in this order: agent-ready-material-generation-skill specific domain contract → generic $figma-generate-library workflow → $figma-use API mechanics. Apply the higher-priority rule only to the conflicting concern, and continue to obey every non-conflicting lower-priority API, safety, schema, and runtime requirement.

  • Treat existing figma-design-system-gen.* schema, writer, package, validator, and contract identifiers as a stable legacy artifact namespace, not as the public skill name. Preserve them for compatibility unless an explicit artifact-format migration is requested.

  • Apply the top-level Agent-ready text contract to every public component: expose text as a Figma Text Property when an instance consumer must supply or override it as content. Prioritize Button.label; Input.value, placeholder, label, helperText; Dialog.title, description, confirmLabel, cancelLabel; Card.title, description; and EmptyState.title, message, actionLabel. Do not manufacture a property for content the component does not own, and keep decorative text, fixed brand copy, and non-overridable system labels internal. This content-parameter decision overrides a designated structure's omission, but never mutates the raw source IR.

  • Apply the direct Semantic Color contract: bg/* pairs with text/*; border/*, ring/*, and decorative/* are the other public prefixes. Treat Status as a documentation grouping over bg/{destructive|success|warning} and text/{destructive|success|warning}-foreground, not a status/* namespace. Fold shared primary interaction states into bg/primary-hover and bg/primary-pressed. Default bg/accent to the neutral scale—neutral/100 in Light and neutral/800 in Dark—and permit brand/100 plus brand/900 only when visual.accent_source=brand is explicitly supplied. Generate border/default, border/strong, and border/destructive, with border/strong as the reusable one-step-higher-contrast boundary formerly named border/input. Generate the paired ring/focus, ring/strong, and ring/destructive; each Ring aliases the next stronger Primitive step than its corresponding Border in the effective mode: Light moves +100, Dark moves -100. Therefore the defaults are ring/focus=neutral/300|700, ring/strong=neutral/400|600, and ring/destructive=destructive/600|400. Do not generate data/*; charts and categorical visualization use decorative/* directly. Every Semantic Variable owns Light/Dark Primitive aliases directly. Do not introduce color/*, utility_aliases, chart-*, tag/*, fill/chart-*, stroke/chart-*, component categories, or parallel surface tiers such as base, subtle, or raised; strong is reserved exclusively for the paired reusable boundary roles border/strong and ring/strong. Every projected Primitive and Semantic Color Variable must have a Variable.description stating What it controls and Used by. text/secondary-foreground is mandatory for every meaningful description, explanation, supporting line, caption, note, timestamp, author, and metadata item; in Light bind it to neutral/500 with the canonical recorded contrast waiver. text/muted-foreground is restricted exclusively to placeholder and disabled content. It is forbidden for every meaningful descriptive, explanatory, supporting, caption, note, or metadata text and its Variable description must explicitly direct designers to text/secondary-foreground; in Light bind it to neutral/200 with the canonical contrast waiver, and in Dark choose the lowest-emphasis neutral step meeting the requested text-contrast target on both bg/background and bg/muted. Shadcn compatibility names remain code mapping metadata only.

  • Generate text/brand as the direct brand-emphasis text role. Use it only for links, inline navigation/actions, and short highlighted brand text. For each mode, choose the nearest brand step to brand/500 that meets the configured normal-text contrast target on both bg/background and bg/secondary. Do not use it for body copy, descriptions or metadata, status content, placeholders, disabled content, or content on bg/primary; Link Button label, icons, and spinner use BRAND_CONTENT → text/brand.

  • Keep neutral hue coherence deliberately restrained. Cap derived neutral OKLCH chroma by personality at minimal=.0045, modern=.012, expressive=.018, editorial=.006, and technical=.005; validation permits only .002 conversion tolerance above the applicable cap.

  • Before building or repairing every component, load the live Color collection and read every candidate Variable's ID, exact name, description, collection, resolved type, scopes, code syntax, mode values, and Primitive alias targets. The caller supplies only structured consumer facts and a local appearance intent; it must not preselect an exact Variable name. Apply the global surface/foreground pair, status-family/channel, and content-purpose constraints first, then filter the live metadata catalog by name, usage description, scope, resolved type, and complete aliases; exactly one candidate must survive. Metadata is therefore the selection input and decisive filter, not a post-selection check. bg/primary pairs with text/primary-foreground, bg/secondary with text/secondary-foreground, bg/accent with text/accent-foreground, and each status surface with its same-family foreground. Structured Error states route their status-bearing boundary/content channels to the destructive family: for example Input Error uses border/destructive; a Destructive Button uses bg/destructive plus text/destructive-foreground. Placeholder content uses text/muted-foreground. Name-only lookup, component/Variant substring inference, caller-supplied standard roles, direct Primitive binding, missing/generic descriptions, stale catalogs after a foundation change, global constraint mismatches, and zero or multiple candidates are blocking errors. Before calling setBoundVariableForPaint, resolve the selected Semantic Variable for the actual consumer and effective mode, and seed the paint's raw RGB/opacity with that resolved value; a generic gray/black placeholder behind a valid binding is a blocking visual mismatch because Figma exports and screenshots can expose the fallback. Record consumer facts, candidate counts, decisive metadata fields, selected Variable metadata, resolved fallback color, and rationale for every binding.

  • Treat component-inventory.json as the only authoritative Core/Normal/Pro component catalog. Interpret its core, normal, and pro groups cumulatively, preserve their order and bilingual labels, and never add components automatically from product_type. Add any business-specific or retired component only through an explicit scope.include, then apply scope.exclude last.

  • Treat a user-designated component's source node kind, root Auto Layout, and resizing as structure, not visual styling. Preserve whether the source is a COMPONENT_SET or a standalone COMPONENT, its explicit unavailable Variant combinations, and each actual configuration's direction, wrap, HUG/FILL/FIXED axes, alignment/distribution, padding, gap, stroke-in-layout behavior, and intentional fixed dimensions. A designated Button root must remain horizontal HUG × HUG; fixed-width Button main Components are a blocking error. An instance may use FILL when composed in a compatible parent, but that does not change the main Component's default HUG contract.

  • Execute every Figma mutation sequentially, including writes to different Pages. Never use parallel multi-Page fan-out for calls that create, update, delete, import, bind, move, rename, or otherwise mutate Figma nodes, Variables, Styles, Components, libraries, or workflow state. Split multi-Page writes into one use_figma call per target Page, set the current Page at most once in that call, wait for its result, validate it, and only then issue the next write.

  • Parallel multi-Page fan-out is allowed only for read-only discovery or audit calls that cannot mutate Figma, shared state ledgers, or external state and whose results do not depend on one another. If read-only status is uncertain, execute sequentially.

  • Never write guessed node IDs or Figma execution data into the canonical grammar.

  • Treat presentation-style-contract.json as the sole runtime authority for generated presentation styling. When the user supplies a Figma object as a visual standard, inspect it once, normalize its complete role-based structure and visual properties into this bundled local contract, update the matching validation profile, and then generate exclusively from the local contract. Never require the source Figma file, URL, file key, node ID, or live object to remain accessible. Keep presentation styling in this contract and keep foundation derivation, color semantics, component behavior, and inventory logic outside it.

  • Use raw unbound #FFFFFF (Light) / #000000 (Dark) presentation paint on every Page-direct documentation root and Contract Bar, including Component and instructional roots. Never generate bg/documentation or an equivalent documentation-only product Variable, token export, or color swatch. Every Frame named exactly Specimen Stage or ending in / Specimen Stage is fill-less (fills=[]) with no fill Variable binding in both Foundation and Component documentation. Keep the primary Component group HUG × HUG and center its bounding box horizontally and vertically within the stage's inner bounds; annotation chrome is not part of the centering measurement. The raw unbound root background rule and the fill-less Stage rule must both be verified from live Figma read-back. In the Foundation Typography frame, Type Scale / 字体层级 itself is also fill-less (fills=[]) and has no fill Variable binding.

  • Treat component-appearance-contract.json as the sole runtime authority for component appearance. Every active Core, Normal, and Pro component is fully refined in the design-system-v0.6 baseline and must resolve one exact bundled local appearance authority before projection: a normalized profile record or an explicit executable requirement record. Preserve its public properties and defaults, anatomy, child order, layout laws, intrinsic geometry, paint/stroke/effect presence, semantic part roles, state deltas, icon/Slot composition, ComponentSet documentation grammar, and mandatory Examples. Re-derive only Foundation values and semantic token resolutions from the current run's key design decisions. UNREFINED, generic/inferred appearance, Foundation-only fallback, runtime source reads, and old cached plans without the exact current baseline ID and contract SHA-256 are blocking errors. Source file/node IDs remain provenance only.

  • Treat Skeleton as a transparent structural Component whose visible Avatar, Line, and Object placeholder Instances—and their local helper main Components—bind their fill to bg/secondary. Never paint the Skeleton root, never use bg/muted for its visible placeholders, and never substitute a raw or unbound literal fill.

  • Treat Slider Horizontal as a freeform 240 × 16 ComponentSet whose Variant roots are always fillless. Center every .Marker vertically, bind its primary fill and 1px border/default OUTSIDE stroke through local Variables, and keep the local .Marker main Component childless so the Marker instance has no descendants; a nested Vector or any other geometry child is forbidden. Remove every stroke from Value; Active-state surface rules never apply to the Slider root.

  • Treat every Date Picker Variant root as HUG × HUG and stroke-free in every State, including Focus; focus presentation belongs only to the nested Input. Fail when its nested Input exceeds the root bounds. Bind Decoration left directly to the exact bundled local .Icon / Calendar Component with proportional SCALE / SCALE behavior; Generic Icon wrappers, generated calendar geometry, remote icons, and substitutes are forbidden.

  • Preserve the explicit v0.8 detail contract in every future generation: each Tabs Slot contains exactly two Label Tab instances ordered Active then Inactive; every Dialog Footer two-Button group binds an 8px space/2 gap; Dialog Slot left/right padding binds space/4 (16px) to match Header/Footer; Select ends with the exact local .Icon / Chevron Down; every visible Field Label Text layer aligns LEFT and its fill-width Label container aligns content to the leading edge with primary-axis MIN; Slider stays 240×16 with Overall=240×4@(0,6), Default 0–60%, Range Narrow 40–60%, Range Wide 20–80%, and 16px endpoint-centered Markers; Date Picker fixes .Icon / Calendar left and .Icon / Chevron Down right; Empty Description is exactly 280px wide with CENTER text alignment; every Pagination Number Button defaults to the editable text 1; and Pagination documentation contains exactly one first-page-active Example with exactly five numbered pages ordered 1, 2, 3, 4, 5 between Previous and Next, with no ellipsis or additional page. Treat zero gaps, placeholder 100×100 Slider children, wrapper substitutes, centered Field labels, generic Button pagination copy, the old two-row/ten-page Pagination specimen, or derived alternatives as blocking drift.

  • Preserve the explicit shallow status-tint refinement in every future generation: derive only destructive/100 and success/100 with a 0.90 light-endpoint blend instead of the generic 0.80 interpolation so they remain visually closer to their 50 tints. With canonical anchors the exact results are destructive/100=#FFE7E4 and success/100=#D1FBD7. Keep their 50, 200–950, and 500 anchor values unchanged, and never apply this exception to warning, brand, or decorative families.

  • Generate Calendar dates through one local reusable .Calendar / Day ComponentSet: Position = Middle | Left | Right | Single × State = Default | Selected | Active | Disabled, plus one editable day Text Property. Cells are 28×28 and centered; selected/active range edges follow the joined full-radius law, Default/Disabled remain standalone full-radius cells, and all paint/radius decisions bind generated local Foundations. Document this set deterministically with non-Size axes vertical and explanatory copy. Every Calendar header includes real local Small/Outline/Default Button instances using the exact bundled .Icon / Chevron Left and .Icon / Chevron Right Components with proportional scaling. Every Calendar root is vertical HUG × HUG and binds all four paddings to space/4 (16px), resolving the three-month root to 652 × 252 around its intrinsic 620 × 220 visual. Never read the designated external sample at generation time.

  • Obey component-appearance-contract.json#/learning_policy whenever an Obra source is captured or refreshed. Learn only node kind, ordered public properties, Variant axes/defaults/unavailable combinations, semantic anatomy and child order, Auto Layout and resizing, intrinsic fixed dimensions, paint/stroke/effect channel presence, state deltas, text roles, icon roles and anchors, Slots, responsive behavior, and specimen composition. Do not learn Obra brand copy, example text/data, images, canvas coordinates, runtime IDs, raw colors or source Variable IDs, unmapped foundation values, accidental implementation, missing Text Style bindings, broken constraints, deprecated APIs, or unrequested prototypes. Normalize colors to local semantic intent, typography to canonical local Text Styles, and icons to real Instance/Swap nodes with proportional SCALE / SCALE; unresolved or ambiguous evidence is an error. The latest explicit user rule always wins after source capture. The bundled 44-record source_learning_snapshot is the complete run-independent evidence set; do not reread Obra during generation unless the user explicitly asks to refresh the learned source.

  • Obey component-appearance-contract.json#/deterministic_generation for every derivation and Figma projection. Randomness, time-based branching, arbitrary copy variation, unordered emission, generic fallback, and “choose any valid option” are forbidden. Resolve the same normalized inputs through the declared inventory, source, property, Variant axis/value, profile-layer, anatomy, and row-major documentation orders; use contract-defined or content-derived stable identities; and fail on missing or ambiguous contracted values. Before a generated artifact can drive Figma, derive it twice and use scripts/determinism_contract.py to require equal canonical UTF-8 JSON SHA-256 values after excluding only the declared runtime identity fields. A mismatch is blocking, not a retry signal.

  • Apply shared_slot_style from component-appearance-contract.json to every generated real Slot whose default content is empty or placeholder text. Keep the Slot container's raw unbound #C89DFF dashed inside stroke as authoring chrome, but bind the centered Editable slot placeholder Text fill through the contract's PLACEHOLDER_OR_DISABLED_CONTENT Semantic intent; metadata selection must resolve it to the existing text/muted-foreground Color Variable and seed the fallback paint from that Variable's effective mode. Raw or unbound Slot placeholder text color is forbidden. The Slot container uses left/start primary-axis alignment with centered counter-axis alignment and HUG × HUG sizing. The placeholder must use automatic layout positioning, centered text alignment, and fit without clipping; shrink only fallback placeholder typography when necessary and never force the Slot back to a former fixed size. Treat every visible non-placeholder child, including user-supplied Text, as real Slot content: preserve it, never inject the placeholder, and remove the Slot container’s authoring stroke and dash pattern immediately after insertion. Apply this to nested instances and examples as well as main Components; empty main Slots keep their placeholder chrome. Treat the local record as the sole runtime source and fail closed when it is missing; the historical Figma source is not a runtime dependency.

  • For the Agent package, load GENERATION.md and the affected component contracts before deriving or repairing. These local contracts drive the shared writer and live audits. Preserve the accepted v0.8 refinements: Markdown Link and Inline Code use text/brand; Response uses Avatar With Image followed by an editable Label and default-visible Hover actions; Complete expanded Reasoning wraps with HUG height and no truncation; ToolCall Text contains only Summary, collapsed disclosure uses .Icon / Chevron Right, and File includes a substantial code example; SourceCard defaults to the Card width (380px) and fills its nested content tracks; populated Slots have no authoring stroke; DiffViewer shares the Markdown Code Block file shell. ChatMessageFile is file-only with all 23 formats × Loading/Complete/Error; ChatMessageMedia is a separate Queued/Generating/Complete/Error Component Set, normalized from its bundled reference contract and using canonical local tokens/styles. Reconcile Media before File to migrate legacy media consumers, and map legacy file Default to Complete. ChatBox preserves its bundled composer reference with visible editable input text and independent Show upload, Show model, and Show voice Booleans; compose its connected four-state Send Button and five-state Upload Card, remove Folder/Permissions and hidden text proxies, and run the dedicated eight-combination ChatBox audit.

  • Treat packages/agent/components/a2ui.json as the canonical A2UI reference contract. Generate all nine public groups inside one Component / A2UI frame: shell, Header, Footer, Question Item, Question, Text, Capabilities, Card and Table. Preserve the 22 public configurations, native Content/Options Slots, connected local controls and Avatar With Image, HUG heights and FILL content widths. The shell uses Default / Collapsed / Complete; Complete hides Footer. Place exactly three examples below every group: ChatMessageApprovalRequest (Text), ChatMessageTaskPlan (Table), ChatMessageClarification (Question), each a real A2UI instance populated through Content Slot. Retire the former three independent public families and docs; check live consumers before deleting owned legacy sources. Keep the reference file/node IDs as provenance only. Execute the shared agent-a2ui groups, agent-a2ui-docs and agent-a2ui-audit in both repeatability runs.

  • Paint presence is semantic. fills=[] or strokes=[] means absent and must remain absent unless the resolved local appearance profile explicitly declares a paint slot. Variable binding may replace the color of an existing/required slot but may not create a fill, stroke, or focus ring implicitly. Disabled, hover, focus, invalid, and selection states may change only fields declared by their resolved profile. By default, every focus boundary uses a declared stroke channel with ring/focus, or ring/destructive for an error/destructive focus selection; only an explicit local user refinement may define an exact alternative such as Tab Inactive Focus matching Hover. Focus shadows and DROP_SHADOW effects remain forbidden.

  • Treat icon color as terminal vector geometry, never as a wrapper paint. For every icon, spinner, glyph, or decoration target, keep the owning Instance and every non-terminal Icon, Icon Vector, Frame, Group, Component, or Instance wrapper free of fills and strokes; bind the selected Semantic foreground to each actual terminal vector fill/stroke leaf. Fail closed when no terminal paint leaf exists, and make live validation reject any painted icon wrapper so a semantic fill can never become a rectangular icon background.

  • Treat component-appearance-contract.json#/image_assets as the only image source for every generated component. Use bundled assets/images/avatar-primary.png for every avatar/person image, including every Avatar With Image size and every nested Avatar in Avatar Stack; use assets/images/content-primary.jpg only for general content imagery. Verify path existence and exact SHA-256 while compiling the single generation plan. After component structure reconciliation and before component appearance reconciliation, emit the canonical asset-targets stage, resolve target nodes only through documentation-frame/component/contract paths, upload the bundled bytes to every returned node with scaleMode=FILL, and reject external URLs, generated substitutes, additional uploads, stale hashes, persisted target IDs, or one-off target patches.

  • Make every generated Foundation and Component documentation title bilingual. Render the documentation-frame title as {English} · {中文} and every first-level or nested content title as {English} / {中文}. Kicker text, Contract Bar values, token labels, and Variable names are not content titles and keep their canonical forms. Reject monolingual documentation headings in the spec and require live Figma template read-back to verify the projected text.

  • Treat spec-only validation as preflight, never as completion. Every concrete Figma run must persist a run manifest, compile the bundled presentation templates into an execution contract, and finish with a machine-readable live Figma audit from the exact target file. The final validator must bind all four artifacts by run ID, file key, SHA-256 digests, exact projection inventory, and template read-back before completion_eligible may be true.

  • Record every user-designated Figma style source in the run manifest even after its visual rules are normalized locally. Preserve its file key, node ID, URL, role, active/superseded status, and normalized contract pointer for provenance, while setting runtime_dependency: FORBIDDEN so generation never depends on that external object.

Start by routing references

Read only the references needed for the current stage, but read each selected file completely.

Resolve all bundled paths relative to this SKILL.md. Invoke bundled scripts by their resolved absolute paths; do not assume the current working directory is the skill folder.

| Stage | Required reference | |---|---| | Collect or normalize inputs | design-decisions.md | | Resolve Core, Normal, or Pro component scope | component-inventory.json | | Apply read-only discovery evidence | discovery-evidence.schema.json | | Derive foundations | foundation-derivation.md | | Define the canonical IR | system-spec.md | | Extract or derive components, states, composition, or appearance | component-grammar.md, shadcn-component-ir.schema.json, figma-component-structure-ir.schema.json, and component-appearance-contract.schema.json when user-designated Figma references exist | | Define or audit Agent-ready behavior | agent-ready-rules.md | | Lay out Figma documentation | presentation-grammar.md | | Capture or update user-supplied presentation styling | presentation-style-contract.json | | Validate, repair, or hand off | validation-and-repair.md |

Execution modes

Select one mode before Phase 0:

  • FIGMA_ONLY — the user requests only a Figma design system. Run the existing Phase 0–8 workflow and existing 12 deliverables unchanged. Do not create Contract IR or the L0–L7 Markdown package.
  • MARKDOWN_WITH_FIGMA_EVIDENCE — the user supplies an existing Figma library and wants only Markdown. Keep Figma strictly read-only, clarify missing key decisions, derive and freeze system-spec.json, reconcile its Tokens and components against live Figma evidence, then invoke $design-system-contract-gen to render and validate the contract. Read figma-evidenced-markdown.md completely before starting this mode.
  • COMBINED — the user requests both Figma and the Agent-readable Markdown contract. Run Phase 0–3 once, freeze the validated system-spec.json and exact SHA-256, project Figma through the existing Phase 4–8 workflow, project Markdown through $design-system-contract-gen using its from-spec branch with contract.generation_mode=COMBINED, then run Phase 9 combined acceptance.

If the user requests only Markdown without a Figma source, route to $design-system-contract-gen in MARKDOWN_STANDALONE or MARKDOWN_FROM_SPEC mode. If the user supplies a Figma library as evidence for that Markdown, this skill owns the read-only orchestration and the Markdown skill owns only the frozen-spec projection.

Mode selection must not alter design derivation. FIGMA_ONLY and COMBINED use the same Phase 0–3 inputs, defaults, schemas, generator, validation, and canonical spec bytes. Combined mode adds a sibling projection and a final cross-artifact gate; it does not make Figma depend on Markdown.

Read-only Figma evidence branch

In MARKDOWN_WITH_FIGMA_EVIDENCE, execute only the read-only parts of Phase 0, the decision collection in Phase 1, and the canonical derivation and spec-only validation in Phases 2–3. Focus Figma discovery on Variables, Styles, aliases, modes, semantic bindings, public Components and Component Sets, Properties, defaults, states, anatomy, Auto Layout, resizing, descriptions, and relationships. Do not inspect unrelated product screens or flows unless needed to resolve an explicitly scoped component or Token.

Before freezing the spec, apply the source and conflict policy in figma-evidenced-markdown.md. After freezing it, compare every scoped Token and component against a second live read-only Figma capture and write figma-spec-reconciliation.json. Do not execute Phases 4–8, do not load a Figma writer, do not create temporary specimens, and do not run Phase 9 combined acceptance. Pass the frozen spec, accepted contract context, and reconciliation artifact to $design-system-contract-gen, then run its validate-figma-evidence gate. A conflict may be documented, but it may never silently rewrite the frozen spec or be marked verified.

Fixed entry pages

Always generate Cover and Getting Started from references/presentation-style-contract.json#/templates/instructional_panel/entry_pages. Cover uses the selected B fixed 1440×900 dark editorial template (dark grid, two-line title with brand-emphasis System, native orbit geometry, footer); only declared content fields and token resolutions vary. Getting Started contains both Human and Agent four-step paths, shared delivery checks, and an Agent task example. Never retain the old generic paragraph or infer new copy/layout each run. After all presentation passes, run canonical entry-pages batches 0 and 1 sequentially, then entry-pages-audit batches 0 and 1; require zero violations and visually verify both frames in both repeatability runs. Preserve root identities when replacing owned content.

Workflow

Complete the phases in order. Keep a canonical spec on disk and update it after each accepted decision. Do not start Figma writes before Phase 3 passes.

Phase 0 — Discover source truth

  1. Inspect the codebase for tokens, components, prop vocabulary, frameworks, icon packages, fonts, and naming conventions.
  2. Inspect the target Figma file read-only through the official skills for pages, variables, styles, collections, modes, aliases, scopes, code syntax, component bindings, libraries, and conventions. Under Rule 4, do not create a new token system before this inventory and gap analysis.
  3. Classify each fact by provenance: user, code, figma, library, derived-default.
  4. Produce a gap analysis: code-only, Figma-only, compatible overlap, and conflicts.
  5. Resolve a conflict automatically only when one source is clearly authoritative. Otherwise present both values with provenance and ask one focused question.

When the bundled shadcn baseline applies, treat shadcn-component-ir.json as the source snapshot. It was extracted from the installed b1VoQUK0 Vite preset and contains behavior only: source identity, anatomy slots, public CVA axes, primitive dependencies, exports, data/ARIA contracts, and source-evidenced states. Never recover or copy its utility classes, resolved colors, spacing, radii, typography, or elevation into the canonical grammar.

When the user designates Figma components as structural standards, capture them in figma-component-structure-ir.json under its strict schema. Read only ComponentSet identity, ordered Component Properties, types, defaults, value sets, child Property bindings, each partial binding's exact applies_when Variant selection, root layout profiles with exact applies_when coverage, semantic anatomy profiles, variant counts, and requested documentation-frame colocation. A root layout profile includes Auto Layout direction/wrap, per-axis HUG/FILL/FIXED behavior, alignment/distribution, padding, gap, stroke inclusion, and dimensions only on FIXED axes. Exclude visual styles, resolved Variables, Descriptions, annotations, plugin metadata, and shared plugin data. This source overrides the default Figma structural projection only; it does not silently replace the shadcn behavior/code contract or the generated system's visual/token/metadata contracts.

When the user designates a Kit as the component visual baseline, capture its executable result separately in component-appearance-contract.json. Save the complete source-node index so the user never has to resend links, but normalize every ready component into local selectors and layered profiles in BASE → SIZE → VARIANT → STATE → COMPOUND order. Conflicting writes to the same target/field in one layer are errors. Correct an obvious source anomaly only through a recorded source_anomaly_corrections entry. A future generation or repair reads the local record, not the source Kit.

During an Obra refresh, inspect every source component in the bundled snapshot scope and record source variant count, ordered property types, ordered Variant axes/values, root-layout signature count, hierarchy signature count, and actual Text Style coverage before applying user refinements. Source coverage is evidence, not permission to copy defects: Obra's known missing Text Style bindings are recorded with unstyled_source_policy=DO_NOT_COPY, while generated output still requires exactly one canonical local Text Style on every Text node. Preserve the source-observed 120 Button variants in the snapshot, then deterministically project the explicit user refinement that removes Invalid to the 96-variant local structure. Reject an incomplete refresh, an unexpected source-drift relation, or a snapshot hash mismatch.

Do not mutate Figma in this phase.

Phase 1 — Collect high-leverage decisions

  1. Normalize the user's input against design-decisions.schema.json.
  2. Reuse decisions already evident in code or Figma; do not ask the user to repeat them.
  3. Ask only for unresolved brand, product, visual-direction, theme, accessibility, completeness, or scope decisions that materially change the result.
  4. Apply documented smart defaults to everything else and record every applied default.
  5. Lock the v1 component scope before derivation. Require scope.completeness as core, normal, or pro; default to normal only when the user does not choose. Resolve it from the user-designated cumulative catalog, then apply explicit includes and excludes. Product type must not mutate the catalog. Completeness never changes foundation variables, but it may project a component's internal axes, values, public Properties, bindings, and anatomy when component-completeness-contract.json explicitly declares that projection.

Prefer inputs such as platform, product type, component-library completeness, primary color, font family, icon source, personality, density, radius character, themes, and accessibility target. Never ask the user to configure individual hover colors, spacing steps, component padding, radii, icon sizes, states, variants, or low-level Figma properties.

Phase 2 — Derive the canonical system spec

Use the deterministic generator when possible. After Phase 0, serialize verified font/icon findings separately and pass them through --discovery; never hand-edit an availability flag:

python3 <skill-dir>/scripts/derive_system.py decisions.yaml --discovery discovery-evidence.json --output system-spec.json

JSON input works with the Python standard library. YAML input requires PyYAML; use JSON when it is unavailable. Then review the result rather than accepting it blindly.

Derive in this order:

  1. Foundation grammar: color, typography, spacing, radius, and iconography; preserve every supplied or canonical chromatic base at its family’s 500 step, bind bg/primary to brand/500, bind Light status backgrounds to their family 100 with same-family 500 foregrounds, and bind Dark status backgrounds to their family 800 with same-family 400 foregrounds. The Light fixed pairs retain explicit contrast waivers; the Dark pairs must meet the configured text-contrast target. Derive the neutral scale with the restrained personality-specific chroma caps above even when an explicit neutral endpoint exists, and bind bg/accent to neutral 100/800 by default rather than borrowing the brand ramp. Use brand 100/900 for Accent only after the explicit visual.accent_source=brand opt-in. Generate the exact 52 direct Semantic Colors under bg, text, border, ring, and decorative, including text/brand; include the fixed cross-theme aliases bg/tooltip=black/100 (#000000) and bg/mask=black/50 (#00000080), plus text/inverse=neutral/0 (#FFFFFF) in both modes for every visible Tooltip foreground element; the Border/Ring pairs are border/default=neutral/200|800 → ring/focus=neutral/300|700, border/strong=neutral/300|700 → ring/strong=neutral/400|600, and border/destructive=destructive/500|500 → ring/destructive=destructive/600|400. Bind Light text/secondary-foreground to neutral/500 for descriptions and metadata, and bind Light text/muted-foreground to neutral/200 for placeholders and disabled states only; record both explicit contrast waivers and keep Dark muted content contrast-aware against bg/background and bg/muted. Keep shadcn identities such as card, popover, and sidebar only as code compatibility metadata. Derive variable_descriptions for the 146 Primitive and 52 Semantic Variables, plus the canonical component Variable-metadata selection contract. Derive eight hue-balanced vivid decorative scales with reusable background/foreground/stroke sets for tags, badges, charts, data visualization, and accents; do not generate a duplicate data/* layer. Generate the tier-independent Shadow/sm, Shadow/md, Shadow/lg, and Shadow/xl Effect Styles with exact EffectStyle.description values and exact softened (radius, opacity) layers [(3,.06)], [(5,.08),(3,.05)], [(20,.09),(8,.06)], and [(40,.12),(15,.08)]; every node with a drop shadow must reference one of these shared Effect Styles, never a detached literal effect. Reserve motion as an extension point. Expose typography through exactly three public categories: heading, paragraph, and monospace; generate Paragraph mini/sm/md/lg = 12/14/16/18px at all three weights 400/500/600, and generate Monospace only at mini=12px and sm=14px using the selected or default monospace family. Normalize context.interface_language to chinese or english (default English), and let it affect only Typography line height: Chinese body/monospace 1.5× and heading 1.3×; English body/monospace 1.4× and heading 1.2×. Round every result to the nearest integer and reject decimal line heights; language must not alter any other Foundation, component, or presentation output. Use the canonical radius inventory none/xs/sm/md/lg/xl/2xl/3xl/4xl/full = 0/4/8/12/16/24/28/36/44/9999 unless explicit source truth requires other values. When radius=round, radius/full is conditional rather than universal: use it only for a genuinely pill-like single-line control/item or a structural pill/circle; line count alone does not force full radius. Any configuration with two or more stacked text lines, a visible supporting/description row, wrapped content, or a multiline editor must use multiline_control and an appropriate hierarchical radius (radius/lg in the round character). Compact transient surfaces may also declare a component-specific hierarchical exception: Tooltip always resolves its dedicated role through the compact-control tier (radius/sm in the round character), including Default and Shortcut one-line variants, and must never switch to radius/full. Line count overrides the component-level default only where the component contract declares line-driven radius behavior, so never classify an entire ComponentSet from its component name alone; a public second-line option must be a Variant axis when its radius differs from the one-line configuration.

  2. Token architecture: Primitive Color → direct designer-facing Semantic Color → code-only compatibility mappings. The exact Semantic prefixes are bg, text, border, ring, and decorative; every Semantic Variable owns a Light/Dark Primitive alias directly. Status is a documentation grouping over bg/* and text/*, not a prefix. Do not create status/*, interaction/*, data/*, a generic color/* value-owner layer, a utility_aliases layer, chart-*, tag/*, fill/chart-*, or stroke/chart-*. Color variables named for a component category are forbidden. Do not add theme tiers; compose product surfaces from bg/background, bg/secondary, bg/muted, and bg/accent instead of inventing base, strong, or bg/{component}. Keep shadcn component names only in compatibility_aliases metadata for code generation; never project them to Figma Variables.

  3. Component grammar: structure + variability + semantics + constraints. Apply Rule 2 to classify every capability as Variant, Boolean, Text, Instance Swap, Slot, Nested Component, or fixed anatomy before building an adapter. Every canonical string that is an instance content parameter must appear in adapter_plan.text_properties; every semantic Text layer must either bind to one of those properties or carry an allowed fixed-internal classification. Start from the behavior-only b1VoQUK0 shadcn IR when a canonical component has a baseline mapping. Preserve the ordered union of source-evidenced states that the component actually owns, then append only visual states proven by canonical code Booleans; merge semantic aliases such as selected ↔ checked instead of exposing duplicate states. A generic HTML/ARIA passthrough attribute or styling hook is not sufficient state ownership by itself: keep it in the source accessibility/code contract. Do not invent a code state from generic component knowledge or an old blueprint. Custom extensions without a source mapping may use explicitly declared canonical states. Keep this code-facing grammar separate from adapter_plan.figma_component_sets: when figma_structure_refs exist, retain the exact source node kind, user-designated Figma Property names, order, types, defaults, values, unavailable combinations, binding targets, binding occurrence counts and applies_when distributions, actual configuration count, root layout profiles, and anatomy profiles as immutable source evidence even when they differ from normalized code props or state vocabulary. Reconcile adapter_plan.figma_text_property_projections afterward: reuse an equivalent source Text Property and audit all semantic bindings, or add the missing Agent-ready Text Property overlay. Use ALL_SEMANTIC_TEXT_LAYERS when matching text exists throughout the anatomy and PRESENT_SEMANTIC_TEXT_LAYERS when it is configuration-specific; never synthesize a layer solely to satisfy binding coverage. When a target delegates or derives the content instead of owning it, record figma_text_property_omissions and do not create an unbound property. Project every active component through exactly one design-system-v0.6 refined authority: ordered figma_appearance_refs plus exact normalized profile copies, or the equally complete explicit executable requirement record declared for that component. Missing authority blocks compilation; an absent normalized profile never authorizes structure-plus-Foundations, generic, or inferred appearance. Materialize every entry in references/icon-asset-contract.json as a real local standalone .Icon Component before component reconciliation. User-supplied SVGs stored under assets/icons/ are the only icon-geometry authority: preserve their bytes and SHA evidence, append future user batches to the contract (or explicitly replace the same semantic id), and never draw, approximate, image-generate, or fall back to generated icon geometry. A registered legacy alias resolves only to its exact bundled Component. The existing Breadcrumb dot is a structural separator exception, not a reusable icon asset. Bind every imported terminal paint to its declared semantic foreground role, preserve proportional geometry, and set both terminal artwork and every use Instance to SCALE × SCALE with constrainProportions=true. Clear stale swap geometry overrides before proportional appearance while preserving semantic names, visibility, and Property references. A single canonical family may project to multiple public Figma structures: Tabs owns Tab and Tabs in Component / Tabs; Field owns Vertical Field and Horizontal Field in Component / Field; Dialog owns Dialog, .Dialog Header, and .Dialog Footer in Component / Dialog; Table owns Basic Table Header and Basic Table Cell in Component / Table. Continue to keep Tabs and SegmentedSelector as separate canonical semantics.

  4. Composition grammar: rigid → instance swap; optional rigid → boolean plus instance swap; flexible → slot.

  5. Presentation grammar: use the exact page skeleton Cover → Getting Started → Foundations → --- → Components. Utilities, a trailing separator, and Playground / Component Compositions are forbidden in Core, Normal, and Pro. Make all five Foundation documentation frames direct children of the Foundations Page, and every Component / {Name} documentation frame a direct child of the Components Page. Never wrap these documentation frames in an intermediate grid, section, or root container. Place the direct Page children with explicit coordinates in horizontal-first row-major (Foundations: 10×N; Components: 6×N, excluding the index) order using space/20 gaps. Apply frame_fill_policy from presentation-style-contract.json to every generated presentation Frame: immediately after figma.createFrame() or figma.createAutoLayout(), assign fills=[], then add a fill only for an explicit allowlisted visual-surface role whose contract path declares it. Never let Figma's default white Frame fill survive on Header, Identity, Section, Row, column/grid wrappers, card collections, annotation containers, or component-group containers. Foundation documentation roots and other non-exempt Page-direct display Frames use an unbound raw outer background: #FFFFFF in Light and #000000 in Dark. Resolve Dark from an explicit Color mode first, then an exact Dark name hint, and otherwise default to Light. Component documentation roots follow the same raw unbound background rule; their nested Specimen Stages remain fill-less. The three instructional roots (Components / Index, Foundations / Summary, and Getting Started / Root) retain their instructional template. After changing an outer paint, revalidate all visible foreground contrast and repair stale foreground bindings that depended on the former surface. Build every documentation and explanatory shell exclusively from presentation-style-contract.json. The explanatory frames preserve target text and content-stage children while matching the local instructional_panel roles; their root and Contract Bar use raw unbound white/black presentation paint, and the Contract Bar has dividers only between cells, and their transparent radius/none stage has zero padding. Never fetch a historical Figma source while generating. Keep the foundation summary and component index above the documentation frames as direct Page children. Never create category or one-page-per-component pages. Frame overflow policy: generated FRAME containers default to clipsContent=false so nested effects and shadows remain visible. The only enabled-clipping roles are root Frames named Application Color / {Mode} / {VariableName} and Decorative Hue / {Mode} / {Hue}; both must keep clipsContent=true with their contracted non-zero rounded corners so their internal regions are clipped to the card shape. Run the canonical frame-clip reconciliation after all frame-creating mutations, then block completion unless live readback exactly matches this allowlist, including rendered Instance descendants. Current presentation-surface override: every Specimen Stage Frame is fill-less and unbound, regardless of Foundation, Component, or instructional parent. In Color / Application, bind Light Column to bg/muted and Dark Column to bg/background. This explicit rule supersedes any older raw Stage-fill or same-token-for-both-columns wording that remains in historical rationale. Toast source specialization: expose only Type = Success | Info | Warning | Error | Loading, keep fixed anatomy Leading icon / Message / Action / Close icon, and use exact type messages This is a {type} toast. Preserve instance editability without letting one shared Text Property overwrite every Type: keep message for Success and use deterministic conditional Text Property isolation for Info, Warning, Error, and Loading, each with its exact type default. The root is horizontal, exactly 40px high, 320–480px wide, stroke-free, Shadow/md, and radius/full in the round character; bind both horizontal paddings to space/4 (16px). Use exact Type pairs: Success bg/success + text/success-foreground, Info bg/secondary + text/foreground, Warning bg/warning + text/warning-foreground, Error bg/destructive + text/destructive-foreground, Loading bg/secondary + text/foreground. Message and leading artwork share the same Type foreground Variable. The trailing .Icon / Close always uses text/secondary-foreground. Show action reveals the real Extra small Ghost Default Button without changing height. Reject any raw or unbound #FFFFFF inside component definitions; structural Frames such as AL remain fillless unless a named appearance contract assigns a semantic surface. Avatar source specialization: project only Avatar With Image, Avatar Placeholder, and Avatar Stack as separate public ComponentSets colocated in Component / Avatar; delete Avatar With Icon and Avatar With Status Badge. Every individual Avatar boundary, image, placeholder surface, Stack holder, and nested Avatar instance must be a perfect circle with equal width and height, FIXED × FIXED sizing, proportional constraints, and radius/full; the Stack container itself remains HUG × HUG. Avatar With Image preserves Size = Default | Small | Large, contains exactly one Image rectangle, never creates a Content wrapper, and applies avatar-primary directly as a FILL image paint at every size. Avatar Placeholder preserves the same three fixed square sizes, centers Background and CN on both axes, uses the generated secondary surface/foreground pair, and has a border/default stroke with weight=1 and align=OUTSIDE. Avatar Stack follows the captured Obra sample with Size = Small | Regular, horizontal HUG × HUG Auto Layout, centered counter axis, exact -8px overlap, three avatars visible by default, and independent Show 3rd, Show 4th, and Show 5th Booleans. In every Stack variant, the root and all Holders remain paint-free, every Holder has clipsContent=false, and the exact visible circular root of each nested Avatar instance—including hidden fourth and fifth items—owns exactly one Variable-bound border/default stroke with weight=1 and align=OUTSIDE. Never put the Stack border on the Holder or behind the image, because the Small 24px Avatar intentionally overflows its 20px Holder and would cover that stroke. Every nested Avatar uses avatar-primary only. Breadcrumb source specialization: project .Breadcrumb item, .Breadcrumb separator, and the standalone Breadcrumb together in Component / Breadcrumb. Every item root is paint-free and borderless in every legal state. State=Default binds the visible Label text or Icon terminal vector paint to text/secondary-foreground; Hover and Active change only that visible foreground to text/foreground, use the same visual result, and do not change geometry, typography, root paint, stroke, or effects. Preserve the unavailable State=Active, Content=Icon combination. Content=Label contains only editable Label text; Content=Icon contains only the replaceable Icon instance—never add Dropdown Menu or chevron-down anatomy. Preserve the two separator variants (Default chevron-right and Custom dot). The standalone public Breadcrumb remains a horizontal HUG × HUG composition container, but its real Breadcrumb Items Slot must ship with a visible, immediately useful local default composition: four local item instances alternating with three local separator instances, final item Active. Never render Editable slot, an empty dashed Slot, fixed placeholder geometry, remote nested instances, or a placeholder-only public Breadcrumb. A Breadcrumb repair is incomplete until all three public sources coexist in the live Component / Breadcrumb frame and an independent Figma readback proves the exact variant inventory, conditional anatomy, semantic paint bindings, canonical Text Style binding, proportional icon constraints, seven-child local default composition, no placeholder text, and screenshot-visible breadcrumb content; a contract-only or test-only update must never be reported as a Figma repair. Progress source specialization: reproduce Obra node 1953:17809 through the bundled local contracts as one 13-variant Progress ComponentSet with Progress = 0 | 10 | 20 | 25 | 33 | 40 | 50 | 60 | 66 | 75 | 80 | 90 | 100 and one independent Show % Boolean defaulting to false. Every variant root is horizontal FIXED × HUG at a default width of 342, start/center aligned, with a Variable-bound space/4 gap. Its first child is a FILL × FIXED 8 clipped no-paint Bar; Bar contains a 342 × 4 default Overall track and, except at 0, one exact default-width Progress indicator. Center Overall and Progress vertically at y=2 inside Bar. Set Overall to horizontal STRETCH and every Progress indicator to horizontal SCALE, so the track fills the root and the represented percentage remains proportional whenever an instance is stretched horizontally. Give Overall and every nonzero Progress indicator radius/full on both left and right ends; asymmetric leading-only or zero-radius indicators are forbidden. Percentage is the second root child, uses paragraph/mini/500, binds a metadata-purpose foreground, and binds visibility to Show %. Preserve the source indicator node types and default widths exactly: Rectangle at 10/20/25/40/50 with widths 34/68/86/137/171; Vector at 33/60/66/75/80/90/100 with widths 113/205/226/256/274/308/342. Use the generated muted surface, primary surface, metadata foreground, radius/full, and no strokes or effects on reusable anatomy. Select source specialization: preserve the full Obra source as the Pro projection with Lines = 1 Line | 2 Lines | 2 Lines Alt and 54 variants. Core and Normal expose only Lines = 1 Line | 2 Lines Alt and therefore contain exactly 36 variants; 2 Lines is Pro-only. Keep the Lines axis in every tier, preserve 1 Line as the default, and recompute every layout/binding occurrence after tier filtering. Every projected Select variant, regardless of Size or Lines, binds both horizontal paddings to space/3 (12px), one spacing step above the former space/2. In a Normal or Core Figma repair, remove only exact Lines=2 Lines variants and compact the remaining 2 Lines Alt column plus its external annotation chrome; never delete 2 Lines Alt as a substring match. Update the documentation Contract Bar to the projected count (36 CONFIGS for Core/Normal, 54 CONFIGS for Pro) and reject a visually stale count even when the ComponentSet itself is correct. DropdownMenu source specialization: project Dropdown Menu, Dropdown Menu Item, Dropdown Menu Overflow, Dropdown Menu Group Label, and .Dropdown Menu Item Left Decoration as five separate public ComponentSets colocated in Component / DropdownMenu. Preserve the source evidence, menu Slot, item visibility bindings, decoration Instance Swap, and source-specific layout profiles before explicit local projection. Every tier retains Dropdown Menu.Style with only Default across five Spacing values (5 variants; Translucent forbidden), and retains Dropdown Menu Item.State with only Default/Hover/Active/Disabled across three Sizes and three Types (36 variants; Focus forbidden). In the projected .Dropdown Menu Item Left Decoration, every Type=Icon terminal paint and every Type=Text Text node binds to text/secondary-foreground for Default, Large, and Small; text/foreground, muted foreground, raw colors, and unbound paints are forbidden. The parent Dropdown Menu Item also treats both left and right decoration Instances as supporting content bound to text/secondary-foreground; State and Type profiles must never recolor those decoration Instances. Do not absorb neighboring Menubar or Navigation Menu sets. Below the primary group, add exactly three top-aligned equal-column examples: avatar single-select, grouped options with real separators, and avatar two-line items. Build every menu, row, group label, separator, nested decoration, and selected check from real local instances inserted through the real Dropdown Slot API; detached copies, manual row reconstruction, remote imports, and copied reference colors are forbidden.

  6. Adapter plan: keep the canonical record target-neutral, then project it independently to Figma and code. Without a designated structural source, use the normalized figma_variant_axes, Boolean/Text/Instance/Slot lists, and owning-State strategy. With figma_structure_refs, treat adapter_plan.figma_component_sets as the immutable source structure contract, then apply only the higher-priority figma_text_property_projections reconciliation for canonical content parameters. Do not merge other normalized code properties into that instance panel. Keep explicit code mappings for any different Figma state/value vocabulary; never turn transient states into a public code prop or copy structural-only Figma controls into code without an explicit mapping.

  7. Agent-ready contract: apply Rules 0–6 from agent-ready-rules.md to every public component, then finish with an MCP-only Agent Readiness Validation that scores Discoverable, Understandable, Configurable, Composable, and Implementable without filling evidence gaps from code, screenshots, or prior knowledge.

  8. Explainability ledger: record input, rule, output, and provenance for important derivations.

Resolve component inventory from user-designated cumulative completeness catalog + explicit include - explicit exclude. Read the exact ordered groups and bilingual labels from component-inventory.json; do not maintain a second executable inventory in prose.

Treat system-spec.schema.json as the interchange contract. Keep grammar platform-neutral and implementation-independent; keep adapter plans separate.

Phase 3 — Validate grammar before Figma

Run:

python3 <skill-dir>/scripts/validate_system.py system-spec.json --report preflight-validation-report.json

This produces SPEC_ONLY_PREFLIGHT evidence and is never completion-eligible. Before the first Figma write, create a run manifest conforming to run-manifest.schema.json. Record the target file, every active or superseded user-designated visual source, all required local template targets, and the artifact names for the run. Then compile the executable style and projection contract:

python3 <skill-dir>/scripts/compile_execution_contract.py system-spec.json run-manifest.json --output execution-contract.json
python3 <skill-dir>/scripts/emit_figma_library.py compile \
  --spec system-spec.json \
  --execution-contract execution-contract.json \
  --output figma-generation-plan.json

Compilation must fail if any bundled presentation template is absent, duplicated, or not projected exactly into the spec. The execution contract pins the system-spec and run-manifest digests, the bundled style-contract digest, the cross-session refinement-registry digest, exact Variable/Style inventory, target selectors, expected node counts, the one-contract-one-writer gates, and mandatory live read-back. Core, Normal, and Pro must all execute scripts/emit_figma_library.py; completeness may change only component inclusion and property/variant projection. Tier-specific writers, one-off repair entrypoints, skip-if-exists behavior, persisted target node IDs, and runtime imports from external Figma files or libraries are forbidden.

The writer packs appearance repair and appearance audit jobs greedily in canonical component/variant order under the 50,000-character use_figma source limit. Shared Foundation aliases, radius roles, and target identity are emitted once per pack; jobs still execute sequentially and fail closed at the first component error. A Figma rate-limit response is an execution error and must never be counted as a successful mutation or audit.

Resolve all errors. Review warnings and record explicit waivers with reasons. At minimum verify:

  • color coherence, exact 52-variable direct Semantic vocabulary, theme completeness, foreground contrast, accessibility target, exact projected-variable description coverage, role-aware selection-strategy conformance, and exact token_policy.component_variable_metadata_selection; reject status/*, interaction/*, data/*, color/*, chart-*, tag/*, fill/chart-*, stroke/chart-*, component names, and base, default, subtle, or raised theme roles; allow strong only for border/strong and ring/strong; verify text/brand is the nearest accessible brand step and passes on bg/background plus bg/secondary, every neutral stays below its personality chroma cap plus .002, bg/accent uses neutral/100 in Light and neutral/800 in Dark unless visual.accent_source=brand explicitly permits brand/100 and brand/900, ring/focus uses neutral/300 Light and neutral/700 Dark, ring/strong uses neutral/400 Light and neutral/600 Dark, and ring/destructive uses destructive/600 Light and destructive/400 Dark unless explicitly overridden, Light text/secondary-foreground is exactly neutral/500, Light text/muted-foreground is exactly neutral/200, Light status pairs use same-family 100/500, Dark status pairs use same-family 800/400, every deliberate Light low-contrast choice retains its canonical waiver, every Dark status pair meets the configured text threshold, and Dark text/muted-foreground is the first lowest-emphasis candidate meeting the configured text threshold on both bg/background and bg/muted;
  • control-height coherence: Web must expose exactly xs / sm / md / lg = 24 / 28 / 32 / 36; the values must be strictly increasing on a 4px rhythm with equal 4px adjacent increments, while density changes derived padding and gaps instead of inflating this foundation scale;
  • direct Primitive-bound Semantic values, complete code-only shadcn compatibility coverage, scopes/code-syntax intent, naming, and token economy; require zero projected compatibility or application aliases;
  • type hierarchy, spacing/radius monotonicity, and icon-source viability;
  • component anatomy, mainstream property vocabulary, semantics, constraints, and composition;
  • all five Rule 0 capabilities—Discoverable, Understandable, Configurable, Composable, and Implementable—are derivable for both Coding Agent and Design Agent consumers;
  • Rule 1 naming and taxonomy are normalized across component identities, categories, layers, properties, and variant values, with explicit adapter mappings for authoritative source API differences;
  • Rule 2 classifies every capability into the correct schema mechanism, keeps public enum combinations within budget, and defines one stable hierarchy signature or an explicit split/composition rationale;
  • every canonical string content parameter has a Figma Text Property projection, every semantic Text layer is bound or explicitly classified as decorative text, fixed brand copy, or a non-overridable system label, and the recommended Button/Input/Dialog/Card/EmptyState property names are considered before less common text controls;
  • Rule 3 defines semantic layer trees, Auto Layout intent, per-axis HUG/FILL/FIXED behavior, nested-component reuse, constraints, overflow, and required resize/content probes;
  • every designated root layout profile selects its declared occurrence count, all profiles cover the full Variant matrix exactly once without overlap, FIXED axes alone carry fixed dimensions, and every Button profile is horizontal HUG × HUG with centered content;
  • Rule 4 starts from an existing Variable/Style inventory, preserves one designated token vocabulary, classifies raw/duplicate/drift values, and defines semantic bindings plus a safe migration plan;
  • Rule 5 defines source-backed PURPOSE/USE/AVOID/KEYWORDS descriptions, Property semantics, composition records, relationship metadata, review flags, and natural-language discovery probes for reusable public Components;
  • Rule 6 defines the post-build MCP-only sample, evidence classifications, five-dimension scoring, readiness thresholds, issue severity, Component IR probes, and final report contract;
  • the bundled shadcn IR passes its schema, excludes resolved visual values, and resolves every baseline reference;
  • every component state set preserves source order, incorporates canonical state-backed code Booleans without semantic duplicates, and has complete ownership, Boolean binding, runtime mapping, order, and per-state descriptions;
  • variant budget and illegal combinations;
  • Agent, developer, and designer projections remain derivable from one canonical source.

Do not begin Figma compilation while validation errors remain.

In COMBINED mode, now freeze system-spec.json. Compute its exact byte SHA-256 and prohibit further writes to that file for the rest of both projection branches. Pass its path, digest, the normalized design decisions, and any already accepted product/contract context to $design-system-contract-gen using its from-spec branch, while recording contract.generation_mode=COMBINED in Contract IR. The Markdown branch must not rederive the spec, inspect Figma, or reinterpret canonical Foundation and component values. The Figma branch continues below unchanged.

Phase 4 — Compile foundations in Figma

Load $figma-generate-library and $figma-use, then follow their workflow under the precedence and mutation-order rules defined in the non-negotiable boundary above. This skill's specific Page, component-matrix, checkpoint, and sequential-write contracts override conflicting generic workflow guidance.

  1. Reconcile the validated spec with a final read-only Rule 4 inventory of existing Variables, Styles, collections, modes, aliases, scopes, code syntax, and live bindings. Produce reuse, conflict, drift, and gap decisions before creating tokens.
  2. Reuse compatible existing tokens first. For proven gaps, create primitives before semantics and semantics before justified component tokens; never establish a parallel token system.
  3. Generate the complete foundation infrastructure regardless of core, normal, or pro: Primitive Color, the exact direct Semantic Color vocabulary, modes, scopes, code syntax, text styles, and all four canonical Shadow Effect Styles. Completeness controls component inventory only. Treat a missing Shadow/sm, Shadow/md, Shadow/lg, or Shadow/xl Effect Style, missing/incorrect EffectStyle.description, or detached replacement effect in any tier as a blocking error. In Figma, create exactly bg/{background|primary|primary-hover|primary-pressed|secondary|muted|accent|destructive|success|warning}, text/{foreground|primary-foreground|inverse|secondary-foreground|muted-foreground|accent-foreground|destructive-foreground|success-foreground|warning-foreground}, border/{default|strong|destructive}, ring/{focus|strong|destructive}, and every decorative/{hue}/{background|foreground|stroke} role. Each one binds directly to a Primitive Color in both Light and Dark. Fix bg/muted to neutral/200 Light and neutral/700 Dark; derive text/primary-foreground from neutral/0 or neutral/950 by the highest minimum contrast across primary, hover, and pressed, then use that endpoint in both modes. Recompute Dark text/muted-foreground against both bg/background=neutral/950 and bg/muted=neutral/700. Do not create status/*, interaction/*, data/*, color/* owner Variables, utility_aliases, chart-*, tag/*, fill/chart-*, or stroke/chart-*. Write the canonical usage string to Variable.description on every projected Primitive and Semantic Color Variable; do not reuse one generic sentence across a layer. Write each shadow's canonical two-part description to EffectStyle.description. Component-named shadcn identities exist only as code mapping metadata in compatibility_aliases; they are not Figma Variables, own no values, and never appear in a picker or on the canvas. Keep an explicit old→new migration map and rebind live nodes before removing legacy Variables. Resolve every live Figma binding through an exact, collection-aware lookup that throws when the variable is missing or ambiguous. Never pass undefined to the official paint or scalar binding mechanism; a black fallback is a failed binding, not a valid default. Bind fills, strokes, and gradient stops on their paint objects, then read back paint.boundVariables.color. Bind supported scalar geometry such as padding, size, and corner radii on the node field, then read back the matching node boundVariables entry. Do not treat a node-level paint lookup as proof of a paint binding. When creating a child that must use layoutSizingHorizontal = "FILL" or layoutSizingVertical = "FILL", append it to an Auto Layout parent first and set FILL sizing only afterward. Setting FILL on an unparented node is an execution error. After any failed use_figma mutation, assume the write may be partial: run a narrow read-only audit, then repair idempotently by exact IDs or deterministic names before continuing.
  4. Create navigable foundation documentation with five independent top-level frames: Color / Application, Typography, Scale, Radius, and Elevation. Color / Application is a designer-facing selection guide, not an infrastructure diagram: show Background, Text, Border, Ring, Status, and Decorative as functional groups. Status displays the bg/{status} and text/{status}-foreground pairs without creating a status/* namespace. Never show status/*, interaction/*, data/*, color/*, chart-*, tag/*, fill/chart-*, stroke/chart-*, base, card, popover, sidebar, or another component category. Decorative Colors must not become a standalone root group: place the eight Light hue cards inside Light Column → Section / Decorative → Cards and the eight Dark hue cards inside the matching Dark path. Each hue card shows its background, foreground, and stroke roles together; document tags, badges, charts, data visualization, and non-semantic accents as valid uses. Code compatibility mappings stay outside Figma and off the canvas. Separate modes into two complete side-by-side columns—Light on the left and Dark on the right. Set one explicit Color mode on each column, let all swatches inherit that mode, and bind both column surfaces to bg/background so the Dark column renders on the actual dark background. Never place Light and Dark as two mini-swatches inside the same card. For every Decorative hue-set card, load and follow the bundled local templates.decorative_color_card entry in presentation-style-contract.json: use the 284×146 title-plus-three-equal-role-tiles hierarchy, exact background / foreground / stroke order, mode-aware role-label contrast, fixed usage copy, local token bindings, and the required matching-mode parent. Remove any legacy root-level Decorative Colors / Grid and fail live audit if one remains or if any card is outside its matching mode board. Never read, import, clone, or retain an external Figma node, file key, node ID, component key, or remote Variable ID during generation. For every single-role application color card, load and follow the local templates.application_color_card entry; preserve its hierarchy, dimensions, variable bindings, typography, contrast indicators, raw theme root fill, and metadata rules while adapting role/mode content. Never fetch the historical source Figma object during generation. Resolve every displayed HEX value from the card's current Semantic Variable alias in its effective Light/Dark mode; after any alias mutation, regenerate those static labels and fail final live validation if a label is stale. Bind color Variables at paint level with figma.variables.setBoundVariableForPaint; direct setBoundVariable("fills", ...) calls are invalid. Treat the contrast-dot group as visibility-dependent HUG content: validate its horizontal layout, 4px gap, two 4px dots, explicit modes, and contrast visibility rather than a fixed width. Do not apply the single-role template to decorative hue-set cards; use decorative_color_card instead. When reading shared plugin data, query only namespaces matching [A-Za-z0-9_.]+; hyphens are invalid in Figma's Plugin API namespace and must never be passed to getSharedPluginDataKeys. After any failed Figma write, read the target back before retrying because transaction rollback behavior can differ by runtime. Do not display Primitive palettes, compatibility targets, CSS properties, CSS variable names, code syntax, or mapping chains on the canvas. Present typography, spacing, radius, and the four Shadow Effect Styles as labeled specimens matching the local presentation contract. Build Type Scale as one vertical, no-wrap, single-column list; within heading, paragraph, and monospace, order font size from large to small and equal-size weights from 400 to 600. In Scale, place Spacing / 间距 and Control Size / 控件尺寸 in two equal-width columns and keep the contents of each column vertical. Render the canonical six Control Size variables size/control/xs|sm|md|lg|xl|2xl = 24|28|32|36|40|44 as fill-width specimens in ascending order. Render the ten Radius tokens none/xs/sm/md/lg/xl/2xl/3xl/4xl/full in a five-column, two-row grid while preserving the canonical 0/4/8/12/16/24/28/36/44/9999 values.
  5. Validate metadata and screenshots; repair before continuing. Read back every local Color Variable and require exact equality with the 146-Primitive + 52-Semantic projection, including exact black/100=#000000, black/50=#00000080, bg/tooltip→black/100, bg/mask→black/50, and text/inverse→neutral/0 in both modes, including descriptions, scopes, code syntax, and direct Primitive bindings in both modes. Require zero projected compatibility/application aliases and reject status/*, interaction/*, data/*, color/*, chart-*, tag/*, fill/chart-*, and stroke/chart-*. Resolve text/secondary-foreground and text/muted-foreground in every mode, verify their explicit Light bindings and waivers, verify status pairs resolve to same-family 100/500 in Light and 800/400 in Dark, verify all three Border→Ring one-step-stronger alias pairs, retain the canonical Light contrast records, require Dark status contrast to pass, and fail if Dark muted content skips a lower-emphasis eligible candidate. Reject any remaining base, default, subtle, or raised role and any strong role outside border/strong and ring/strong. Read back all four Effect Styles and require exact names, ordered effects, and canonical descriptions. After changing any foundational variable, search all Foundation and Component documentation text for stale resolved values or sequences derived from that variable. Variable-bound geometry may update automatically while contract bars, guidance cards, and token labels remain static; treat any mismatch as a failed migration.

Use the canonical spec as input, not as permission to bypass upstream safety checks.

Checkbox color completion is evaluated on rendered terminal geometry, not the Instance wrapper. After local icon materialization, both Checked?=Indeterminate configurations require every visible fill or stroke inside Lucide / minus to bind text/primary-foreground; text/foreground, unbound fallback paint, and non-terminal wrapper paint are forbidden. Complete component localization, structural/default-composition repair, Slot reconciliation, and component-specific repair before the canonical appearance pass, then run the blocking appearance audit before geometry and live-readback completion.

Phase 5 — Compile components one at a time

Process components in dependency order: primitives/atoms → controls → fields → composites → overlays.

For each component:

  1. Inventory existing local assets by deterministic local name/type and record provenance. Remote libraries and historical Figma nodes may be inspected only before normalization when the user explicitly designates them; the executable plan and writer may never retain or import their file keys, node IDs, component keys, Variable IDs, or Styles. Resolve every nested instance, icon, and Slot prototype from the target file's local assets or fail closed.
  2. Choose reuse, wrap, or rebuild using API, token, naming, and ownership compatibility.
  3. Compile canonical anatomy and properties through the Figma adapter plan. If adapter_plan.figma_component_sets is non-empty, first reproduce each listed source exactly at the structure level: source_node_type, Property order/name/type/default/value set, explicit unavailable combinations, actual configuration count, child binding targets, fields, occurrence counts and applies_when Variant selections, root layout profiles, anatomy profiles, and documentation-frame colocation. Create a standalone COMPONENT when declared; never wrap it in a one-child ComponentSet. For every actual root configuration, create/resize children first, then set direction, wrap, alignment, padding, gap, and finally its per-axis sizing; because resize() resets Auto Layout sizing to FIXED, perform any required resize() before restoring HUG/FILL. Never carry a fixed width into a HUG profile, and never generate a combination listed in unavailable_variant_combinations. Then apply adapter_plan.figma_text_property_projections: reuse an equivalent source Text Property when present, otherwise add the canonical lowerCamelCase Text Property. Bind every matching layer for ALL_SEMANTIC_TEXT_LAYERS; for PRESENT_SEMANTIC_TEXT_LAYERS, bind every layer that exists and preserve configurations where the source contains none. Do not create a property listed in figma_text_property_omissions. This text-only Agent-ready reconciliation is the sole permitted Property overlay; it does not alter figma_component_sets or authorize merging other normalized code properties. Keep an unbound Text layer only when figma_internal_text_exemptions records its ComponentSet, semantic role, one allowed category, and rationale. Before any visual write, resolve the component's exact design-system-v0.6 refined authority from the plan. Materialize every required target, apply explicit NONE versus SEMANTIC_INTENT paint presence, and preserve all contracted geometry, visibility, state and effect channels while resolving the current generated Foundations. Use figma_component_builder.js for normalized appearance records or the exact explicit requirement executor for requirement-backed records such as Toast; neither path authorizes invented generic anatomy or Foundation-only appearance. Colocate Tabs' two structures in Component / Tabs, Field's two structures in Component / Field, Dialog's three structures in Component / Dialog, and Basic Table Header/Cell in Component / Table. Keep the local visual/token/metadata system on every generated node. For Input, apply the persisted structure projection before creation: remove Show cursor and State=Empty in every tier and keep Cursor hidden in every remaining State, including Focus and Error Focus; use space/3 for both horizontal paddings in every size. Pro keeps Position Default/Left/Right/Middle and Size Regular/Large/Small/Extra small; Normal keeps only Position Default, removes the Position axis, and removes Extra small; Core additionally removes the Prepend/Append layers and visibility Properties. In Pro, Left removes only the right stroke, Right removes only the left stroke, Middle removes both side strokes, and Default keeps all four. Treat Prepend, Append, Decoration left, and Decoration right as description_or_metadata; pass that purpose to the live Variable-metadata selector and require text/secondary-foreground in every state. For Textarea, remove State=Empty in every tier, retain one bg/background fill in every remaining state, and set effects=[] in every state. Input/Textarea Focus bind ring/strong on the root stroke; Error Focus binds ring/destructive; neither uses a shadow effect. For Select, project Size to Default/Large/Small in every tier and remove Extra small. Every variant ends with a required real Right icon Instance whose default component is .Icon / Chevron Down; expose it through an Instance Swap but never a visibility Boolean. Make Prepend: use HUG width. For a Figma TEXT node, materialize and audit this as textAutoResize=WIDTH_AND_HEIGHT plus layoutGrow=0; the Plugin API normalizes layoutSizingHorizontal back to FIXED for TextNode even though its width follows content. Treat State=Placeholder value text as the explicit description_or_metadata exception—bind it to text/secondary-foreground, not the global text/muted-foreground placeholder role. For Tabs, remove the public Show counter Boolean and its visibility binding in every tier while keeping the internal counter hidden. Every tier exposes exactly Default/Large on both Tab and Tabs. Every Tabs root binds all four paddings to space/1 (4px); nested Default/Large Tab heights remain 28/32px and the HUG outer Tabs heights resolve to 36/40px. The real Tabs Slot is always paint-free; selected Tab instances alone own their selected surface. Make Tab.State=Inactive Focus visually identical to Inactive Hover with no ring or effect, and keep Active effect-free unless a later explicit user declaration overrides it. For Badge, project eight additional Decorative {Hue} Variant values—Blue, Cyan, Teal, Green, Amber, Orange, Purple, and Pink—in every completeness tier without mutating the captured source IR, then remove the State axis, Show spinner, and Spinner anatomy. The result is exactly 13 Variants. Use paragraph/mini/400 for every label, a default minHeight=20 with HUG height, and retain independent false-by-default Show left icon / Show right icon Booleans plus their swaps on every standard and Decorative Variant. Each Decorative Variant uses its exact decorative/{hue}/background and decorative/{hue}/foreground pair. For Card, retain only the root outer border: Header, Body, and Footer section wrappers have no strokes, and no Divider or Separator anatomy may be inserted between them. The Card root and all three section wrappers are HUG height; a fixed section or Card height is forbidden. Header, Body, and Footer apply the current design-decision spacing on all four sides through one bound spacing token (space/5=20px in the round/pro test profile), while keeping 380px fixed width. Every Header, Body, and Footer Slot uses vertical Auto Layout, FILL width, HUG height, top-left alignment (MIN / MIN), and a Variable-bound space/4 (16px) gap; this Card-specific layout overrides the shared empty-Slot layout. For Separator, preserve all six Spacing × Direction variants. Its root is a spacing-only container and must have no fill, stroke, effect, or radius. Every variant contains exactly one Rectangle named Divider and no generic Content: Default direction uses FILL × FIXED 1, Vertical uses FIXED 1 × FILL, and the Divider fill binds to border/default. The border/default Variable must support both STROKE_COLOR and SHAPE_FILL. For Checkbox and Radio, project the State axis to Default/Disabled only in every tier, removing Focus and Error Focus. Both roots are fixed 16×16, paint-free, and may contain only their exact source-backed Background and indicator anatomy; never create a generic Content layer and fail if any child exceeds the root bounds. Checkbox Background binds the selection_control radius role, which is always radius/xs (4px); False uses bg/background plus border/default, while True and Indeterminate use bg/primary with exactly one centered 12px proportional text/primary-foreground check or minus icon. Radio uses a 16px Ellipse Background; False uses bg/background plus border/default, while True uses bg/primary with one centered 6px text/primary-foreground Dot. Disabled changes root opacity only. For Toast, expose exactly one designer-facing Type Variant axis in the order Success / Info / Warning / Error / Loading and never expose a State Variant axis. Every Toast keeps the exact child order Leading icon / Message / Action / Close icon; leading icon, editable Message text, and the trailing Close icon are always present. The root has no stroke, uses a default 320px minimum and 480px maximum width, gives Message FILL width, and keeps Close anchored at the trailing edge. Expose Show action as a false-by-default Boolean; when true it reveals one real Button instance immediately before Close with Variant=Ghost, Size=Extra small, and State=Default, without changing root height. Apply the generated Shadow/md Effect Style to every Toast root. The exact local component-appearance-contract.component_requirements.toast record is Toast's complete design-system-v0.6 refined appearance authority; it is not an exception, an unrefined component, or permission for a generic/Foundation-only fallback. Preserve the Rule 0 code-oriented mapping: Figma properties map to typed props, nested instances and slots map to composition, Variables map to tokens, and Auto Layout exposes machine-readable layout intent. Apply Rule 2 before node creation: finite exclusive enums become Variants; independent optional capabilities become Booleans; editable core content becomes Text Properties; replaceable rigid elements become Instance Swaps; flexible regions become constrained Slots; required reusable substructures remain Nested Components.
  4. Compile adapter_plan.state_axis on the owning ComponentSet when it contains more than default. Never create __{Component}State, and never turn transient states into a public code prop. Apply state_backed_boolean_properties before adding Figma properties: remove every mapped code Boolean from the Figma Boolean list, including semantic aliases and inverse states, while retaining its real code mapping. Keep only independent configuration Booleans. Reject unresolved SOURCE_EVIDENCE mappings before node creation. Every state-bearing Variant and description must retain the exact canonical state ID.
  5. Before binding visuals, reload the live Color Variable metadata catalog and resolve each component-part/state intent through token_policy.component_variable_metadata_selection; use the bundled variable_metadata_selector.js helper or an exact equivalent. All creation, reconciliation, incremental repair, exact appearance application, shared Slot styling, and read-back must be emitted by the sole emit_figma_library.py entrypoint from figma-generation-plan.json; the bundled JavaScript files are internal templates/libraries and are never standalone execution paths. Process appearance mutations in bounded batches of at most ten configurations and rediscover targets by canonical local name/type on every call. Do not infer color from a component name, Variant label, or substring such as invalid, error, or destructive. Validate the exact Variable name, canonical description, scopes, mode aliases, and usage intent, then persist binding evidence. Bind visual properties to the selected variables and preserve only explicitly allowed fixed geometry. Resolve every root and nested part through adapter_plan.radius_usage; never assign a literal corner radius or use the generic control radius when the round policy requires radius/full. Apply Rule 3 to reusable anatomy: use Auto Layout for normal flow, set HUG/FILL/FIXED independently per axis from real responsive behavior, reuse compatible nested Components, and document any intentional absolute positioning, clipping, or fixed dimension. Apply Rule 4 to fills, strokes, text, typography, gaps, padding, radius, effects, borders, and reusable sizing. Reuse the correct existing semantic Variable/Style; do not bind business semantics directly to primitives or create component-local duplicates. Treat both Text Style and text-color binding as file-wide component invariants, not per-component appearance opt-ins. Every source TEXT node owned by a local Main Component or ComponentSet variant—including hidden variants, private helpers, and Slot placeholders—must bind exactly one non-mixed textStyleId resolving to a local canonical Text Style and must bind every visible SOLID text-fill paint to an eligible Semantic Color Variable with TEXT_FILL scope. Resolve Text Style in this order: explicit appearance typography_role; exact canonical typography signature after treating zero PIXELS and zero PERCENT letter spacing as equivalent; then the exact shared Slot placeholder role paragraph/mini/400. Missing or ambiguous styles are blocking errors. Repair nested Instance content through its local Main Component source once, then audit proxy descendants for inheritance instead of writing duplicate overrides. Any raw font-only text, empty/mixed/unresolvable textStyleId, raw/unbound/primitive text paint, missing fill, or unresolved alias blocks completion.
  6. Add component properties, nested instances, slots, documentation, a component-set description, and a non-empty description on every individual public Variant Component. Derive each Variant description from its exact designer-facing property values—including state—plus the canonical component semantics; never copy one generic sentence across all variants. Derive documentation contract-bar axis names, option counts, and tier labels from the final completeness-projected adapter_plan.figma_component_sets, never from the immutable source capture; stale Pro counts on a Normal/Core frame are blocking. Keep the component canvas designer-facing: do not add an API & Accessibility panel or expose code-mapping logic there. Apply Rule 1 naming throughout reusable subtrees unless a user-designated structural contract supplies exact public Property/value spelling. Preserve those exact Figma names and values, and keep normalized lowerCamelCase/lowercase vocabulary in the code adapter mapping instead of renaming the source-backed Figma API. Keep a stable semantic layer hierarchy across all variants. Preserve optional nodes and control visibility instead of deleting anatomy; split or compose configurations that require incompatible trees. Apply Rule 5 to the public ComponentSet: write the concise four-section PURPOSE/USE/AVOID/KEYWORDS Description, add semantic guidance for ambiguous Properties, and expose a separate source-backed composition/relationship record. Do not duplicate long descriptions on private helpers or state specimens.
  7. Resize the component set from actual child bounds after layout. Keep only the configured compact structural padding; reject oversized fixed rectangles or unused blank regions. After all text and annotation children exist, recompute every fixed freeform card or callout from its final child bounds plus padding; a structurally contained parent may still clip late-created text.
  8. Load templates.component_set_matrix from the bundled presentation-style contract and apply it to every generated ComponentSet without any adaptive or square-grid fallback. Style the boundary with a raw, unbound #9747FF dashed outline, no fill, and 4px corner radius; add matching raw, unbound dashed dividers between every adjacent variant row and column. Size is the only horizontal column axis, in declared order from left to right. State is always a vertical row axis. Every other Variant Property—including Variant, Type, Position, Style, Spacing, Side, and multiple remaining axes—forms declared-order outer groups stacked vertically by Cartesian order; a ComponentSet without Size is therefore single-column. Apply the explicit Progress override: its sole Progress Variant Property is a vertical single-column row axis, ordered 0, 10, 20, 25, 33, 40, 50, 60, 66, 75, 80, 90, 100. Put an explanatory axis note plus exact Property: Value labels outside the boundary in raw, unbound #9747FF: Size labels above columns, State labels left of rows, and every other Variant Property label left of its group with a bracket whenever the group spans multiple rows. Treat this authoring chrome as a documented raw-value exception and keep it as non-published siblings in the outer documentation matrix frame. Matrix identities, ordering, coordinates, labels, dividers, and brackets are deterministic contract output; random, adaptive, square-root, fixed-column, or unordered grids are blocking errors.
  9. Run a compact structural and appearance audit that returns one pass/fail summary, failed check IDs with minimal evidence, and every temporarily mutated node ID. Re-read the real Variant nodes and compare anatomy, geometry, paint-slot presence, effect channels, Variable bindings, and allowed state deltas with the resolved local contract. Require zero unprofiled variants, generic fallbacks, source-signature mismatches, and invariant violations. In particular, Switch must contain one Background and one Toggle, preserve checked/unchecked endpoint motion through focus/disabled, and have no visible root paint; Button must preserve its per-Variant border policy so Primary disabled never gains a stroke. Every Focus selection must use a stroke-bound ring/* role and resolve its effect channel to NONE unless its explicit local user refinement declares and validates an exact non-shadow alternative. Do not dump a full record for every Variant when the success path can be summarized; truncated audit output is incomplete evidence.
  10. Validate the public ComponentSet with metadata, then screenshot the complete Component / {Name} documentation frame. Treat metadata and screenshots as complementary and equally blocking: metadata proves structure; the screenshot must catch overflow, clipping, implausible type scale, matrix-order drift, overlapping or duplicate Size/State/group labels, missing dividers, illegible annotation, literal escape text such as \\n, implausible visible copy, remote nested-component fallback blocks, opaque black scaffold fallbacks, visually empty composites, indistinguishable declared states, uncontracted fills, and unexplained whitespace. Persist the screenshot SHA-256 and native pixel dimensions, exact detected-versus-verified ComponentSet counts, and explicit zero counters for every listed defect; a bare PASS assertion is invalid. Structural wrappers such as Wrapper and Field layout AL are fillless unless a named appearance target explicitly contracts a surface. EmptyState generates only Default and preserves the visual order Slot → Title → Description → Button group through direct root children Slot → Title + Description → Button group. The root binds space/4 (16px); the fillless nested text stack alone binds space/1 (4px), so live pairwise gaps are exactly 16/4/16px. The first child follows the shared generic Slot contract, Button group is the local .Empty / Button Group helper with its own nested Slot, Description uses text/secondary-foreground, and Content/Content Stack/a second direct Slot/Media-only/Link anatomy is forbidden. Dialog generates only Desktop scrollable with Size 480/640/800, width-FILL Header/Slot/Footer, height-FILL shared-style body Slot, and no mobile Footer; right and full-width Footer layouts must pass explicit alignment and Button-width readback. Calendar, Progress, Dropdown, Dialog, Field, EmptyState and every other active composite must expose enough visible anatomy to prove the learned relationship contract rather than merely pass node-count checks. Drawer, DataTable, and ToggleGroup are excluded from Core, Normal, and Pro and must never be generated. Field-specific gate: every Field root and structural Wrapper/AL/Selection Content Frame is fillless and borderless in all states. Both Field families retain their fixed 320px root; Horizontal Field retains its fixed 120px Label Wrapper, while its AL content track is FILL and vertical. Every Label, Input, Select, Textarea, Slider, Selection Content row, and Option label fills its available content width. Description and Error message keep non-empty canonical defaults, HEIGHT auto-resize, exact Text Property bindings, and FILL width whenever visible; Figma's forced FIXED readback for hidden Boolean-controlled Text is the only allowed exception. Radio and Checkbox Types use a FILL-width horizontal Selection Content row containing one exact fixed 16px local Default-unchecked control followed by a non-empty Option label bound to the editable option Text Property; the control itself never stretches and Field exposes no Slot.
  11. Repair all failures, repeat the compact audit and screenshot, and record the checkpoint. Pause for approval only when the user explicitly requests per-component review; otherwise continue through the selected completeness tier without intermediate confirmation.

Never create an icon variant per icon or a standalone IconButton. Never create a full Cartesian variant matrix above the configured budget. Apply the split/composition strategy from component-grammar.md.

Phase 6 — Apply designer presentation

Project the canonical grammar into designer-readable documentation:

  • stable pages and categories;
  • one named 1440px shared-template presentation frame per component set, using vertical auto layout, hug-content height, space/12 padding and section gap, and an unbound raw outer fill of #FFFFFF in Light or #000000 in Dark;
  • Foundation and Component documentation frames as direct Page children below the foundation summary and component index; do not create an intermediate container, and explicitly place the frames in horizontal-first row-major (Foundations: 10×N; Components: 6×N, excluding the index) order with variable-bound space/20 horizontal and vertical gaps;
  • the template header's uppercase kicker, merged {English} · {Chinese} Section Title at exactly 44px, one-sentence Chinese definition, and four-cell contract bar;
  • the shared specimen stage with space/8 padding, radius/md, and muted fill; set every first-level content heading to exactly 24px and render every first-level or nested content title bilingually, including Application Colors / 应用颜色, Variants / 变体, and States / 状态; use a component-specific freeform matrix or foundation-specific auto-layout specimen rows inside it; make Type Scale a direct-child, fill-width, single-column vertical list and order each category by font size descending then weight ascending; give every Type Scale card two equal-fill horizontal columns with metadata left and styled sample right; make Scale a two-column layout whose Spacing and Control Size columns each stack vertically; show the ten Radius Scale tokens in semantic order in a five-column, two-row equal-width grid;
  • Components / Index, Foundations / Summary, and Getting Started / Root use the bundled local instructional_panel template: preserve target text and content-stage children, allow text width and root height to follow content, and match every other root/header/Identity/Contract Bar/stage-container property exactly;
  • the instructional root and Contract Bar use raw unbound #FFFFFF in Light / #000000 in Dark; its Contract Bar is borderless with border/default dividers only between cells; its content-stage container has space/8 gap, zero padding, no fill, and radius/none. Never reintroduce frame_style_overrides or the specimen-template gray stage on these three frames;
  • readable and stable variant order;
  • in Component / Card, place Examples / 使用案例 below the primary component group and render exactly three real Card-instance compositions matching the reference: Login Form, Image Card, and Meeting Notes. Insert Header/Body/Footer content through the real Card Slot API, reuse matching local Field/Input/Link/Button/Badge/Avatar instances, and never detach or reconstruct a Card for documentation. Do not add example dividers unless an example explicitly requires one; every permitted divider is horizontal, FILL width, parented inside the Slot content container, and must not exceed that container's edges;
  • in Component / Pagination, place Examples / 使用案例 below the primary component group and render exactly one fillless row with five pages: Previous, 1, 2, 3, 4, 5, Next, with page 1 active. Previous and Next must be real local Ghost Button instances; every page number must be a real local Pagination Number Button instance with its nested Button label configured through the component API. Ellipsis, extra pages, a second row, detached copies, manual page text, and one-off reconstruction are forbidden;
  • in Component / Table, place one Examples / 使用案例 block after the Basic Table Header/Cell matrices. Compose exactly one 4-column, 5-row table from 4 real local Basic Table Header instances plus 16 real local Basic Table Cell instances. Use the contract copy, right-align the body price column, bind alternating rows to bg/secondary, bind the remaining cells to bg/background, and bind every bottom separator to border/default. Never detach, import remote cells, manually reconstruct a cell, or copy raw screenshot colors;
  • in Component / DropdownMenu, place Examples / 使用案例 below the primary component group and render exactly three top-aligned equal columns titled Select Example: avatar single-select, grouped options with real separators, and avatar two-line items. Every surface and row is a real local Dropdown-family or Separator instance, nested Avatar/check decorations are configured through component properties, and menu content is inserted through the real Slot. Detached copies, manual row reconstruction, remote imports, and reference-image colors are forbidden;
  • Alert uses bg/background with a 1px INSIDE border/default stroke. Icon + Content, Icon-aligner, and Content are fillless/strokeless; Content is vertical HUG so Description is the second line. Neutral Description uses text/secondary-foreground. In Error, Title, Description, and every rendered terminal fill or stroke channel of Icon bind the exact same text/destructive-foreground Variable; a wrapper-only binding, an unbound nested vector, or a gate that accepts merely one matching leaf is forbidden. Reapply these terminal bindings after every Instance Swap or resetOverrides() geometry normalization. Add exactly two real-local-instance examples below the primary group with bundled Success/Error icon Components;
  • a no-fill ComponentSet with #9747FF dashed outline, 4px radius, matching internal dividers, and external variant-property labels;
  • meaningful anatomy layer names;
  • concise component description containing the agent-readable grammar projection.
  • a concise, property-specific description on every public Variant Component; the canonical presentation.variant_descriptions map is the source of truth.
  • a source-backed state matrix and one concise description per state from presentation.state_descriptions; state labels use exact IDs such as focus-visible, never hand-normalized synonyms.
  • no Utilities page, trailing separator, or standalone Playground frame; component examples belong only inside their owning Component / {Name} documentation frame.

Example generation is a mandatory atomic phase of its owning component documentation, never an optional repair or a stage that may be remembered manually. After compiling figma-generation-plan.json, read only generation_chain.mandatory_example_execution.required as the tier-active source of truth. In both repeatability runs, execute each entry's exact required_sequence—build stage first, dedicated audit stage immediately afterward—and persist exact count, pass status, and SHA-256 evidence for both results. Do not skip an active Card, Dropdown, Alert, Table, EmptyState, or Pagination Example because the primary ComponentSet exists or a later geometry/screenshot audit might notice the omission. Missing, reordered, extra, failed, stale, or unaudited Example evidence blocks final live-audit assembly and completion. Use python3 scripts/emit_figma_library.py example-schedule --plan figma-generation-plan.json to obtain the deterministic per-run schedule; never substitute a handwritten stage list.

Derive the template header, contract bar, and component description from the same canonical component record. Do not maintain them as separate sources of truth.

Component page placement is a terminal generation requirement: after all component, Agent documentation, example, and instructional-frame size changes, emit and execute documentation-layout through scripts/emit_figma_library.py for batch 0 (Foundations) and batch 1 (Components), then execute the matching documentation-layout-audit batches before final screenshots and completion. Repeat these steps in the second-run repeatability check. Use the bundled page_frame_placement contract: Components has six Component / * artboards per row, the index sits above the rows, and Integration / * artboards sit below them. Preserve frame sizes and source identities; hidden helpers do not consume columns. Reflow again after any later frame-size change. Never reuse the old 10-column Markdown placement or leave all component artboards on one unbounded row.

Phase 7 — Technical QA and repair

Run the production loop:

generate → validate → repair → validate again

Check the canonical spec with the bundled validate_system.py and the Figma library with the official skills. Finish only when required checks pass for:

  • foundations and tokens, including all four Shadow Effect Styles in every completeness tier;
  • live Effect Style read-back from getLocalEffectStylesAsync(): require exactly Shadow/sm, Shadow/md, Shadow/lg, and Shadow/xl with the canonical descriptions and ordered effects, then prove each Elevation specimen resolves through a non-empty effectStyleId to the matching local style. A screenshot, detached effects array, generated JSON record, or visible shadow alone is not completion evidence; stale copy such as 0 published effect styles is a repair failure;
  • each component and its bindings;
  • accessibility;
  • agent-readable metadata and predictable naming;
  • developer-mappable tokens and APIs;
  • designer readability, findability, inspectability, and maintainability;
  • every-top-level-artboard screenshots captured after the final write and matched exactly to the live artboard inventory, with screenshot SHA-256, native dimensions, explicit zero-valued overflow/type-scale/literal-escape/fill/matrix/remote-instance/black-fallback/empty-composite/indistinguishable-state/label-overlap counters, and equal detected-versus-verified ComponentSet matrix counts, plus unresolved-binding audits. Missing or stale screenshots, unchecked artboards, literal \\n/\\t, implausible visible copy, metadata-only matrix claims, or any visual finding block completion.
  • tight component-set content bounds, all five independent foundation frames, canonical stacked template headers, and zero Utilities/Playground output.
  • direct-Page freeform horizontal-first row-major placement (Foundations: 10×N; Components: 6×N, with the index excluded), no intermediate documentation container, raw #FFFFFF Light / #000000 Dark outer frame fills with no Variable binding, and the canonical annotated ComponentSet visual treatment.
  • exact 44px Section Titles and exact 24px first-level content headings in every Foundation and Component documentation frame.
  • exact role-based live read-back evidence that Components / Index, Foundations / Summary, and Getting Started / Root match the bundled local instructional_panel contract for the root shell, header, Identity, Contract Bar, and content-stage container while preserving target content; pre-Figma spec validation alone is never sufficient.
  • complete read-back evidence that every Variant Component has a non-empty description matching its property combination.
  • Figma MCP read-back evidence that a Coding Agent can derive the code schema and a Design Agent can discover, configure, and compose real component instances without guessing or detaching them.
  • a full Rule 1 MCP naming audit with no placeholder layers, ambiguous component identities, generic properties, mixed variant-value synonyms, or undocumented Figma-to-code name mappings.
  • a full Rule 2 MCP schema audit proving correct Property classification, bounded Variant combinations, constrained swaps/slots, canonical defaults, and consistent Variant hierarchy signatures.
  • a full Rule 3 MCP layout audit plus short/long/minimum-width/larger-container/multilingual instance probes proving semantic hierarchy, responsive sizing, alignment, and overflow behavior.
  • a full Rule 4 MCP audit of Variables, Styles, aliases, modes, scopes, code syntax, raw values, drift candidates, and live Component bindings, including safe migration evidence for every replacement.
  • a live component-variable metadata audit proving the Color catalog was reloaded after the final foundation mutation; every bound semantic Variable has the expected name, canonical non-generic description, compatible scopes, direct per-mode Primitive aliases, current-mode-resolved raw paint fallback, and recorded component/part/state intent; no component/Variant substring heuristic, whole-root invalid-state status binding, Primitive binding, unresolved black fallback, or generic-gray fallback remains.
  • a live component-appearance audit pinned to the current local contract SHA-256, proving every checked legal Variant was read back from the target file; every required anatomy path, intrinsic geometry, paint-slot presence, stroke rule, effect channel, anchoring, visibility, and permitted state delta matches; unprofiled_variants, generic_fallback_variants, and source_signature_mismatches are all zero. Screenshots complement this deterministic evidence and can never replace it.
  • a full Rule 5 MCP semantic audit proving four-section public descriptions, Property guidance, composition/relationship accuracy, visible review flags, and successful natural-language component discovery probes.
  • radius-binding evidence that every eligible pill-like round single-line root/item resolves to radius/full, while multiline inputs, cards, messages, overlays, and the component-specific Tooltip compact-surface exception retain their documented hierarchy; every Tooltip Type resolves to radius/sm in the round profile.
  • compact-audit evidence that successful runs fit within the tool output budget and list only failures in detail; output truncation invalidates the affected audit.
  • fixed documentation-card fit evidence computed after final text insertion, plus screenshot confirmation that no content is clipped or hidden.

Report waivers and residual risks explicitly. Never label a best-effort approximation as production-ready.

Phase 8 — AGENT READINESS VALIDATION

After Phase 7 passes and the intended Library is complete, read and execute Rule 6 from agent-ready-rules.md.

  1. Freeze source Components for the duration of scoring. Do not repair metadata, properties, bindings, or composition while the audit is running.
  2. Build the deterministic sample and run all five dimensions using Figma MCP evidence only.
  3. Record each answer field as DIRECT, SUPPORTED_INFERENCE, GUESS_REQUIRED, or CONFLICTING; leave unsupported values unknown instead of guessing.
  4. For Composable testing, create only temporary real-instance specimens in an audit sandbox, retain exact returned IDs, validate through MCP, and remove only those owned temporary nodes.
  5. Generate the required Button, TextField-or-resolved-Input, Card, and Dialog MCP-only Component IR samples.
  6. Calculate the five 0–100 scores, Overall score, issue severities, Ready for Agent result, and ordered repairs using the Rule 6 thresholds.
  7. If repairs are needed, close the audit as-is, return to Phase 7, repair, and run a fresh Phase 8 audit. Never reuse the pre-repair score as the final result.

Finish only when the final report is self-contained, evidence-backed, and explicit about every unavailable or conflicting field.

Phase 9 — Combined Figma and Markdown acceptance

Run this phase only in COMBINED mode and only after Phase 8 and the Markdown skill's native validation both pass.

Require these artifacts from the Markdown branch:

  • contract-ir.json;
  • the complete L0–L7 design-system-contract/ package;
  • contract-manifest.json;
  • successful Contract IR and package validation;
  • byte-identical second rendering.

Run the combined validator from the installed $design-system-contract-gen skill:

python3 <design-system-contract-gen-dir>/scripts/contract_package.py validate-combined \
  --ir contract-ir.json \
  --package design-system-contract \
  --system-spec system-spec.json \
  --figma-plan figma-generation-plan.json \
  --figma-audit figma-live-audit.json \
  --figma-validation validation-report.json \
  --report combined-acceptance-report.json

Completion requires:

  • the exact system-spec SHA-256 in figma-generation-plan.json#/artifact_digests/system_spec_sha256;
  • the same digest with sha256: prefix in contract-manifest.json#/canonical_spec_sha256 and every managed Markdown file;
  • validation-report.json#/status=PASSED;
  • figma-live-audit.json#/passed=true, zero violations, and identical two-run normalized readback;
  • Markdown-native validation and deterministic repeat rendering;
  • every scoped Foundation Token and component Figma mapping is verified with non-empty live targets and readback evidence;
  • no unresolved drift that contradicts the canonical spec.

Do not claim combined completion when either branch merely generated files without passing its own native validation. A combined failure does not retroactively invalidate a separately passing Figma branch; report branch results independently and the combined verdict as failed.

Decision policy

For each potential input, classify it before acting:

  • USER: brand, product context, visual direction, accessibility target, or genuine scope fork.
  • DERIVE: scales, state colors, component dimensions, property defaults, inventory, and other predictable consequences.
  • FIGMA_ADAPTER: variables, styles, auto layout, component properties, slots, nodes, and page construction.
  • CODE_ADAPTER: framework-specific component code, prop typing, CSS variables, and package exports.

When evidence conflicts, use this precedence only when it matches the stated goal:

explicit user decision → designated source of truth → existing compatible convention → mainstream convention → skill default

Never silently replace a user's existing design-system convention merely because the default differs.

Mainstream compatibility rules

  • Textarea uses two editable Text Properties with deterministic visible defaults: value = Value and placeholder = Enter value. Placeholder alone binds to placeholder; Value, Focus, Error, Error Focus, and Disabled bind to value. Any visible non-placeholder Textarea state with empty characters, a missing Value layer, or the wrong Text Property binding blocks generation and screenshot approval.
  • Input Position controls both joining borders and joining radii. Default keeps single_line_control on all four corners; Left binds its two right corners to radius/none; Right binds its two left corners to radius/none; Middle binds all four corners to radius/none. Apply and audit four explicit corner Variable bindings; unbound numeric seam radii are forbidden.
  • Prefer stable property names: variant, size, state, orientation, side, align, disabled, selected, checked, expanded, loading, label, value, showLabel, leadingIcon, trailingIcon, showLeadingIcon, showTrailingIcon. Use state as the owning Figma ComponentSet's designer-facing Variant axis for finite evidence-backed conditions, but explicitly omit it from code props. Keep real state-like code Booleans in the code contract, record their State bindings, remove their duplicate Figma Boolean controls, and map remaining State values to CSS/HTML/data/role/ARIA mechanisms.
  • Apply Rule 1 casing and taxonomy: semantic PascalCase component/layer names, controlled categories, lowerCamelCase properties, normalized lowercase variant values, and explicit adapter mappings when an authoritative code API uses different strings.
  • Map Figma variants to enum props, booleans to boolean props, text to string props, instance swap to component props, slots to children/slots, and tokens to CSS/theme variables.
  • Never encode independent optional elements, arbitrary content, or asset identity as Variant axes. Use Boolean, Text, Instance Swap, Slot, or Nested Component mechanisms according to Rule 2, and keep equivalent Variant trees structurally consistent.
  • Use Auto Layout for normal component flow and map its direction, gap, padding, alignment, distribution, and per-axis sizing to code layout rules. Permit absolute positioning and fixed sizes only for documented intrinsic or layered behavior.
  • Bind reusable visual properties through the existing Primitive → Semantic → justified Component token architecture. Prefer semantic tokens, keep one designated vocabulary, and allow raw values only for documented fallbacks, fixed structural geometry, assets, or excluded documentation chrome.
  • Describe every reusable public Component with concise, source-backed PURPOSE/USE/AVOID/KEYWORDS semantics. Keep uncertain claims marked Needs Product/Design Review, and keep composition/relationship metadata separate from the short public Description.
  • Use the installed shadcn preset only for component rules and the abstract comfortable + soft baseline. Do not copy Tailwind utilities or preset-resolved colors, spacing, radii, typography, elevation, or lime brand values. Resolve the brand from the user's design_decisions.brand.primary_color.
  • Preserve design_decisions.brand.primary_color exactly at color/brand/500. Derive all other brand steps around it, requesting 38% of the 500 anchor chroma at every chromatic family’s 100 step before gamut mapping so pale colors remain visibly tinted instead of gray. Reduce that request only when required to fit sRGB; never rotate hue or change the exact 500 anchor. Tint the neutral scale subtly toward the brand hue, and map bg/primary to brand/500 in every theme; never silently substitute brand/600 or a theme-specific step.
  • Add the exact Primitive neutral/0=#FFFFFF. In Light, bind bg/background to neutral/0 and bg/secondary to neutral/50. In Dark, derive the counterpart through the fixed hierarchy bg/background→neutral/950 and bg/secondary→neutral/800. Semantic values must remain Primitive aliases; never store raw #FFFFFF directly on bg/background.
  • Treat every accepted color-generation change as a two-surface transaction: update the bundled generator/contract and the in-scope live test Figma file in the same task. In Figma, create or update the exact Primitive, rewrite every affected Light/Dark Semantic alias, refresh all displayed HEX labels, and then read back Primitive values, alias target IDs, swatch Variable bindings, mode resolution, descriptions, scopes, and code syntax. A local-only pass or an auto-updated swatch with a stale HEX label is incomplete.
  • Unless explicitly overridden per family in design_decisions.status_colors, preserve success/500=#16A34A, destructive/500=#EB1C23, and warning/500=#FA8714. Derive each remaining scale around its selected 500 anchor. Bind Light bg/{success|destructive|warning} to its family 100 and the paired foreground to family 500; bind Dark status backgrounds to family 800 and the paired foreground to family 400. Retain canonical contrast waivers only for the explicit Light pairs; Dark pairs must meet the configured text-contrast target.
  • Keep Button content color coupled: label, leading icon, trailing icon, and spinner must bind every terminal descendant fill/stroke paint leaf to one identical Semantic foreground Variable. Set figma.skipInvisibleInstanceChildren=false before resolving nested targets: an ancestor's hidden default never exempts its descendants, and zero terminal paint leaves is a blocking error rather than a vacuous pass. Primary content uses text/primary-foreground, never text/foreground; Destructive content uses text/destructive-foreground. Code icons inherit currentColor. Never introduce separate Button icon/spinner color properties or tokens. Configure each icon and spinner Instance with constrainProportions=true and {horizontal:SCALE, vertical:SCALE} constraints; require its content to stay within the Instance bounds, and use a compatible intrinsic-size helper or rescale source and wrapper together instead of resizing only the wrapper.
  • Treat proportional icon scaling as a global base rule, not a Button exception: every icon-like Instance in every component uses constrainProportions=true and {horizontal:SCALE, vertical:SCALE} constraints, even when a local appearance profile omits scale_mode. Apply the rule explicitly to the standalone Spinner component as well: every Spinner root, its internal Ellipse indicator, and every nested Spinner Instance preserve proportions and use SCALE / SCALE constraints.
  • Size every component-consumer content icon, decoration, and spinner from the owning component's exact Size value: Extra small=12px, Small=14px, Default|Regular|Medium=16px, and Large=20px; components without a Size axis use 16px. A bundled SVG may retain a 24×24 intrinsic viewBox/source Component, but 24px is never a fixed consumer-instance size. Apply the size after localization/Instance Swap reset so source geometry cannot leak back into the component. Checkbox check/minus, Radio indicator, and Slider marker remain governed by their explicit state-indicator contracts.
  • Treat icon visibility Booleans as visibility-only capabilities. For the same component Variant selection, enabling or disabling any icon Boolean must leave the root height unchanged. Every hidden optional icon is pre-sized to the same Size-derived value as its visible state, and that value must fit within the root's inner height after vertical padding; a Boolean that causes Button, Input, Select, Badge, Toast, or any other component to grow is a blocking generation and live-audit failure.
  • Treat terminal icon occupancy as a blocking geometry contract, not a subjective screenshot check. For every bundled local icon source Component and every generated content-icon consumer Instance, compute the union of rendered terminal fill/stroke geometry (including stroke render bounds). Its maximum axis must occupy at least 55% of the owning square canvas and no terminal render bound may exceed that canvas by more than 0.51px. Validate both the 24px source Component and the final Size-derived consumer after every SVG import, localization, Instance Swap, reset, and proportional resize. Never call resize(24,24) on the container returned by figma.createNodeFromSvg() because the current Figma runtime may return a 100px import wrapper and scale the already-canonical 24px path data a second time; preserve the canonical path coordinates, move its children into the 24px source Component, and validate their rendered occupancy before allowing the stage to pass.
  • Keep Button state ownership narrow. The canonical code state remains state=[default, hover, active, focus-visible, disabled]; the Figma Button State axis is exactly Default / Hover & Active / Focus / Disabled. Preserve aria-invalid and aria-expanded only as non-owning passthrough/code evidence; never expose Invalid as a Button State value. Require separate showLeadingIcon and showTrailingIcon Boolean visibility bindings on every live Button Variant.
  • Apply the explicit Button appearance refinements from the bundled local contract: Extra small labels use 12px and every other size uses 14px; for a fixed Size and Variant, label typography and every internal element size are invariant across State; Outline has no root fill in any state and uses its stroke channel, with Focus switching that stroke to the applicable ring/* role and never adding an effect; Link Hover & Active and Focus underline the label through disjoint Size-aware conditional Text Properties whose selectors never overlap; Destructive uses bg/destructive and pairs label, icons, and spinner with text/destructive-foreground, with no component-specific exception.
  • Allow the documented designer-only Figma state axis only on the owning ComponentSet, with code_state_property=false, explicit state_backed_boolean_properties, and a concrete runtime mapping for every value. Do not expose the same condition again as a Boolean even when code and state use different names. Avoid all other Figma-only public APIs and duplicate synonyms such as type, style, appearance, look, and mode for the same variant concept.
  • Never create a component-specific Color Variable. When a direct Semantic role is insufficient, extend the shared role with a reusable level or emphasis axis. A component-named color may exist only as code-compatibility metadata targeting one of the direct Semantic names; it is never projected to Figma. Non-color component tokens still require stable independent semantics, a complex shared state model, or an explicit theme override.

Deliverables

For FIGMA_ONLY, produce these artifacts for a complete run:

  1. normalized design decisions;
  2. gap/conflict analysis with provenance;
  3. canonical system-spec.json conforming to the bundled schema;
  4. run-manifest.json with target and user-designated Figma source provenance;
  5. spec-only preflight-validation-report.json;
  6. compiled execution-contract.json proving the local style templates are required inputs;
  7. deterministic figma-generation-plan.json produced by the sole writer entrypoint and containing no external runtime locators;
  8. compiled Figma foundations and component library;
  9. two complete live writer/reconciler runs whose normalized read-back SHA-256 values are equal;
  10. figma-live-audit.json captured from the exact target file with exact inventory, role-based template evidence, cross-session registry provenance, writer provenance, and full component visual-fidelity evidence;
  11. final validation-report.json produced with all live artifacts and completion_eligible: true;
  12. concise derivation summary explaining repairs, waivers, residual risks, and the highest-impact inferred decisions.

For MARKDOWN_WITH_FIGMA_EVIDENCE, produce these artifacts without modifying Figma:

  1. normalized design-decisions.json and, when needed, contract-context.json;
  2. focused read-only Figma evidence for the scoped Tokens and public components, with file identity and stable evidence locators;
  3. spec-only validated and frozen system-spec.json plus its exact SHA-256 and preflight report;
  4. figma-spec-reconciliation.json, preserving both canonical and Figma comparison snapshots for every scoped Token and component;
  5. contract-ir.json bound to the frozen system-spec SHA-256 and reconciliation evidence;
  6. the complete L0–L7 design-system-contract/ package and contract-manifest.json;
  7. Markdown-native validation and deterministic repeat-render evidence;
  8. figma-evidenced-markdown-report.json, including comparison totals, conflict resolutions, mapping status, and figma.modified=false.

For COMBINED, preserve all 12 Figma artifacts and additionally produce:

  1. contract-context.json when product, principle, governance, or lifecycle inputs extend the canonical design-decision schema;
  2. contract-ir.json bound to the frozen system-spec SHA-256;
  3. the complete L0–L7 design-system-contract/ package and contract-manifest.json;
  4. Markdown-native validation and deterministic repeat-render evidence;
  5. combined-acceptance-report.json reporting the independent Figma result, independent Markdown result, shared digest result, mapping-evidence result, drift result, and overall verdict.

Numeric width-style Size axes such as Dialog 480|640|800 are non-control sizing: content icons resolve through the no-Size default 16px, never through the numeric width value.

Treat 1440px as the minimum documentation-frame width. If a canonical ComponentSet matrix is wider than the specimen stage's inner bounds, expand the documentation frame and its fixed intermediate component-group wrappers until every declared Size column and annotation is fully visible; clipping a legal column is blocking.

Run the final gate only after live Figma read-back:

python3 <skill-dir>/scripts/validate_system.py system-spec.json \
  --run-manifest run-manifest.json \
  --execution-contract execution-contract.json \
  --figma-audit figma-live-audit.json \
  --require-live-figma \
  --report validation-report.json

Preserve the spec and validation report outside /tmp when they are intended as project artifacts. Use /tmp only for ephemeral execution state required by the official Figma skills.

  • v0.8 asset refinement: all Loading glyphs use exact bundled assets/icons/loading.svg, including Core Button/Toast, Agent media and uploads. Run the shared loading-icons stage after icon imports, before component construction, and as a terminal repair/audit. Preserve its SVG geometry, node opacity and paint opacity; only semantic color and proportional size may change. Generated spinner rings and dashed-circle substitutes are forbidden.

  • Markdown Code Block, ToolCall File and DiffViewer share appearance.actions_gap=space/4 (16px), with HUG action groups and local connected icon instances.

  • Content images use the five original user JPEGs registered in Markdown default_media.content_assets. Never inline a downsampled thumbnail to fit the 50k script transport. Run agent-markdown-media-asset to resolve carriers, verify each local SHA-256, then call Figma upload_assets for its pending targets and POST the verified upload_source_asset bytes. Use original bytes by default. The fifth image has one pinned JPEG-80 upload encoding at the unchanged 5400×3600 size because its original exceeds the upload limit; retain both originals and this explicit transport derivative. Continue only after all upload responses succeed. Markdown build/audit must verify each image's original dimensions. Media Set tiles use the five assets in declared order; Image ratios share content-primary. Preserve avatar-primary.

  • 2026-09-07 ChatBox/A2UI refinement: resolve their role/* radius references through the current Foundation radius usage map, never substitute fixed scale levels learned from a reference. ChatBox shell uses multiline_control, Upload Card uses card and its icon tile compact_control; A2UI shell/content/Card use card and Footer Buttons use control. ChatBox text states are Placeholder / Value / Focus / Disabled, with separate Recording waveform and Sending state. Voice is a 40px icon-only control using the exact bundled user microphone.svg, not a text Button; Recording replaces typing text with the contracted waveform. Populate five connected upload cards with distinct Markdown/PDF/Document/Spreadsheet/ZIP assets, preserve editable names, and keep one clipped horizontal scrolling row at every width. A2UI Header Show progress is a default-false Boolean, including all three default examples. Every A2UI Slot, empty or populated, is FILL horizontally and HUG vertically; this explicit family rule overrides generic empty-Slot HUG width. Check these rules in canonical validation, shared writer and live audits.

  • ChatBox action refinement: every toolbar action, including Send and both Recording actions, uses the same control radius role. Never mix circular Send with rectangular peers; a full-radius role makes every icon action circular and text action pill-shaped, while a small-radius role applies to all. Focus includes a separate visible caret beside editable text. Recording uses a 24px waveform track with 128 narrow bars, maximum 16px high; its toolbar contains only left Cancel (Close/X) and right Finish (Check), no other control nodes. Upload cards never wrap: five fixed-width cards remain in a clipped FILL-width viewport with overflowDirection=HORIZONTAL, verified at 800px and 420px composer widths.

Documentation preview surfaces

Documentation backgrounds are presentation chrome, not product semantics. Do not generate bg/documentation, a renamed equivalent, CSS variable, alias, or product color swatch for them. Use raw unbound #FFFFFF in Light and #000000 in Dark on documentation roots and Contract Bars. Resolve the explicit Color preview mode through ancestors first, then a Dark name hint, otherwise Light, at generation/reconciliation time. Raw paints do not switch automatically when the user changes a mode: rerun documentation-backgrounds to reconcile, then audit. Preserve the fixed Cover B, fill-less Specimen Stages, and real product surfaces. For legacy files, unbind all documentation consumers, remove exact obsolete swatches, verify no remaining references on all pages, then run documentation-variable-cleanup to remove the exact legacy Variable. Run documentation-backgrounds and documentation-backgrounds-audit for Getting Started, Foundations, and Components; require zero violations and absence of the forbidden Variable.