展示 HN:Figma-use – 用于 AI 代理控制 Figma 的 CLI
Show HN: Figma-use – CLI to control Figma for AI agents

原始链接: https://github.com/dannote/figma-use

## Figma-Use:AI驱动的Figma自动化 Figma-use是一个CLI工具,连接LLM和Figma,使AI代理能够使用熟悉的JSX语法直接操作设计。与依赖冗长JSON和MCP协议的传统方法不同,它利用了一种高效的token方式——发送LLM易于理解的JSX代码。这大大减少了通信开销,尤其是在复杂操作中。 主要功能包括:一个将JSX转换为Figma节点的`render`命令,用于创建基本形状和组件的命令,以及用于管理变量、样式和评论的工具。它还支持创建带有变体的组件集。一个`SKILL.md`文件为Claude Code和Cursor等AI代理提供了全面的参考。 Figma-use通过利用Figma内部的多人协作协议(实验性)实现了显著的速度提升(约快100倍)。虽然可能存在与Figma更新不稳定的风险,但它解锁了强大的自动化可能性。安装涉及CLI安装和一个Figma插件。它还提供了一个MCP端点以实现兼容性。 最终,Figma-use通过AI的力量,使开发者能够以前所未有的轻松和效率构建和修改Figma设计。

Dan Note 创建了“figma-use”,一个命令行界面 (CLI),使 AI 代理能够*设计* Figma,而不仅仅是读取它。该工具提供超过 100 个用于操作 Figma 元素(形状、文本、样式等)的命令,并拥有一个比现有插件 API 快得多的 JSX 导入功能。 figma-use 基于 Bun、Elysia 和 Figma 的插件系统构建,解决了 Figma 官方 API 仅可读的限制。它允许 AI 使用比复杂 JSON 模式更有效的方法,主动构建设计,从简单的按钮到完整的组件系统。 一个演示视频展示了它的功能。开发者正在寻求关于可用性、所需命令以及 JSX 语法的直观性的反馈。可以通过 `bun install -g @dannote/figma-use` 进行安装。
相关文章

原文

CLI for Figma. LLMs already know React and work great with CLIs — this combines both.

echo '<Frame style={{padding: 24, backgroundColor: "#3B82F6", borderRadius: 12}}>
  <Text style={{fontSize: 18, color: "#FFF"}}>Hello Figma</Text>
</Frame>' | figma-use render --stdin

No JSON schemas, no MCP protocol overhead — just JSX that any LLM can write.

📄 Includes SKILL.md — drop-in reference for Claude Code and other AI agents.

Watch demo on YouTube

▶️ Watch the demo — AI builds a button component set in Figma in seconds.

MCP servers exchange verbose JSON. CLIs are token-efficient:

# 47 tokens
figma-use create frame --width 400 --height 300 --fill "#FFF" --radius 12 --layout VERTICAL --gap 16

vs MCP JSON request + response: ~200 tokens for the same operation.

For AI agents doing dozens of Figma operations, this adds up fast. If you still prefer MCP, see MCP Server section.

Every LLM has been trained on millions of React components. They can write this without examples:

<Frame style={{ flexDirection: 'column', gap: 16, padding: 24 }}>
  <Text style={{ fontSize: 24, fontWeight: 'bold' }}>Title</Text>
  <Text style={{ fontSize: 14, color: '#666' }}>Description</Text>
</Frame>

The render command takes this JSX and creates real Figma nodes — frames, text, components, auto-layout, the works.

bun install -g @dannote/figma-use

figma-use plugin install  # Install plugin (quit Figma first)
figma-use proxy      # Start proxy server

Open Figma → Plugins → Development → Figma Use

Render: JSX → Figma (Experimental)

⚠️ Uses Figma's internal multiplayer protocol — ~100x faster than plugin API, but may break if Figma changes it.

# Terminal 1: Start Figma with debug port
figma --remote-debugging-port=9222

# Terminal 2: Start proxy
figma-use proxy
# From stdin
echo '<Frame style={{width: 200, height: 100, backgroundColor: "#FF0000"}} />' | figma-use render --stdin

# From file
figma-use render ./Card.figma.tsx

# With props
figma-use render ./Card.figma.tsx --props '{"title": "Hello"}'

Frame, Rectangle, Ellipse, Text, Line, Star, Polygon, Vector, Group

// Layout
flexDirection: 'row' | 'column'
justifyContent: 'flex-start' | 'center' | 'flex-end' | 'space-evenly'
alignItems: 'flex-start' | 'center' | 'flex-end' | 'stretch'
gap: number
padding: number
paddingTop / paddingRight / paddingBottom / paddingLeft: number

// Size & Position
width: number
height: number
x: number
y: number

// Appearance
backgroundColor: string  // hex color
borderColor: string
borderWidth: number
borderRadius: number
opacity: number

// Text
fontSize: number
fontFamily: string
fontWeight: 'normal' | 'bold' | '100'-'900'
color: string
textAlign: 'left' | 'center' | 'right'

defineComponent creates a Figma Component. First usage renders the master, subsequent usages create Instances:

import { defineComponent, Frame, Text } from '@dannote/figma-use/render'

const Card = defineComponent('Card',
  <Frame style={{ padding: 24, backgroundColor: '#FFF', borderRadius: 12 }}>
    <Text style={{ fontSize: 18, color: '#000' }}>Card</Text>
  </Frame>
)

export default () => (
  <Frame style={{ gap: 16, flexDirection: 'row' }}>
    <Card />  {/* Creates Component */}
    <Card />  {/* Creates Instance */}
    <Card />  {/* Creates Instance */}
  </Frame>
)

defineComponentSet creates a Figma ComponentSet with all variant combinations:

import { defineComponentSet, Frame, Text } from '@dannote/figma-use/render'

const Button = defineComponentSet('Button', {
  variant: ['Primary', 'Secondary'] as const,
  size: ['Small', 'Large'] as const,
}, ({ variant, size }) => (
  <Frame style={{ 
    padding: size === 'Large' ? 16 : 8,
    backgroundColor: variant === 'Primary' ? '#3B82F6' : '#E5E7EB',
    borderRadius: 8,
  }}>
    <Text style={{ color: variant === 'Primary' ? '#FFF' : '#111' }}>
      {variant} {size}
    </Text>
  </Frame>
))

export default () => (
  <Frame style={{ gap: 16, flexDirection: 'column' }}>
    <Button variant="Primary" size="Large" />
    <Button variant="Secondary" size="Small" />
  </Frame>
)

This creates 4 variant components (Primary/Small, Primary/Large, Secondary/Small, Secondary/Large) inside a ComponentSet, plus instances with the requested variants.

Bind colors to Figma variables by name:

import { defineVars, Frame, Text } from '@dannote/figma-use/render'

const colors = defineVars({
  bg: { name: 'Colors/Gray/50', value: '#F8FAFC' },
  text: { name: 'Colors/Gray/900', value: '#0F172A' },
})

export default () => (
  <Frame style={{ backgroundColor: colors.bg }}>
    <Text style={{ color: colors.text }}>Bound to variables</Text>
  </Frame>
)

The value is a fallback. At render time, colors get bound to actual Figma variables by name.


The render command is the fastest way to create complex layouts. For simpler operations or modifications, use direct commands:

figma-use create frame --width 400 --height 300 --fill "#FFF" --radius 12 --layout VERTICAL --gap 16
figma-use create rect --width 100 --height 50 --fill "#FF0000" --radius 8
figma-use create ellipse --width 80 --height 80 --fill "#00FF00"
figma-use create text --text "Hello" --fontSize 24 --fill "#000"
figma-use create line --length 100 --stroke "#000"
figma-use create component --width 200 --height 100
figma-use create instance --component <id>
figma-use set fill <id> "#FF0000"
figma-use set stroke <id> "#000" --weight 2
figma-use set radius <id> 12
figma-use set opacity <id> 0.5
figma-use set text <id> "New text"
figma-use set font <id> --family "Inter" --style "Bold" --size 20
figma-use set layout <id> --mode VERTICAL --gap 12 --padding 16
figma-use set effect <id> --type DROP_SHADOW --radius 10 --color "#00000040"
figma-use node get <id>              # Get node properties
figma-use node tree                  # Page structure as readable tree
figma-use node children <id>         # List children
figma-use find --name "Button"       # Find by name
figma-use find --type FRAME          # Find by type
figma-use selection get              # Current selection
figma-use export node <id> --output design.png
figma-use export screenshot --output viewport.png
figma-use export selection --output selection.png
figma-use page list
figma-use page set "Page Name"
figma-use viewport zoom-to-fit <ids...>
figma-use variable list
figma-use variable create "Primary" --collection <id> --type COLOR --value "#3B82F6"
figma-use style list
figma-use style create-paint "Brand/Primary" --color "#E11D48"
figma-use font list                  # All available fonts
figma-use font list --family Roboto  # Filter by family name
figma-use comment list                       # List file comments
figma-use comment add "Review this"          # Add comment
figma-use comment add "Here" --x 200 --y 100 # Comment at position
figma-use comment delete <id>                # Delete comment
figma-use version list                       # Version history
figma-use me                                 # Current user info
figma-use file info                          # File key and name
figma-use eval "return figma.currentPage.name"
figma-use eval "figma.createRectangle().resize(100, 100)"

Human-readable by default:

$ figma-use node tree
[0] frame "Card" (1:23)
    400×300 at (0, 0) | fill: #FFFFFF | layout: col gap=16
  [0] text "Title" (1:24)
      "Hello World" | 24px Inter Bold

Add --json for machine parsing:

figma-use node get <id> --json

Includes ready-to-use SKILL.md — a comprehensive reference that teaches AI agents all commands and patterns. Works with Claude Code, Cursor, and any agent that supports skill files.

# Claude Code / pi
mkdir -p ~/.claude/skills/figma-use
cp node_modules/@dannote/figma-use/SKILL.md ~/.claude/skills/figma-use/

# Or download directly  
curl -o ~/.claude/skills/figma-use/SKILL.md \
  https://raw.githubusercontent.com/anthropics/figma-use/main/SKILL.md

For simpler setups, add to your project's AGENTS.md:

## Figma

Use `figma-use` CLI. For complex layouts, use `figma-use render --stdin` with JSX.
Run `figma-use --help` for all commands.

If your client only supports MCP, the proxy exposes an endpoint at http://localhost:38451/mcp with 80+ auto-generated tools. Run figma-use mcp for config snippet.


┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  AI Agent   │────▶│  figma-use  │────▶│   Plugin    │
│             │ CLI │    proxy    │ WS  │             │
└─────────────┘     └──────┬──────┘     └─────────────┘
                           │
                    MCP ───┤ WebSocket (multiplayer)
                           ▼
                    ┌─────────────┐
                    │   Figma     │
                    │   Server    │
                    └─────────────┘
  • CLI commands → Plugin API (full Figma access)
  • MCP endpoint → Same as CLI, JSON-RPC protocol
  • render command → Multiplayer protocol (~100x faster, experimental)

MIT

联系我们 contact @ memedata.com