Mục tiêu xuất mặc định của figmascope là Jetpack Compose. Nhưng bundle là agnostic với agent — các loại node IR, định dạng token và string ref ánh xạ gọn gàng tương tự sang React + Tailwind. Bạn chỉ cần bảo agent nhắm vào JSX thay vì Kotlin.
Hướng dẫn này trình bày ánh xạ IR sang JSX, cách mở rộng tailwind.config.js với token từ tokens.json, và các pattern prompting tạo ra ít drift nhất ở phía React.
Một lưu ý quan trọng trước
Compose là những gì figmascope kiểm tra nhiều nhất. IR, định dạng token và các ràng buộc CONTEXT.md được thiết kế với Compose trong đầu. React + Tailwind hoạt động được — IR ánh xạ gọn gàng — nhưng bạn sẽ thấy drift nhiều hơn một chút, đặc biệt xung quanh typography và bố cục overlay. Gắn cờ bất cứ điều gì có vẻ sai và chạy kiểm tra token sau lần đầu tiên.
Bước 1: Tạo và giải nén bundle
unzip ~/Downloads/context-bundle.zip -d ./design/
ls design/
# CONTEXT.md _meta.json components/ screens/ strings.json tokens.json
Bước 2: Mở rộng Tailwind config với design token
Trước khi prompting, ánh xạ tokens.json vào tailwind.config.js của bạn. Đây là bước quan trọng làm cho Tailwind nhận biết token — thay vì các giá trị hex hardcode trong chuỗi className, bạn nhận được các tên ngữ nghĩa có thể truy ngược về thiết kế.
// tailwind.config.js
const tokens = require('./design/tokens.json')
// Build color map: { 'brand-7f5cfe': '#7F5CFE', ... }
const colors = Object.fromEntries(
Object.entries(tokens.color).map(([key, val]) => [
`brand-${key}`, val
])
)
// Build spacing map: { 'ds-4': '4px', 'ds-8': '8px', ... }
const spacing = Object.fromEntries(
Object.entries(tokens.spacing).map(([key, val]) => [
`ds-${key}`, `${val}px`
])
)
// Build border-radius map
const borderRadius = Object.fromEntries(
Object.entries(tokens.radius).map(([key, val]) => [
`ds-${key}`, val === 9999 ? '9999px' : `${val}px`
])
)
module.exports = {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {
colors,
spacing,
borderRadius,
}
}
}
Điều này tạo ra các class Tailwind như bg-brand-7f5cfe, p-ds-16, rounded-ds-12. Không phải tên class đẹp nhất, nhưng chúng có thể truy ngược — mỗi class ánh xạ lại thành một khóa token.
Nếu bạn muốn có bí danh ngữ nghĩa, hãy thêm một lớp bí danh:
// in theme.extend.colors:
primary: tokens.color['7f5cfe'],
background: tokens.color['f6f2ea'],
surface: tokens.color['ffffff'],
Cung cấp cho agent cả hai — config token thô và bí danh ngữ nghĩa — để nó có thể chọn tên phù hợp trong ngữ cảnh.
Bước 3: Prompt agent nhắm vào React + Tailwind
CONTEXT.md nói mục tiêu mặc định là Compose. Ghi đè rõ ràng trong prompt của bạn:
Implement ./design/screens/home.json as a React functional component using Tailwind CSS.
Framework override: ignore the Compose instructions in CONTEXT.md. Target React + Tailwind.
Rules:
- Read ./design/tokens.json. The tokens are extended into Tailwind config —
use Tailwind classes that correspond to token keys (e.g. bg-brand-7f5cfe, p-ds-16).
- UI strings come from ./design/strings.json. Import and reference them by key.
- IR node kind mapping:
stack (axis:vertical) → <div className="flex flex-col gap-[Xpx]">
stack (axis:horizontal) → <div className="flex flex-row gap-[Xpx]">
overlay → <div className="relative"> with absolute-positioned children
absolute → <div className="absolute" style={{top, left, width, height}}>
leaf (text) → <span> or <p> with Tailwind text classes
leaf (rectangle) → <div> with bg and rounded classes
- Do not hardcode hex values. All colors must use Tailwind classes from the token config.
- Do not hardcode strings. Use the strings.json keys.
Output to: src/screens/HomeScreen.tsx
Bảng ánh xạ IR sang JSX
Đây là bảng ánh xạ đầy đủ cho React + Tailwind:
| IR kind | Thuộc tính | JSX pattern |
|---|---|---|
stack | axis: "vertical" | <div className="flex flex-col gap-ds-{n}"> |
stack | axis: "horizontal" | <div className="flex flex-row gap-ds-{n}"> |
overlay | children xếp chồng | <div className="relative"> với children className="absolute ..." |
absolute | x, y, w, h | <div className="absolute" style={{"{{"}}top: y, left: x, width: w, height: h{{"}}"}}> |
leaf | type: "text" | <span className="text-{size} font-{weight} leading-{lh} text-brand-{color}"> |
leaf | type: "rectangle" | <div className="bg-brand-{color} rounded-ds-{r}"> |
Giá trị gap và padding: sử dụng các class spacing ds-{n} từ phần mở rộng Tailwind config. Nếu giá trị gap không phải là khóa token gọn, sử dụng cú pháp giá trị tùy ý của Tailwind: gap-[20px].
Ví dụ thực tế: IR màn hình home sang JSX
Sử dụng cùng IR từ hướng dẫn Compose:
import strings from '../../design/strings.json'
export function HomeScreen() {
return (
<div className="flex flex-col gap-ds-24 p-ds-16 bg-brand-f6f2ea min-h-screen">
<h1 className="text-2xl font-bold leading-tight text-brand-1a1a2e">
{strings['home.title'].value}
</h1>
<div className="flex flex-col gap-ds-12">
<div className="bg-white rounded-ds-12 p-ds-16">
<span className="text-xs font-medium text-brand-7f5cfe">
{strings['home.card.label'].value}
</span>
</div>
</div>
</div>
)
}
Mọi className đều có thể truy ngược. gap-ds-24 → spacing.24 → 24px. text-brand-7f5cfe → color.7f5cfe → #7F5CFE. Nếu một giá trị drift (ví dụ: agent viết gap-6 thay vì gap-ds-24), nó có thể thấy ngay trong code review.
Tại sao tokens.json + Tailwind config hoạt động
Cả hai hệ thống đều ưu tiên token. Tailwind mở rộng config cơ sở với các giá trị tùy chỉnh; tokens.json đã được cấu trúc như một bản đồ giá trị tùy chỉnh. Bước mở rộng (Bước 2 ở trên) là thiết lập một lần — sau đó, agent sử dụng tên class Tailwind liên kết ngữ nghĩa với hệ thống thiết kế thay vì các class tiện ích tùy ý.
Kết quả: khi design token thay đổi (giả sử màu chính chuyển từ #7F5CFE sang #6B4EE6), bạn cập nhật một giá trị trong tokens.json, chạy lại import config, và Tailwind tái tạo. Code component không thay đổi.
Kiểm tra token drift
Sau khi triển khai, hãy yêu cầu agent kiểm tra drift:
Audit src/screens/HomeScreen.tsx for token drift.
Check:
1. Any hex color values not referenced through a Tailwind class from the token config.
2. Any hardcoded px or rem spacing values that should be ds-{n} classes.
3. Any UI strings not sourced from design/strings.json.
List violations. Produce a diff that fixes them.
Overlay và absolute — các trường hợp khó
Các node overlay cần một parent relative và các children được định vị absolute. IR liệt kê các children theo thứ tự z (đầu tiên = lớp dưới cùng). Hãy bảo agent giữ thứ tự này trong JSX — React render theo thứ tự DOM và CSS position: absolute xếp chồng theo đó.
Các node absolute sử dụng tọa độ pixel thô từ Figma. Chúng hầu như luôn đến từ các thiết kế không được xây dựng với auto-layout. Nếu bạn thấy nhiều node absolute, thường có nghĩa là file Figma có định vị thủ công — code được tạo ra sẽ dễ gãy ở các kích thước viewport khác nhau. Cân nhắc gắn cờ điều này và cấu trúc lại thành bố cục flex.
Xử lý chuỗi trong React
Khác với Android (nơi các khóa strings.json ánh xạ thành ID tài nguyên R.string.*), trong React bạn import JSON trực tiếp:
import strings from '../../design/strings.json'
// sử dụng
{strings['home.title'].value}
// hoặc với fallback
{strings['home.title']?.value ?? strings['home.title']?.fallback ?? 'Untitled'}
Nếu bạn đang sử dụng thư viện i18n (react-i18next, next-intl), các khóa ký hiệu chấm trong strings.json ánh xạ trực tiếp vào namespace khóa dịch. Hãy bảo agent biết thư viện i18n bạn đang sử dụng để nó tạo ra pattern gọi đúng.
Những hạn chế thực tế ở phía React
Tiện ích typography. Các tiện ích text của Tailwind (text-xs, text-2xl) không ánh xạ 1:1 với các token typography trong tokens.json. Tailwind có thang ký tự cố định; file token có kích thước tùy ý. Bạn cần mở rộng config fontSize của Tailwind với giá trị token hoặc sử dụng giá trị tùy ý (text-[24px]). Cả hai đều hoạt động; mở rộng config gọn hơn.
Line height. Vấn đề tương tự — các tiện ích leading của Tailwind không khớp với giá trị lineHeight tùy ý. Sử dụng leading-[{value}] hoặc mở rộng config.
Gradient. Không được hỗ trợ trong IR. Bất kỳ gradient fill nào xuất hiện dưới dạng cảnh báo trong _meta.json và bị bỏ qua khỏi thuộc tính fill của node. Xử lý thủ công.
Không có điều nào trong số này là rào cản — chúng là những hạn chế đã biết. Nền tảng nhận biết token là vững chắc; các cạnh chỉ cần xử lý thủ công.
Bắt đầu với figmascope để xuất bundle của bạn, sau đó sử dụng hướng dẫn này cùng với quy trình Cursor hoặc quy trình Claude Code để điều khiển triển khai.