Communitygithub.com

PMDevSolutions/Aurelius(菲格玛到React自主工作流)

编排端到端的 Figma 到 React 转换流水线,强制实施测试驱动开发(TDD)、自动像素差异视觉质量保证(QA)、端到端(E2E)测试,并具备应用类型感知能力(Web 应用、Chrome 扩展、PWA)。

Aurelius(菲格玛到React自主工作流) 是什么?

该技能(Aurelius)提供了一个完整的自主流水线,用于将 Figma 设计转换为生产就绪的 React 应用。它首先从 Figma 中提取设计系统(颜色、排版、间距、效果),并将其转换为 Tailwind CSS 配置和 CSS 自定义属性。然后,它生成功能完善的 TypeScript React 组件,这些组件能忠实再现原始设计,并支持 Next.js、Vite 和 Remix 等流行框架。其核心原则是强制使用测试驱动开发(TDD),并在测试覆盖和像素级视觉保真度方面设置硬性门禁——在最终交付前,使用像素匹配(pixelmatch)自动循环比对确保设计准确无误。该技能通过四个阶段运作:交互式发现阶段(收集图样上下文和用户偏好)、脚手架搭建阶段(准备测试)、自主执行阶段(生成令牌、组件和页面)以及验证交付阶段(运行测试和像素比对)。它支持不同的应用类型(Web 应用、Chrome 扩展、PWA),并智能调整其测试策略。通过使用锁文件(design-tokens.lock.json)和预设的构建规范(build-spec.json),该流水线还支持无头重放,从而实现一致且可重复的转换,无需每次都进行手动输入。

兼容平台✓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 项目中,并能达到与 Figma 源文件像素级一致的精度。

核心原则:

  • TDD 是强制的 — 先写测试,后写组件,绝不颠倒顺序
  • 每个组件都是一个功能完整的 TypeScript 组件,并具有明确的 props 接口
  • 所有样式都使用基于 Figma 设计令牌的 Tailwind 实用类
  • 没有硬编码的颜色值、字体大小或间距——一切都引用令牌系统
  • 图片使用正确的导入或公共目录引用,绝无断链路径
  • 输出结果能感知框架(Next.js App Router、Vite SPA、Remix 路由)
  • 像素级完美验证 — 使用 pixelmatch 自动进行差异循环比对,而非手动比较
  • 应用类型感知 — Chrome 扩展、PWA 和 Web 应用各自拥有合适的测试策略

何时使用

在以下场景使用此技能:

  • 将 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
   → 如果存在:跳过所有发现性问题。直接加载规范。
   → 记录日志:“发现 build-spec.json 来自 figma-intake — 跳过发现阶段”

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="英雄区插图" width={1200} height={600} priority />

// Vite - 使用标准导入
import heroImage from "@/assets/images/hero.webp";

<img src={heroImage} alt="英雄区插图" width={1200} height={600} loading="eager" />

规则:

  • 以 1x 和 2x 分辨率导出 Figma 图片以支持视网膜屏
  • 使用 WebP 格式,并准备 JPEG/PNG 作为备选
  • 放置在 public/images/ 或 src/assets/images/ 目录中
  • 每个 <img> 必须包含有意义的 alt 属性
  • 首屏/折叠线上方的图片使用 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

生成器使用 ts-morph AST 解析每个组件,并发出 CSF3 故事,包含以下内容:prop 感知的控制、每个字符串字面量联合值的一个变体故事、布尔值的 True/False 故事、on* 回调的动作参数,以及一个 MDX 自动文档页面。行为由 .claude/pipeline.conf 配置。

...(已截断以进行翻译)

相关技能