openpencil/docs/reference/file-format.md

2.2 KiB

File Format

.fig File Structure

┌─────────────────────────────────┐
│ Magic header: "fig-kiwi" (8B)   │
│ Version (4B uint32 LE)          │
│ Schema length (4B uint32 LE)    │
│ Compressed Kiwi schema          │
│ Message length (4B uint32 LE)   │
│ Compressed Kiwi message         │  ← NodeChange[] (entire document)
│ Blob data                       │  ← Images, vector networks, fonts
└─────────────────────────────────┘

Import Pipeline

.fig file → Parse header → Decompress Zstd → Decode Kiwi schema
  → Decode Message → NodeChange[] → Build SceneGraph
  → Resolve blob refs → Render on canvas

Kiwi Binary Codec

The codec handles Figma's 194-definition Kiwi schema with NodeChange as the central type (~390 fields). Key components:

  • kiwi-schema — vendored from evanw/kiwi, patched for ESM and sparse field IDs
  • codec.ts — encode/decode Messages using the Kiwi schema
  • protocol.ts — wire format parsing and message type detection
  • schema.ts — 194 message/enum/struct definitions

Sparse Field IDs

Figma's schema uses non-contiguous field IDs (e.g., 1, 2, 5, 10 with gaps). The vendored kiwi-schema parser is patched to handle this correctly.

Compression

.fig files use Zstd compression for both the schema and message payloads. The fzstd library handles decompression. For clipboard encoding, fflate provides lightweight compression.

Supported Formats

Format Import Export
.fig (Figma) ✅ —
.svg Planned Planned
.png Planned Planned
.pdf — Planned

Clipboard Format

Copy/paste uses the same fig-kiwi binary encoding:

  1. Copy — encode selected NodeChange[] to Kiwi binary, compress, write to clipboard as application/x-figma-design MIME type
  2. Paste — read clipboard, decompress, decode Kiwi binary, create nodes in scene graph
  3. Synchronous — encoding happens in the copy event handler (not async Clipboard API) to ensure browser compatibility

This enables bidirectional clipboard between OpenPencil and Figma.