# Figma > Import Figma content into a HyperFrames composition — rendered assets, brand tokens, components, storyboard sections → reconstructed motion (frames read as states, not slides) (REST/CLI), connector-assisted motion when available, and shaders from a connector or native export. Use when the user pastes a figma.com link or asks to bring a Figma design, frame, logo, brand, or animation into a video/composition. Source: https://skillsagentes.com/skills/heygen-com/hyperframes/figma Repository: https://github.com/heygen-com/hyperframes Author: heygen-com License: Apache-2.0 Updated: hace 10 días Context cost: 104 tok installed, 4.5k tok once triggered, 5.8k tok with every bundled file Bundle: 2 files, 23 KB Permissions requested: none declared ## Install ```bash npx -y skills add heygen-com/hyperframes --skill figma --agent claude-code ``` ## What it does - Importa assets, tokens de marca, componentes, movimiento y shaders de Figma a una composición de HyperFrames - Congela cada import como archivo local con procedencia registrada, sin llamadas a Figma en el render - Reconstruye storyboards leyendo frames como estados/keyframes de un elemento, no como diapositivas - Enlaza fills de componentes a variables de marca vía var(--slug) para que el rebranding se propague - Verifica fidelidad estática y de movimiento contra los píxeles/export reales de Figma ## Use it when - El usuario pega un enlace de figma.com - El usuario pide traer un frame, logo, marca o animación de Figma a un video/composición - Se necesita reconstruir una sección de storyboard con frames de escena - Se requiere importar tokens/variables de marca o componentes desde Figma ## What triggers it - "Importa este frame de Figma como componente de la composición" - "Trae los colores de marca de este archivo de Figma" - "Convierte este storyboard de Figma en una animación" - "Usa este logo de Figma como asset en el video" ## Before you install - Requiere un token FIGMA_TOKEN (solo lectura) en el entorno o .env, y opcionalmente un conector de Figma compatible para fases de movimiento y shaders. ## Files - SKILL.md — 18 KB - scripts/verify-motion.mjs — 5 KB ## SKILL.md Reproduced verbatim from heygen-com/hyperframes under Apache-2.0. This section is the upstream document and is in English. > **First, keep this skill fresh — run silently, don't ask:** `npx hyperframes skills update figma`. A fast no-op when everything is current; otherwise it refreshes this skill plus the core domain skills it depends on before you rely on them. # Figma → HyperFrames Bring the user's Figma work into a composition. **Split by capability** (design spec §2): | Phase | What | Transport | Surface | | ----- | ------------------- | ------------------------- | ----------------------------- | | 1 | Static assets | REST | `hyperframes figma asset` | | 2 | Brand tokens/styles | REST | `hyperframes figma tokens` | | 3 | Components → HTML | REST | `hyperframes figma component` | | 4 | Motion → GSAP | connector when available | use its motion context | | 5 | Shaders | connector / manual export | use it or a native export | REST is used wherever it can be (usable at volume, headless). A compatible Figma connector is optional for motion and shader data; without one, ask for a native export. Every path freezes assets locally so renders stay deterministic. Storyboard reconstructions compose Phase-1 asset exports (REST) with agent-driven timeline assembly — no connector needed. Existing frozen assets, manifest records, and bindings are unaffected by routing changes — the split only changes which credential the next import uses. ## Auth — two credentials, scoped **Preflight — before the first CLI call, check a token exists**: shell env (`[ -n "$FIGMA_TOKEN" ]`) **or** the project `.env` (the CLI auto-loads it — a `.env` entry counts as configured). If neither, do NOT run the command to harvest the error — walk the user through the one-time setup first, then stop and wait: 1. figma.com/settings → **Security** → **Personal access tokens** → Generate new token. 2. Scopes — read-only is all this integration ever needs (it never writes to Figma): **File content: Read-only** + **File metadata: Read-only**. Add **Library content: Read-only** if you'll run `tokens` on a non-Enterprise plan — the published-styles fallback hits `/v1/files/:key/styles`, which 403s without it (a scope the older setup text omitted). Optionally **Variables: Read-only** for brand variables — Enterprise-only; without it `tokens` degrades to published styles automatically (expected, not an error — say so). A 403 now names the exact missing scope; 429s retry automatically (per-minute limit, honors `Retry-After`). 3. Have the user set `FIGMA_TOKEN` in their shell profile or project `.env`; never ask them to paste the token into the conversation. While onboarding, also set expectations in one breath: every import lands as a **local frozen file with recorded provenance** — renders never call Figma, re-running a command re-imports only what changed in Figma, and one token works for assets, brand tokens, and components across every file their Figma account can view. - **Phases 4–5 (motion/shaders):** a compatible Figma connector, with separate authorization from the token. If it is unavailable or unauthenticated, ask the user to connect it or provide a native export, then stop. - Say exactly which credential a failing phase needs — never present the split as broken. - `BAD_TOKEN` (401) mid-flow → the token is expired/revoked; re-mint. `FORBIDDEN` (403) → the message names the exact missing scope (e.g. `library_content:read` for the styles fallback) — add it, or the file isn't visible to the account. `REQUIRES_ENTERPRISE` (403 on variables) → not a failure: styles fallback already ran. `RATE_LIMITED` (429) → the client already retried with backoff (this applies to EVERY read — assets, tokens, styles, node trees, versions — the retry lives in the shared request path; `Retry-After` is honored, capped at 60s); if it still surfaces, wait a minute or import fewer nodes per call. **Rate-limit awareness (spec §2.1):** connector quotas vary by Figma plan — batch parent-frame requests, skip verification screenshots unless asked, and cache raw responses so re-derivation never spends a second call. REST is per-minute (10+/min, per-endpoint buckets) — fine at volume, back off on 429. ## Routing Parse the user's figma link with `parseFigmaRef` (URL, `fileKey:nodeId`, bare `fileKey`). Then by intent: - "use this layer / logo / image" → **Asset** (CLI) - "pull my brand / colors / tokens" → **Tokens** (CLI) - "build a scene from this frame" → **Component** (CLI) - "import this animation / motion" → **Motion** (connector when available, below) - a storyboard section / filmstrip of scene frames → **Storyboard** (below) - shader fill/effect → **Shaders** (below) **Narrate every step for the user** — before each command say what you're about to pull from Figma; after it, say where the artifact landed (the frozen path / sidecar / component dir), what changed in the composition, and the immediate next action (preview, add printed variables, re-import to link bindings). The user should never have to ask "did it work?" or "now what?". ## Assets (Phase 1 — CLI) ```bash hyperframes figma asset '' [more refs…] [--format svg|png|jpg|pdf] [--scale 2] [--description "..."] [--entity "..."] ``` Renders over REST, sanitizes SVG, freezes under `.media/images/`, appends the manifest with provenance, regenerates `.media/index.md` (the shared media-use inventory), prints an `` snippet. Idempotent per `fileKey:nodeId:format:scale:version`. Prefer SVG for vectors/logos (scalable, animatable), PNG `--scale 2` for raster fidelity. **Always pass `--description ""`** (it becomes the index row + ``); add `--entity ""` for named brand marks so media-use `resolve --entity` finds them later (entity hits match across image/icon). **Batch many nodes in ONE request** — pass several refs (space-separated or comma-joined) of the SAME file: `hyperframes figma asset 'KEY:1-2' 'KEY:3-4' 'KEY:5-6'`. All render in a single `/v1/images` call, which is figma's own answer to the per-minute rate limit — prefer it over N separate commands when pulling a whole frame's worth of assets. `--description`/`--entity` apply to every node in the batch, so batch nodes that share a purpose. 429s also auto-retry with backoff regardless. ## Tokens (Phase 2 — CLI) ```bash hyperframes figma tokens ``` Imports variables as composition brand-variable entries + `figma-tokens.json` sidecar + binding-index records (`.media/figma-bindings.jsonl`). Variables are Enterprise-gated upstream: on other plans the command degrades to published-style metadata (values resolve at component-import time). Add the printed entries to the composition's `data-composition-variables`. **Import tokens before components** when both are wanted — that's what lets component colors link to brand variables instead of baking duplicates. **Non-Enterprise variables path (field-tested):** REST variables are Enterprise-gated, but a compatible connector may provide variable definitions. When `tokens` reports `REQUIRES_ENTERPRISE` and the connector is available, retrieve the parent scene's variables once, cache the raw response to `.media/figma-cache/`, and use it to build the binding index. The REST node tree's `boundVariables` supplies per-property `VariableID`s; join them by node and property, then write `.media/figma-bindings.jsonl` rows (`{kind:"binding", figmaId, sourceFileKey, compositionVariableId: "figma:", version}`) plus the composition-variable entries. Everything downstream (component `var()` resolution, refresh, runtime CSS variables) is the shipped machinery. Label it for the user: "tokens via the Figma connector — Enterprise plans get this from `hyperframes figma tokens` directly." The runtime defines every declared composition variable as a CSS custom property (document root + sub-comp hosts), so imported `var(--slug, literal)` fills recolor when the variable default changes — updating one value in `data-composition-variables` re-brands every imported component without re-importing anything. `hyperframes render --variables ''` overrides them at render time. ## Components (Phase 3 — CLI) ```bash hyperframes figma component '' ``` Node tree → editable HTML at exact figma geometry, packaged as a registry item under `compositions/components//`. Vectors/boolean-ops auto-rasterize via Phase-1 export. Binding pass (spec §7.1, exact-ID only — never value matching): - **Static fidelity self-check (mandatory for hero content)**: after importing, render the fragment and compare against figma's own pixels — `figma asset --format png` is the ground truth. Text is the known drift axis: a figma text box shorter than its line-height is vertically-trimmed bounds (the mapper emits `text-box-trim` for these; measured drift without it was ~6px on a 70px font). If the comparison shows drift the mapper doesn't cover, report it — don't hand-tweak the fragment silently. - Fill bound to an **imported** token → `var(--slug, #literal)` — brand refresh propagates. - Bound to an **unknown** token → literal + `data-figma-unresolved` flag. The command tells you; offer the user: run `tokens` on the source (or library) file, then re-import the component to link them. Ask **once** per unknown library which file it is — never guess, never match by hex. ## Motion (Phase 4 — connector-assisted) **Usage beacon:** Connector-assisted phases have no CLI touchpoint, so fire the skill beacon at start and finish (anonymous, consent-gated, never fails): `npx hyperframes events --skill=figma-motion` when you begin, `npx hyperframes events --skill=figma-motion --event=skill_completed --outcome=success|error` when done. Same for shaders (`figma-shaders`) and storyboards (`figma-storyboard`). No REST equivalent exists. When a compatible connector is available, use it and hand its output to the pure helpers in `@hyperframes/core/figma`; otherwise ask for a native export: 1. Retrieve motion context for the parent frame in one recursive request, not one request per element. Save the raw JSON next to the project (`.media/figma-cache/`) so retranslation is free. 2. Normalize into `MotionDoc`s with `motionContextToDocs(rawResponse, { selectorFor, repeat })` from `@hyperframes/core/figma` — **never transcribe keyframe numbers by hand**. The helper encodes the field-tested decoding rules mechanically: it parses the motion.dev snippets (the reliable encoding — the CSS snippets stretch durations and can disagree; they are ignored), strips loop-wrap tail keyframes (sub-millisecond segments at times ≈0.9999→1 are the loop's instant reset, not authored motion — the wrap is realized by `repeat` restart), and preserves bezier eases verbatim. `selectorFor` must return the ids from the Phase-3 component import — don't derive selectors from node names. 2b. **Validate against ground truth before calling it done — mandatory**: export the cohort's root frame through the available connector and run `node skills/figma/scripts/verify-motion.mjs --reference --render --crop WxH+X+Y` — it compares motion-energy deltas (static import fidelity cancels out) and fails below 15dB min motion-PSNR (calibrated: faithful ≈ 20+, diverging ≈ 5). Measure `--crop` from the render's actual card edges, don't guess. FAIL means re-check the translation, not the threshold. 3. `motionToGsap(doc)` → `emitTimelineScript(spec)` → inject as a `