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
.figExport capability: generates downloadable.figfiles- 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.
packonly updatescanvas.figthat already exist inCODE_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.figto restore the source code. inspectA 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
.figfiles 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:
- Project structure conversion(general): transform a React project into the Figma Make directory specification — can be executed in any environment
- 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 toolassets/empty-canvas.fig: blank canvas template- Script execution depends on
pakoandkiwi-schema. Run it once directly first; ifERR_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 projectreferences/meta-json-spec.md:meta.jsoncomplete field definitions and examplesreferences/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:
-
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
-
Entry structure:
- Where the main application component is (usually
App.tsxorpage.tsx) - Where the mount entry is (
main.tsx/index.tsx) - Whether there is routing (multiple routes need to be converged into a single entry)
- Where the main application component is (usually
-
Styling approach:
- Tailwind CSS(CDN / PostCSS / v4)
- CSS Modules
- Styled Components / Emotion
- Pure CSS / SCSS
- CSS variables / design tokens
-
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)
-
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.tsxandsrc/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.tsxor 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
packwill 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 asa3f2c1d.png) - The source project's business images should preferably remain in
src/assets/, and do not need to be forcibly moved toimages/ - 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-faceto reference - For CDN fonts such as Google Fonts, directly keep the
@import url(...)link
Notes on large files:
canvas.figis 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
@themedefinitions (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.cssexported 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.cssas the main style source, andsrc/index.cssonly 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.figfilerender_coordinates: page viewport size; adjustwidthandheightaccording to the actual page (seereferences/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 intoimages/
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 productioncanvas.figto 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:
- inspect the blank template and confirm that the logical path you intend to use this time actually exists.
- Create and retain template-compatible
src/**export shell within the target source directory. - Copy the blank template to a candidate file, and pack on the candidate file.
- 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 > 0canvas.code-manifest.json.summary.totalCodeFiles > 0canvas.code-manifest.json.entriescontainsApp.tsxas well asApp.tsxall 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 ofDashboard.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 itssrc/subdirectory<artifact-dir>: Figma Make asset directory, not equivalent to the source directory--prune-missing: prune oldCODE_FILEnodes that do not exist on disk--sanitize-for-export: clear old chat/history cache and rebuildimportedCodeFiles
canvas.fig Key Features:
fig-makededicated 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.mjspack / 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
.figwill 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.tsxhas a responsibility comment at the top -
src/App.tsxhas a responsibility comment at the top: "Figma Make export thin shell" -
src/main.tsxhas a responsibility comment at the top: "Vite mount layer" - Both entries render the same set of
src/components/**shared components in
Metadata Verification:
-
meta.jsonexists, containsfile_name、exported_at、client_meta -
ai_chat.jsonexists (at least{}) -
package.jsonexists, does not containreact/react-domdependencies -
vite.config.tsexists -
index.htmlexists -
images/directory exists
canvas.fig Verification:
-
canvas.figexists -
canvas.code-manifest.jsonexists - 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
extractreverse 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.figconsistent; do not use onlyprobe.hasMakeAssets === trueas content acceptance
Style Verification:
-
style.cssandsrc/index.cssuse the same style source - Do not directly copy the Tailwind build output as the final styles
Dependency verification:
- Does not depend on
@/orpackage@versionaliases 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.
- Inspect the template and confirm the available
CODE_FILE.logicalPath - Keep the original business entry and create a thin export shell compatible with the template
- 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 - Create the root directory
index.tsx - Migrate styles to
src/styles/globals.css - Complete the metadata files
- Generate
canvas.fig
Scenario B: Next.js project (V0, etc.)
- Remove all Next.js-specific code (
"use client"、next/image、next/link, routing, etc.) - Move the contents of
app/page.tsxorpages/index.tsxtosrc/components/ - Migrate
app/globals.csstosrc/styles/globals.css - Migrate the static assets under
public/tosrc/assets/orimages/ - Exclude Next.js-specific dependencies (
next、@vercel/*) and keep UI component dependencies - Create dual entries (
index.tsx+src/App.tsx) and complete the metadata files
Scenario C: AI Studio project
- Extract dependencies from the Import Map in
index.htmland convert them to npm package installation - Extract the contents of the
<style>tag tosrc/styles/globals.css process.env.*Change toimport.meta.env.VITE_*- CDN image references can be kept, or downloaded to
src/assets/ - 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.
- Check whether
index.tsx(root entry) andsrc/App.tsx(export shell) are in sync - If they are not in sync, make
src/App.tsxreuse the shared components of the root entry - Do not deletethe existing original assets such as
canvas.fig、meta.json、images/, etc. - Pack them into candidate files and complete strict verification; do not directly overwrite the original
canvas.fig - After verification passes, replace the official files and refresh
canvas.code-manifest.jsonandmeta.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 finalstyle.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 undercanvas.figare 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.figwill 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.tsxas thin as possible, only doing wrapping - The default template cannot automatically add arbitrary local file paths; before adding split files, check the template manifest
inspectsucceeds buttotalCodeFilesis 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@versionalias - Do not stuff the multi-page routing shell unchanged into the final page component
@/The alias should be configured throughvite.config.tsofresolve.alias, rather than relying on an external build environment