openpencil/openspec/specs/fig-import/spec.md
Danila Poyarkov f4b45d4f13 Replace "fig-kiwi" format name with "Kiwi binary" in docs
fig-kiwi is the magic header string in .fig files, not a format name.
The format is Kiwi binary — used for both .fig files and clipboard.
2026-03-02 15:31:25 +03:00

3.8 KiB

fig-import Specification

Purpose

.fig file import pipeline. Parses Figma file header, decompresses Zstd payload, decodes Kiwi schema, extracts NodeChange[], resolves blob references, and populates the scene graph.

Requirements

Requirement: .fig file import

The editor SHALL import .fig files via the Kiwi codec pipeline: parse header (magic "fig-kiwi" + version), decompress Zstd, decode Kiwi schema, extract NodeChange[], and build the scene graph.

Scenario: Import a .fig file

  • WHEN user opens a .fig file
  • THEN all nodes from the file appear on the canvas with correct types, positions, sizes, and visual properties

Requirement: File open via keyboard

⌘O SHALL open a file dialog for .fig import.

Scenario: Open file dialog

  • WHEN user presses ⌘O
  • THEN a file picker dialog appears filtered for .fig files

Requirement: Blob reference resolution

The import pipeline SHALL resolve blob references (images, vector networks, font data) from the .fig file's blob section.

Scenario: Import with vector blobs

  • WHEN a .fig file containing vector nodes with vectorNetworkBlob data is imported
  • THEN the vector paths are correctly decoded and renderable

Requirement: .fig file export

The editor SHALL export documents as .fig files. The pipeline: scene graph → Kiwi encode NodeChange[] → compress → write ZIP with Kiwi header, schema, message, and thumbnail.

Scenario: Save As .fig

  • WHEN user selects File → Save As
  • THEN a save dialog appears and the document is written as a valid .fig file

Scenario: Save existing file

  • WHEN user selects File → Save (⌘S) with a previously opened file
  • THEN the file is overwritten in place without a dialog

Requirement: Thumbnail generation for .fig export

Exported .fig files SHALL include a thumbnail.png in the ZIP archive, as required by Figma for file preview.

Scenario: Thumbnail in exported file

  • WHEN a .fig file is exported
  • THEN the ZIP archive contains a thumbnail.png

Requirement: Zstd compression via Tauri Rust

On the desktop app, .fig export SHALL use Zstd compression via a Tauri Rust command for performance. In the browser, deflate fallback via fflate SHALL be used.

Scenario: Desktop export uses Zstd

  • WHEN a .fig file is exported in the Tauri desktop app
  • THEN the payload is compressed with Zstd via the Rust backend

Scenario: Browser export uses deflate

  • WHEN a .fig file is exported in the browser
  • THEN the payload is compressed with deflate as a fallback

Requirement: Tauri native file dialogs

File Open and Save dialogs SHALL use Tauri's plugin-dialog for native OS dialogs on the desktop app. Save filters for .fig files.

Scenario: Native open dialog

  • WHEN user presses ⌘O in the desktop app
  • THEN the native OS file picker opens filtered for .fig files

Scenario: Native save dialog

  • WHEN user selects Save As in the desktop app
  • THEN the native OS save dialog opens with default filename "Untitled.fig"

Requirement: Tier 1 rendering parity for import

The .fig import pipeline SHALL correctly import and render gradient fills, image fills, effects (shadows, blurs), stroke properties (cap, join, dash), and arc data.

Scenario: Import file with gradients

  • WHEN a .fig file containing nodes with gradient fills is imported
  • THEN all gradient types (linear, radial, angular, diamond) render correctly with their stops and transforms

Requirement: .fig import/export round-trip

A .fig file imported and then exported SHALL produce a file that Figma can open with the same visual result.

Scenario: Round-trip fidelity

  • WHEN a .fig file is imported into OpenPencil and re-exported
  • THEN the exported file opens in Figma with matching visual output