Communitygithub.com

PMDevSolutions/Aurelius

協調從 Figma 到 React 的端到端轉換流程,強制實施 TDD、自動化像素比對視覺 QA、E2E 測試,並具備應用程式類型感知能力(網頁應用程式、Chrome 擴充功能、PWA)。

Aurelius 是什麼?

這個技能負責將 Figma 設計檔完整轉換為生產就緒的 React 應用程式。它會從 Figma 中提取設計系統(顏色、排版、間距、效果),然後轉換為 Tailwind CSS 設定檔與 CSS 自訂屬性,最後生成能忠實重現原始設計的 TypeScript React 元件。整個流程分為四個階段:互動探索、TDD 支架、自主執行與驗證交付。最終產出是一組 React 元件、頁面與設計代號系統,可直接整合到 Next.js、Vite 或 Remix 專案中,並透過自動化像素比對循環驗證其與 Figma 來源達像素等級的準確度。此技能強制執行測試驅動開發(TDD),要求所有元件在實作前都必須先有測試檔,以此作為設計與程式碼之間的合約。它還支援多種應用程式類型(網頁應用程式、Chrome 擴充功能、PWA),並能根據專案架構(Next.js App Router、Vite SPA、Remix 路由)調整輸出內容。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/PMDevSolutions/Aurelius/tree/HEAD/.claude/skills/figma-to-react-workflow

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

Figma 到 React 自主工作流程

概述

此技能負責協調將 Figma 設計轉換為生產就緒 React 應用程式的完整流程。它從 Figma 中提取設計系統(顏色、排版、間距、效果),將其轉換為 Tailwind CSS 設定與 CSS 自訂屬性,然後生成能忠實重現原始設計的功能性 TypeScript React 元件。

工作流程分為四個階段:互動探索、TDD 支架、自主執行與驗證交付。最終產出是一組 React 元件、頁面以及一個設計代號系統,可直接整合到 Next.js、Vite 或 Remix 專案中,並經過驗證,可達到像素等級的準確度。

核心原則:

  • TDD 是強制的 — 測試必須在元件之前撰寫,絕對不能在之後
  • 每個元件都是一個功能性 TypeScript 元件,並帶有明確的 prop 介面
  • 所有樣式都使用由來自 Figma 的設計代號支援的 Tailwind 工具類別
  • 不允許硬編碼的顏色值、字型大小或間距 — 所有內容都參考代號系統
  • 圖片使用正確的導入或公開目錄引用,絕不使用中斷的路徑
  • 輸出內容會感知框架(Next.js App Router、Vite SPA、Remix 路由)
  • 像素完美驗證 — 使用 pixelmatch 進行自動化差異比對循環,而非手動比較
  • 應用程式類型感知 — Chrome 擴充功能、PWA 和網頁應用程式各自獲得適當的測試策略

使用時機

在以下情況使用此技能:

  • 將 Figma 設計檔轉換為 React 應用程式
  • 從 Figma 中提取設計系統並轉換為 Tailwind 設定
  • 從 Figma 元件集中生成元件庫
  • 根據 Figma 重新設計重建現有 UI
  • 從 Figma 原型開始新的 React 專案

觸發短語:

  • "將這個 Figma 設計轉換為 React"
  • "從 Figma 生成 React 元件"
  • "從 Figma 提取設計代號"
  • "從這個 Figma 檔案建立 React 應用程式"
  • "Figma 到 Next.js"
  • "Figma 到 Vite"

階段 1:探索(互動式)

此階段需要使用者輸入。在使用者確認計畫之前,請勿自主進行。

流程整合檢查

在詢問任何問題之前,檢查上游工件是否存在:

1. 檢查:.claude/plans/build-spec.json
   → 如果存在:跳過所有探索問題。直接載入規格。
   → 記錄:"找到來自 figma-intake 的 build-spec.json — 跳過探索"

2. 檢查:src/styles/design-tokens.lock.json
   → 如果存在:在階段 2 中跳過代號提取。使用鎖定檔中的值。
   → 記錄:"找到 design-tokens.lock.json — 使用鎖定的代號值"

如果 build-spec.json 存在,則直接跳至階段 2,並預先載入規格中的框架、元件和選項。

步驟 1.1:收集 Figma 上下文

使用 Figma MCP 檢查設計檔。

1. get_metadata        — 檔案名稱、頁面、最後修改時間、元件數量
2. get_variable_defs   — 設計代號(顏色、排版、間距、效果)
3. get_design_context  — 版面結構、元件層級、自動佈局設定
4. get_screenshot      — 每個頁面/框架的視覺參考

步驟 1.2:提取設計代號

將 Figma 變數和樣式對應到代號結構:

設計代號
├── 顏色
│   ├── 原始色(blue-500、gray-100 等)
│   ├── 語意色(primary、secondary、destructive、muted)
│   └── 元件專用(card-bg、button-primary、input-border)
├── 排版
│   ├── 字型家族(包含後備字型堆疊)
│   ├── 字型大小(比例:xs 到 5xl)
│   ├── 字型粗細
│   ├── 行高
│   └── 字母間距
├── 間距
│   ├── 基本單位
│   └── 比例(0.5 到 96)
├── 邊框圓角
│   ├── 比例(sm、md、lg、xl、full)
│   └── 元件專用覆寫
├── 陰影/效果
│   ├── 盒子陰影(sm、md、lg、xl)
│   └── 下拉陰影
└── 中斷點
    └── 手機、平板、桌上型電腦、寬螢幕

步驟 1.3:調查元件

識別所有 Figma 元件並將其對應到 React 元件:

Figma 元件React 元件類別
Button/Primary<Button variant="primary">基本元件
Card<Card>容器
Navigation/Header<Header>佈局
Hero Section<HeroSection>區段
Input/Text<Input type="text">表單

步驟 1.4:確認輸出目標

要求使用者確認:

  1. 框架: Next.js(App Router)、Next.js(Pages Router)、Vite 或 Remix
  2. 樣式方法: Tailwind CSS(預設)、CSS Modules 或 styled-components
  3. 元件庫基礎: shadcn/ui、Radix UI、Headless UI 或無
  4. 狀態管理: React state、Zustand、Jotai 或無
  5. 輸出目錄: 例如 src/components/、app/ 等

在繼續之前,呈現元件清單和代號摘要以供使用者批准。

階段 2:執行(自主)

一旦使用者批准探索計畫,就自主執行所有步驟。

代號鎖定檔限制

如果 src/styles/design-tokens.lock.json 存在,所有生成的程式碼都必須參考鎖定檔中的值:

  • 顏色:使用鎖定檔中對應的 Tailwind 類別,絕不近似十六進位值
  • 排版:使用鎖定檔中的確切字型家族、大小和粗細
  • 間距:使用鎖定檔中的間距比例值
  • 文字內容:使用 lockfile.textContent 中的確切字串

當鎖定檔存在時,絕不近似或猜測值。 如果鎖定檔中沒有某個值,請先將其新增到鎖定檔中,然後再引用它。

測試優先閘門(強制)

強制執行 TDD。 在測試檔存在之前,不得開始實作元件。這是一個硬性閘門,而非建議。

在撰寫任何元件實作之前:

  1. 執行:./scripts/verify-test-coverage.sh
     → 如果退出碼為 1:停止。先叫用 tdd-from-figma 技能。
     → 如果退出碼為 0:繼續進行實作。

  2. 對於要生成的每個元件:
     a. 要求:src/components/**/{ComponentName}.test.tsx 存在
        → 如果缺少:停止。先撰寫測試(叫用 tdd-from-figma)。
        → 這不是可選的。沒有預先存在的測試,任何元件都不能出貨。
     b. 讀取測試檔以了解預期行為
     c. 實作必須讓所有測試通過
     d. 在撰寫元件後執行:pnpm vitest run {test-file}
     e. 如果測試失敗:修正元件,而不是測試

  3. 在批次中的所有元件撰寫完成後:
     → 執行:pnpm vitest run --reporter=verbose
     → 所有測試都必須通過(TDD 的綠色階段)才能繼續
     → 如果有任何失敗:修正元件直到綠色。不要繼續進行階段 3。

  4. 驗證測試覆蓋率達到門檻:
     → 執行:pnpm vitest run --coverage
     → 必須達到:pipeline.config.json → tdd.coverageThreshold(預設:80%)

為什麼要有這個閘門: 測試編碼了鎖定檔中的確切值(文字內容、ARIA 角色、元件結構)。如果沒有預先撰寫的測試,就沒有機制來驗證實作是否符合設計。測試是 Figma 設計與 React 程式碼之間的合約。

步驟 2.1:生成 Tailwind 設定

使用提取的代號建立或擴充 tailwind.config.ts:

// tailwind.config.ts
import type { Config } from "tailwindcss";

const config: Config = {
  content: ["./src/**/*.{ts,tsx}", "./app/**/*.{ts,tsx}"],
  theme: {
    extend: {
      colors: {
        // 從 Figma 變數對應的語意代號
        primary: {
          DEFAULT: "var(--color-primary)",
          foreground: "var(--color-primary-foreground)",
          // ... 完整比例
        },
        // ... 所有顏色代號
      },
      fontFamily: {
        sans: ["var(--font-sans)", "system-ui", "sans-serif"],
        heading: ["var(--font-heading)", "system-ui", "sans-serif"],
      },
      fontSize: {
        // 從 Figma 排版樣式對應
      },
      spacing: {
        // 從 Figma 間距變數對應
      },
      borderRadius: {
        // 從 Figma 角落圓角代號對應
      },
      boxShadow: {
        // 從 Figma 效果樣式對應
      },
    },
  },
  plugins: [],
};

export default config;

使用自訂屬性生成一個伴隨的 CSS 檔:

/* src/styles/tokens.css */
:root {
  /* 顏色 - 原始色 */
  --color-blue-500: #3b82f6;
  /* ... */

  /* 顏色 - 語意 */
  --color-primary: var(--color-blue-500);
  --color-primary-foreground: #ffffff;
  /* ... */

  /* 排版 */
  --font-sans: "Inter", system-ui, sans-serif;
  --font-heading: "Plus Jakarta Sans", system-ui, sans-serif;
  /* ... */
}

步驟 2.2:生成 React 元件

對於在階段 1 中識別的每個元件,生成:

每個元件的檔案結構:

src/components/
├── ui/
│   ├── button.tsx          # 基本元件
│   ├── input.tsx
│   ├── card.tsx
│   └── ...
├── layout/
│   ├── header.tsx          # 佈局元件
│   ├── footer.tsx
│   └── ...
├── sections/
│   ├── hero-section.tsx    # 頁面區段
│   ├── features-grid.tsx
│   └── ...
└── pages/                  # 完整頁面組合(或 Next.js 的 app/)
    ├── home-page.tsx
    └── ...

元件範本:

// src/components/ui/button.tsx
import { type ButtonHTMLAttributes, forwardRef } from "react";
import { cn } from "@/lib/utils";

interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: "primary" | "secondary" | "outline" | "ghost";
  size?: "sm" | "md" | "lg";
}

const Button = forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant = "primary", size = "md", ...props }, ref) => {
    return (
      <button
        ref={ref}
        className={cn(
          "inline-flex items-center justify-center rounded-md font-medium transition-colors",
          "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary",
          "disabled:pointer-events-none disabled:opacity-50",
          {
            "bg-primary text-primary-foreground hover:bg-primary/90": variant === "primary",
            "bg-secondary text-secondary-foreground hover:bg-secondary/90": variant === "secondary",
            "border border-input bg-transparent hover:bg-accent": variant === "outline",
            "hover:bg-accent hover:text-accent-foreground": variant === "ghost",
          },
          {
            "h-8 px-3 text-sm": size === "sm",
            "h-10 px-4 text-sm": size === "md",
            "h-12 px-6 text-base": size === "lg",
          },
          className
        )}
        {...props}
      />
    );
  }
);
Button.displayName = "Button";

export { Button, type ButtonProps };

元件生成規則:

  1. 所有元件都是功能性的,並在適當的情況下使用 forwardRef
  2. 每個元件都有明確的 TypeScript interface 用於 props
  3. 所有樣式都使用引用代號值的 Tailwind 類別
  4. 元件接受 className prop 以便組合
  5. 使用 cn() 工具函式(clsx + tailwind-merge)進行類別合併
  6. 為互動元素包含適當的 ARIA 屬性
  7. 同時匯出元件及其 props 類型

步驟 2.3:生成頁面組合

將區段元件組合成符合 Figma 框架的完整頁面:

// app/page.tsx (Next.js App Router)
import { Header } from "@/components/layout/header";
import { HeroSection } from "@/components/sections/hero-section";
import { FeaturesGrid } from "@/components/sections/features-grid";
import { Footer } from "@/components/layout/footer";

export default function HomePage() {
  return (
    <div className="flex min-h-screen flex-col">
      <Header />
      <main className="flex-1">
        <HeroSection />
        <FeaturesGrid />
      </main>
      <Footer />
    </div>
  );
}

步驟 2.4:處理圖片和資產

對於來自 Figma 的靜態圖片:

// Next.js - 使用 next/image
import Image from "next/image";
import heroImage from "@/assets/images/hero.webp";

<Image src={heroImage} alt="Hero 插圖" width={1200} height={600} priority />

// Vite - 使用標準導入
import heroImage from "@/assets/images/hero.webp";

<img src={heroImage} alt="Hero 插圖" width={1200} height={600} loading="eager" />

規則:

  • 從 Figma 以 1x 和 2x 匯出圖片以支援 Retina 螢幕
  • 使用 WebP 格式,並提供 JPEG/PNG 作為備援
  • 放置在 public/images/ 或 src/assets/images/ 中
  • 每個 <img> 都必須有有意義的 alt 屬性
  • Hero / 上方折頁圖片使用 priority(Next.js)或 loading="eager"
  • 下方折頁圖片使用 loading="lazy"

步驟 2.5:生成工具檔

src/lib/
├── utils.ts          # cn() 輔助函式、格式化工具
└── fonts.ts          # 字型載入(Next.js:next/font,Vite:@fontsource)

步驟 2.6:執行測試(如果測試檔存在)

生成所有元件後,如果 tdd-from-figma 已撰寫測試檔:

pnpm vitest run --reporter=verbose

如果測試失敗: 修正元件實作以符合測試預期。測試是權威性的——它們編碼了鎖定檔中的確切值。請勿修改測試以符合實作。

迭代直到所有測試通過(TDD 的綠色階段)。

步驟 2.7:生成 Storybook 故事(非阻塞)

一旦元件建置完成且其單元測試通過,便自動生成 Storybook 故事和 MDX 文件。呼叫 storybook-story-generation 技能(或直接執行指令稿)。這是流程的 階段 4.5,且是 非阻塞 的——此處的失敗會記錄警告,流程會繼續執行。

# 為每個元件生成 .stories.tsx + .mdx(跳過已有故事的元件)
./scripts/generate-stories.sh

# 在不寫入的情況下預覽,或強制重新生成
./scripts/generate-stories.sh --dry-run
./scripts/generate-stories.sh --force

階段 3:驗證與測試

元件層級 TDD 驗證

在停止所有生成活動後,對整個專案執行最終驗證循環:

# 1. 執行完整的測試套件
pnpm vitest run --reporter=verbose

# 2. 檢查型別
pnpm tsc --noEmit

# 3. 檢查覆蓋率
pnpm vitest run --coverage

所有測試必須通過。 如果測試失敗,請修正元件實作,而不是測試。測試編碼了鎖定檔中的確切值、結構和行為契約。

像素完美驗證

生成 PixelMatch 指令稿以自動化視覺回歸測試:

# ./scripts/pixel-diff.sh
# 1. 建置應用程式
# 2. 為每個頁面/元件擷取螢幕截圖
# 3. 與 Figma 基準進行像素差異比對
# 4. 報告通過/失敗與差異百分比

E2E 測試

為 Playwright 或 Cypress 生成端到端測試(根據專案類型和慣例):

// e2e/home-page.spec.ts
import { test, expect } from "@playwright/test";

test.describe("首頁", () => {
  test.beforeEach(async ({ page }) => {
    await page.goto("/");
  });

  test("顯示標題", async ({ page }) => {
    await expect(page.locator("h1")).toContainText("歡迎");
  });

  test("導航連結存在", async ({ page }) => {
    await expect(page.locator("nav a")).toHaveCount(4);
  });
});

組態

可選的 pipeline.config.json 控制閘門、階段和行為:

{
  "tdd": {
    "enforce": true,
    "coverageThreshold": 80,
    "failOnMissingTests": true
  },
  "pixelDiff": {
    "enabled": true,
    "threshold": 0.02,
    "generateBaseline": false
  },
  "e2e": {
    "framework": "playwright",
    "viewport": {
      "mobile": [375, 667],
      "tablet": [768, 1024],
      "desktop": [1280, 800]
    }
  },
  "output": {
    "framework": "next-app",
    "componentDir": "src/components",
    "pageDir": "app",
    "styling": "tailwind"
  },
  "storybook": {
    "enabled": true,
    "autoGenerate": true
  },
  "appType": "spa",
  "chromeExtension": false,
  "pwa": false
}

輸出

此工作流程的輸出包含:

  1. 設計代號系統 在 tailwind.config.ts 和 src/styles/tokens.css 中
  2. React 元件 在 src/components/ 中(基本元件、佈局、區段)
  3. 頁面組合 在 app/ 或 src/pages/ 中
  4. 通過的測試 用於單元測試、型別檢查、像素差異比對和 E2E
  5. Storybook 故事 用於開發(透過非阻塞生成)

每個工作流程的結果都是完全可重現的——相同的 Figma 檔案和設定會產生完全相同的輸出。

相關技能