openpencil/packages/fig
Danila Poyarkov 7b011bceaf
fix(fig): treat the unset override key as no key (#967)
Figma saves layers without an override key with Kiwi's all-ones GUID, so
many siblings share it. The importer stored it as a real key, and export
addressed each instance layer by that key, so two such siblings got the
same derived geometry address and export threw "Ambiguous instance
geometry address". Instance linkage and override path matching also
treated the shared value as an identity. The importer now reads the unset
GUID as no key, through an isUnsetGuid helper that the cleared-style and
default-slot checks share.

The Preline UI kit has 1,165 such text and rounded rectangle layers; after
an edit it now exports and reopens with all 104 pages.
2026-10-07 21:33:09 +00:00
..
docs fix(fig): write text glyphs from the layout the renderer draws (#928) 2026-10-06 11:37:02 +00:00
scripts feat(fig): occurrence-scoped instance interpretation as the single .fig reader 2026-10-01 11:20:27 +04:00
src fix(fig): treat the unset override key as no key (#967) 2026-10-07 21:33:09 +00:00
tests fix(fig): treat the unset override key as no key (#967) 2026-10-07 21:33:09 +00:00
AGENTS.md feat(fig): occurrence-scoped instance interpretation as the single .fig reader 2026-10-01 11:20:27 +04:00
package.json build: update dependencies (#873) 2026-10-04 12:48:24 +00:00
README.md fix(fig): write text glyphs from the layout the renderer draws (#928) 2026-10-06 11:37:02 +00:00
tsconfig.json fix: explain unsupported browsers instead of a blank window (#745) 2026-09-22 14:40:59 +04:00
tsconfig.test.json feat(fig): scaffold package shell 2026-06-30 10:51:36 +03:00
tsdown.config.ts refactor(fig): own Figma clipboard encoding and conversion 2026-09-11 00:36:03 +03:00

@open-pencil/fig

.fig file-format package for OpenPencil.

The package owns the outer .fig archive boundary and is the staged home for Figma-specific SceneGraph conversion policy. Production SceneGraph read/write remains available through @open-pencil/core/io while conversion modules move behind this package's public API.

Current ownership:

  • Complete .fig archive parsing through parseFigBuffer()
  • .fig archive assembly through writeFigArchive()
  • Canvas payload and image resource handling
  • readFigContainer() / writeFigContainer() helpers for raw fig-kiwi payloads
  • .fig source and archive result types
  • NodeChange-to-SceneGraph property conversion, including styles, plugin metadata, text, paint, vector, and font policy, through @open-pencil/fig/node-change
  • Component-property, symbol-override, derived-symbol-data, and instance synchronization policy through @open-pencil/fig/instance-overrides
  • Effective raw-metadata precedence and invalidation over SceneGraph's format-neutral edited-field tracking
  • SceneGraph-to-NodeChange export conversion with an explicit text-shaping runtime service for saved glyphs
  • Package-local archive, conversion, instance, export, and dist smoke tests

Architecture documentation

Start with the package docs for the source model, instance evaluation, materialization, document sessions, export, and validation contracts.

Planned ownership:

  • Oracle-backed .fig fixtures

Non-goals:

  • Generic Kiwi schema/runtime internals — use @open-pencil/kiwi
  • Format-neutral IO registration, export targeting, CanvasKit thumbnails, or browser workers — use @open-pencil/core/io
  • Editor actions, renderer behavior, Vue/app UI, CLI formatting, or MCP transport

This follows the existing @open-pencil/pen pattern: a format package owns its source model/parser and SceneGraph policy, while core registers it in the shared IO system.

Checks

cd packages/fig
bun run check