SuperAPI AI Directory

react-to-figma-make

Frontend & websites

View repository

Updated 10-15 21:51

About this skill

React Export to Figma Make

Overview

This skill will help you convert React components or applications into a standard structure conforming to the Figma Make project specification after compatibility modifications. After the conversion is complete, the project will have:

  • Figma Make editability: can be opened, edited, and iterated in the Figma Make platform
  • .fig Export capability: generates downloadable .fig files
  • Dual-entry architecture: supports both standalone running and Figma Make export
  • Design token preservation: preserves the CSS variables and theme definitions of the original design system
  • Asset integrity: includes meta.json、ai_chat.json、images/ and other metafiles required by Figma Make

This skill produces a complete Figma Make-compatible project directory, and by default writes the artifacts consumable by the host tool into the general artifact directory:

.axhub/make/artifacts/figma/<resource-id>/
├── canvas.fig
├── meta.json
├── ai_chat.json
├── canvas.code-manifest.json
├── manifest.json
├── images/
└── thumbnail.png            # 可选

If the target project uses .axhub/make/project.json to describe resources, these paths need to be registered in the corresponding resources.prototypes[].artifacts.figma , so that make-server or other hosts can directly export .fig。

Core principles and current capability boundaries

canvas-fig-sync.mjs pack is a template node synchronizer, not a general-purpose filesystem importer.

  • pack only updates canvas.fig that already exist in CODE_FILE.logicalPath。
  • Paths newly added on disk but not present in the template will not automatically become new CODE_FILE。
  • When using --prune-missing , paths that exist in the template but not on disk will be deleted.
  • When using --sanitize-for-export , chat history and code snapshots will be cleared; if the source mapping is incorrect, you cannot rely on the cleared .fig to restore the source code.
  • inspect A successful exit of the command only proves that the binary can be parsed, not that the source code is complete or can run.

Therefore, before the first generation, you must inspect the template and align the exported source paths with the existing logical paths of the template. The paths are determined by the actual template manifest, not by fixed filenames of Figma Make. The common entries and optional paths that can be confirmed in the current bundled empty-canvas.fig include:

Disk path (relative to --from) CODE_FILE.logicalPath Responsibility
src/App.tsx App.tsx The Figma Make entry of the current template, must be preserved
src/styles/globals.css styles/globals.css Optional style nodes already present in the current template
src/<manifest 中已有路径> Corresponds to logicalPath Optional business modules or other resources

In the current template, components/Dashboard.tsx is only a historical example slot, not a general specification, and does not mean the target page must be a Dashboard. It can be used only when this conversion explicitly selects that existing slot. If the original page depends on multiple local modules not covered by the template, prefer using the project's existing build tools to mechanically bundle the business code into src/App.tsx, or bundle it into an existing slot explicitly selected from the manifest for this conversion. Do not manually rewrite the business logic into another implementation; preserve the original page entry and treat the export shell as an independent adaptation layer that can be repeatedly generated and continuously synchronized.

When to use

  • You have an existing React project and want to import it into Figma Make for visual editing
  • You need to generate .fig files from React code for design delivery
  • You want bidirectional collaboration between Figma Make and a code editor
  • You have a V0 / AI Studio / self-built React project and want to bring it into the Figma Make ecosystem

Environment Requirements

This skill is divided into two parts:

  1. Project structure conversion(general): transform a React project into the Figma Make directory specification — can be executed in any environment
  2. canvas.fig generation and validation: this skill has built-in related operation scripts, located in the skill's own directory:
    • scripts/canvas-fig-sync.mjs: canvas.fig write-back and inspection tool
    • assets/empty-canvas.fig: blank canvas template
    • Script execution depends on pako and kiwi-schema. Run it once directly first; if ERR_MODULE_NOT_FOUNDappears, install the dependencies in the package to which the script belongs using the package manager specified by the host project, and do not add these two packages to the runtime dependencies of the target prototype.

If there are additional page rendering acceptance scripts, they can also be executed at this stage.

Reference Files

This skill comes with the following reference files; consult them as needed when converting specific technical domains:

  • references/project-structure.md: complete directory structure and file responsibility description of a Figma Make project
  • references/meta-json-spec.md:meta.json complete field definitions and examples
  • references/style-migration.md: guide for migrating from various CSS approaches to the Figma Make styling system

Conversion Workflow

Step 1: Analyze the source project

Analyze the following aspects of the target React project:

  1. Framework identification:

    • Pure React (Vite / CRA / custom)
    • Next.js (needs SSR removal,"use client"、next/image , etc.)
    • AI Studio (Import Map + CDN mode)
    • Other meta-frameworks
  2. Entry structure:

    • Where the main application component is (usually App.tsx or page.tsx)
    • Where the mount entry is (main.tsx / index.tsx)
    • Whether there is routing (multiple routes need to be converged into a single entry)
  3. Styling approach:

    • Tailwind CSS(CDN / PostCSS / v4)
    • CSS Modules
    • Styled Components / Emotion
    • Pure CSS / SCSS
    • CSS variables / design tokens
  4. Dependency analysis:

    • Core dependencies (React, ReactDOM — externalized, not bundled)
    • UI frameworks (Ant Design, shadcn/ui, Radix, etc. — keep)
    • Chart libraries, animation libraries, etc. — keep and confirm compatibility
    • Framework-specific dependencies (Next.js, Vercel — remove)
  5. Static asset inventory(especially important for large projects):

    • Images: format, quantity, total size, reference method (import / public / CDN)
    • Fonts: local files vs CDN references
    • Other media such as video/audio
    • SVG: whether it is used as a React component

Output a conversion checklist listing the various conversion tasks that need to be handled.

Step 2: Create the Figma Make project structure

In the target directory <output-dir>/<page-name>/ , create the following fixed structure; synchronize the final consumable artifacts to .axhub/make/artifacts/figma/<resource-id>/:

<page-name>/
├── index.tsx              # 项目主入口
├── style.css              # 根入口样式(桥接层)
├── canvas.fig             # Figma 二进制设计数据(第 5 步生成)
├── meta.json              # 项目元数据
├── ai_chat.json           # AI 聊天历史(可为空 {})
├── canvas.code-manifest.json  # CODE_FILE 索引清单(第 5 步生成)
├── package.json           # Vite 项目依赖声明
├── vite.config.ts         # Vite 构建配置
├── index.html             # Vite HTML 入口
├── images/                # 设计稿图片资源
└── src/
    ├── App.tsx            # Figma Make 导出薄壳(导出入口)
    ├── main.tsx           # Vite 挂载层
    ├── index.css          # Figma Make 入口样式
    ├── components/        # 可选;仅使用 template manifest 已存在的路径
    ├── pages/             # 多页面(如需要)
    └── styles/
        └── globals.css    # 全局样式 / 设计 Token

.axhub/make/project.json example of resource metadata in:

{
  "artifacts": {
    "figma": {
      "resourceId": "home",
      "canvasFigPath": ".axhub/make/artifacts/figma/home/canvas.fig",
      "metaPath": ".axhub/make/artifacts/figma/home/meta.json",
      "aiChatPath": ".axhub/make/artifacts/figma/home/ai_chat.json",
      "codeManifestPath": ".axhub/make/artifacts/figma/home/canvas.code-manifest.json",
      "imagesDir": ".axhub/make/artifacts/figma/home/images",
      "manifestPath": ".axhub/make/artifacts/figma/home/manifest.json"
    }
  }
}

Responsibility layering constraints(this is an acceptance constraint, not a suggestion):

File Responsibility Should not contain
index.tsx Project main entry Page visual implementation
src/App.tsx Figma export thin shell, reusing shared components Business logic independent of the root entry
src/main.tsx Vite development mount,ReactDOM.createRoot Business code
src/components/** The true subject of page visuals and interactions Entry adaptation logic
style.css Root entry style forwarding Large amount of business styles
src/index.css Figma entry style layer Independent styles separate from style.css

Step 3: Migrate and refactor the source code

3.1 Converge the entries

Converge all page logic of the source project into two thin entries + one set of shared components.

Root directory index.tsx(project main entry):

/**
 * 项目主入口
 */
import './style.css';
import React from 'react';
import App from './src/App';

export default function PageName() {
  return <App />;
}

src/App.tsx(Figma Make export shell):

/**
 * Figma Make 导出薄壳
 * 将根入口及其本地依赖机械同步到这个入口,
 * 或同步到 template manifest 中明确存在的其他逻辑路径。
 */
import React from 'react';
import './styles/globals.css';

export default function App() {
  return <main>{/* 机械同步或打包后的页面主体 */}</main>;
}

src/main.tsx(Vite mount layer):

/**
 * Vite 开发挂载层
 * 仅用于 Figma Make 独立开发预览
 */
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Key principles:

  • The two entries (index.tsx and src/App.tsx) must render the same page content
  • The page body can be directly and mechanically bundled into src/App.tsx, or split into logical paths that already exist in the template manifest
  • Do not hardcode Dashboard.tsx、AppContent.tsx or other project-semantic file names; check the template first before choosing a path
  • Do not create a path that does not exist in the template and then assume pack will be added automatically
  • If the source project has multi-page routing, converge it into a single page or choose the core page

3.2 Handle framework-specific code

Based on the framework type of the source project, perform targeted cleanup:

Next.js project:

// ❌ 移除
"use client"
import { useRouter } from 'next/navigation'
import Image from 'next/image'
import Link from 'next/link'
import type { Metadata } from 'next'

// ✅ 替换
// 删除 "use client"
// 删除 useRouter,改用 useState 管理页面状态
<img> 替代 <Image>
<a> 替代 <Link>

AI Studio project:

// ❌ 移除
// Import Map 依赖(CDN URL)
// index.html 中的 <script type="importmap">

// ✅ 替换
// CDN 导入改为 npm 包导入
// process.env.* 改为 import.meta.env.VITE_*

General cleanup:

// ❌ 移除
import { Analytics } from '@vercel/analytics/next'
// 所有 SSR 相关代码

// ✅ 保留
// React Hooks
// 第三方 UI 组件
// 样式文件导入

3.3 Handle path aliases

Convert all non-standard path aliases to relative paths:

// 源代码中的 @/ 别名
import { Button } from '@/components/ui/button'

// 转换为相对路径(基于文件位置)
import { Button } from './components/ui/button'   // 从 src/App.tsx
import { Button } from '../components/ui/button'  // 从 src/pages/xxx.tsx

If the source project uses package@version format imports (a Figma Make export characteristic), change them to bare package names:

// ❌
import { motion } from 'framer-motion@11.0.0'

// ✅
import { motion } from 'framer-motion'

3.4 Handle large static assets

React projects usually contain a large number of images, fonts, and other binary files. These assets need to be handled properly during conversion:

Image asset migration:

Source project reference method Migration strategy
import logo from './assets/logo.png' Keep in src/assets/, import path unchanged
<img src="/images/hero.png"> (public directory) Copy to images/, update path to ./images/hero.png
<img src="https://cdn.example.com/img.png"> (CDN) Keep the CDN link unchanged
SVG as a React component (import { ReactComponent as Icon }) Keep in src/components/ or src/assets/
In CSS, url('./bg.png') just keep the relative path correct

images/ directory rules:

  • Figma Make's images/ directory stores images associated with the design file, usually named with a hash (such as a3f2c1d.png)
  • The source project's business images should preferably remain in src/assets/, and do not need to be forcibly moved to images/
  • Only the images/ content that comes with importing from Figma Make needs to retain its original hash name

Font files:

  • Place local font files in src/assets/fonts/
  • In src/styles/globals.css , use @font-face to reference
  • For CDN fonts such as Google Fonts, directly keep the @import url(...) link

Notes on large files:

  • canvas.fig is a binary file (usually several hundred KB to several MB), cannot be edited manually, and can only be generated through tools
  • Do not put the source project's node_modules/、build/、.next/ Copy the directories such as into the output.
  • If the source project contains more than 50 images or 10 MB in total, consider trimming to the subset needed for the core pages.

3.5 Migrate styles

Goal: root entry style.css and export entry src/index.css use the same set of style sources.

style.css(root entry styles):

@import "tailwindcss";

/* 如果有 globals.css,通过 import 引入 */
@import "./src/styles/globals.css";

src/index.css(Figma exported styles):

@import "tailwindcss";

/* 保持与 style.css 一致的样式来源 */
@import "./styles/globals.css";

src/styles/globals.css(main style file):

Migrate the following from the source project into this file:

  • CSS variables / design tokens
  • @theme definitions (Tailwind v4)
  • Global base styles
  • Custom font references
  • Custom animation definitions

Style migration strategy(for detailed guidance, see references/style-migration.md):

Source style approach Migration method
Tailwind CSS v4 Keep directly @import "tailwindcss" + @theme
Tailwind CSS v3 Migrate to v4 syntax,@theme inline replaced by @apply
CSS Modules Merge into the component-level CSS file and switch to prefixed regular class names
Styled Components / Emotion Extract into CSS classes and remove the JS-in-CSS dependency
Plain CSS / SCSS Migrate directly, compiling SCSS to CSS
CSS variables Keep in the globals.css of :root or @theme in

Notes on large style files:

  • The src/index.css exported by Figma Make is sometimes the full compiled Tailwind output (which can reach tens of thousands of lines),do not use it directly as the final styles
  • Use src/styles/globals.css as the main style source, andsrc/index.css only for style bridging

Step 4: Create the Figma Make metafile

4.1 meta.json

{
  "client_meta": {
    "background_color": { "r": 0.96, "g": 0.96, "b": 0.96, "a": 1 },
    "thumbnail_size": { "width": 400, "height": 300 },
    "render_coordinates": { "x": 0, "y": 0, "width": 1280, "height": 960 }
  },
  "file_name": "<项目显示名称>",
  "developer_related_links": [],
  "exported_at": "<ISO 8601 时间>"
}
  • file_name: the display name of the final exported .fig file
  • render_coordinates: page viewport size; adjust width and heightaccording to the actual page (see references/meta-json-spec.md)
  • exported_at: use the current ISO 8601 time (new Date().toISOString())

4.2 ai_chat.json

{}

When creating a new project, an empty object is sufficient.

4.3 package.json

{
  "name": "<page-name>",
  "private": true,
  "version": "0.0.1",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
  },
  "devDependencies": {
    "vite": "^6.0.0",
    "@vitejs/plugin-react": "^4.0.0",
    "typescript": "^5.0.0"
  }
}

Dependency rules:

  • Exclude:react、react-dom、next、next-*、@vercel/*、next-themes
  • Keep: all other runtime dependencies (UI libraries, utility libraries, icon libraries, etc.)
  • Use the project's package manager to install dependencies (npm / yarn / pnpm are all fine)

4.4 vite.config.ts

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': '/src'
    }
  }
});

4.5 index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title><项目名称></title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

4.6 images/ directory

Create an empty images/ directory. This directory is used to store image assets associated with the Figma Make design.

  • If this is a project imported from Figma Make, keep images/ the existing hash-named images under
  • The source project's business images are recommended to remain in src/assets/ ; there is no need to move them into images/

Step 5: Generate canvas.fig

Before executing any command with --prune-missing , you must first complete the export shell and template path mapping. Do not use the production canvas.fig to try things by trial and error.

Use the canvas-fig-sync.mjs script included with this skill to generate an exportable .fig file.

The following commands assume that you are currently in the target project root directory in the terminal, and that this skill is located at <skill-dir>:

First generation(no existing canvas.fig) execute in the following order:

  1. inspect the blank template and confirm that the logical path you intend to use this time actually exists.
  2. Create and retain template-compatible src/** export shell within the target source directory.
  3. Copy the blank template to a candidate file, and pack on the candidate file.
  4. Verify the candidate file's nodes, references, and runnability; only after passing, replace the official canvas.fig。
# ① 检查模板已有 CODE_FILE 路径
node <skill-dir>/scripts/canvas-fig-sync.mjs inspect \
  --fig <skill-dir>/assets/empty-canvas.fig \
  --manifest <artifact-dir>/template.code-manifest.json

# ② 使用 Node 跨平台复制模板,避免覆盖正式产物
node -e "require('node:fs').copyFileSync(process.argv[1], process.argv[2])" \
  <skill-dir>/assets/empty-canvas.fig \
  <artifact-dir>/canvas.candidate.fig

# ③ 将已经对齐模板路径的源码写入候选文件
node <skill-dir>/scripts/canvas-fig-sync.mjs pack \
  --fig <artifact-dir>/canvas.candidate.fig \
  --from <source-dir> \
  --prune-missing \
  --sanitize-for-export \
  --manifest <artifact-dir>/canvas.pack-manifest.json

# ④ 生成候选文件的最终 CODE_FILE 清单
node <skill-dir>/scripts/canvas-fig-sync.mjs inspect \
  --fig <artifact-dir>/canvas.candidate.fig \
  --manifest <artifact-dir>/canvas.code-manifest.json

<source-dir> is a page source directory containing persisted src/App.tsx source code directory;<artifact-dir> is .axhub/make/artifacts/figma/<resource-id>/. The two are usually not the same directory. When the Make server downloads, it will again use <source-dir> to execute pack, so the export shell cannot be deleted after the first generation.

Before promoting the candidate file to the official canvas.fig , read both manifests and enforce:

  • canvas.pack-manifest.json.updatedLogicalPathCount > 0
  • canvas.code-manifest.json.summary.totalCodeFiles > 0
  • canvas.code-manifest.json.entries contains App.tsx as well as App.tsx all local relative dependencies
  • does not exist in pack warnings Unresolved relative import
  • Except for App.tsx , only require that templates actually referenced by this export entry already have paths; do not require fixed existence of Dashboard.tsx

If any item is not satisfied, you must stop; do not overwrite the existing canvas.fig, and do not record an empty shell as a successful export. After verification passes, use cross-platform file operations to replace canvas.candidate.fig with canvas.fig。

Parameter description:

  • <source-dir>: page source directory; the script will read code from its src/ subdirectory
  • <artifact-dir>: Figma Make asset directory, not equivalent to the source directory
  • --prune-missing: prune old CODE_FILE nodes that do not exist on disk
  • --sanitize-for-export: clear old chat/history cache and rebuild importedCodeFiles

canvas.fig Key Features:

  • fig-make dedicated binary container, containing the Figma node tree and CODE_FILE nodes; it is not an ordinary ZIP
  • cannot be edited manually; it can only be operated via the canvas-fig-sync.mjs pack / inspect / extract commands
  • File size is usually from a few hundred KB to a few MB, depending on the number of code files
  • After each page content change, it needs to be packed again; otherwise the exported .fig will be inconsistent with the current page

Step 6: Verification Checklist

After the conversion is complete, check item by item:

Structure Verification:

  • The project directory conforms to the fixed structure (index.tsx + src/App.tsx + src/main.tsx + src/components/)
  • index.tsx has a responsibility comment at the top
  • src/App.tsx has a responsibility comment at the top: "Figma Make export thin shell"
  • src/main.tsx has a responsibility comment at the top: "Vite mount layer"
  • Both entries render the same set of src/components/** shared components in

Metadata Verification:

  • meta.json exists, contains file_name、exported_at、client_meta
  • ai_chat.json exists (at least {})
  • package.json exists, does not contain react / react-dom dependencies
  • vite.config.ts exists
  • index.html exists
  • images/ directory exists

canvas.fig Verification:

  • canvas.fig exists
  • canvas.code-manifest.json exists
  • the inspect command can be executed successfully
  • of the pack manifest updatedLogicalPathCount > 0
  • summary.totalCodeFiles > 0
  • manifest contains the entry and all its local relative dependencies
  • pack warnings do not contain Unresolved relative import
  • use extract reverse extract to a temporary directory; key source code matches the export shell content
  • the binary returned by the actual download API matches the official canvas.fig consistent; do not use only probe.hasMakeAssets === true as content acceptance

Style Verification:

  • style.css and src/index.css use the same style source
  • Do not directly copy the Tailwind build output as the final styles

Dependency verification:

  • Does not depend on @/ or package@version aliases to run
  • No leftover Next.js / Vercel-specific code
  • All required dependencies are installed

Asset integrity verification:

  • All image reference paths are correct (no 404 broken links)
  • Font files have been copied or CDN links are accessible
  • Does not contain node_modules/、build/、.next/ and other redundant directories

Rendering verification:

In the target project directory:

cd <output-dir>/<page-name>
npm install   # 或 yarn / pnpm install
npm run dev   # 启动 Vite 开发服务器
# 浏览器中检查页面渲染是否正常
  • The page renders normally
  • No console errors
  • The main visual is basically consistent with the original project

Common scenarios

Scenario A: Pure React + Vite project

This is the simplest scenario, because both the source project and the target structure are based on Vite.

  1. Inspect the template and confirm the available CODE_FILE.logicalPath
  2. Keep the original business entry and create a thin export shell compatible with the template
  3. Mechanically package the main business body and local dependencies into src/App.tsx, or sync them to the existing path of the template selected this time
  4. Create the root directory index.tsx
  5. Migrate styles to src/styles/globals.css
  6. Complete the metadata files
  7. Generate canvas.fig

Scenario B: Next.js project (V0, etc.)

  1. Remove all Next.js-specific code ("use client"、next/image、next/link, routing, etc.)
  2. Move the contents of app/page.tsx or pages/index.tsx to src/components/
  3. Migrate app/globals.css to src/styles/globals.css
  4. Migrate the static assets under public/ to src/assets/ or images/
  5. Exclude Next.js-specific dependencies (next、@vercel/*) and keep UI component dependencies
  6. Create dual entries (index.tsx + src/App.tsx) and complete the metadata files

Scenario C: AI Studio project

  1. Extract dependencies from the Import Map in index.html and convert them to npm package installation
  2. Extract the contents of the <style> tag to src/styles/globals.css
  3. process.env.* Change to import.meta.env.VITE_*
  4. CDN image references can be kept, or downloaded to src/assets/
  5. Create dual entries and complete the metadata files

Scenario D: Existing project imported from Figma Make (complete the export capability)

At this point the focus is not on creating the structure from scratch, but on ensuring that the existing project's export shell stays in sync with the current page.

  1. Check whether index.tsx(root entry) and src/App.tsx(export shell) are in sync
  2. If they are not in sync, make src/App.tsx reuse the shared components of the root entry
  3. Do not deletethe existing original assets such as canvas.fig、meta.json、images/ , etc.
  4. Pack them into candidate files and complete strict verification; do not directly overwrite the original canvas.fig
  5. After verification passes, replace the official files and refresh canvas.code-manifest.json and meta.json.exported_at

Common points to note

Build outputs and assets

  • Do not treat src/index.css(Figma Make's Tailwind build output) directly as the final style.css, as it may have tens of thousands of lines
  • If the directory already contains original assets such as canvas.fig、meta.json、images/ , do not delete them
  • images/ Files under
  • canvas.fig are binary files and cannot be edited manually

Entry synchronization

  • After modifying the root directory page, you must synchronously update src/App.tsx, otherwise the exported .fig will be inconsistent with the current page
  • The two entry points being out of sync for a long time is the most common "drift" problem — keep src/App.tsx as thin as possible, only doing wrapping
  • The default template cannot automatically add arbitrary local file paths; before adding split files, check the template manifest
  • inspect succeeds but totalCodeFiles is 0, entry dependencies are missing, or there are unresolved imports, it is still a failed artifact

Dependencies and paths

  • Do not continue to retain a runtime dependency on the package@version alias
  • Do not stuff the multi-page routing shell unchanged into the final page component
  • @/ The alias should be configured through vite.config.ts of resolve.alias , rather than relying on an external build environment