算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
figma-preflight【设计与创意】Mandatory read-only gate that runs before any write to a Figma file, through figma_execute (figma-console MCP) or use_figma (official Figma MCP). Runs 8 checks in order (live connection, confirmed target node-id, metadata, variables, design system and icon search, canon references, state coverage, file lock) and either approves the write or returns a…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Mandatory pre-write checklist. Blocks the write (figma_execute, or use_figma on path B of
Check 0) until all checks pass.
This skill is a gate. It approves the write or returns a fix list. It never mutates the canvas.
figma_execute tool (Desktop Bridge)use_figma toolfigma_execute, figma_get_status, and every other
figma_* tool named here.get_metadata, get_variable_defs, search_design_system,
whoami, use_figma.Checks 1 to 4 name the official server's read tools. When only figma-console is connected, read the same kind of data with its own tools. These are alternatives, not one-to-one equivalents: the output shapes differ.
| Check | Official Figma MCP tool | figma-console alternative |
|---|---|---|
| 1, 2 | get_metadata | figma_get_file_data, figma_get_file_for_plugin, figma_get_selection (for the active selection) |
| 3 | get_variable_defs | figma_get_variables, figma_get_token_values, figma_get_styles, figma_get_text_styles |
| 4 | search_design_system | figma_search_components, figma_get_library_components, figma_get_design_system_summary |
Run all 8 in order (Check 0 to Check 7). Each must pass before the next runs. Fails closed (blocks the write).
Two paths pass this check. Only an MCP call proves the connection: a shell command NEVER does.
figma_get_status with
probe:true, returning setup.valid=true plus the correct connectedFile. A shell command
cannot attest that the plugin is paired: ports 9223 to 9232 are a pure WebSocket with no HTTP
endpoint (field note, 2026-08). Write path: figma_execute through the Desktop Bridge.whoami plus a successful
get_metadata on the target (that call also satisfies Check 2). Write path: use_figma. Path B
is not validated by this repo: keep writes small, read back every change. Follow the official
server's own instructions for use_figma.figma-bridge-doctor/scripts/figma-status.sh (in the figma-bridge-doctor skill's scripts/
directory, macOS only; in Claude Code run it as
bash "${CLAUDE_SKILL_DIR}/../figma-bridge-doctor/scripts/figma-status.sh", which needs that skill
installed next to this one) is LOCAL evidence only: Figma is running, servers are listening. By
design it does not report pairing (it prints current_file_pairing=ask_figma_get_status). Use
it for diagnosis, not as a verdict.figma-bridge-doctor skill: when figma-console is installed, try it before you fall back to
path B.Advisory pre-check A0 (optional, path A; path B already runs it): Call
whoami(official Figma MCP server) once per session if you do not know which seat the connected account holds OR you are writing to a file you do not own. A seat mismatch (for example a Dev seat writing to a published library) fails loudly with a permission error, so this is an early feedback convenience, not a silent failure preventer. Skip for: a solo developer on personal drafts, sessions where you already know the seat, or when you are on the Starter plan's MCP tool call budget. The 7 hard checks below cover the silent failures.
get_metadata and ask the user to disambiguate.get_metadata been called on the target page or frame in this session?get_metadata now and parse the structure.get_variable_defs MUST have been called on the relevant scope.Will the write create a frame or component that COULD be an existing component?
If YES: search_design_system MUST have been run with a relevant query.
Block "new Button" / "new Card" / "new Input" writes if the search was not run.
ICONS / ILLUSTRATIONS (anti-hallucination, field note, 2026-06): NEVER hand-draw an icon
(createNodeFromSvg with invented geometry) before checking what the design ALREADY has. Two
sources to scan FIRST:
lucide-react-native import name, a require('../assets/icons/calendar.png') asset, or an
SVG file.Match the app's REAL icon. A tab bar that uses brand PNG icons must use those assets or their componentized equivalents, never a generic geometric calendar, trophy or user that you drew. If a needed icon has no component, use the real asset (image fill) and FLAG the library gap. Never substitute a look-alike you invented. Block any icon-bearing write where neither the icon library nor the app asset was checked.
The WHOLE feature, not only the node you are about to write (field note, 2026-08). The check
above is per write, and that is how one feature accumulated dozens of hand-drawn icons under
many different names across several sessions: each individual write looked innocent. When you enter a
feature that ALREADY EXISTS, run an adherence sweep before you start: count the nodes with an icon
name (icon-* or its equivalent in the file's language, for example icone-* in Portuguese;
spinner-*; a glyph in a TEXT node) that are NOT a library instance. If the number is not zero,
that is debt to report at the start, not to discover when the designer points at it. The same
sweep closes the work: zero ad hoc icons on the page is the proof. "I replaced N icons" is not.
figma-canon/references/):
plugin-api-core.md + figma-execute-atomicity.md + auto-layout-canon.mdplugin-api-data.mdplugin-api-anomalies.md (for a 429 lockout it points on to rate-limit-recovery.md)state-coverage.md + ai-slop-signatures.md +
naming-canon.mdhandoff-format.mdfigma-canon/references/state-coverage.md.One Figma file has one writer at a time. The lock script is
scripts/figma_lock.py in this skill (Python 3, standard library only).
The commands below call it as "${CLAUDE_SKILL_DIR}/scripts/figma_lock.py". Claude Code replaces
${CLAUDE_SKILL_DIR} with this skill's directory (the folder that holds this file) when it loads
the skill. Other agents: if the text still shows ${CLAUDE_SKILL_DIR}, put the absolute path of
that folder in its place; never run a command with the variable empty.
python3 "${CLAUDE_SKILL_DIR}/scripts/figma_lock.py" claim <fileKey> --agent <agent> --task <task> [--ttl 1800]
python3 "${CLAUDE_SKILL_DIR}/scripts/figma_lock.py" check <fileKey>
python3 "${CLAUDE_SKILL_DIR}/scripts/figma_lock.py" release <fileKey> --agent <agent> --task <task>
python3 "${CLAUDE_SKILL_DIR}/scripts/figma_lock.py" sweep
How the script behaves:
fileKey under ~/.cache/figma-maxxing/locks/ (override with
FIGMA_LOCK_DIR). Every session on the machine must use the same lock directory. A session
with a different FIGMA_LOCK_DIR does not see the others' locks.--ttl in seconds, default 1800), with no PID tracking. A lock tied to
the PID of a transient tool shell dies immediately (agent tool shells exit right after every
command), which is why this lock is TTL based (field note, 2026-08).{"error": "lock directory is busy"}), 2 on a usage error (a fileKey
that is not 1 to 64 letters, digits, _ or -; a --ttl that is not positive; release
without a task). A usage error prints the argparse message, not JSON.check prints {"held": false} or
{"held": true, "agent": ..., "task": ..., "claimed_at": ..., "expires_at": ...}. It always
exits 0 and never reserves the file.claim prints {"claimed": true, "renewed": false, ...} on a fresh claim. A claim by the
same agent and task renews the lock ("renewed": true). A claim on a lock held by someone
else exits 1 and prints the holder: {"claimed": false, "held": true, "agent": ..., ...}.
Expired locks are treated as free.release prints {"released": true, "held": false}. If someone else holds the lock it exits 1
and prints the holder. If nothing is held it prints {"released": false, "held": false} and
exits 0.sweep deletes expired lock files and prints {"swept": <count>}. It is housekeeping only:
an expired lock is already treated as free.--agent defaults to the environment variable FIGMA_LOCK_AGENT, then to the literal agent.
--task defaults to FIGMA_LOCK_TASK. A claim with no task at all gets a generated
adhoc-<uuid> task that you would have to copy from the claim output to release. Always pass
an explicit --agent (for example claude-code) and --task.release --force releases a lock held by another task. It exists for the human, not for the
agent. Never use it yourself.The gate:
fileKey from the Figma URL, figma_get_status, or the figma-map.md written by
figma-orient (default docs/figma-map.md, or the agent's own memory system).python3 "${CLAUDE_SKILL_DIR}/scripts/figma_lock.py" check <fileKey>. A free check does not reserve
the file. Only a successful claim authorizes you to proceed.held=false: claim it with
python3 "${CLAUDE_SKILL_DIR}/scripts/figma_lock.py" claim <fileKey> --agent <agent> --task <task> --ttl 1800.held=true and you ARE the holder (agent and task match): proceed.held=true and you are NOT the holder: BLOCK the write. Surface who holds it and tell the
user to either wait until expires_at or release the conflicting lock manually. Do NOT bypass.finally, on success and on failure alike. In a shell script, use
trap. Keep exactly the same --agent and --task as the claim (or the same
FIGMA_LOCK_AGENT and FIGMA_LOCK_TASK). An abrupt death without cleanup depends on TTL
expiry. Never release the lock of another task.python3 "${CLAUDE_SKILL_DIR}/scripts/figma_lock.py" release <fileKey> --agent <agent> --task <task>.{"error": "lock directory is busy"}) does not declare
the gate broken. Re-test. Only proceed without a lock when
figma-bridge-doctor/scripts/figma-status.sh shows other_sessions_count=0, and flag it in
your reply. That script is macOS only, and it tells this session's MCP server apart from the
others through the agent's process tree (environment variable FIGMA_AGENT_PROCESS, default
claude; see the script's header). Where it cannot run or cannot show
other_sessions_count=0, do not write without a lock: report the script error to the user and
stop.A lock held by someone else normally blocks the write. This exception applies only when BOTH are true:
figma_get_status shows the plugin's currentPage on the holder's page, the task of the
lock names the holder's subject, and every one of your targets is addressed by node-id on
another page.Who may override:
setCurrentPageAsyncfigma-bridge-doctor skill
(section "After reconnecting in a WRITE session: rival-write audit", full text in
figma-bridge-doctor/references/rival-write-audit.md)
on the section you wrote, and report the resultSame page, or no proof that the pages are disjoint, stays BLOCKED. This is NOT a new default of the gate. It codifies two field cases, and the designer can revoke it.
PASS figma-preflight: all 8 checks clear. Proceeding to write.
- Connection: path A, Bridge connected (port 9223) | path B, official MCP (writes via use_figma)
- Target: <node-id> (<name>)
- Metadata: cached <Nm ago>
- Variables: <N> tokens loaded
- DS search: <N> components found
- Canon loaded: <ref list>
- States planned: <state list>
- File lock: held by <agent> task=<task> until <expires_at>
FAIL figma-preflight: <N> gap(s) before write can proceed:
1. <gap description> -> <fix action>
2. ...
Run the fixes, then re-invoke figma-preflight.
The user can override with an explicit:
State the override in your reply, in one line ("preflight skipped on request"), so it stays in the transcript.
After the preflight OK, BEFORE generating any JS for figma_execute (or use_figma on path B):
figma-canon/references/naming-canon.md if there is a new layer.python3 "${CLAUDE_SKILL_DIR}/scripts/figma_lock.py" release <fileKey> --agent <agent> --task <task>. Forgetting to
release blocks future sessions until the TTL expires.figma.currentPage = X assignment, a missing
await on an async call, figma.notify(), setPluginData, createConnector. The optional
precheck hook (hooks/figma-canon-precheck.py at the root of the figma-maxxing repo, opt-in)
flags these patterns. If it fires:
read the message, fix it at the source, do NOT retry blindly.locked (field note, 2026-08). In one large bind sweep
through the figma-console bridge, a handful of binds under a GROUP with locked: true did not
take, with no error, while each node read locked: false. Figma's typings say locked does
not affect plugin writes, and the cause is not established. The check is cheap: in a write that
sweeps a tree, check the chain (for (let p=n; p; p=p.parent) if (p.locked) ...), not only the
target, and rely on the read-back in rule 5 either way.boundVariables[prop][i]. If you created a node, read its id in the
parent. An independent count AFTER the batch, compared against the expected number, is the
only closure that counts.For a NEW SCREEN write (not an edit), after the per-screen checks, answer these before the write:
Read-only. Use it on requests such as "audit the flow", "is there an orphan screen?", "where does this button lead?".
Build the graph of the scope:
reactions[] = wired edgesEmit a punch list. Never mutate the canvas.
figma-canon: this gate reads the relevant refs as part of Check 5.figma_execute (Desktop Bridge) and official use_figma: preflight runs BEFORE
any Figma write.figma-bridge-doctor: owns Bridge recovery when Check 0 fails on path A.figma-orient: preflight uses the orient output as input for Checks 1 and 2.figma-click-flow: the visual arrow overlay is a separate skill. The audit here only analyzes
the graph in memory.