Export code
Export code turns a whole frame, with every nested frame, text, image, vector and component instance inside it, into a project a developer can keep. Keyframed animation comes along: Motion for React, CSS @keyframes for HTML and Svelte.
Use it
Section titled “Use it”- Select a frame, or any layer inside it. Code mode always exports the frame that contains the selection.
- Switch to Code in the mode switch at the left end of the bottom bar (
Shift+D), or open the … menu and choose Export code…: both open Code mode. - With a layer picked, its CSS sits at the top of the right bar and the frame’s code below it. Pick a target in the framework dropdown: React + Tailwind (default), HTML + CSS or SvelteKit.
- The header has Copy and Download .zip icon buttons; a floating copy button also sits on the code. Two dropdowns above the code pick the framework and the file; it opens on the main file. Code is syntax-highlighted in light and dark.
- With a layer picked, its section lists size, layout, typography, fill and variables as rows: click a value to copy it. The CSS toggle shows the CSS and Tailwind snippets. The page title and the zip are named after the frame (
Landing pagegiveslanding-page-react.zip).
What you get
Section titled “What you get”| In the design | In the code |
|---|---|
| Auto layout (horizontal, vertical) | display: flex with gap, padding, alignment and wrap |
| Auto layout grid | display: grid with its columns (grid-cols-12) and column/row spans |
| Fill, hug, fixed sizing | flex: 1, align-self: stretch, no size, or a width (fluid with max-width from 320 px) |
| A frame without a stack whose layers sit one below the other | a column (flex-direction: column), each layer offset by margins; wide layers stretch up to their design width |
| A frame without a stack whose layers overlap | position: relative, its layers position: absolute, pinned by their constraints; layers 320 px or wider pinned left get percentage widths |
| Breakpoints | the same markup, with max-[390px]: classes (Tailwind) or @media (max-width: …) rules for what each breakpoint overrides |
| Components and instances | one file per component; text, images, colours and visibility that differ between instances become typed props; an override on an instance nested inside another component becomes a prop of the outer one (feature1LabelColor) forwarded to the inner one |
| Text | h1 for the largest heading on the page, then h2/h3 by size and weight, p for body copy, a for linked text |
| Layers named Nav, Header, Footer, Hero, Features, Pricing, Card… | nav, header, footer, section, article |
| Component sets with variants | one component named after the set with a prop per variant (variant?: 'outline', disabled?: boolean), picking one file per variant (ButtonOutline); instances write <Button variant="outline" /> and leave out Default values (React and Svelte; HTML writes each variant inline) |
| Components named Button or Link | button type="button" and a href |
| Colours, fonts, radii, spacing | a tokens file (@theme for Tailwind, CSS variables otherwise); colour variables keep their names |
| Images | img pointing at a file bundled in the project (public/assets/ for React, static/assets/ for Svelte, assets/ for HTML) |
| Vectors, polygons, stars | inline svg |
Class names come from layer names (Feature card becomes FeatureCard and .feature-card), and the same frame always gives the same files.
Animation
Section titled “Animation”| In the design | React (Motion) | HTML and Svelte (CSS) |
|---|---|---|
| Keyframes on position, scale, rotation, opacity, text colour | motion.* element with keyframe arrays and times (src/animations.ts) | @keyframes per property (styles/animations.css, or inside the Svelte component) |
| A bezier curve | ease: [x1, y1, x2, y2] | cubic-bezier(x1, y1, x2, y2) |
| Easing presets and springs (Standard, Ease out, Overshoot, Elastic, Bounce…) | the exact curve sampled into a function (src/lib/easing.ts) | the exact curve sampled into linear(…) |
| Hold keyframes | hold | step-end |
| Start time | delay | animation-delay |
| Loop (interactive settings) | repeat: Infinity over the work area | infinite over the work area |
| Playback “when scrolled into view” | whileInView | paused until an IntersectionObserver adds is-inview |
| A layer with a “While hovering” interaction | whileHover | :hover |
Position moves are written as translate (CSS variables --tx/--ty registered with @property, so x and y keep their own timing).
What does not map
Section titled “What does not map”- Effects with no CSS equivalent (noise, displacement, chromatic aberration…) are left out and listed under Not exported. Drop shadow, inner shadow, layer blur and background blur are kept.
- Shaders, 3D, particles and video effects are not exported.
- Animation of anything but position, scale, rotation, opacity and text colour (blur, skew, 3D rotation, fills, masks, effect parameters…) is listed under Not exported, as is animation on a whole component instance: animate the layers inside it.
- Scroll-scrubbed and paused playback play on load instead.
- A frame without a stack whose layers overlap stays absolutely positioned: it does not reflow on a phone. Wrap the layers with a stack (
Shift+A) before exporting for responsive code. - An image that cannot be downloaded at export time keeps its original link, which expires.
From the CLI and agents
Section titled “From the CLI and agents”feega motion code <nodeId> --target svelte --out ./siteThe export_code MCP tool returns the same files as JSON, free and without AI:
{ "node_id": "<frameId>", "target": "react" }{ "name": "Landing", "target": "react", "files": [{ "path": "src/components/Button.tsx", "content": "…" }], "assets": [{ "path": "public/assets/<assetId>.png", "ref": "/assets/<assetId>.png", "url": "https://…" }], "notes": [] }feega motion code downloads each assets entry to its path; url is a link that expires, so fetch it right away.
The endpoint behind both is GET /api/v1/motion/{nodeId}/code?target=react|html|svelte.