Skip to content
Back to skills

Figma Ops

ASecurity

Router and composition workflows for Figma via the official Figma MCP: which Figma skill/tool for which job, capture-to-canvas (screenshots or shotcraft crops into a Figma file), moodboard and reference-board composition (grid, plus, loose-plus arrangements with a deterministic layout planner), canvas craft rules the API skills don't cover, and multi-account routing. Triggers on: figma, moodboard, brand board, reference board, put these screenshots in figma, compose in figma, arrange images i...

  • 50 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 22, 2026
ai-agentsgoswiftbashnodeexpressapifrontend

Works with

  • claude code
  • terminal
  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 15 files and shows the line behind each finding

Scanned September 22, 2026

npx -y skills add 0xDarkMatter/claude-mods --skill figma-ops --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Figma Ops?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Figma Ops
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/0xdarkmatter-figma-ops/badge)](https://www.skillsdirectory.com/skills/0xdarkmatter-figma-ops)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: figma-ops
description: "Router and composition workflows for Figma via the official Figma MCP: which Figma skill/tool for which job, capture-to-canvas (screenshots or shotcraft crops into a Figma file), moodboard and reference-board composition (grid, plus, loose-plus arrangements with a deterministic layout planner), canvas craft rules the API skills don't cover, and multi-account routing. Triggers on: figma, moodboard, brand board, reference board, put these screenshots in figma, compose in figma, arrange images in figma, plus arrangement, which figma skill, figma account, upload to figma, delete figma page."
license: MIT
when_to_use: "Any Figma request that isn't obviously a single official skill's job: 'put these screenshots in Figma', 'make a moodboard from these references', 'arrange this more organically', 'which Figma skill do I use for X', 'it says I don't have edit access', 'this file is in my other Figma account', 'delete the old pages'."
argument-hint: "[route|compose|verify] [figma-url]"
compatibility: "Official Figma MCP server (Claude Code figma plugin) for canvas work; Node 18+ for scripts/*.mjs; shotcraft optional for live-site capture"
allowed-tools: "Read Write Bash Glob Grep AskUserQuestion"
metadata:
  author: claude-mods
  related-skills: color-ops, icon-ops, frontend-design
---

# 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](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.

```bash
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](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:

```bash
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](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](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:

```json
{ "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](references/moodboard-composition.md) — the three
  patterns with coordinates, grouping logic, and what each round taught.
- [references/capture-to-canvas.md](references/capture-to-canvas.md) — shotcraft →
  upload → true-AR placement, end to end, with the dimension reader.
- [references/skill-map.md](references/skill-map.md) — the official + community Figma
  skill landscape and what this skill deliberately leaves to them.
- [references/lessons.md](references/lessons.md) — the session log this skill was
  distilled from, kept as evidence for the rules in §6.
- [references/place-and-verify.md](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.

Files in this skill

  • SKILL.md16.6 KB
  • assets/light-board.example.json2.6 KB
  • assets/plus-layout.example.json1.8 KB
  • references/capture-to-canvas.md4.2 KB
  • references/lessons.md4 KB
  • references/moodboard-composition.md4.4 KB
  • references/place-and-verify.md4.4 KB
  • references/skill-map.md4.8 KB
  • scripts/emit-placement.mjs7.8 KB
  • scripts/plan-layout.mjs13.5 KB
  • scripts/stage-assets.mjs10.2 KB
  • scripts/verify-board.mjs6.9 KB
  • scripts/verify-freshness.mjs6.1 KB
  • tests/check-invariants.mjs2.3 KB
  • tests/run.sh13.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…