Skip to content
Agentmart
Submit a tool

figma-read

Read a Figma design offline from a .fig export — layer tree, copy, component properties, layout, colors, design-token names, and original vector or raster…

Skill by paulorsv01

IndexedMIT
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/paulorsv01-figma-read

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Read a Figma design offline from a .fig export — layer tree, copy, component properties, layout, colors, design-token names, and original vector or raster assets — without the Figma API or auth. Use when a .fig export or decoded cache exists, when the user shares a .fig file, and on a figma.com/design URL or a request to inspect, read or implement a design, screen, component or frame.

Use cases: design, frontend, backend, security

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found
Runs as
Python package

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/figma-read

What's inside

Skill name
figma-read
Description
Read a Figma design offline from a .fig export — layer tree, copy, component properties, layout, colors, design-token names, and original vector or raster assets — without the Figma API or auth. Use when a .fig export or decoded cache exists, when the user shares a .fig file, and on a figma.com/design URL or a request to inspect, read or implement a design, screen, component or frame.
License
MIT
Instructions
265 lines in SKILL.md · view on GitHub

Before installing

  • Ships executable scripts

Files (32)

  • SKILL.md
  • openai.yaml · agents/
  • asset-context.mjs · scripts/
  • assets.mjs · scripts/
  • decode.mjs · scripts/
  • export.mjs · scripts/
  • fig-source.mjs · scripts/
  • query.py · scripts/
  • raster-assets.mjs · scripts/
  • svg.mjs · scripts/
  • vector-svg.mjs · scripts/
  • skill.toml
  • asset-context.test.mjs · tests/
  • assets-cli.test.mjs · tests/
  • cli.test.mjs · tests/
  • extract-fixtures.mjs · tests/
  • asset-context.mjs · tests/fixtures/
  • dots.bin · tests/fixtures/
  • dots.json · tests/fixtures/
  • dots.svg · tests/fixtures/
  • magnifyingGlass.bin · tests/fixtures/
  • magnifyingGlass.json · tests/fixtures/
  • magnifyingGlass.svg · tests/fixtures/
  • plus.bin · tests/fixtures/
  • plus.json · tests/fixtures/
  • plus.svg · tests/fixtures/
  • quarterNote.bin · tests/fixtures/
  • quarterNote.json · tests/fixtures/
  • quarterNote.svg · tests/fixtures/
  • raster-assets.test.mjs · tests/
  • spec-assets.test.mjs · tests/
  • vector-svg.test.mjs · tests/

SKILL.md (first lines)

# figma-read

Reads a designer-exported `.fig` directly. Everything the Figma inspect panel shows —
component properties, layout, colors, bound design tokens — and its original vector and
raster assets are inside the file.

## When this skill applies

It needs a local `.fig`. A cache or a `.fig` on disk → use it, nothing to ask (the Quick
start below is one command either way: decode is a no-op when the cache is current, and a
purged cache re-decodes itself). Only when **no `.fig` exists at all**, check the recorded
preference with `query.py config`:

- `always` — this skill is the way designs get read here. Ask the user to export
  (**Figma → File → Save local copy**) and where they saved it. Do not fall back.
- `mcp` — use the Figma MCP instead; don't ask for an export.
- `ask` — ask the user which they want this time.
- **unset** — ask once, explain the trade-off, and offer to record the answer with
  `query.py config --set-when-no-fig <always|ask|mcp>` so it isn't asked again.

The trade-off to state when asking: a `.fig` is one manual export that then gives the whole
document offline, with no rate limits and no auth, and stays reusable. The MCP needs no export
but costs a call per node, needs auth, and rate-limits partway through larger reads. The export
is a snapshot, so it goes stale when designers keep working.

## Quick start — one command answers "implement this screen"

The user exports once: **Figma → File → Save local copy**. Then chain decode and query in a
single invocation:

```bash
node <skill>/scripts/decode.mjs "<file.fig>" --url "<figma-url>" && \
python3 <skill>/scripts/query.py spec "<figma-url-or-node-id>"
```

`spec` prints the whole subtree — layout, sizes, colors with token names, copy, fonts,
effects — plus every component it uses, each printed once. Decode is skipped when the cache
is already current, so the chain costs nothing to repeat. If the cache was purged from
`$TMPDIR`, `query.py` re-decodes on its own (disable with `--no-decode`).

**`<skill>` is the absolute directory this `SKILL.md` was loaded from — write it out in full,
every call.** The scripts sit beside this file, not under the working directory: the cwd is the
user's project, and when the skill is installed as a plugin it lives in a cache elsewhere, so a
bare `scripts/query.py` will not exist. A shell variable is no help either — each command runs in
its own shell, so an assignment made in one call is gone by the next.

`decode.mjs` writes its cache under **`$TMPDIR/figma-read/`** — never into the project. Always
pass `--url`: it tags the cache with the file key so any later node URL resolves to the right
design automatically. Use `--out <dir>` if a cache needs to persist; `query.py` reads with
`--dir`. Node ids come from the URL: `node-id=8099-18638` → `8099:18638`; both forms and the
full URL are accepted.

The cache directory is keyed by the `.fig` **path**, so re-exporting the same design to a new
path (Downloads first, then the project) leaves two caches under one file key. `decode.mjs`
says so when it creates the second one, and a query given a URL picks the cache whose `.fig`
is newest, naming its choice and the `--dir` that forces the other. A bare node id still
refuses to guess. Nothing chooses silently.

## Commands

All of these are `python3 <skill>/scripts/query.py …`, abbreviated here to `query.py`.
**Node-taking commands accept batches**, except `export --asset`, which requires one root.

```bash
query.py spec  <node> [<node>…]      # the whole implementable answer — start here
query.py texts <node>                # all copy: TEXT nodes, props AND overrides
query.py inspect <node> [<node>…]    # single-node deep dive (inspect panel + text/effects)
query.py tree  <node> --depth 3      # bare hierarchy when spec is more than needed
query.py find  <regex> --type TEXT   # locate by layer name (auto-loosens spaces)
query.py raw   <node> --fields a,b   # anything not covered above
query.py assets <node> [<node>…] --kind raster  # one line per distinct asset, no asset writes
query.py svg   <node> [<node>…] --current-color  # filled vectors as SVG
query.py export <node> --asset <hash>  # exactly the selected original image, byte-for-byte
query.py list | info | config       # what is decoded / file stats / preference
```

`spec` flags: `--symbols all|direct|none` (default `all` — follow instances into their
components, deduped), `--max-lines N` (default 600; the cut always states the real totals),
`--no-collapse`, `--keep-hidden`.

`svg` re-decodes the original `.fig` once per batch; keep that file available. It writes
one SVG per requested node under `$TMPDIR/figma-read/assets/`, or to `--out <directory>`.
Omit `--current-color` to keep the design's literal color; semantic tokens are retained in
`data-figma-token`. `--current-color` requires a monochrome icon.

Select a filled `VECTOR` or its icon `SYMBOL`/`FRAME`. Containers collect visible vectors,
skip hidden construction subtrees, and warn about multiple vectors or omitted container
paints. Instance overrides, boolean operations, parametric shapes, strokes, gradients,
effects and rounded vector corners are unsupported: select the source component, or
outline/flatten the artwork in Figma and re-export. A vector uses its enclosing frame's
size as the viewBox, preserving padding; normalized geometry is scaled to its node size
before applying transforms. Each region gets its own path: binary `windingRule=0` means
`evenodd`, and `1` means `nonzero`.

## Discovering assets in context

`query.py assets <node-or-url> [<node-or-url>…]` lists the distinct assets of a node without
extracting images or writing asset files. It needs the original `.fig`, decodes once per
batch, and accepts one document per invocation. URLs must match the cache's file key (tag it
with `decode.mjs --url`); `--dir` also accepts plain node IDs.

**Two levels.** The default is the inventory: a count header, then **one line per distinct
asset** — identity, name, type, occurrence count, state, a representative path relative to
the queried root, and the ready `export …--asset <hash>` or `svg <id>` command (or why it
cannot be exported). Evidence is asked for per asset with
`--occurrences <hash|source-id>` (repeatable), which prints that asset's occurrence chains.
This matters: a real section holds 370 distinct assets against 8857 occurrences, so the
default answers "what can I take from here" in ~35 lines where the full evidence was 15k.

Filters: `--kind raster|vector`, `--exportable`, `--name <regex>` (the same matcher as `find`,
including the retry that loosens spaces). `--limit` caps records — and occurrences inside
`--occurrences` — in `find`'s form, with the cut stating the real total. `--json` obeys the
same default, filters and limit; do not reach for it to bypass them.

Two candidates whose exported SVG is byte-identical are **one record**: an icon SYMBOL and
the single VECTOR inside it export the same bytes, so the extra identities are listed as
`= <id>` and stay queryable. A SYMBOL holding two vectors exports both, is not equivalent to
either, and stays a separate record labelled `inside <id>`. The digest decides this per
asset; it is not a rule about types.

From paulorsv01/agents, MIT.

More from paulorsv01/agents

Signals

Stars
0
Forks
0
Open issues
0
Last commit (this folder)
Sep 24, 2026 (1 month ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from paulorsv01

Cite this page

figma-read skill. Agent Mart. https://agentmart.dev/skills/paulorsv01-figma-read (last updated 2026-10-24)