* feat: author behaviours on main components
A main component or component set can behave as a Switch, Checkbox,
Slider, or Tabs, after Reka UI's primitives. The behaviour lives in
OpenPencil plugin data: boolean values bind to variant or boolean
properties with the values meaning on and off, a number keeps its own
range since Figma has no number property, and the control's
subcomponents bind to the component's slots. A Behaviour section in the
properties panel adds, binds, and removes it, each as one undo step,
and flags required bindings that are missing. The canvas-only layout's
pill becomes a component that preview will reuse.
* feat: preview instances with behaviours on the canvas
View > Preview (Cmd+Alt+Enter) puts the canvas in preview: a lone canvas
switches to the canvas-only layout with a Previewing pill, and a split
canvas previews on its own side. Clicking a Switch or Checkbox flips it,
dragging a Slider moves its thumb and range, and clicking a Tabs trigger
shows its panel. Preview keeps its state on copies of the instances it
touched, in a private graph with the document's ids, and the canvas
draws those copies in place of the originals, so the document, undo,
autosave, and collaborators never see it. Escape or the pill leaves
preview, Reset restores every control, and editing shortcuts, labels,
and outlines stay off while previewing.
* feat: translate behaviour and preview strings; cover preview with an e2e flow
* refactor(vue): reuse VariantDefinitionControl for behaviour property options
* refactor: split variant actions and preview interactions by domain
Variant authoring was one 706-line closure; it is now graph queries
(model), undo snapshots (history), property definition edits
(definitions), and the editor facade (index). Preview interactions move
into play/kinds, one module per control, registered by behaviour kind so
a new kind cannot ship without its contract and interaction. Behaviour
contracts are keyed by kind. In the Vue SDK, slot and variant authoring
controls get their own folders beside component-props and behaviour,
and the app's variant section joins slot/ and behaviour/.
* refactor: keep the behaviour model in scene-graph's plugin-data registry
Master now defines every OpenPencil plugin-data key in one typed registry
in scene-graph. The behaviour schema registers there as a field, and the
model and contracts move beside slots, exported from the package root;
the @open-pencil/core/behaviours subpath is gone.
* feat: interaction states and keyboard focus in preview
A behaviour can bind a variant property to the default, hover, pressed,
focus, and disabled states; binding it maps values named like those
states. Preview switches the instance's copy to the matching variant as
the pointer hovers, presses, and releases, keeps other values when the
set draws the combination and falls back to rest otherwise, and skips
disabled instances. Tab moves visible keyboard focus between controls,
Space, Enter, arrows, Home, and End use the focused one, and Escape
takes visible focus off before leaving preview. A Button kind covers
controls that only have states.
* feat: toggle, radio, group, progress, collapsible, and accordion behaviours
Radio group, toggle group, and accordion hold their items in a slot;
each item is an instance with its own behaviour, so a press inside the
slot goes to the group, which turns the pressed item on and the others
off through the item's own interaction. Progress shares the slider's
number handling through rangeControl, and a collapsible shows and hides
its content slot from its trigger, remembering its open state even
when no property draws it. Tabs and groups share arrow-key navigation.
* feat: text field, textarea, and number field behaviours
A behaviour value can now be text, bound to a text property, so
preview types into a copy of the field through the same property path
the editor uses. A bound Filled value switches to the placeholder
variant when the field empties. A number field keeps its own range,
shows its value through a text property, and steps from its increment
and decrement slots and the arrow keys. Text fields show focus from a
click, and the focused control receives every key; Option still types,
and only Cmd or Ctrl combinations stay shortcuts.
* fix: keep behaviour bindings when saving as .fig
Saving as .fig gives component properties new GUIDs, but behaviours
kept the old ids in their plugin data, so every binding read as missing
after reopening. The export now renames the ids behaviours bind with
the same GUIDs, on its own copy of the document.
* fix: let previewed controls resize layout imported from .fig
Layers from a .fig keep the sizes Figma computed, and auto layout
prefers them, so an opened collapsible or accordion item kept its
closed height in preview. When preview shows, hides, or retypes a
layer in a copy, it drops those sizes from the layer's copied ancestors
so auto layout sizes them again; untouched layers keep Figma's sizes.
* fix: publish behaviours and other plugin content with library assets
Every OpenPencil plugin-data field now declares its role: content that
exists only as plugin data (behaviours, OkHCL picks), format copies of
node fields written for files, or bookkeeping about where a document
or node came from. Library snapshots keep a node's content plugin data,
including other plugins' entries, and drop the rest; the asset hash
counts the same entries, so a behaviour-only change is offered as an
update while a .fig round trip still changes nothing.
* feat: name behaviour rows by meaning and create what they need
The Behaviour section named every main value "Value" under a "Values"
heading, and a component without matching properties left an empty
picker with no way forward. Rows are now named for the control (On,
Checked, Pressed, Text), rows the control needs or already uses come
first, and the optional rest folds under More options; a button keeps
its states in view. An empty row creates what it needs in one undo
step: a text layer and text property, Off and On variants on a set, or
a slot frame for a part. The missing chip names the row it means and
takes you there.
* fix(dom-css): position free layers, hug content, and round ellipses
HTML and Tailwind export stacked the layers of frames without auto
layout in block flow, wrote fixed pixel sizes for auto layout frames
set to Hug and for auto-sizing text, and drew ellipses as boxes. Layers
a parent does not lay out are now absolutely positioned at their
coordinates inside a relative frame, hugging axes are left to the
content, and ellipses get a 50% radius.
* feat: run preview as live Reka UI islands over the canvas
Preview simulated controls on the canvas: copies of instances, a
handler per kind, its own key routing, and append-only text. It now
runs them as real components. Each top-level layer that holds an
instance with a behaviour becomes an island: its layers are projected
to DOM through dom-css into a shadow root laid over the pane at its pan
and zoom, and each behaviour mounts its Reka UI primitives on its
layers, so text fields are real inputs and focus, keys, and layout are
the browser's. Core's resolvePlayState shows instances in a state on a
private graph, so the component's variants draw it, and controls are
keyed by layer path so a variant switch keeps their DOM. The canvas
leaves island layers to the islands, and the canvas play runtime and
its key routing are gone.
* fix: derive variant properties from Property=Value component names
figma.combineAsVariants and Combine as variants only derived variant
properties from slash-separated names, so components named as Figma
names variants, such as State=On, Size=Large, became a set with no
properties. Both now derive each named property and its values, after
the slash form.
* feat: script and tool access to behaviours by name
Behaviour contracts follow Reka UI's anatomy: tabs keep their triggers
in the list slot and their content panels in a panels slot, and a slot
of repeated parts names the Reka part of its children. A behaviour
spec names component properties and slots instead of ids and resolves
to the stored behaviour and back, with errors that list what the
component has.
Scripts get an `openpencil` global next to `figma`, in the Figma API's
style: setBehaviour, getBehaviour with bindValue, bindPart, states,
and missing, behaviourKinds, and createSlot. The eval tool, the CLI,
and app automation compile scripts through one compileScript, so the
CLI now returns the last expression as the others do. MCP and AI chat
get set_behaviour, get_behaviour, and create_slot.
* feat: write controls in design JSX with Reka UI's element names
`<Switch.Root modelValue="State">` renders a main component, or a set
when its children are variants, that behaves as a switch, and
`<Switch.Thumb>` the slot that draws its thumb, one slot across the
set's variants. Inputs become the text property of a field, tab
triggers and panels go in their List and Panels slots, and a group's
items are `<RadioGroup.Item of={…} />` instances in its Items slot.
JSX export writes components with behaviours the same way, so they
render back unchanged. The authoring reference documents controls, and
the codegen and chat prompts now include it verbatim instead of
dedenting its code examples.
* chore: format the CLI export test
* docs: document slots, behaviours, preview, and the openpencil API
The components guide covers slots, behaviours, and preview with its
shortcut; scripting covers the openpencil global and eval's last-
expression result; the MCP and AI chat pages list the new tools; the
features overview, README, and roadmap mention working controls. The
chat prompt says how to build a control, and the codegen prompt builds
components with behaviours on their Reka UI primitives.
* chore: format the eval CLI test
* docs: explain behaviours and preview islands, and guide the openpencil API
A development page explains the behaviour model, the four authoring
surfaces, how preview islands turn a control's state into live Reka UI
components, and how to add a kind; the architecture page links it. The
Core guide sets the rules for OpenPencilAPI: Figma-only `figma`,
OpenPencil features on `openpencil` in the same style, one
compileScript, names over ids, and docs with every member. Package
READMEs mention the openpencil global, PlayIslands, Reka-named JSX, and
the behaviour model. Design JSX's behaviour modules move into a
behaviours folder instead of a suffixed sibling.
* refactor: center pasted layers through translate
centerNodesAt repeated translate's loop, which test:dupes reports on
master too.
* fix: validate behaviour ranges and guess on and off by name
A number value now needs max above min and a positive step: the schema,
specs, and the panel reject a range a slider cannot step through. Binding
a variant property guesses on and off by value name, as specs do, and a
boolean property gets no on/off pair. Part bindings are read through
partBinding, a replaced document restarts preview from its designed
state, and the e2e preview shortcut uses ControlOrMeta.
* feat: make the Behaviour section say what to do next
A slider's range fields now carry inline Min, Max, Step, and Start labels.
States offers Add state variants, which adds a Default, Hover, Pressed,
Focus, and Disabled variant and binds them; Add Off and On variants and
Add state variants turn a lone main component into a component set first,
and a part's slot can be added to a set, in every variant under one slot
id. Rows that could do nothing are gone: no empty pickers and no hints to
combine variants by hand, and an unbound Disabled is left to the states.
A warning line names what is still needed and replaces the missing chip,
and the Switch's main value is called Checked.
* fix: keep each slot to one part and keep creating slots at hand
A slot draws one part, so the Behaviour section no longer offers a slot
another part uses, and specs (the openpencil API, tools, and JSX) reject
binding one slot to two parts. A part's picker keeps an action to add a
new slot in its footer, so adding the first slot no longer hides it for
the other parts.
55 KiB
| title | description |
|---|---|
| Roadmap | OpenPencil product roadmap and Figma compatibility tracking. |
Roadmap
OpenPencil is moving toward production-grade Figma compatibility while keeping design documents programmable, local-first, and fast on large files.
Current focus
- Improve
.figimport/export fidelity against real Figma files and Figma's own rendering. - Make saves, recovery, storage synchronization, and automation resilient to crashes, interrupted writes, expired credentials, and temporary provider failures.
- Keep large design systems responsive in the browser and desktop app.
- Make international text reliable across platforms, starting with non-Latin font discovery, Arabic/Persian shaping, RTL layout, and broader CJK fixtures.
- Treat the scene graph as a programmable design document: every important read, write, export, diff, and validation operation should be reachable through UI, CLI, MCP, and SDK surfaces.
- Keep local files and local-first workflows first-class while making an optional OpenPencil Cloud backend and self-hosted deployments practical.
Recently delivered
v0.14.0 established several foundations that earlier versions of this roadmap treated as future work:
- A searchable Assets panel, component details, instance insertion, frame presets, richer component properties, layout grids, constraints, and deeper typography controls.
- A local-first Storage Workspace for S3-compatible providers with background synchronization and remote document previews.
- Editable PowerPoint export; editable HTML, CSS, Tailwind, JSX, SVG, and image-vectorization workflows.
- Private local MCP transport discovery, an installable OpenPencil agent skill, and stronger CLI/MCP support for large and multi-document sessions.
- Published
@open-pencil/scene-graph,@open-pencil/pen,@open-pencil/kiwi,@open-pencil/fig,@open-pencil/dom-css, and@open-pencil/vuepackages with documented public boundaries.
Current development version
Since v0.14.0, the development branch adds editable ruler guides and snapping preferences, Option/Alt distance measurements, multidimensional variant authoring, component-library publication and revision review, local document recovery, saved AI conversations, CLI font diagnostics, and opt-in browser WebMCP access. These workflows are implemented on the development branch but are not part of v0.14.0.
See canvas navigation, components and libraries, document recovery, AI chat, and font diagnostics.
Near-term work
Figma fidelity
- Preserve and round-trip more Figma metadata safely.
- Add visual regression coverage for full multi-page
.figdocuments.bun tools/generate/visual-oracles/src/cli.ts export-fixturesexports current smoke fixture pages to/tmpfor manual comparison without committing large images;tests/fixtures/figma-oracles/visual-comparison-report.jsonrecords the current Figma-vs-OpenPencil oracle diff findings. - Close high-impact renderer gaps: remaining mask edge cases, blend isolation, pattern fills, and broader variable-font fixtures.
- Improve boolean operation editing/export now that imported Figma
BOOLEAN_OPERATIONnodes remain boolean operations.
Editor depth
- Complete variable inspector coverage for common numeric/text/layout fields.
- Extend component and instance authoring with deeper override inspection and slots. Multidimensional variant definitions, instance property editing, and component-library publish/update workflows are already supported.
- Treat variables, styles, components, and libraries as governed design-system assets with proposal, review, publish, update, migration, and conformance workflows.
- Complete layout-grid style parity beyond existing grid geometry controls and editable page/frame guides.
- Extend inspection aids beyond the existing Option/Alt measurements between selected and hovered layers.
- Expand vector editing workflows without regressing imported vector fidelity.
Reliability and international text
- Make document saves atomic and recoverable, including unsaved documents created through MCP and interrupted local or remote writes.
- Surface provider, model-budget, renderer, and automation failures with actionable recovery paths instead of silent stalls.
- Make desktop automation recover from orphaned processes and renderer crashes without manual cleanup.
- Prevent non-Latin font discovery and rendering crashes across platforms; add Arabic/Persian shaping and RTL layout, then broaden CJK and mixed-script visual fixtures.
- Build a portable-font strategy for reproducible documents across machines on top of existing substitution visibility and agent-readable font status, including curated redistributable fonts, embedded or linked document fonts, and licensing metadata (#502, #503).
Cloud and self-hosting
- Provide an optional OpenPencil Cloud backend for account-based workspace sync, sharing, collaboration, comments, and managed team libraries without making cloud accounts mandatory for the editor.
- Support organizations and teams with invitations, viewer/editor/admin roles, link-sharing policies, service accounts, API tokens, and enterprise identity through standard OIDC/SSO integrations.
- Publish documented backend APIs and webhooks for workspace, document, membership, comment, version, and automation events so Cloud and self-hosted deployments integrate with existing developer workflows.
- Add workspace organization for projects, folders, templates, search, indexing, and server-generated previews while preserving stable document identity.
- Add version history with automatic snapshots, named checkpoints, restore, retention controls, and an auditable record of important document and membership changes.
- Provide a durable collaboration relay for deterministic initial sync, presence, reconnects, and restricted-network environments while keeping direct local/P2P workflows available where practical.
- Publish a production-ready self-hosted deployment for teams that need their own storage, identity, network boundary, data location, and retention policy.
- Make self-hosting maintainable with guided deployment, upgrades, backups, health monitoring, observability, and documented recovery procedures.
- Provide explicit data-governance controls for export, deletion, encryption, retention, auditability, and deployment-region or residency requirements.
- Keep AI and media capabilities BYOK so Cloud and self-hosted users connect and control their own model and provider credentials.
- Let documents move between device-only, OpenPencil Cloud, self-hosted, and user-owned storage without losing identity or history.
- Add explicit conflict, offline, sync-health, migration, backup, quota, and recovery UX for every remote deployment mode.
Agent workflows
- Polish the official
SKILL.mdguidance for OpenPencil so agents use the full inspect → act → render/measure → compare → iterate loop instead of relying on one-shot prompting. - Publish tested AI workflow recipes for common tasks: create from prompt, edit a selected design, compare against a screenshot or Figma reference, fix visual regressions, extract tokens, and batch-migrate files.
- Accept screenshots and reference images as first-class agent inputs, and return selection/page/viewport renders as native image content to vision-capable MCP and chat clients.
- Support opt-in web retrieval, external MCP connectors, and sandboxed code execution through explicit capability and permission boundaries rather than granting every model ambient access.
- Make structured node-tree diffs a first-class, Git-friendly review artifact for UI, CLI, MCP, SDK, and CI edits instead of relying only on screenshot comparisons.
- Expand design lint findings with expected/actual evidence and safe autofixes; measure rule precision before enabling lint rules as blocking gates.
- Keep deterministic golden renders and replayable edit-operation histories so regressions can be reproduced from document state and actions, not only from final pixels.
- Make agent workflows measurable by default: every substantial operation should be able to produce a render, structured diff, lint result, or comparison artifact.
- Keep MCP, CLI, and SDK operations aligned so agent skills can run the same workflow in desktop, browser, CI, or headless file mode.
Tooling and API parity
- Maintain a public tool/API reference that maps editor operations to CLI commands, MCP tools, SDK APIs, and Figma Plugin API-compatible eval usage.
- Add coverage tests that detect when a core editor capability exists in the UI but is missing from CLI/MCP/SDK, or vice versa.
- Keep tool outputs structured enough for agents to chain safely: node IDs, bounds, diffs, render artifacts, diagnostics, and machine-readable error details.
- Improve deterministic CLI/MCP export and comparison tools for CI.
- Add more design linting and migration helpers for batch
.figand.penworkflows. - Make
.pena first-class editable save target across app, CLI, MCP, and SDK workflows rather than an import-only or automation-specific format. - Extend HTML, CSS, Tailwind, and JSX support from editable import toward URL-based website capture, direct JSX paste/edit workflows, and component-aware design↔code updates that preserve intentional code structure instead of regenerating whole files.
- Provide an adapter contract for additional design sources such as Stitch and Pixso, prioritizing formats with documented or testable semantics over brittle UI scraping.
- Package desktop-side MCP integration so local agent workflows do not require global installs.
Performance and scale
- Incremental layout and render invalidation for large documents.
- Better renderer profiling surfaces for slow nodes, effects, masks, and imported files.
- Smarter raster/retained caching that preserves fidelity during zoom and pan.
Interactive shader layers
- Add Unicorn Studio-style shader scenes as first-class design layers: animated gradients, particles, noise fields, metaballs, lighting, displacement, and pointer-reactive backgrounds.
- Provide a preset-first editor for common generative visuals before exposing raw shader code.
- Support timeline and interaction inputs such as time, pointer position, scroll, layer bounds, colors, variables, and imported image textures.
- Render shader layers through CanvasKit/WebGL while keeping deterministic raster export for PNG/JPG/WEBP and thumbnails.
- Store shader layer configuration in OpenPencil documents and export graceful fallbacks when a target format cannot preserve the live effect.
Later
SDK and embedded editor
- Expand the documented Vue SDK and core package platform with complete example applications for custom editor shells, embedded design surfaces, and automation-specific UIs.
- Provide maintained examples for read-only previews, editable canvases, design review surfaces, and agent-controlled editors.
- Ship an official VS Code/Cursor extension (#81) for previewing and opening
.fig/.pendocuments, connecting to the running editor, invoking CLI/MCP workflows, handing selections between code and canvas, and navigating between generated code and design nodes. Reuse the app, SDK, and automation bridge rather than implementing a second editor inside the extension. - Define public API stability and migration expectations across the reusable npm packages.
- Keep the renderer, editor core, and tool registry framework-agnostic enough for headless and embedded use.
Product depth
- Prototyping: frame connections, triggers, overlays, transitions, preview mode, and AI/JSX-authorable interaction definitions.
- Motion: reusable code-authored animation presets, timelines, easing, and deterministic playback/export that compose with prototype interactions and shader inputs.
- Tables and data grids: structured rows, columns, headers, resizing, merged cells, and normal scene nodes inside cells instead of drawing tables as unrelated rectangles.
- Comments: pins, threads, resolution state, and collaboration-aware display.
- Extend shared libraries beyond the existing component publish/consume/update workflow to broader style management and governance.
- Platform asset libraries: use licensed system-native and third-party icon sources, including SF Symbols where platform and redistribution rules allow, alongside the existing Iconify/Lucide workflow.
- Figma Slides (
.deck) interoperability: import/export, slide editing, presentation, speaker notes, and filmstrip workflows. This ranks below core Figma Design fidelity, reliability, Cloud/self-hosting, and international-text work. - Platform polish: Windows code signing, PWA support, packaged updater improvements, and desktop-side MCP bundling.
Non-goals
- Mandatory accounts or a cloud-only document model. OpenPencil Cloud, self-hosted backends, and user-owned remote storage must remain optional alongside local files.
- A hosted service that requires OpenPencil to proxy users' AI provider keys; AI and media integrations remain BYOK even when a backend provides identity, sync, or collaboration.
- Read-only automation surfaces that cannot modify documents.
- Feature work that sacrifices
.figimport/export fidelity for convenience.
This section tracks OpenPencil's current compatibility with Figma Design features. It is based on Figma's public Help Center feature areas and the current OpenPencil scene graph, Kiwi import/export, CanvasKit renderer, UI panels, CLI, and MCP tools.
Legend:
- ✅ Supported — implemented for common files and expected to work directly.
- ◐ Partial — implemented for important cases, but missing parity, UI, or edge-case behavior.
- ↩ Round-trip only — imported/preserved/exported for
.figfidelity, but not rendered or editable as a first-class OpenPencil feature. - — Not supported — not currently modeled or intentionally out of scope.
Support tiers used for prioritization:
- Visual fidelity — fields that change pixels in normal design exports. These get real Figma oracle fixtures, renderer tests, and visual metrics first.
- Round-trip fidelity — fields that should survive read → write → Figma import but do not need OpenPencil UI/rendering yet. These need raw-preservation and invalidation tests.
- Product/runtime systems — prototypes, libraries, FigJam, Slides, Dev Mode, CMS/AI, and media timelines. These stay schema-only or raw-preserved until OpenPencil has matching product concepts.
- Unsafe/internal metadata — fields that can corrupt Figma import or overwrite user edits when stale. These are filtered or preserved only with fixture evidence.
Official Figma feature areas
Figma's design documentation groups features into these areas:
- Layers, frames, groups, sections, shape layers, text, vectors, and boolean operations.
- Fills, gradients, images, patterns, blend modes, strokes, effects, corner radius, and corner smoothing.
- Auto layout: vertical, horizontal, wrap, grid, padding, gap, hug/fill/fixed/min/max, and ignore auto layout.
- Components, instances, variants, component properties, slots, libraries, and library updates.
- Variables: color, number, string, boolean, collections, modes, aliases, scopes, and prototype variables.
- Prototyping: flows, hotspots, triggers, actions, overlays, smart animate, easing, conditionals, expressions, and variable actions.
- Dev Mode: inspect, measurements, annotations, Code Connect, dev resources, ready-for-dev states, and Figma MCP.
- Collaboration/file workflows: comments, version history, thumbnails, branches, library publishing, and multiplayer metadata.
Figma compatibility matrix
| Area | Import | Render | UI edit | Export round-trip | CLI/MCP | Notes |
|---|---|---|---|---|---|---|
| Pages / canvases | ✅ | ✅ | ✅ | ✅ | ✅ | Multi-page documents and per-page viewport are supported. |
| Frames | ✅ | ✅ | ✅ | ✅ | ✅ | Includes clipping and auto-layout container behavior. |
| Groups | ✅ | ✅ | ✅ | ✅ | ✅ | Grouping preserves visual positions. |
| Sections | ✅ | ✅ | ✅ | ✅ | ✅ | Section rendering and title pills are OpenPencil-specific approximations. |
| Rectangles / rounded rectangles | ✅ | ✅ | ✅ | ✅ | ✅ | Per-corner radii and smoothed corners render for fills, strokes, clips, masks, and effects. |
| Ellipses / arcs | ✅ | ✅ | ◐ | ✅ | ✅ | arcData renders/exports; no full inspector controls. |
| Lines | ✅ | ✅ | ✅ | ✅ | ✅ | Stroke caps, joins, dashes, alignment, and miter limits render and have inspector controls. |
| Polygons / stars | ✅ | ✅ | ◐ | ✅ | ✅ | pointCount and starInnerRadius modeled. |
| Text | ✅ | ✅ | ✅ | ✅ | ✅ | Case, justification, vertical alignment, truncation/max lines, common OpenType features, and derived Figma glyph fallback are supported; uncommon typography metadata remains round-trip only. |
| Vectors / vector networks | ✅ | ✅ | ◐ | ✅ | ✅ | Vector edit support exists; Figma Draw tools are not fully replicated. |
| Boolean operations | ✅ | ✅ | ◐ | ✅ | ✅ | Figma BOOLEAN_OPERATION nodes import/export as boolean operations; inspector editing remains limited. |
| Components | ✅ | ✅ | ◐ | ✅ | ✅ | Component metadata, descriptions, links, and publish fields mostly round-trip. |
| Component sets / variants | ✅ | ✅ | ◐ | ✅ | ✅ | Multidimensional variant definitions and common instance properties are editable; broader Figma-specific property parity remains incomplete. |
| Instances / overrides | ✅ | ✅ | ◐ | ✅ | ✅ | Component-property refs and typed assignments are modeled and editable; raw symbol overrides and derived data remain preserved for fidelity. |
| Slots | ✅ | ✅ | ✅ | ✅ | ✅ | Slot properties, settings, and instance slot content import, render, and round-trip. The editor creates, configures, and removes slots on main components and fills them in instances; scripts do the same through createSlot(), resetSlot(), and limitViolations. |
| Connectors | ◐ | ◐ | — | ◐ | ◐ | Type exists, but Figma connector semantics are weak. |
| Shape-with-text / FigJam shapes | ◐ | ◐ | — | ◐ | ◐ | Type exists, but not a full FigJam feature implementation. |
| Slices | ◐ | — | ◐ | ◐ | ✅ | Slice-like export regions exist via tooling, not as true Figma slice nodes. |
| FigJam / Slides / Code / CMS / Buzz node families | ↩ | — | — | ↩ | — | Current Kiwi schema recognizes many newer Figma node families (TABLE, SLIDE, CODE_COMPONENT, CMS_RICH_TEXT, REPEATER, WEBPAGE, etc.), but OpenPencil only preserves/round-trips them where safe; they are not first-class scene nodes. |
| Solid fills | ✅ | ✅ | ✅ | ✅ | ✅ | Color variables supported for common fill cases. |
| Gradients | ✅ | ✅ | ✅ | ✅ | ✅ | Linear/radial/angular/diamond support; Figma edge cases may differ. |
| Image fills | ✅ | ✅ | ◐ | ✅ | ✅ | Fill/fit/crop/tile support exists; imported crop/tile affine transforms are applied, but exact Figma parity is still partial. |
| Pattern / noise / custom fills | ✅ | ◐ | — | ✅ | — | Schema metadata imports/exports; Figma pattern fills with a referenced source node render as repeated source tiles with scale, spacing, alignment, and basic hex offsets. Noise/custom paints still render with a solid fallback pending real paint payload samples; Figma-authored noise/texture/glass effect payloads are captured separately. |
| Video/GIF/media fills | ↩ | — | — | ↩ | — | Kiwi schema includes media paint/export enums, but OpenPencil has no video/GIF playback or media layer support. |
| Layer/fill/effect blend modes | ✅ | ◐ | ✅ | ✅ | ✅ | Appearance, fill, and effect controls are exposed; Canvas applies common modes, while Figma isolation edge cases remain partial. |
| Opacity | ✅ | ✅ | ✅ | ✅ | ✅ | Node opacity uses save layers in the renderer. |
| Strokes | ✅ | ✅ | ✅ | ✅ | ✅ | Weight, alignment, dashes, and side weights are supported. |
| Stroke caps / joins / miter limit | ✅ | ✅ | ✅ | ✅ | ✅ | Inspector controls support mixed cap/join/miter editing; CanvasKit rendering and .fig roundtrips preserve miter limits. |
| Effects: shadows and blurs | ✅ | ✅ | ✅ | ✅ | ✅ | showShadowBehindNode is rendered but not exposed in UI. |
| Fill / stroke / effect styles | ✅ | ✅ | ◐ | ✅ | ✅ | Imported local definitions are modeled and selectable with undo-safe detach; creating and publishing styles still needs a style manager. |
| Corner radius | ✅ | ✅ | ✅ | ✅ | ✅ | Uniform and independent radii supported. |
| Corner smoothing | ✅ | ✅ | ✅ | ✅ | ✅ | The inspector supports mixed smoothing percentages with undo; uniform and independent-radius corners render, while exact Figma parity still needs broader fixture tuning. |
| Masks | ✅ | ◐ | — | ✅ | ✅ | Figma schema mask, maskType, and maskIsOutline fields import and export; common sibling alpha/vector/luminance mask stacks render, including consecutive mask layers. UI controls and deeper Figma edge cases remain incomplete. |
| Auto layout: vertical/horizontal | ✅ | ✅ | ✅ | ✅ | ✅ | Yoga-backed layout. |
| Auto layout: wrap | ✅ | ✅ | ✅ | ✅ | ✅ | UI toggle exists. |
| Auto layout: grid | ✅ | ◐ | ◐ | ✅ | ✅ | CSS-grid-like support is partial; newer schema fields for grid child alignment and auto tracks are not fully exposed. |
| Padding / gaps / alignment | ✅ | ✅ | ✅ | ✅ | ✅ | Common flex controls are exposed. |
| Hug / fill / fixed sizing | ✅ | ✅ | ✅ | ✅ | ✅ | Min/max support is partial in UI. |
| Ignore auto layout / absolute positioning | ✅ | ✅ | ◐ | ✅ | ✅ | Mode is modeled; UI coverage is partial. |
| Strokes included in layout | ✅ | ◐ | — | ✅ | ✅ | Stored/exported and used in layout paths, but no obvious panel control. |
| Reverse z-index / align-content | ✅ | ◐ | — | ✅ | ✅ | Modeled and exported; UI is limited. |
| Constraints | ✅ | ◐ | ✅ | ✅ | ✅ | Horizontal and vertical pin, center, stretch, and scale modes are editable; imported edge-case parity remains partial. |
| Layout grids / guides | ✅ | ✅ | ◐ | ✅ | ✅ | Layout-grid geometry and page/frame guides are editable, including guide creation, movement, duplication, transfer, and removal. Full grid-style management remains incomplete. |
| Text styles | ✅ | ✅ | ◐ | ✅ | ✅ | Imported local text styles are modeled, selectable, and detachable; authoring and publishing style definitions still needs a style manager. |
| Rich style runs | ✅ | ✅ | ◐ | ✅ | ✅ | Import/render/export support; editing mixed runs is partial. |
| Text auto resize | ✅ | ✅ | ◐ | ✅ | ✅ | Used by renderer/layout; UI does not expose every mode. |
| Text truncation / max lines | ✅ | ✅ | ✅ | ✅ | ✅ | Ending truncation and maximum-line controls are available in the inspector. |
| Text case | ✅ | ◐ | ✅ | ✅ | ✅ | Original, upper, lower, and title case are editable; broader render parity still needs fixtures. |
| Vertical text alignment | ✅ | ◐ | ✅ | ✅ | ✅ | Top, center, and bottom alignment are editable; imported edge-case parity needs more coverage. |
| Justified text | ✅ | ◐ | ✅ | ✅ | ✅ | Justification is exposed in the typography inspector; render parity remains partial. |
| Font variations / OpenType features | ✅ | ✅ | — | ✅ | — | Imported fontVariations, common ligature/caps/numeric OpenType fields, and raw toggledOnOTFeatures / toggledOffOTFeatures are applied to CanvasKit text styles and exported; UI controls are not exposed. |
| Variables: collections/modes/aliases | ✅ | ◐ | ◐ | ✅ | ✅ | Color/number/string/boolean model exists; inspector coverage is still incomplete. |
| Variables bound to fills/strokes | ✅ | ✅ | ✅ | ✅ | ✅ | Common color bindings render and edit. |
| Variables bound to text/layout/visibility/effects | ◐ | ◐ | ◐ | ◐ | ✅ | Text content and numeric layout bindings resolve on read; colour and numeric bindings also re-resolve when a variable or mode changes, string ones do not. Effect bindings are not modelled. |
| Variables in prototypes / expressions / conditionals | — | — | — | — | — | Depends on prototype system, which is not implemented. |
| Libraries / publish / update review | ↩ | — | ◐ | ↩ | — | Figma library metadata survives round-trip. OpenPencil supports its own component-library publishing, catalogs, revision previews, and linked-instance updates, not synchronization with Figma-hosted libraries. |
| Prototype flows / starting points | — | — | — | — | — | Not modeled. |
| Prototype hotspots / triggers / actions | — | — | — | — | — | Not modeled. |
| Prototype overlays / scroll-to | — | — | — | — | — | Not modeled. |
| Smart animate / easing / spring / duration | — | — | — | — | — | Not modeled. |
| Interactive components | — | — | — | — | — | Figma's component-level prototype connections are not supported; OpenPencil's own behaviours make components run as Reka UI controls in preview. |
| Dev Mode inspect / measurements / annotations | — | ◐ | ◐ | — | ◐ | OpenPencil has CLI/MCP inspection and Option/Alt distance overlays, but not Figma Dev Mode annotations or its full UI. |
| Code Connect / dev resources / ready-for-dev | — | — | — | — | — | Not modeled. |
| Comments | — | — | — | — | — | Not modeled. |
| Version history / branches | — | — | — | — | — | Not modeled. |
| Real-time collaboration | — | ✅ | ✅ | — | — | OpenPencil has its own P2P collaboration, not Figma-compatible metadata. |
Raw Kiwi metadata coverage
OpenPencil deliberately preserves many Figma/Kiwi fields even when they are not rendered or editable. These live under SceneNode.source.fig and are applied late during .fig export. A schema coverage test compares the current fig.kiwi NodeChange fields against modeled codec fields, raw-preserved fields, and intentionally schema-only metadata buckets so drift stays visible.
| Field group | Import/export | Render | UI | Fidelity impact |
|---|---|---|---|---|
source.fig.rawSize |
✅ | Indirect | — | Preserves original Figma size for round-trip. Cleared when size is edited. |
source.fig.rawTransform |
✅ | Indirect | — | Preserves exact Figma transform. Cleared when transform is edited. |
source.fig.rawNodeFields |
✅ | Mixed | — | Late-applied to exported NodeChange for round-trip fidelity; modeled edits invalidate only matching stale raw fields, while unrelated prototype/library metadata survives. Raw-field and schema coverage tests guard preservation drift. |
source.fig.layout |
✅ | ✅ | ◐ | Preserves original Figma stack metadata while using normalized layout fields. |
source.fig.symbolOverrides |
✅ | Indirect | — | Important for instance override fidelity. |
source.fig.componentPropAssignments |
✅ | Indirect | ◐ | Used for component property fidelity; not raw-editable. |
source.fig.derivedSymbolData |
✅ | Indirect | — | Critical for instance-derived geometry/layout/text. |
source.fig.derivedSymbolDataLayoutVersion |
✅ | — | — | Figma bookkeeping. |
source.fig.uniformScaleFactor |
✅ | Indirect | — | Important for scaled instances. |
| Style IDs: fill/stroke/text/effect/grid | ↩ | — | — | Preserves style linkage for Figma, but OpenPencil has no style manager yet. |
| Component property refs/defs/specs | ✅ | Indirect | ◐ | Full Figma component-property authoring is incomplete. |
| State-group metadata | ↩ | — | — | Preserved only. |
| Version/sort/publish/library metadata | ↩ | — | ◐ | Figma metadata is preserved; OpenPencil's component-library publish/update workflow uses its own stable asset identities and revision review. |
| Variable and parameter consumption maps | ✅ | ◐ | ◐ | Filtered/preserved for safe round-trip; normalized bindings cover common cases. |
| Page fields: background, page type, guides | ↩ | ◐ | ◐ | Background color, background paints, page type, and guides round-trip for imported pages. Normalized page/frame guides render as overlays and support undoable editing. |
Text internals: textData, layout versions, font version, derived data |
✅ | ✅ | — | Important for text fidelity; most internals are not editable. Imported derived text data, leading trim, decoration style, underline decoration paint/offset/thickness/skip-ink, semantic font metadata, and raw OpenType feature toggles are preserved for round-trip when safe; decoration style/thickness/color and leading trim now render through CanvasKit, and raster export bounds account for decoration overflow. |
fontVariations |
✅ | ✅ | — | Variable font axes are imported, rendered, and exported for text nodes and style runs. |
| Raw paint/effect/vector/geometry payloads | ✅ | ✅ | ◐ | Converted fields render; raw payloads preserve Figma import/export details, including mask, background paint, layout grid, export setting, and prototype interaction metadata where safe. |
Highest-priority visual gaps
These are parsed or visible in Figma docs and most likely to cause visible differences in real design files:
- Masks — tune remaining exact Figma stack semantics beyond common alpha/vector/luminance and consecutive-mask paths.
tests/fixtures/figma-oracles/masks.jsonrecords live Figma API values for alpha, vector, and luminance masks. - Corner smoothing — expand Figma fixture comparisons and tune remaining stroke/effect edge cases.
- Pattern/noise/custom fills — tune first-class pattern rendering for nested/effectful pattern sources and exact Figma hex spacing.
tests/fixtures/figma-oracles/pattern-noise-custom-paints.jsoncaptures a real async FigmaPATTERNpayload and Figma-authored noise/texture/glass effect payloads; realNOISE/CUSTOMpaint payloads remain blocked on Figma-authored samples. - Variable-font and rich text fixtures — broaden real-file coverage for variable axes, derived text data, leading trim, decoration style, underline offset/skip-ink, semantic font metadata, and raw OpenType feature metadata;
tests/fixtures/figma-oracles/rich-text-decoration.jsoncaptures the first live Figma rich-text oracle. - Boolean operation editing — improve inspector/tooling workflows for imported boolean-operation nodes.
- Layout grids and guides — broaden grid-style parity and Figma edge-case coverage; common grid geometry and page/frame guide editing are already supported.
- Full component property and slot workflows — support authoring, not just preserving imported payloads.
- Prototype/media/interaction metadata — schema now includes more interaction, media runtime, animation, and slide fields; start by preserving flows/connections/runtime metadata before building playback.
Code map
| Concern | Files |
|---|---|
| Scene graph fields | packages/scene-graph/src/types.ts |
| Source edit tracking | packages/scene-graph/src/source-metadata.ts |
.fig metadata policy |
packages/fig/src/source-metadata.ts |
| Kiwi import mapping | packages/fig/src/node-change/convert.ts |
| Kiwi export mapping | packages/fig/src/node-change/export/node.ts, packages/fig/src/node-change/serialize.ts |
| Kiwi schema | packages/kiwi/src/fig/schema/fig.kiwi, tests/engine/io/fig/import/schema-coverage.test.ts |
| Renderer dispatch | packages/core/src/canvas/scene.ts |
| Fills / images / gradients | packages/core/src/canvas/fills.ts |
| Strokes | packages/core/src/canvas/strokes.ts |
| Effects / shadows | packages/core/src/canvas/shadows.ts |
| Text rendering | packages/core/src/canvas/text.ts, packages/core/src/canvas/text-derived.ts |
| Layout engine | packages/core/src/layout/** |
| Property panels | src/components/properties/**, packages/vue/src/controls/** |
| CLI | packages/cli/src/index.ts, packages/cli/src/commands/** |
| MCP/tools | packages/core/src/tools/**, packages/mcp/src/tool/registration.ts |