Awesome-omni-skill figma-use

Control Figma via CLI — create shapes, frames, text, components, set styles, layout, variables, export images. Use when asked to create/modify Figma designs or automate design tasks.

install
source · Clone the upstream repo
git clone https://github.com/diegosouzapw/awesome-omni-skill
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/design/figma-use" ~/.claude/skills/diegosouzapw-awesome-omni-skill-figma-use && rm -rf "$T"
manifest: skills/design/figma-use/SKILL.md
source content

figma-use

CLI for Figma. Two modes: commands and JSX.

# Commands
figma-use create frame --width 400 --height 300 --fill "#FFF" --layout VERTICAL --gap 16
figma-use create icon mdi:home --size 32 --color "#3B82F6"
figma-use set fill 1:23 "$Colors/Primary"

# JSX (props directly on elements, NOT style={{}})
echo '<Frame p={24} bg="#3B82F6" rounded={12}>
  <Text size={18} color="#FFF">Hello</Text>
</Frame>' | figma-use render --stdin --x 100 --y 100

Before You Start

figma-use status  # Check connection

If not connected — start Figma with remote debugging:

# macOS
open -a Figma --args --remote-debugging-port=9222

# Windows
"C:\Users\%USERNAME%\AppData\Local\Figma\Figma.exe" --remote-debugging-port=9222

# Linux
figma --remote-debugging-port=9222

Start Figma with

--remote-debugging-port=9222
and you're ready.

Two Modes

Imperative — single operations:

figma-use create frame --width 400 --height 300 --fill "#FFF" --radius 12
figma-use set fill <id> "#FF0000"
figma-use node move <id> --x 100 --y 200

Declarative — render JSX trees:

echo '<Frame p={24} gap={16} flex="col" bg="#FFF" rounded={12}>
  <Text size={24} weight="bold" color="#000">Title</Text>
  <Text size={14} color="#666">Description</Text>
</Frame>' | figma-use render --stdin --x 100 --y 200

stdin supports both pure JSX and full module syntax with imports:

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

const Button = defineComponent(
  'Button',
  <Frame bg="#3B82F6" p={12} rounded={6}>
    <Text color="#FFF">Click</Text>
  </Frame>
)

export default () => (
  <Frame flex="row" gap={8}>
    <Button />
    <Button />
  </Frame>
)

Elements:

Frame
,
Rectangle
,
Ellipse
,
Text
,
Line
,
Star
,
Polygon
,
Vector
,
Group
,
Icon
,
Image
,
Instance

Use

<Instance>
to create component instances:

<Frame flex="row" gap={8}>
  <Instance component="59763:10626" />
  <Instance component="59763:10629" />
</Frame>

⚠️ Always use

--x
and
--y
to position renders. Don't stack everything at (0, 0).

Icons

150k+ icons from Iconify by name:

figma-use create icon mdi:home
figma-use create icon lucide:star --size 48 --color "#F59E0B"
figma-use create icon heroicons:bell-solid --component  # as Figma component

In JSX:

<Icon name="mdi:home" size={24} color="#3B82F6" />

Images

Load images from URL:

<Image src="https://example.com/photo.jpg" w={200} h={150} />

Export JSX

Convert Figma nodes back to JSX code:

figma-use export jsx <id>           # Minified
figma-use export jsx <id> --pretty  # Formatted

# Format options
figma-use export jsx <id> --pretty --semi --tabs

# Match vector shapes to Iconify icons (requires: npm i whaticon)
figma-use export jsx <id> --match-icons
figma-use export jsx <id> --match-icons --icon-threshold 0.85 --prefer-icons lucide,tabler

Round-trip workflow:

# Export → edit → re-render
figma-use export jsx <id> --pretty > component.tsx
# ... edit the file ...
figma-use render component.tsx --x 500 --y 0

Compare two nodes as JSX:

figma-use diff jsx <from-id> <to-id>

Export Storybook (Experimental)

Export all components on current page as Storybook stories:

figma-use export storybook                      # Output to ./stories/
figma-use export storybook --out ./src/stories  # Custom output dir
figma-use export storybook --match-icons        # Match vectors to Iconify icons
figma-use export storybook --no-semantic-html   # Disable semantic HTML conversion

Semantic HTML: By default, components are converted to semantic HTML elements based on their names:

  • Input/*
    ,
    TextField/*
    <input type="text">
  • Textarea/*
    <textarea>
  • Checkbox/*
    <input type="checkbox">
  • Radio/*
    <input type="radio">
  • Button/*
    <button>
  • Select/*
    ,
    Dropdown/*
    <select>

Use

--no-semantic-html
to disable this and keep
<Frame>
elements.

Generates

.stories.tsx
files:

  • ComponentSets → React component with props + stories with args
  • VARIANT properties → Union type props (
    variant?: 'Primary' | 'Secondary'
    )
  • TEXT properties → Editable string props (
    label?: string
    )
  • Components grouped by
    /
    prefix →
    Button/Primary
    ,
    Button/Secondary
    Button.stories.tsx

Example output for Button with variant and label:

// Button.tsx
export interface ButtonProps {
  label?: string
  variant?: 'Primary' | 'Secondary'
}
export function Button({ label, variant }: ButtonProps) {
  if (variant === 'Primary')
    return (
      <Frame>
        <Text>{label}</Text>
      </Frame>
    )
  // ...
}

// Button.stories.tsx
export const Primary: StoryObj<typeof Button> = {
  args: { label: 'Click', variant: 'Primary' }
}

Variables as Tokens

Reference Figma variables in any color option with

var:Name
or
$Name
:

figma-use create rect --width 100 --height 100 --fill 'var:Colors/Primary'
figma-use set fill <id> '$Brand/Accent'

In JSX:

<Frame bg="$Colors/Primary" />
<Text color="var:Text/Primary">Hello</Text>

Style Shorthands

Size & Position:

ShortFullValues
w
,
h
width, heightnumber or
"fill"
minW
,
maxW
minWidth, maxWidthnumber
minH
,
maxH
minHeight, maxHeightnumber
x
,
y
positionnumber

Layout:

ShortFullValues
flex
flexDirection
"row"
,
"col"
gap
spacingnumber
wrap
layoutWrap
true
justify
justifyContent
"start"
,
"center"
,
"end"
,
"between"
items
alignItems
"start"
,
"center"
,
"end"
p
,
px
,
py
paddingnumber
pt
,
pr
,
pb
,
pl
padding sidesnumber
position
layoutPositioning
"absolute"
grow
layoutGrownumber
stretch
layoutAlign
true
→ STRETCH

Appearance:

ShortFullValues
bg
fillhex or
$Variable
stroke
strokeColorhex
strokeWidth
strokeWeightnumber
strokeAlign
strokeAlign
"inside"
,
"outside"
opacity
opacity0..1
blendMode
blendMode
"multiply"
, etc.

Corners:

ShortFullValues
rounded
cornerRadiusnumber
roundedTL/TR/BL/BR
individual cornersnumber
cornerSmoothing
squircle smoothing0..1 (iOS style)

Effects:

ShortFullValues
shadow
dropShadow
"0px 4px 8px rgba(0,0,0,0.25)"
blur
layerBlurnumber
overflow
clipsContent
"hidden"
rotate
rotationdegrees

Text:

ShortFullValues
size
fontSizenumber
weight
fontWeight
"bold"
, number
font
fontFamilystring
color
textColorhex

Grid (CSS Grid layout):

ShortFullValues
display
layoutMode
"grid"
cols
gridTemplateColumns
"100px 1fr auto"
rows
gridTemplateRows
"auto auto"
colGap
columnGapnumber
rowGap
rowGapnumber

Components (via .figma.tsx)

First call creates master, rest create instances:

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

const Card = defineComponent(
  'Card',
  <Frame p={24} bg="#FFF" rounded={12}>
    <Text size={18} color="#000">
      Card
    </Text>
  </Frame>
)

export default () => (
  <Frame gap={16} flex="row">
    <Card />
    <Card />
  </Frame>
)
figma-use render ./Card.figma.tsx --x 100 --y 200
figma-use render --examples  # Full API reference

Variants (ComponentSet)

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

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

Creates real ComponentSet with all combinations.

Diffs

Compare frames and generate patch:

figma-use diff create --from <id1> --to <id2>
--- /Card/Header #123:457
+++ /Card/Header #789:013
 type: FRAME
 size: 200 50
-fill: #FFFFFF
+fill: #F0F0F0

⚠️ Context lines need space prefix:

 size: 200 50
not
size: 200 50

Apply with validation:

figma-use diff apply patch.diff            # Fails if old values don't match
figma-use diff apply patch.diff --dry-run  # Preview
figma-use diff apply patch.diff --force    # Skip validation

Visual diff (red = changed pixels):

figma-use diff visual --from <id1> --to <id2> --output diff.png

⚠️ After initial render, use diffs or direct commands. Don't re-render full JSX trees.

Query (XPath)

Find nodes using XPath selectors:

figma-use query "//FRAME"                              # All frames
figma-use query "//FRAME[@width < 300]"                # Frames narrower than 300px
figma-use query "//COMPONENT[starts-with(@name, 'Button')]"  # Name starts with
figma-use query "//FRAME[contains(@name, 'Card')]"     # Name contains
figma-use query "//SECTION/FRAME"                      # Direct children
figma-use query "//SECTION//TEXT"                      # All descendants
figma-use query "//*[@cornerRadius > 0]"               # Any node with radius
figma-use query "//FRAME[@width > 100 and @width < 500]"  # Range

Attributes:

name
,
width
,
height
,
x
,
y
,
cornerRadius
,
opacity
,
visible
,
characters
,
fontSize
,
layoutMode
,
itemSpacing

XPath functions:

contains()
,
starts-with()
,
string-length()
,
not()
,
and
,
or

Common Commands

# Create
figma-use create frame --width 400 --height 300 --fill "#FFF" --layout VERTICAL --gap 16
figma-use create text --text "Hello" --font-size 24 --fill "#000"
figma-use create rect --width 100 --height 50 --fill "#F00" --radius 8

# Find
figma-use query "//FRAME[@name = 'Header']"
figma-use find --name "Button"
figma-use find --type FRAME
figma-use selection get

# Explore
figma-use node ancestors <id>              # Get parent chain (useful for navigation)
figma-use node bindings <id>               # Get variable bindings for fills/strokes
figma-use page bounds                      # Find free space for new objects
figma-use variable find "Text/Neutral"     # Search variables by name

# Modify
figma-use set fill <id> "#FF0000"
figma-use set radius <id> 12
figma-use set text <id> "New text"
figma-use set text-resize <id> height   # Wrap text (height auto, fixed width)
figma-use set layout <id> --mode VERTICAL --gap 12 --padding 16
figma-use set layout <id> --mode GRID --cols "1fr 1fr 1fr" --rows "auto" --gap 16
figma-use node move <id> --x 100 --y 200
figma-use node resize <id> --width 300 --height 200
figma-use node delete <id> [id2...]
figma-use node to-component <id>

# Export
figma-use export node <id> --output design.png
figma-use export screenshot --output viewport.png

# Navigate
figma-use page list
figma-use page set "Page Name"
figma-use viewport zoom-to-fit <id>

Full reference: REFERENCE.md

Analyze

Discovery tools for understanding design systems:

# Repeated patterns — potential components
figma-use analyze clusters
figma-use analyze clusters --min-count 5

# Color palette
figma-use analyze colors                   # Usage frequency
figma-use analyze colors --show-similar    # Find similar colors to merge

# Typography
figma-use analyze typography               # All font combinations
figma-use analyze typography --group-by size

# Spacing
figma-use analyze spacing --grid 8         # Check 8px grid compliance

# Accessibility snapshot — extract interactive elements
figma-use analyze snapshot                 # Full page
figma-use analyze snapshot <id> -i         # Interactive only (buttons, inputs, etc.)
figma-use analyze snapshot --depth 6       # Limit depth

Use cases:

  • Component extraction — find copy-pasted elements that should be components
  • Design audit — identify inconsistencies, similar-but-different elements
  • Design system creation — discover existing colors, typography, spacing patterns
  • Onboarding — understand structure of unfamiliar design files

Output shows counts, examples, and warnings (e.g., off-grid spacing, hardcoded colors).

Lint (Experimental)

Check designs for consistency and accessibility issues:

figma-use lint                          # Recommended preset
figma-use lint --page "Components"      # Lint specific page
figma-use lint --preset strict          # Stricter rules
figma-use lint --preset accessibility   # A11y only (contrast, touch targets)
figma-use lint --rule color-contrast    # Single rule
figma-use lint -v                       # With fix suggestions
figma-use lint --json                   # For CI/CD
figma-use lint --list-rules             # Show all rules

Presets:

recommended
,
strict
,
accessibility
,
design-system

17 rules:

  • Design tokens:
    no-hardcoded-colors
    ,
    consistent-spacing
    ,
    consistent-radius
    ,
    effect-style-required
  • Layout:
    prefer-auto-layout
    ,
    pixel-perfect
  • Typography:
    text-style-required
    ,
    min-text-size
    ,
    no-mixed-styles
  • Accessibility:
    color-contrast
    ,
    touch-target-size
  • Structure:
    no-default-names
    ,
    no-hidden-layers
    ,
    no-deeply-nested
    ,
    no-empty-frames
    ,
    no-groups
  • Components:
    no-detached-instances

Exit code 1 if errors found — use in CI pipelines.

Output

Human-readable by default — prefer this to save tokens. Use

--json
only when you need to parse specific fields programmatically.

Node IDs

Format:

session:local
(e.g.,
1:23
). Inside instances:
I<instance-id>;<internal-id>
.

Get IDs from

figma-use selection get
or
figma-use node tree
.

Colors

Hex:

#RGB
,
#RRGGBB
,
#RRGGBBAA
Variables:
var:Colors/Primary
or
$Colors/Primary


Best Practices

Always verify visually

figma-use export node <id> --output /tmp/check.png

Always zoom after creating

figma-use viewport zoom-to-fit <id>

Position multiple renders separately

echo '...' | figma-use render --stdin --x 0 --y 0
echo '...' | figma-use render --stdin --x 500 --y 0    # Not at same position!

Copy between pages

figma-use node clone <id> [id2...] --json | jq -r '.[].id'
figma-use node set-parent <new-id> --parent <target-page-id>
figma-use node move <new-id> --x 50 --y 50

Replace node

# Replace with component (creates instance)
figma-use node replace-with <id> --target <component-id>

# Replace with JSX from stdin
echo '<Icon name="lucide:x" size={16} />' | figma-use node replace-with <id> --stdin

Convert to component

figma-use node to-component <id>
figma-use node to-component "1:2 1:3 1:4"  # Multiple

Instance internal IDs

figma-use set text "I123:456;789:10" "New text"  # I<instance>;<internal>

Row layout needs width

# ❌ Collapses to 1×1
<Frame flex="row" gap={8}>

# ✅ Explicit width
<Frame w={300} flex="row" gap={8}>

Sections

figma-use create section --name "Buttons" --x 0 --y 0 --width 600 --height 200
figma-use node set-parent <id> --parent <section-id>

⚠️ Deleting section deletes all children!

Comment-driven workflow

Wait for designer feedback and react:

figma-use comment watch --json

Output when comment arrives:

{
  "id": "123456",
  "message": "Make this button bigger",
  "user": { "handle": "designer" },
  "client_meta": { "node_id": "1:23" }
}

Agent workflow — run once per comment, then restart:

  1. figma-use comment watch --json
    — blocks until new comment
  2. Parse the JSON, get
    message
    and
    target_node
    (exact element under comment)
  3. Process the request (modify design, etc.)
  4. Reply:
    figma-use comment add "Done!" --reply <comment-id>
  5. Resolve:
    figma-use comment resolve <comment-id>
  6. Exit. External runner restarts for next comment.

Options:

  • --timeout 60
    — exit after 60s if no comment (returns
    {"timeout":true}
    )
  • --interval 5
    — poll every 5s (default: 3s)

Vector paths — iterative workflow

Draw, screenshot, adjust, repeat — like a designer tweaking Bezier curves:

# 1. Draw initial shape
figma-use create vector --path "M 50 0 L 100 100 L 0 100 Z" --fill "#F00"

# 2. Check result
figma-use export node <id> --output /tmp/shape.png

# 3. Adjust: scale, move, flip
figma-use path scale <id> --factor 0.8
figma-use path move <id> --dx 20 --dy -10
figma-use path flip <id> --axis x

# 4. Or replace path entirely
figma-use path set <id> "M 50 0 C 80 30 80 70 50 100 C 20 70 20 30 50 0 Z"

# 5. Screenshot again, repeat until good
figma-use export node <id> --output /tmp/shape.png

For complex illustrations, import SVG:

figma-use import --svg "$(cat icon.svg)"