算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
figma-handoff-gate【设计与创意】Pre-ship gate for a Figma handoff. Runs 17 checks before a section is declared ready for developers: action completeness (every drawn action has a designed outcome, and inverse pairs such as add and remove both exist), annotation layout and contrast, dense spec cards with no AI stuffing, a hand-crafted surface with no trace of the process, and proof …
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Pre-ship gate for handoff sections. It catches handoff-specific bugs that a slop and precision pass misses: orphan actions, weak annotations, inflated screen counts, process residue on the canvas, proof taken at the wrong scale.
Run figma-slop-check first. This gate assumes the screens already passed it.
The detector snippets below are Plugin API JavaScript. Run them through figma_execute (figma-console MCP server, Desktop Bridge plugin running in Figma Desktop). The gate reports. It changes nothing on the canvas until the user approves a fix (see "Apply-fix commands").
figma-slop-check passes on the same section.The canon is figma-canon/references/handoff-format.md. Its "Terms" section (figma-canon/references/handoff-format.md#terms) defines spec card, caption and note card, the three surfaces these checks name.
Required checks (all must pass). Report a broken requirement as [BLOCKER]. Report an item that a check only asks you to flag (for example a gap over 120px in check 1) as [WARN]. Any finding of either level puts the result in the FAIL template, which lists both as issues before ship.
SCREEN_TO_ANNOTATION_GAP = 80px (screen right edge to annotation column left edge)CLUSTER_TO_CLUSTER_GAP_H = 160px (cluster to next cluster)ROW_GAP_V = 200px (cluster row to next cluster row)SECTION_TITLE_CLEARANCE = 48pxfigma-canon/references/handoff-format.md#spacing-canon for the full tablefigma-canon/references/handoff-format.md for the diagramWhy: / Edge: prefixes. That accent is part of the note card spec, not amber slop.deliverable + valueTICKET-123), internal tool names ("the v2 validator"), registry or rule codes, and the like@user_NNN placeholders (use realistic names or strip)figma-canon/references/ai-slop-signatures.mdfigma-canon/references/handoff-format.md#state-variants-live-in-component-sets, and your project's own build skill or workflow, if anyfigma-canon/references/handoff-format.md#4-lens-pre-ship-critique-mandatory for the questions of each lens@user_123: replace them with realistic names in the file's language.figma-canon/references/handoff-format.md#project-locale-and-sample-namesfigma-canon/references/handoff-format.md#reports--comms and "Self-corrections in reports" in figma-canon/references/ai-slop-signatures.md' and "findAll(section, n => n.type === "TEXT" && (n.characters.includes("\u2014") || /[\u2019\u2018\u201C\u201D]/.test(n.characters)))
findAll(section, fn) above is shorthand. In the Plugin API it is section.findAll(fn).const re = /[\u2014\u2018\u2019\u201C\u201D]/;
const section = await figma.getNodeByIdAsync("123:456"); // the section's node id
const nodes = [section, ...section.findAll(() => true)];
return nodes
.filter(n => re.test(n.name) || ("description" in n && re.test(n.description || "")))
.map(n => ({ id: n.id, name: n.name }));
figma-canon/references/state-coverage.md#16181D, stroke #2A2E37, title #FFFFFF, body #C4C8D0Why: / Edge: prefixes (for example a green and an amber). With no project accent, use #E5484D (configurable) for the label. With no second accent, reuse the label accent for the prefixes, as figma-canon/references/handoff-format.md specifies.HandoffNote component instance (NOT raw frames). No prebuilt component ships with these skills: if the file has no annotation component, build one once from the spec in figma-canon/references/handoff-format.md, then reuse instancesWhen [trigger], [outcome]. (a human sentence: subject + verb + condition)figma-canon/references/handoff-format.md#annotation-pattern-cross-project-canon-2026-05-25The single most-repeated miss (field note, 2026-05: a developer saw an "add" action drawn and had to ask how removing would work). The developer builds exactly what is drawn: every visual action needs its outcome drawn, or the developer has to guess.
findAll every interactive element: buttons, CTAs, icon buttons, info/help (i) icons, toggles, radio/checkbox rows, list rows (tappable), chips, links, kebab/overflow menus, swipe affordances, FABs. List them.
screen.findAll(n => n.reactions && n.reactions.length > 0) (reactions live on nested children, not on the screen frame root: see "Prototype reads" in figma-canon/references/plugin-api-anomalies.md). Then walk the screen for the element types above that are drawn but not wired, by layer and component names and by eye. An unwired control is exactly what this check hunts.figma-preflight ("Cross-screen flow") cross-checks the same screens for dangling CTAs and dead ends.(i) / ? / help affordance MUST open a designed info screen or sheet (not a dangling icon).This is mechanical on purpose: it removes reliance on "remembering to design the whole flow". Run it as the LAST gate check before declaring the handoff done.
Calibrated on a client handoff (field note, 2026-07). Rule: nothing in a delivered handoff may look machine-made; every surface must read as hand-crafted. In a file that a client, owner or external stakeholder will open:
figma-canon/references/plugin-api-core.md): frame.layoutGrids = frame.layoutGrids.map(g => ({ ...g, visible: false })).page.findAllWithCriteria({ types: ["TEXT"] }) and match them against a term list (ChatGPT, GPT, adversarial, fix list, sprint, QA, external review, prompt, plus the names of the AI tools, skills and pipelines your own process used), then triage the hits by hand. On a large page, raise the figma_execute timeout (default 5000 ms, maximum 30000 ms). Watch for false positives: "This is a prompt message." is the prompt slot of an iOS navigation bar, and a place name can contain "AI" as a substring ("Mumbai").The checks above measure STRUCTURE. None of them measures USE, and all of them inherit the scale of the artifact you looked at. On one delivery of an options board, figma-slop-check (both lenses), this gate and a flow-graph audit (such as the audit mode of figma-preflight) all came back green, and four real defects survived.
17a. Proof of a small element is a capture of the NODE, at scale >= 2x. The send button of a composer was an empty ellipse, with no icon, on 16 screens. It had been checked several times on a render of the whole section scaled down to 40%, where 36px becomes a colored dot. Rule: list the elements under ~48px that you created or cloned (send button, chip, badge, toggle, avatar, icon) and capture ONE of each type in isolation, at 2x or more: figma_capture_screenshot with that element's nodeId and scale set to 2 or higher. A container render does not judge a small element.
17b. An entry point is not wiring. Wiring between frames and reachability are one axis. The starting point of the prototype is another. A perfectly connected graph can open on a random screen when the stakeholder presses Present. Before writing "clickable" or "you can walk through it", run:
figma.currentPage.flowStartingPoints.map(f => f.nodeId)
and confirm that the screens you are going to present are in the result. Flow starting points belong to a page, and figma.currentPage is whatever page is active, which another session or the designer can switch. Make sure the page that holds the prototype is the active one first (re-assert it from a known node, as in "findAllWithCriteria runs on figma.currentPage" in figma-canon/references/plugin-api-anomalies.md).
17c. Simulate the recipient, in writing. Before sending, answer as the recipient:
PASS figma-handoff-gate: all 17 checks clear. Handoff ship-ready.
Section: <section name>
Frames: <N>
Components used: <N>
Last verified: <timestamp>
Action -> outcome map:
<action> -> <frame name> (<node-id>)
...
FAIL figma-handoff-gate: <N> issue(s) before ship:
[BLOCKER] 1. <issue> -> location <node-id> -> apply-fix: <command>
[WARN] 2. <issue> -> location <node-id> -> fix: <description>
...
Action -> outcome map:
<action> -> <frame name> (<node-id>)
<action> -> ORPHAN
...
Run apply-fix commands OR address manually, then re-invoke gate.
Either result carries the action -> outcome map from check 15. Each orphan action is a [BLOCKER], never a [WARN].
For automated fixes, the gate emits explicit commands like:
figma_execute: set frame "01-home" gap to 80pxfigma_execute: rebind caption-body from FILL-in-HUG to AUTO+FILLThese are plain-language fix descriptions addressed to figma_execute, not tool syntax: figma_execute takes Plugin API JavaScript. At apply time, write that code for the approved fix.
The user approves each fix before execution. NO mass mutation. An approved fix is a write to the file, so it goes through figma-preflight like any other figma_execute write.
If frames are mutated AFTER a gate pass, re-run the gate before re-declaring done.
figma-slop-check: runs BEFORE this gate (machine-made tells and precision pass first)figma-canon: this gate reads figma-canon/references/handoff-format.md (every check) + figma-canon/references/ai-slop-signatures.md (checks 5 and 10: "Hype copy ban" and "Self-corrections in reports")figma-preflight: gates every approved apply-fix write, and its audit mode cross-checks check 15figma-slop-check. If such a workflow exists, it writes component descriptions and this gate does not. Either way, this gate validates frame layout and spec cards, and check 11 sweeps descriptions for dashes and curly quotes