Commit graph

44 commits

Author SHA1 Message Date
Danila Poyarkov 35db955cb9 fix(kiwi): improve fig roundtrip fidelity
- Refresh the bundled Figma Kiwi schema from a newer embedded schema
- Preserve additional raw node fields and omitted imported stack sizing
- Tighten idempotent roundtrip checks while documenting known G0 import gaps
2026-05-24 19:27:19 +03:00
Joseph Cumines bfe1b63299 fix(formatting) 2026-05-24 21:10:27 +10:00
Joseph Cumines 2a6c455464 Merge remote-tracking branch 'upstream/HEAD' into fix/fig-roundtrip-fidelity 2026-05-24 21:09:42 +10:00
Danila Poyarkov abd795bd9a chore: format codebase 2026-05-24 12:15:29 +03:00
Joseph Cumines c4073dc284 fix(kiwi): repair .fig roundtrip - missing nodes, schema mismatch, GUID collisions
Exporting a .fig from OpenPencil and reimporting lost most nodes
(38323 to 57 on gold-preview.fig) and the same files wouldn't open
in Figma. gold-preview.fig now roundtrips into Figma. I haven't
traced each symptom to a specific fix with confidence, but the
changes address the underlying causes:

- fractionalPosition overflow past 94 siblings produced characters
  outside Figma's printable ASCII range (33-126); gold-preview.fig
  has nodes with 492 children so this hit immediately. New telescoping
  ~-prefix scheme matches Figma's own encoding.
- re-export used OpenPencil's subset kiwi schema, likely producing
  field IDs misaligned with the embedded schema. Preserve and use
  the original schema (graph.figSchemaDeflated) instead.
- variable GUIDs assigned before canvas entries could collide with
  source.id-derived canvas GUIDs. Reversed the order, scan all
  imported GUIDs to advance the counter.
- auto-layout child sort ignored parentIndex.position, using only
  transform position which may not reflect original tree order for
  imported nodes. Sort by position first, transform as tiebreaker.
- Object.assign of rawNodeFields overwrote explicit serialization.
  Materialize with paint variables, apply blocklist, skip keys
  already set on nc.

Also fixes: strokeWeight defaulting on strokeless nodes, colorVar
assetRef to guid conversion, per-corner radii emission, textAlignVertical
hardcoding, textAutoResize override for imported nodes, stackReverseZIndex
roundtrip, variable key/version preservation, blendMode on effects,
textCase emission.

Adds exhaustive roundtrip test comparing G0 to G1 to G2 across schema
bytes, node count, tree paths, scene props, and raw node fields.
2026-05-24 18:29:14 +10:00
Danila Poyarkov c337905a02 fix(canvas): preserve text OpenType toggles 2026-05-23 01:43:00 +03:00
Danila Poyarkov 054199ac15 fix(kiwi): preserve edited font variation axes 2026-05-23 00:26:58 +03:00
Danila Poyarkov 8c85d2b953 fix(canvas): improve Figma mask and text fidelity 2026-05-23 00:18:33 +03:00
Danila Poyarkov 3dc0904466 fix(canvas): support luminance masks and tile transforms 2026-05-22 23:44:10 +03:00
Danila Poyarkov 24ac31d4ab fix(fig): restore lazy badge visibility overrides 2026-05-21 14:54:18 +03:00
Danila Poyarkov da9dbbb9c6 fix(editor): preserve edits over imported metadata 2026-05-21 14:54:17 +03:00
Danila Poyarkov b5451c354f fix(fig): preserve kiwi version in export worker 2026-05-21 14:54:17 +03:00
Danila Poyarkov a48b23129f fix(fig): stabilize engine test suite 2026-05-21 14:54:17 +03:00
Danila Poyarkov dfea52475c test(fig): cover source metadata roundtrips 2026-05-21 14:54:17 +03:00
Danila Poyarkov 213db6373a refactor(kiwi): group fig format internals
- Move codec, NodeChange conversion, and instance overrides under kiwi/fig
- Flatten the codec entrypoint to kiwi/fig/codec
- Keep schema-runtime as the generic Kiwi parser/compiler boundary
2026-05-21 14:54:13 +03:00
Danila Poyarkov 54310308dc refactor(kiwi): split schema text from runtime
- Move the Kiwi runtime under schema-runtime to match folder naming
- Load the Figma schema from a .kiwi text asset with static validation
- Assert Figma clipboard-derived field numbers for fragile layout/text fields
2026-05-21 14:54:12 +03:00
Danila Poyarkov 68ebef5f9b fix(fig): omit populated instance children on export
- Match Figma files where INSTANCE node changes carry symbol refs, not child nodes
- Prevent exported roundtrips from expanding every populated instance subtree
- Tighten glyph blob preservation now that instance children are omitted
2026-05-21 14:54:11 +03:00
Danila Poyarkov c1ddbf7039 fix(fig): deduplicate exported text glyph blobs
- Preserve imported Figma glyph outlines for fallback rendering
- Reuse identical glyph command blobs across exported text nodes
- Cover real fixture preservation and generated glyph deduplication
2026-05-21 14:54:10 +03:00
Danila Poyarkov e6da2736fe fix(fig): sync lazy link component overrides
- Carry resolved text styling and glyph data through component-property text clones
- Align lazy cloned child placement and hidden chevrons with their resolved source
- Cover the gold-preview dropzone link lazy import regression
2026-05-20 15:02:01 +03:00
Danila Poyarkov 957db338ba fix(fig): sync lazy instance override clones
- Re-propagate resolved overrides after lazy instance population
- Preserve Figma showShadowBehindNode on effects
- Mask unfilled stroke shadows behind their fill geometry
2026-05-20 13:12:16 +03:00
Danila Poyarkov 82fc5fb7bb fix(fig): propagate cloned component property overrides
- Resolve component-property refs through override keys on cloned children
- Apply instance component-property assignments through clone chains
- Use child shadow shapes for containers without visible fills
- Keep clipped export bounds from leaking hidden descendants
2026-05-20 12:29:51 +03:00
Danila Poyarkov a22d39210c fix(fig): populate lazy pages before export 2026-05-19 21:01:17 +03:00
Danila Poyarkov c11d65fe55 Revert "Revert "fix(fig): preserve OpenPencil round trips""
This reverts commit 9ce6096fc1.
2026-05-19 00:23:23 +03:00
Danila Poyarkov 9ce6096fc1 Revert "fix(fig): preserve OpenPencil round trips"
This reverts commit 5ef8bbd93d.
2026-05-19 00:20:47 +03:00
Danila Poyarkov 5ef8bbd93d fix(fig): preserve OpenPencil round trips 2026-05-19 00:16:41 +03:00
Danila Poyarkov f3649550f2 chore: enable stricter oxlint rules 2026-05-18 18:58:30 +03:00
Danila Poyarkov edf28f3659 fix(fig): scale instance stroke weights 2026-05-18 03:11:47 +03:00
Danila Poyarkov 2d011580f0 fix(fig): scale instance stroke weights 2026-05-18 02:47:05 +03:00
Danila Poyarkov 1de4f65767 fix(fig): propagate derived text glyphs 2026-05-18 02:35:33 +03:00
Danila Poyarkov 773b1539d2 fix(fig): prefer shared stroke styles 2026-05-18 02:30:37 +03:00
Danila Poyarkov ea04a007d3 test(fig): cover derived glyph override patches 2026-05-18 01:33:23 +03:00
Danila Poyarkov 142a973193 fix(fig): render imported text from derived glyphs 2026-05-18 01:17:34 +03:00
Danila Poyarkov 35eb749b70 test(fig): cover field-level override protection 2026-05-18 00:37:56 +03:00
Danila Poyarkov a441e1778b fix(fig): preserve swapped icon stroke styles 2026-05-17 23:49:24 +03:00
Danila Poyarkov 4234cf3b33 fix(fig): apply shared fill styles 2026-05-17 23:31:28 +03:00
Danila Poyarkov 5e782b2850 fix(fig): propagate nested icon swaps 2026-05-17 23:25:09 +03:00
Danila Poyarkov 4d758f26cb fix(fig): apply shared text styles 2026-05-17 23:02:20 +03:00
Danila Poyarkov ff0f072aef fix(fig): use derived text line metrics 2026-05-17 22:49:12 +03:00
Danila Poyarkov 2072f2e916 fix(fig): apply text component props 2026-05-17 22:40:30 +03:00
Danila Poyarkov bb6c537b8e Merge master into image fill hash fix 2026-05-17 13:02:00 +03:00
Danila Poyarkov bf636155cf test(engine): stabilize render and heavy fig tests 2026-05-16 13:39:45 +03:00
Danila Poyarkov ab700fd8be test(engine): stabilize full engine smoke 2026-05-16 13:27:46 +03:00
Danila Poyarkov 39acdd82c7 test(engine): split image coverage by domain 2026-05-16 12:38:00 +03:00
Danila Poyarkov a710841392 test(engine): align io tests with source tree 2026-05-16 11:59:02 +03:00