Files
hyperframes/docs/guides/figma.mdx
T
Vance IngallsandClaude Fable 5 566d49382c feat(skills): reroute /figma by capability - REST/CLI for phases 1-3, MCP for 4-5 (M4) (#1873)
* feat(skills): reroute /figma by capability - REST/CLI for phases 1-3, MCP for 4-5 (M4)

Rewrites the skill from MCP-first to the spec 2 split: asset/tokens/
component route through the hyperframes figma CLI (FIGMA_TOKEN), motion/
shaders stay agent-driven over MCP (no REST equivalent). Adds two-
credential guidance, Starter rate-limit tactics (recursive:true, raw-
response cache, opt-in screenshots), the 7.1 binding flow (tokens before
components, one ask per unknown library, never value matching), and the
shader manual-export default. Catalog blurbs updated in lockstep.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(cli): register figma component subcommand

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(skills): add storyboard-to-animatic guidance to /figma

Field-tested against a real 26-scene storyboard section: the parsing
grammar (frame-sized nodes incl. loose rectangles = scenes, x-order =
time order, TEXT below the strip = director notes paired by x-overlap),
batched still export (chunk ~4 ids per render call - big frames timeout
past ~12), a note-verb -> transition vocabulary (EXPLOSION/SLIDE/MORPH/
CYCLE), and the stills-vs-component routing rule for within-scene motion
notes. Catalog blurbs updated in lockstep.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(skills): storyboard frames are keyframes, not slides

Field-tested against a second real storyboard section: frames sharing an
element (matched by name, else geometry similarity) define that element's
states through time - tween the element between states, crossfade only
when pixels genuinely differ, enter/exit unmatched children, tween frame
backgrounds as a color track. Stills demoted to fallback for frames that
don't decompose. Validated live: a 4-frame logo-rise reconstructed as one
element with four keyframes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(figma): self-explanatory first-run experience + mintlify guide

- NO_TOKEN/BAD_TOKEN errors now carry the full one-time setup (mint URL,
  read-only scope checklist, persist hint) instead of a bare pointer
- figma subcommands print clean guidance on typed client errors, not a
  stack trace (shared withFigmaErrors boundary)
- CLI help gains component subcommand, FIRST-TIME SETUP and WHAT TO
  EXPECT blocks
- /figma skill: preflight the token before the first CLI call and walk
  the user through setup up front; narrate landed-artifact + next action
  at every step
- new docs/guides/figma.mdx (setup, per-phase walkthroughs, provenance,
  troubleshooting table) wired into docs.json nav

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(figma): review fixes — missing withFigmaErrors imports, 401/403 semantics, docs accuracy

- tokens.ts/component.ts called withFigmaErrors without importing it
  (tsup doesn't typecheck, so every invocation shipped as an immediate
  ReferenceError); imports added, tsc --noEmit now clean
- error boundary widened to all Errors so bad-ref/bad-format input
  errors print their message instead of a stack trace
- 401 no longer claims 'missing scopes' (figma signals that as 403);
  new FORBIDDEN code maps non-variables 403 to scope/access guidance
- docs: asset/component refs require a node id (bare fileKey is
  tokens-only), example snippet matches real output, FORBIDDEN row
- skill: preflight counts a project-.env token as configured (CLI
  auto-loads it); BAD_TOKEN/FORBIDDEN guidance split

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(cli): present figma errors via standard errorBox

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 19:13:08 -07:00

118 lines
7.0 KiB
Plaintext

---
title: Figma Import
description: "Bring Figma designs into HyperFrames — frozen assets, brand tokens, editable components, storyboard animatics, and Figma Motion timelines translated to GSAP."
---
The work your designer already did in Figma — layout, color, type, motion — becomes the starting point of a composition instead of a thing to rebuild by hand. Point at a Figma URL; the artifact lands as a native HyperFrames piece: a frozen local file, a composition variable, editable HTML, or a paused GSAP timeline.
## What you can import
| Capability | What you get | Surface |
| --- | --- | --- |
| **Static assets** | A frame/layer rendered to SVG/PNG/JPG/PDF, frozen under `.media/` | `hyperframes figma asset` |
| **Brand tokens** | Figma variables/styles as composition brand variables | `hyperframes figma tokens` |
| **Components** | A frame as editable HTML with brand-linked colors | `hyperframes figma component` |
| **Motion** | A Figma Motion timeline as an editable, paused GSAP timeline | `/figma` skill (agent, MCP) |
| **Shaders** | A shader fill/effect as a frozen still or clip | `/figma` skill (agent, MCP) |
| **Storyboards** | A section of scene frames reconstructed as an animatic | `/figma` skill (agent) |
Two transports, split by what Figma exposes: assets, tokens, and components run over the **REST API** (headless, works in CI, generous per-minute rate limits). Motion and shaders exist only on Figma's **MCP server**, so an agent drives those. Every path freezes files locally — **renders never call Figma**.
## One-time setup
The CLI paths need a Figma personal access token in the `FIGMA_TOKEN` environment variable.
<Steps>
<Step title="Mint a token">
In Figma: **Settings → Security → Personal access tokens → Generate new token.**
</Step>
<Step title="Pick read-only scopes">
The integration never writes to Figma — read-only is all it ever needs:
| Scope | Setting | Needed for |
| --- | --- | --- |
| File content | Read-only | assets, components |
| File metadata | Read-only | version tracking, refresh |
| Variables | Read-only | brand variables — **Figma Enterprise only** |
No Enterprise plan? Skip the Variables scope — `tokens` automatically falls back to your published styles. That's expected behavior, not an error.
</Step>
<Step title="Export it">
```bash
export FIGMA_TOKEN="figd_…"
```
Add the line to your shell profile or the project's `.env` so future sessions skip this step. The same token covers every Figma file your account can view.
</Step>
</Steps>
Motion and shader import use the **Figma MCP connector** instead — a one-click OAuth from your agent, separate from the token. Connect it when your agent asks; no scopes to configure.
## Import an asset
```bash
hyperframes figma asset 'https://www.figma.com/design/KEY/Title?node-id=1-2'
```
The node renders over REST, lands frozen under `.media/images/`, and the command prints a ready-to-paste `<img>` snippet:
```text
imported image_007 → .media/images/image_007.svg
<img src=".media/images/image_007.svg" alt="image_007" data-figma-id="1:2" />
```
- `--format svg|png|jpg|pdf` (default `svg`). SVG for logos and vectors — scalable and animatable. `--format png --scale 2` for raster fidelity.
- Accepted refs: a full Figma URL with `?node-id=…` (right-click a layer → Copy link) or `fileKey:nodeId` shorthand. Asset and component imports always target a specific node; only `tokens` takes a bare `fileKey`.
- Idempotent: the manifest records `fileKey:nodeId:format:scale:version`, so re-running reuses the file unless the design actually changed in Figma.
## Pull your brand
```bash
hyperframes figma tokens KEY
```
Reads the file's variables (or published styles), writes a `figma-tokens.json` sidecar plus a binding index, and prints entries for the composition's `data-composition-variables`. Every scene that references a brand role — instead of a hard-coded hex — is on-brand automatically, and stays on-brand when the file changes.
<Tip>
Import tokens **before** components. That's what lets an imported component's colors link to your brand variables instead of baking duplicate literals.
</Tip>
## Import a component
```bash
hyperframes figma component 'https://www.figma.com/design/KEY/Title?node-id=10-20'
```
The frame's node tree becomes editable HTML at exact Figma geometry, packaged under `compositions/components/<name>/`. Vector and boolean-op nodes that don't map to clean HTML auto-rasterize through the asset path.
Colors bound to a Figma variable resolve against your imported tokens:
- Bound to an **imported** token → emitted as `var(--brand-slug, #0066FF)` — a later brand refresh propagates into the component.
- Bound to a token you **haven't imported** → the literal color is used and the element is flagged `data-figma-unresolved`. The command tells you; run `tokens` on the source (or library) file and re-import to link them.
Matching is by exact Figma ID only — never by hex value — so a coincidentally-shared color can't create a false brand link.
## Motion, shaders, and storyboards
These run through the `/figma` agent skill:
- **Motion** — a Figma Motion timeline (keyframes, easing, repeats) translates structurally into a paused, finite GSAP timeline registered on `window.__timelines`, seekable frame-by-frame like any hand-authored animation, and editable afterward. Tracks that can't translate faithfully fall back to a baked video clip — the agent tells you which path it took and why.
- **Shaders** — Figma's export path doesn't execute shaders, so the default is a native Figma export (PNG or Motion MP4) imported as an asset/clip.
- **Storyboards** — a section of scene frames is decoded, not slideshowed: frames sharing an element are treated as that element's keyframes over time, diffed into element chains and tweened, with text under the strip read as director notes. See the `/figma` skill for the full grammar.
## Provenance and refresh
Every import records where it came from (`fileKey`, `nodeId`, `version`) in `.media/manifest.jsonl`. Nothing in a rendered composition points at Figma — assets are files, tokens are variables, motion is a timeline. When the Figma file moves on, re-running the same import commands re-pulls only what changed.
## Troubleshooting
| Error | Meaning | Fix |
| --- | --- | --- |
| `NO_TOKEN` | `FIGMA_TOKEN` unset | Follow [One-time setup](#one-time-setup) |
| `BAD_TOKEN` (401) | Token expired or revoked | Re-mint the token |
| `FORBIDDEN` (403) | Token missing a read scope, or no access to the file | Check the read-only scopes above and file visibility |
| `REQUIRES_ENTERPRISE` (403) | Variables API needs Figma Enterprise | Not a failure — the styles fallback already ran |
| `RATE_LIMITED` (429) | REST per-minute budget hit | Wait a minute and retry; chunk batch renders |
| "Render timeout" on batch export | Too many large frames in one `/v1/images` call | Chunk to ~4 ids per call |
| `ref has no node id` | Link points at a file, not a node | Copy the link with `?node-id=…` (right-click layer → Copy link) |