Prototype by vibes: describe the motion, get a real Figma prototype transition.
TypeScript · React · GSAP · Vite · Vitest · Claude API · Figma Plugin API
A Figma plugin that turns natural-language prompts into prototype transitions. Pick two frames and a target, describe the motion ("slide left with a bouncy spring"), and the plugin writes a Figma Reaction onto the target and plays a preview that matches what Figma's prototype runtime will do.
Strict separation of concerns so the animation engine can be swapped later without touching the other layers:
| Layer | Path | Role |
|---|---|---|
| Extractor | src/figma/code.ts |
Runs in Figma's sandbox. Reads nodes, exports SVGs, persists thread state on the target node via setPluginData, and applies reactions via setReactionsAsync. No network. |
| Brain | src/api/brain.ts |
Calls Claude. Parses, validates, and sanitizes the LLM's JSON output into a strict AnimationPayload. Strips disallowed easings (spring/bezier gated behind user wording). |
| Renderer | src/ui/ |
React UI + GSAP preview. Agnostic of how the payload was produced — swap GSAP for Lottie by editing this layer only. |
| Types | src/types/index.ts |
The single source of truth for cross-layer data contracts. |
- Node 18+
- A Claude API key in
.env:VITE_ANTHROPIC_API_KEY=sk-ant-... - Figma desktop app (for loading the plugin locally).
npm install
npm run build # outputs dist/index.html (inlined UI) and dist/code.js (sandbox)Scripts:
npm run dev— Vite dev server for the UInpm run typecheck— both tsconfigsnpm run lint— ESLint with zero-warning policynpm run build— production bundle for the plugin
- Figma desktop → Plugins → Development → Import plugin from manifest…
- Select
manifest.jsonat the repo root. - Open any file, select a frame that has a prototype reaction, run the plugin from the Plugins menu.
- Selection changes in Figma → the sandbox finds the enclosing screen + the reaction's destination, exports both as SVG strings (with
A_/B_ID prefixing to prevent DOM collisions), and posts aPREPARED_PAYLOADto the UI. - User prompts → the UI forwards the prompt + prior thread + current reaction to the Brain, which calls Claude with a cached system prompt and a few-shot schema.
- Claude returns
{ assistantText, gsapCode, figmaReaction, mode, targetNodeName, reactionIndex }. The Brain runs it through strict parsers andsanitizeEasing(see below). - Preview plays in-plugin via GSAP using Figma's exact cubic-bezier curves, so the preview's timing and acceleration match Figma's prototype runtime.
- Apply to Figma → the sandbox writes the
FigmaReactionSpeconto the target node.
- Direction semantics match Figma's prototype:
directionis the motion vector (where things are going).TOP= upward motion,BOTTOM= downward, etc.from Xphrasing flips to the opposite motion direction. - Easing gating: the "spring family" (
CUSTOM_SPRING,GENTLE,QUICK,BOUNCY,SLOW) is forbidden unless the current user message contains spring/bounce wording.GENTLEetc. look like bezier names but Figma treats them as spring presets, so they get the same gating. Default isEASE_OUT. - Arbitrary LLM JS is executed in the exported HTML via
new Function(...). That's acceptable for a local MVP; sandbox or validate before any production use.
docs/superpowers/ holds the spec and implementation plan behind each change — written before the code, one pair per pull request. They are working documents rather than polished write-ups, kept in the repo because they record the reasoning behind decisions the source can only state: why easings are gated behind user wording, why the extractor never touches the network, why the preview had to match Figma's own curves.
src/
├─ api/brain.ts # Claude call + parsing + sanitization
├─ figma/code.ts # Sandbox: extractor + reaction writer
├─ types/index.ts # Cross-layer data contracts (single source of truth)
└─ ui/
├─ App.tsx # Chat + prompt + status
├─ AnimationStage.tsx # GSAP preview + Apply-to-Figma + Export HTML
├─ ChatThread.tsx # Chat messages with reaction summary chips
├─ main.tsx # React entry
├─ index.css # Minimal resets
└─ stageSize.ts # Preview sizing helpers
manifest.json # Figma plugin manifest
MIT © Michael Tuv