SuperAPI AI Directory

figma-ops

Design & creation

View repository

Updated 10-15 12:35

About this skill

Figma Operations

The front door for Figma work. The official Figma plugin ships eleven skills that own the Plugin API surface; the community ships fifty more for tokens, components, a11y and docs. This skill does not replicate any of them. It does three things they don't:

  1. Routes — says which skill or tool to load for a given job (§1).
  2. Composes — capture → curate → arrange workflows for moodboards, reference boards and any "put these images in Figma, beautifully" request (§3–§5).
  3. Guards — the canvas craft rules that sit above the API rules: aspect ratio, z-order, overlap budgets, verification loops, page hygiene (§6).

Always load figma-use before any use_figma call. It is the source of truth for the Plugin API and its gotchas. This skill assumes it is loaded and cites its references rather than restating them.

1. Router — which skill for which job

The job Load Tool it wraps
Any script that mutates or reads the canvas figma-use (mandatory prerequisite) use_figma
Design → code, implement a screen the design-to-code guidance served as MCP resource skill://figma/figma-design-to-code/SKILL.md (not a plugin skill) get_design_context, get_screenshot
SwiftUI ↔ Figma, either direction figma-swiftui get_design_context, use_figma
Build a page/screen from app code figma-generate-design + figma-use use_figma, generate_figma_design
Tokens, variables, component library figma-generate-library + figma-use use_figma, search_design_system
Map components to code figma-code-connect Code Connect tools
New blank file figma-create-new-file create_new_file
Mermaid-class diagram in FigJam figma-generate-diagram generate_diagram
FigJam board content figma-use-figjam + figma-use use_figma
Slides deck figma-use-slides + figma-use use_figma
Motion / animation figma-use-motion, figma-implement-motion use_figma, get_motion_context
Images or SVGs into a file this skill §4 upload_assets
Moodboard, reference board, composed arrangement this skill §3–§5 upload_assets + use_figma
Live-site captures as source imagery shotcraft → this skill §4 —
Design-token export/import, a11y audits, variable CRUD community skills — see references/skill-map.md varies

Two routing rules the tables can't express:

  • A read-only inspection comes first, always. Pages, existing frames, fonts, naming conventions. figma-use §9 has the scripts. Never create before you have looked.
  • get_metadata needs editor access, not viewer. "You don't have edit access" on a file you can open in the browser means the share is view-only. Ask for editor, or check you are on the right account (§2).

2. Multi-account routing

One Figma OAuth token binds to exactly one Figma account. If the user belongs to more than one org (agency + client, personal + work), the correct setup is one MCP server per account — typically the plugin server for one and a claude.ai connector for the other. They expose separate tool namespaces; pick the account per call by prefix.

  • Confirm identity with whoami on each server before assuming which file it can see.
  • Do not consolidate to one server: every account switch would become an interactive OAuth re-auth, impossible from a non-interactive session.
  • The durable fact is mechanism → account (plugin = X, connector = Y). Connector UUIDs change on re-add — never key notes on them.
  • A View-only team seat fails the same way as a view-only share. whoami lists seats.

3. Composition workflow — capture → curate → compose

The phases, each with an exit gate. Post a short checklist before each phase and a summary after (the phase contract in figma-generate-library §1 is the model — visible progress, decisions surfaced, never silently defaulting).

Phase Output Exit gate
0 Brief Sources list, art direction (2–3 sentences), palette/vocabulary if any, target file + page User has confirmed the source list; blockers named (attached-not-sent images, login-walled sites)
1 Capture Screenshots / section crops / user-supplied images on disk, at true pixel dimensions Every file exists; dimensions read from the file header, not assumed
2 Curate Shortlist with one line per image saying what it contributes Every image has been looked at by the agent. Unvetted images never enter a composition
3 Upload Nodes in the target file, named after their source files Node IDs returned and recorded (§7 ledger)
4 Arrange Images resized to true aspect ratio and placed per a chosen pattern (§5) Screenshot reviewed; collisions and defects fixed before adding chrome
5 Dress Typography, hairlines, marks, labels — only what the brief's vocabulary calls for Second screenshot; nothing overlaps text; single accent rule honoured if one exists
6 Hand back Rendered PNG sent to the user; page name; what was left open The user sees the render, not just a description of it

Hard gates:

  • No use_figma mutation before Phase 0's source list is confirmed.
  • No image placed before it has been opened and looked at (Phase 2). The gate exists because the mistakes that slip through are obvious to eyes and invisible to exit codes.
  • No chrome (labels, rules, marks) before the bare arrangement screenshot is clean.
  • Build on a new page; never restructure the user's existing page in place. Deleting the old pages is a separate, explicit request (§6).

4. Capture → canvas

Sources. Three kinds, in rising order of value for a moodboard:

  1. Full-page screenshots — good for scroll strips, bad for boards (a 16,000px strip compressed to board width is an unreadable column; use the viewport shot instead).
  2. Section crops — the useful unit. shotcraft's probe-sections.mjs finds them structurally; capture.mjs with elements[]/scrollTo takes targeted ones.
  3. Designed comps the user supplies — usually the strongest material; these are the aesthetic executed, not referenced.

Stage first. scripts/stage-assets.mjs takes a folder and/or a shortlist, copies each image to a staging directory under a meaningful slug (07-ref-collected-system.png, never IMG_0997.PNG — the filename becomes the Figma layer name on upload), reads true pixel dimensions from the file header, and emits the planner's input JSON. It exits 10 until every image has a subject (--names) and an arm (--arms): the grouping is a human decision and the script refuses to guess it.

node scripts/stage-assets.mjs --list shortlist.txt --dir ./refs --out ./staged \
  --names names.json --arms arms.json --json > board.json

Upload. upload_assets with count: N, then POST each staged file as multipart/form-data with a file field. Record the returned placedOnNodeId per file into board.json's id fields (§7 ledger).

The 400×300 trap. Uploaded images land as 400×300 frames with scaleMode: FILL, which crops. The frame tells you nothing about the image; only the header does. resize() every frame to the planner's w×h before placing it.

Uploads land on whichever page is current for the upload tool — not necessarily the page your last script switched to. Find them by ID and appendChild them where they belong.

5. Arrangement patterns

Three patterns, in the order a session usually discovers them. Details, coordinates and the reasoning behind each choice live in references/moodboard-composition.md.

Pattern When Character
Column grid Reference sheet, equal-weight items, "make it aligned" 3 columns + 2-col spans; every rotation 0; captions left-aligned to column
Rigid plus Groups have a meaning along each axis (medium ↑↓, temperature ←→) Four arms from a centre element, ring sizes stepping ~0.72× outward, axes drawn as hairlines with terminal dots
Loose plus "Organic", "clustered around the centre", "loosely a plus" Same grouping, axes removed, inner ring overlapping the centre by ~40px and nudged off-axis, second ring tucked onto the inner ring's corners (≤ 250×80), wordmark floating in the eye

Rules that held across all three:

  • Rotation is opt-in. Zero degrees unless the user asks for angles; "organic" means offset and overlap, not tilt.
  • Group by what images share — type, aesthetic, or colour — and let the axes mean something. A plus with arbitrary arms is just a cross.
  • Sizes step toward the centre. Largest adjacent to the centre, ~0.72× per ring.
  • Overlap has a budget. Inner ring onto centre ≤ 40px; neighbour corners ≤ 250×80. The planner reports every overlap and exits 10 when one exceeds budget.
  • A centre element is allowed to be typographic. The brand at the centre of its influences reads better than a borrowed image there — but once images overlap it, strip its chrome (strokes, ticks, metadata) or it reads as a broken box.
  • Vocabulary in the quadrants or corners, never in the cluster.

Plan coordinates with the script rather than by hand, and generate the placement script rather than typing it:

node scripts/plan-layout.mjs --input board.json --mode loose --jitter 24 --seed 7 --json > plan.json
node scripts/emit-placement.mjs --plan plan.json --phase backdrop            # → use_figma
node scripts/emit-placement.mjs --plan plan.json --phase place --backdrop 45:2 --captions

plan-layout emits backdrop-relative {id, x, y, w, h} placements in z-order, canvas size, and an overlap report (exit 10 over budget). --jitter adds seeded irregularity for "organic" without losing reproducibility — same seed, same plan. emit-placement turns the plan into the exact use_figma script, and refuses any image whose plan entry is vetted: false — the look-at-it gate as data, not memory. Full flow in references/place-and-verify.md.

6. Canvas craft rules (above the API)

Learned the expensive way; each one cost a round-trip this skill now saves.

  • Hairline stroke on every dark image. A dark site on a dark ground disappears; a 1px SOFT 45–55% stroke, strokeAlign: OUTSIDE, defines the edge. Check fills before concluding an image "didn't render".
  • Z-order is append order. Anything that overlaps must be appended after what it sits on. Send axis lines to the back with insertChild(0, …).
  • Font style names are per-family, verify them. Inter uses "Semi Bold"; Archivo uses "SemiBold". listAvailableFontsAsync() first, always.
  • Load fonts before any text property, including textAlignHorizontal on an existing node. Scripts are atomic — a font error means nothing ran, so fix and retry safely (figma-use gotchas: canonical text-edit recipe).
  • Never filter nodes by size to find your marks. width <= 38 also matched the 9px footer squares and moved them 440px. Track IDs; filter by name or ID.
  • Deleting a label deletes only the text. Its leader line and dot stay. Remove the whole triplet, or rebuild all captions after a re-layout rather than nudging.
  • Verify mechanically, then screenshot. Read the board back (the read-only script in references/place-and-verify.md) and run scripts/verify-board.mjs --plan plan.json --board readback.json. It catches what eyes don't: frames still at 400×300, drift, inverted z-order, budget breaches, missing strokes, rotation. Then get_screenshot on the board node at maxDimension 1400–1800 for what programs can't judge: collisions of meaning, stranded chrome, whether it is any good. Node-level screenshots (contentsOnly) are for detail, not verification.
  • Renders go to the user. curl the screenshot URL to design/exports/ and send the file; a description of a board is not a board.
  • Page deletion is explicit and last. Switch currentPage to the survivor first (you cannot remove the current page), clone-don't-move when building alternatives, and remind the user that version history holds the deleted pages.

7. State ledger for long builds

Context gets summarised mid-build. Keep a ledger on disk from Phase 3 onward:

{ "file": "<fileKey>", "page": "44:3", "backdrop": "45:2",
  "images": { "07-ref-collected-system": "44:5" },
  "chrome": { "captions": ["38:2","38:3"], "vocab": ["47:2"] },
  "exports": ["design/exports/board-v3.png"] }

Re-read it at the start of every turn; reconstruct by name (page.query('FRAME[name^=07-]')) if it is missing. Idempotency is by node name — never re-upload an image whose name already exists on the page.

8. Decision forks — ask, don't default

Ask when two arrangements are both defensible and the brief doesn't decide; present each with its cost. Do not ask about things the source decides (an image's aspect ratio, whether a dark image needs a stroke). Rejected work is never built on — if the user says "not jaunty angles", every rotation goes to zero before the next screenshot, not just the new ones.

References

  • references/moodboard-composition.md — the three patterns with coordinates, grouping logic, and what each round taught.
  • references/capture-to-canvas.md — shotcraft → upload → true-AR placement, end to end, with the dimension reader.
  • references/skill-map.md — the official + community Figma skill landscape and what this skill deliberately leaves to them.
  • references/lessons.md — the session log this skill was distilled from, kept as evidence for the rules in §6.
  • references/place-and-verify.md — the last mile: fill in node IDs, emit the two use_figma scripts, read the board back, verify.
  • scripts/stage-assets.mjs — folder/shortlist → slug-named copies + true dimensions → planner JSON (vetted: false by construction). Exits 10 until subjects and arms are supplied.
  • scripts/plan-layout.mjs — deterministic layout planner (grid / plus / loose), seeded --jitter, overlap budget, captions and vetted passed through.
  • scripts/emit-placement.mjs — plan → exact use_figma scripts (backdrop, place, optional captions). Refuses unvetted images.
  • scripts/verify-board.mjs — board read-back vs plan: size, position, rotation, z-order, overlap budget, strokes. Exit 10 with findings.
  • scripts/verify-freshness.mjs — --offline: every skill the router names exists in the local plugin cache; --live: the community index vs skill-map.md.
  • assets/plus-layout.example.json — the real 14-image Agntik fixture.
  • assets/light-board.example.json — a second real fixture (8 light-ground captures, smaller centre, slug IDs, captions) so defaults are validated on more than one board.

The pipeline, end to end: shotcraft (or a folder) → stage-assets → look at every image, set vetted, caption, arm → plan-layout → emit-placement (backdrop) → upload_assets → fill IDs → emit-placement (place) → read back → verify-board → get_screenshot → dress → send the render.