算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
figma-bridge【设计与创意】Expert guide for the figma-bridge MCP (vladmdgolam/figma-mcp-bridge): reading live Figma files through the plugin without API rate limits, and keeping responses small enough to fit in context. Activate when: (1) any mcp__figma-bridge__* tool is about to be used, (2) the user says 'see figma bridge', 'I selected it in Figma', 'check the figma', 'match…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Read and edit live Figma files through the figma-bridge MCP (plugin + local server, no Figma REST API, no rate limits). This skill exists because in real sessions 20% of bridge calls failed, and almost every failure was one of six avoidable mistakes listed under Troubleshooting.
Not the same as Framelink (figma-context-mcp skill, REST API, 6 req/month on free plans). Use the bridge whenever the plugin can be opened in the file. Fall back to Framelink only for files you cannot open in Figma.
list_files first, then pass fileKey everywherelist_files before anything else. It never fails and returns [{fileKey, fileName}] for every file where the plugin is open.fileName matches the task and pass fileKey on every subsequent call. Omitting it is the error "Multiple files connected. Specify a fileKey".fileKey for cloud files is the id in the URL: figma.com/design/<fileKey>/<name>. Locally unsaved files get keys like unsaved-ms7tl1kp-… that change when the file is reopened. When you see "No plugin connected for fileKey", rerun list_files and use the key it prints.Responses over the context limit are not returned; Claude Code dumps them to a file and you get an error. Server builds from 2026-09-07 on default get_document and get_selection to depth 2 and genuinely honor depth on get_node (it was accepted and ignored before, which is why these calls used to overflow). Truncated levels come back as {id,name,type} stubs with childCount and truncated: true. On an older build, assume every read is unbounded and lean harder on find_nodes.
Use this order:
get_design_context({depth: 2, fileKey}). Returns the current selection if there is one, else the current page, depth-limited. This is how you learn what the user selected and get the node ids. Keep depth ≤ 3.find_nodes({root, name | regex, type, limit, fileKey}) returns lightweight {id, name, type} rows without serializing subtrees. Scope with root whenever you have a parent id. Or get_node_by_path({path: "Hero/Card/Title"}) for a readable address that survives file revisions.get_node({nodeId, depth, fields, fileKey}). Default depth: 0 returns the node with children as {id,name,type} stubs; raise depth one level at a time. Combine depth: 1 or 2 with fields to get exactly what you need. Projections that worked well in practice:
["characters","styles.fontSize","styles.fontFamily","styles.fontStyle","styles.fontWeight","styles.lineHeight"]["bounds","children.bounds","children.name"]["styles.fills","styles.strokes","children.styles.fills"]["styles.visible","styles.opacity"]
Omitted style fields are Figma defaults (opacity 1, visible true, cornerRadius 0, empty fills = none).save_children_json({parentId, outputDir, filenamePattern: "{name}.json"}) writes one JSON file per direct child, then grep or jq the files instead of pulling them through context.get_selection and get_document are fine at their depth-2 default. Raising their depth on a large page is still the fastest way to blow the context budget.If a result still overflows, the error names the dump path under ~/.claude/projects/…. Read that file with grep or a short Python snippet. Do not re-issue the same call with a bigger depth.
get_screenshot({nodeIds: [id], scale: 2, fileKey}) writes a PNG to a temp dir and returns {path, width, height}. Read the returned path with the Read tool to actually see it. Use isolate: true to hide siblings for a clean capture of one node.outputPath accepts exactly one nodeId, the extension must match format (or omit format and let the extension decide), and the path must be inside the bridge server's working directory (see Troubleshooting). When unsure, skip outputPath, take the temp path, and cp it where you want.save_screenshots({items: [{nodeId, outputPath}, …], format: "PNG", scale: 2, fileKey}).image_fill_export({imageHash}) turns an IMAGE paint hash from get_node into real PNG bytes.When the user says "see figma bridge, I selected it":
list_files → get_design_context({depth: 2}) to get the selected frame ids and names.get_screenshot of the selected frame and Read it. Now you know what it should look like.get_node with fields on the specific children you are implementing (text specs, bounds, fills). Do not fetch the whole subtree.set_*, create_*, reparent_nodes, group_nodes, duplicate_nodes) only work when the plugin is open in the design editor. Dev Mode is read-only and returns a clear error.delete_nodes requires confirm: true. Ask the user before deleting.create_text defaults to Inter Regular; pass fontFamily/fontStyle explicitly. Text edits auto-load the fonts already on the node.create_image with a relative source resolves against the server cwd; pass an absolute path.set_selection({nodeIds}) then scroll_and_zoom_into_view({nodeIds}). Both work in Dev Mode.6270:81. The hyphen form from Figma URLs (node-id=6270-81) is normalised server-side, so either works. Instance children look like I12740:17806;12740:17793.find_nodes or get_node_by_path; do not guess neighbouring ids.User says: "the gradient panel looks off, see figma bridge, i've selected the right one"
Actions:
list_files → one file, fileKey: "AbC123".get_design_context({depth: 2, fileKey}) → selected frame Gradient editor id 6513:1101 with children Swatches, Stops, Footer.get_screenshot({nodeIds: ["6513:1101"], scale: 2, fileKey}) → Read the PNG.get_node({nodeId: "6513:1101", depth: 2, fields: ["bounds","children.bounds","children.name","children.styles.fills"], fileKey}).find_nodes({root: "6513:1101", type: "TEXT", fileKey}) then get_node on each with the text-spec projection.Result: Two bridge calls carried the whole spec; no overflow, no guessing.
User says: "export all the slides in the Deck frame as pngs into ./export"
Actions:
list_files; find_nodes({name: "Deck", type: "FRAME", limit: 5, fileKey}) → 120:4.get_node({nodeId: "120:4", depth: 0, fileKey}) → child stubs.save_screenshots({items: children.map(c => ({nodeId: c.id, outputPath: "<abs cwd>/export/" + c.name + ".png"})), format: "PNG", scale: 2, fileKey}).cp -R afterwards.Result: One call per batch, files on disk, nothing base64 in context.
Cause: A read returned more than fits in context, usually an explicit high depth on a big frame. Historically the top failure, because depth was ignored server-side; fixed 2026-09-07.
Fix: Read the saved file with grep if you only need one value. Otherwise drop back to the ladder in Step 2 and add fields. If a plain get_node({depth: 0}) still overflows, the Figma plugin is running an old build — rebuild plugin/ and reopen it.
Cause: Written files are confined to the bridge server's process.cwd(), which belongs to whichever client started the leader on port 1994; later sessions proxy through it. The error prints the real root.
Fix: Write inside the printed root and move the file, or omit outputPath and use the returned temp path. Permanently: set FIGMA_BRIDGE_OUTPUT_ROOT on the server. To reset the leader, lsof -i :1994 and close the session holding it.
Cause: The plugin is not open in that file, Figma is in the background with the plugin closed, or the leader process died.
Fix: list_files. If empty, ask the user to reopen the plugin. Do not retry the failing call more than once.
Cause: Stale key, usually an unsaved-… id from a file that was reopened. With exactly one file connected the server now falls back to it, so this only fires when several are open.
Fix: Use the key listed in the error, or rerun list_files.
Cause: find_nodes.regex is a JavaScript RegExp, so Python-style constructs fail. A leading (?i) is now lifted onto the flags automatically; anything else Python-only still throws.
Fix: Use name for a case-insensitive substring match, or rewrite with character classes.
Cause: Id from a previous file revision, a different page, or a different connected file.
Fix: find_nodes by name under a known root, or get_node_by_path. Check fileKey.
Fix: Let the extension pick the format and pass one nodeId; use save_screenshots for several nodes. WEBP needs cwebp on PATH.
Fix: Ask the user to switch the file out of Dev Mode; the plugin must run in the design editor for writes.