Parse local Figma .fig binary files offline and export assets via Figma REST API. Extracts design data, node trees, images, typography, gradients, effects, and icon metadata. Includes integrated icon SVG export combining offline parsing with API export. Generate structured design specification documents for frontend development.
- Parse the
fig-kiwibinary format usingkiwi-schema+fzstd/pako - Decompress zstd/deflate-compressed schema and data chunks
- Decode the full Figma node tree with all properties
- Extract embedded raster images (PNG/JPEG) by hash
- Node tree: Complete hierarchy with type, name, size, position, parent relationships
- Layout: Position coordinates, auto-layout (stack mode, spacing, padding, alignment)
- Typography: Font family, size, weight, line height, letter spacing, text content, styled segments
- Colors: Solid fills, gradients (linear/radial/angular) with stops and transforms
- Effects: Drop shadows, inner shadows, blur, foreground blur with full parameters
- Images: Raster image extraction with hash-to-node mapping
- Icons: Vector nodes, boolean operations, compound shapes with fill colors
When FIGMA_ACCESS_TOKEN and a cloud file_key are available:
- Use Figma REST API to export any node as SVG by its guid
- Batch export all icon nodes identified during offline parsing
- Falls back to manual SVG description when API is unavailable
# Install Node.js dependencies (in a temp/working directory)
npm install kiwi-schema pako fzstdnode scripts/extract_archive.cjs /path/to/design.fig /tmp/figma_extractThis produces:
/tmp/figma_extract/canvas.fig- the main kiwi-encoded design data/tmp/figma_extract/images/- embedded raster images (hash filenames)/tmp/figma_extract/meta.json- file metadata (name, thumbnail, export date)/tmp/figma_extract/thumbnail.png- file thumbnail
node scripts/decode_kiwi.cjs /tmp/figma_extract/canvas.fig /tmp/figma_message.jsonThis produces a large JSON file with all nodeChanges - the full Figma document tree.
node scripts/extract_layout.cjs /tmp/figma_message.json /tmp/figma_layout.jsonProduces a flat JSON array of all nodes with: name, type, guid, size, position, parentGuid, fills, strokes, effects, text data, corner radii, auto-layout properties, opacity, visibility.
node scripts/extract_hierarchy.cjs /tmp/figma_message.json /tmp/figma_tree.txtProduces a human-readable indented tree showing the visual hierarchy with key properties.
# Image hash-to-node mapping
node scripts/extract_images.cjs /tmp/figma_message.json
# Gradient details (stops, transforms)
node scripts/extract_gradients.cjs /tmp/figma_message.json
# Vector/icon node analysis
node scripts/extract_vectors.cjs /tmp/figma_message.json# Requires: FIGMA_ACCESS_TOKEN env var + file_key
python ../figma/scripts/figma_client.py export-images FILE_KEY \
--node-ids "0:11,0:30,0:45" --format svgAfter running steps 1-5, use the extracted data to write a comprehensive design-spec.md. The recommended structure:
- Global Layout - Page dimensions, background, coordinate system
- Color Palette - All unique colors extracted from fills
- Typography Scale - Font sizes, weights, line heights by hierarchy level
- Component Breakdown - Each visual module with:
- Exact pixel coordinates and dimensions
- Spacing calculations (derived from position differences)
- Fill colors, gradients, effects
- Text content and styles
- Icon descriptions with node names and guids
- Image Assets - Hash-to-filename mapping, usage locations
- Icon Inventory - All vector/boolean-op nodes with sizes, colors, parent containers, and exported SVG file paths (e.g.
assets/icons/xxx.svg). After running the SVG export step, cross-reference theexport-manifest.jsonto populate the "导出 SVG 路径" column. Icons that could not be exported (empty rectangles) or are implemented as inline SVG should be marked accordingly.
[8 bytes] Header prelude: "fig-kiwi" (exactly 8 bytes, no null padding)
[4 bytes] Version number (uint32 LE, e.g., 106)
[4 bytes] Chunk 0 size (uint32 LE) - Schema (deflate-raw compressed)
[N bytes] Chunk 0 data
[4 bytes] Chunk 1 size (uint32 LE) - Message (zstd or deflate-raw compressed)
[N bytes] Chunk 1 data
Note: Newer .fig files (version >= ~100) use zstd compression for the message
chunk. Detect by checking for the zstd magic number 0xFD2FB528 (bytes: 28 B5 2F FD)
at the start of chunk 1. Schema chunk always uses deflate-raw.
But modern .fig files are actually ZIP archives containing:
canvas.fig- The kiwi-encoded design data (fig-kiwi format as above)meta.json- File metadatathumbnail.png- Preview imageimages/- Directory of embedded raster images (named by content hash)
- Decompress chunk 0 with
pako.inflateRaw()to get the binary schema - Use
kiwi-schema.decodeBinarySchema()to parse the schema definition - Use
kiwi-schema.compileSchema()to create a decoder - Decompress chunk 1 with
pako.inflateRaw()to get the binary message - Use
compiledSchema.decodeMessage()to decode into JSON
{
"type": "NODE_CHANGES",
"nodeChanges": [
{
"guid": { "sessionID": 0, "localID": 42 },
"parentIndex": { "guid": { "sessionID": 0, "localID": 2 }, "position": "..." },
"type": "FRAME|TEXT|VECTOR|ROUNDED_RECTANGLE|ELLIPSE|BOOLEAN_OPERATION|...",
"name": "Node Name",
"size": { "x": 100, "y": 50 },
"transform": { "m00": 1, "m01": 0, "m02": 450, "m10": 0, "m11": 1, "m12": 200 },
"fillPaints": [{ "type": "SOLID", "color": { "r": 0.09, "g": 0.03, "b": 0.16, "a": 1 } }],
"strokePaints": [...],
"effects": [{ "type": "DROP_SHADOW", "color": {...}, "offset": {...}, "radius": 15, "spread": 0 }],
"cornerRadius": 12,
"opacity": 0.86,
"textData": { "characters": "Hello", "glyphs": [...] },
"fontSize": 16,
"fontWeight": 500,
"lineHeight": { "value": 32, "units": "PIXELS" },
"stackMode": "VERTICAL",
"stackSpacing": 8,
"vectorNetworkBlob": "..."
}
]
}| Field | Description |
|---|---|
guid |
Unique node ID: {sessionID}:{localID} format (e.g., "0:42") |
parentIndex.guid |
Parent node's guid |
transform.m02 / m12 |
X and Y position (relative to parent or canvas) |
size.x / size.y |
Width and height in pixels |
fillPaints |
Array of fill paints (SOLID, IMAGE, GRADIENT_LINEAR, etc.) |
fillPaints[].color |
RGBA color with values 0-1 (multiply by 255 for hex) |
fillPaints[].image.hash |
20-byte array - convert to hex for image filename |
fillPaints[].gradientStops |
Array of { color, position } for gradients |
strokePaints |
Array of stroke paints |
strokeWeight |
Stroke width in pixels |
effects |
Array of effects (DROP_SHADOW, INNER_SHADOW, FOREGROUND_BLUR, etc.) |
cornerRadius |
Single corner radius |
rectangleCornerRadii |
Per-corner radii [tl, tr, br, bl] |
stackMode |
Auto-layout direction: VERTICAL, HORIZONTAL, or absent |
stackSpacing |
Gap between auto-layout children |
paddingLeft/Right/Top/Bottom |
Auto-layout padding |
textData.characters |
Full text content |
textData.glyphs |
Per-character style data (font, size, color) |
fontSize / fontWeight / lineHeight |
Typography properties |
vectorNetworkBlob |
Binary blob for vector paths - CANNOT be converted to SVG offline |
visible |
Boolean, false if node is hidden |
opacity |
0-1 float |
Problem: Vector nodes (icons) store their path data in vectorNetworkBlob, a proprietary binary format. There is no public documentation or open-source decoder for this blob format. The fillGeometry and strokeGeometry fields that contain SVG path strings are only available through the Figma REST API, not in the .fig binary.
Solutions (in priority order):
- Figma REST API (best): If you have
FIGMA_ACCESS_TOKEN+file_key, useexport_images(file_key, node_ids, format='svg')to export any node as clean SVG. This is the recommended approach. See../figma/scripts/figma_client.py. - Manual SVG recreation: Use the extracted node tree (positions, sizes, colors, child relationships) to manually recreate icons in SVG/JSX. The tree shows the geometric primitives (rectangles, ellipses, boolean operations) that compose each icon.
- Screenshot tracing: Use the exported PNG screenshots as visual reference to hand-draw SVG paths.
Image hashes in fillPaints[].image.hash are objects with numeric keys {0: byte, 1: byte, ...} (20 bytes). Convert to hex string to match filenames in the images/ directory:
function hashToHex(hash) {
if (!hash) return null;
let hex = '';
for (let i = 0; i < 20; i++) {
const byte = hash[i];
if (byte === undefined) break;
hex += byte.toString(16).padStart(2, '0');
}
return hex || null;
}Colors in the .fig format use 0-1 float RGBA. Convert to hex:
function colorToHex(c) {
const r = Math.round(c.r * 255);
const g = Math.round(c.g * 255);
const b = Math.round(c.b * 255);
return '#' + [r, g, b].map(v => v.toString(16).padStart(2, '0')).join('');
}transform.m02 and transform.m12 give X and Y position. For top-level children of a FRAME, these are absolute canvas coordinates. For nested children, these are relative to the parent frame's origin.
This skill includes a bundled Figma REST API client (scripts/api/figma_client.py) and
an integrated icon export script (scripts/export_icons.py). These enable SVG export of
vector icons that cannot be extracted offline due to the proprietary vectorNetworkBlob format.
# Python 3.7+ with requests library
pip install requests
# Figma access token (get from https://www.figma.com/developers/api#access-tokens)
export FIGMA_ACCESS_TOKEN="your-token-here"
# The .fig file must also exist in Figma cloud — get file_key from the URL:
# https://www.figma.com/file/FILE_KEY/File-Name → FILE_KEY# Auto-detect all icon nodes from parsed JSON and export as SVG
python scripts/export_icons.py /tmp/figma_message.json FILE_KEY -o ./assets/icons/
# Or specify node IDs manually
python scripts/export_icons.py --node-ids "0:11,0:30,0:55" FILE_KEY -o ./assets/icons/
# Dry run — show what would be exported without API calls
python scripts/export_icons.py /tmp/figma_message.json FILE_KEY --dry-run1. Extract .fig archive → node scripts/extract_archive.cjs design.fig /tmp/fig_extract
2. Decode kiwi binary → node scripts/decode_kiwi.cjs /tmp/fig_extract/canvas.fig /tmp/fig_message.json
3. Identify icon nodes → node scripts/extract_vectors.cjs /tmp/fig_message.json
4. Export icons via Figma API → python scripts/export_icons.py /tmp/fig_message.json FILE_KEY -o ./assets/icons/
5. Update design spec → Use export-manifest.json to populate the "导出 SVG 路径" column in the Icon Inventory table
The export step generates an export-manifest.json in the output directory containing node_id → file path mappings. When writing the design spec's Icon Inventory (矢量图标清单), use this manifest to fill in the exported SVG path for each icon. Icons that failed to export (empty rectangles, 162 bytes) should be noted and re-attempted via .fig binary VectorNetwork decoding or marked as inline SVG.
If FIGMA_ACCESS_TOKEN is not available:
- Use
extract_vectors.cjsoutput to see icon structure (parent containers, child shapes, colors) - Use
extract_hierarchy.cjstree to understand each icon's geometric composition - Manually create SVG/JSX icon components based on the structural description
# Export specific nodes as SVG
python scripts/api/figma_client.py export-images FILE_KEY --node-ids "0:11,0:30" --format svg
# Get full file structure from Figma cloud
python scripts/api/figma_client.py get-file FILE_KEY
# Export design tokens (colors, typography) from cloud file
python scripts/api/export_manager.py export-tokens FILE_KEY --token-format css
# Batch export all components
python scripts/api/export_manager.py export-components FILE_KEY --formats svg,png --output-dir ./exports/- Type is
VECTORorBOOLEAN_OPERATION - Parent is a small
FRAME(typically 16x16, 20x20, 24x24) - Parent name is descriptive (e.g., "faxiandengpao", "tousuyujianyi", "shijian-2")
- Has solid color fill (icon color)
- Size is small (under 32x32)
extract_archive.cjs- Unzip .fig archive, extract canvas.fig + images + metadatadecode_kiwi.cjs- Decode canvas.fig kiwi binary into full JSONextract_layout.cjs- Extract flat node array with all visual propertiesextract_hierarchy.cjs- Generate indented tree visualizationextract_images.cjs- Map image hashes to node usageextract_gradients.cjs- Extract gradient details (stops, transforms, effects)extract_vectors.cjs- Identify vector/icon nodes for SVG export
export_icons.py- End-to-end icon export: auto-detect icons + API export + rename + manifest
figma_client.py- Complete Figma API wrapper (auth, rate limiting, file/image/component endpoints)export_manager.py- Batch export manager (frames, components, pages, design tokens, client packages)
figma-api-reference.md- Figma REST API documentation and examplesexport-formats.md- Asset export format specifications (PNG, SVG, PDF, WEBP)
[FRAME] "Main Frame" 1440x2748 @(-91,-706) fill=[#f9f9f9]
[TEXT] "Title" 64x22 @(478,496) fill=[#070828] "Title Text" 16px
[FRAME] "Icon Container" 20x20 @(450,497) fill=[#ffffff]
[FRAME] "Group 27" 14x15 @(3,3) fill=[#ffffff]
[BOOLEAN_OPERATION] "Union" 14x15 @(0,0) fill=[#1677ff]
[VECTOR] "Rectangle" 14x15 @(0,0) fill=[#1f8ffb] r=1.75
[ROUNDED_RECTANGLE] "Bar 1" 4x2 @(3,4) fill=[#ffffff] r=0.875
{
"name": "Title Text",
"type": "TEXT",
"guid": "0:9",
"size": { "w": 64, "h": 22 },
"position": { "x": 478, "y": 496 },
"parentGuid": "0:2",
"fills": [{ "type": "SOLID", "color": "#070828", "opacity": 1 }],
"text": "Multi-dimension Analysis",
"fontSize": 16,
"lineHeight": { "value": 100, "units": "PERCENT" }
}