Commit graph

730 commits

Author SHA1 Message Date
Danila Poyarkov f9bd0c7be9 fix(canvas): render complex text fills as outlines 2026-05-30 12:32:55 +03:00
Danila Poyarkov 2d4e2a7b10 Release v0.13.1 2026-05-30 01:12:58 +03:00
Danila Poyarkov 6de7cd3871 Release v0.13.0 2026-05-30 00:16:35 +03:00
Danila Poyarkov 6ae425ee3b fix(core): address compatibility review findings 2026-05-28 09:57:46 +03:00
Danila Poyarkov 5fcd8e0e9c fix(canvas): support stretched layout grids 2026-05-28 05:39:40 +03:00
Danila Poyarkov 64e8b21949 fix(canvas): render imported page guides 2026-05-27 19:00:23 +03:00
Danila Poyarkov 42fcb37f4d fix(canvas): render imported layout grids 2026-05-27 17:57:41 +03:00
Danila Poyarkov d3eed6f4a9 fix(canvas): derive rich decoration geometry 2026-05-27 12:16:08 +03:00
Danila Poyarkov 56383c7f51 test(canvas): analyze text decoration oracle 2026-05-27 11:32:22 +03:00
Danila Poyarkov 9a7ef5e2cb test(canvas): update visual oracle metrics 2026-05-27 11:04:27 +03:00
Danila Poyarkov 033326cffb fix(canvas): render raw noise effect fallback 2026-05-27 10:53:12 +03:00
Danila Poyarkov fa6e97b24b fix(kiwi): preserve unsupported effect payloads 2026-05-27 10:27:02 +03:00
Danila Poyarkov 4224179501 fix(canvas): render derived text decoration styles 2026-05-27 10:11:06 +03:00
Danila Poyarkov 4861b37e64 fix(io): include text decoration export bounds 2026-05-27 00:53:47 +03:00
Danila Poyarkov 94dd6cf3aa fix(canvas): tune Figma pattern origin 2026-05-26 21:21:49 +03:00
Danila Poyarkov e02782d1b5 test(canvas): record Figma visual oracle diffs 2026-05-26 20:44:18 +03:00
Danila Poyarkov c1532610db fix(canvas): tighten Figma text and pattern fidelity 2026-05-26 18:30:08 +03:00
Danila Poyarkov d208cc326e fix(canvas): render Figma pattern fills 2026-05-26 17:33:45 +03:00
Danila Poyarkov 1e1d78c7f6 fix(canvas): render Figma leading trim 2026-05-26 16:23:59 +03:00
Danila Poyarkov 3ea310d092 fix(io): preserve imported canvas background paints 2026-05-26 16:00:50 +03:00
Danila Poyarkov 3e1a37d34d fix(kiwi): preserve mask outline metadata 2026-05-26 15:44:35 +03:00
Danila Poyarkov c2a0de5f0c fix(kiwi): support Figma OpenType variant fields 2026-05-26 15:14:23 +03:00
Danila Poyarkov a53ab45e86 fix(kiwi): use Figma mask schema fields 2026-05-26 14:53:23 +03:00
Danila Poyarkov 80daa0d1e9 fix(canvas): render Figma text decoration styles 2026-05-26 13:22:56 +03:00
Danila Poyarkov f77f58e2f6 fix(kiwi): support raw OpenType toggles 2026-05-26 12:01:03 +03:00
Danila Poyarkov 4cd187c766 fix(kiwi): preserve more Figma metadata 2026-05-26 11:57:13 +03:00
Danila Poyarkov a79d671873 fix(kiwi): preserve pattern spacing 2026-05-25 10:23:19 +03:00
Danila Poyarkov 75412ed59f fix(kiwi): preserve rich text schema metadata 2026-05-25 09:19:46 +03:00
Danila Poyarkov 84cf18ba80 fix(kiwi): preserve schema paint fields 2026-05-25 09:19:25 +03:00
Danila Poyarkov 5c09ca0299 test(core): stabilize engine unit tests
- Update EffectType schema assertion for modern Figma enum values
- Treat unsupported OpenType font buffers as unavailable
- Skip CJK outline fallback coverage when the LFS font fixture is not materialized
2026-05-25 01:41:59 +03:00
Danila Poyarkov f4b3453fbd chore(lint): check duplicate type shapes across files
- Add a repo-wide TypeScript AST duplicate shape check to the quality gate
- Extract shared named types for existing cross-file duplicates
- Keep same-file oxlint coverage for editor feedback
2026-05-25 00:55:29 +03:00
Danila Poyarkov 2f8dfd883a chore(lint): catch duplicate type shapes
- Add AST-based duplicate object type shape detection
- Reuse shared variable consumption and visual bounds type shapes
- Keep duplicate type shape checks in the default lint gate
2026-05-25 00:47:33 +03:00
Danila Poyarkov 1ed7de6056 chore(lint): reject broad unknown type assertions
- Add AST-based lint checks for broad unknown object assertions and local JsonObject aliases
- Centralize JsonObject in core and package-local MCP RPC JSON typing
- Replace baseline Record<string, unknown> assertions with named shared/domain types
2026-05-25 00:26:02 +03:00
Danila Poyarkov b4dfd90da0 fix(kiwi): resolve variable radius overrides
- Resolve numeric variable aliases in symbol override radius fields
- Preserve imported 999 corner sentinels through G0 to G1 roundtrips
- Remove the resolved corner-radius roundtrip TODO
2026-05-24 23:46:29 +03:00
Danila Poyarkov 7f2c21bb23 refactor(core): avoid record casts for dynamic writes
- Use KiwiNodeChange index signature for raw Figma field assignment
- Type preserved raw NodeChange keys with keyof NodeChange
- Replace scene graph property write casts with a typed setter
2026-05-24 22:37:03 +03:00
Danila Poyarkov 22280cc758 fix(kiwi): preserve imported derived text data
- Prefer raw derivedTextData for imported Figma nodes during export
- Keep G1 exports idempotent with preserved text glyph and baseline payloads
- Remove the resolved derivedTextData roundtrip TODO
2026-05-24 22:27:31 +03:00
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 afd571341b fix(ai): render common generated JSX aliases 2026-05-24 12:45:42 +03: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 a38c0ac7b5 fix(core): satisfy type-aware lint 2026-05-23 05:25:06 +03:00
Danila Poyarkov 06dce623db refactor(core): split text data serialization 2026-05-23 03:30:07 +03:00
Danila Poyarkov c337905a02 fix(canvas): preserve text OpenType toggles 2026-05-23 01:43:00 +03:00
Danila Poyarkov f36d6b94b7 fix(canvas): apply affine image fill transforms 2026-05-23 01:31:04 +03:00
Danila Poyarkov 762c86e094 Revert "perf(canvas): defer backing rebuilds while zooming"
This reverts commit 21a79d4cd5.
2026-05-23 01:17:48 +03:00
Danila Poyarkov 21a79d4cd5 perf(canvas): defer backing rebuilds while zooming 2026-05-23 01:17:07 +03:00
Danila Poyarkov 0d5db35147 perf(canvas): bound blend and text mask layers 2026-05-23 01:10:24 +03:00
Danila Poyarkov f07d26c50b perf(canvas): bound effect render layers 2026-05-23 01:01:38 +03:00
Danila Poyarkov 7184bc1b06 Revert "perf(canvas): cap retained backing size"
This reverts commit 7b62c8acca.
2026-05-23 00:45:13 +03:00
Danila Poyarkov 7b62c8acca perf(canvas): cap retained backing size 2026-05-23 00:30:30 +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 98616c8610 fix(canvas): render Figma-style corner smoothing 2026-05-22 23:05:24 +03:00
Danila Poyarkov 76ee122dee fix(canvas): render smoothed corners and effect blend modes 2026-05-22 22:50:58 +03:00
Danila Poyarkov 0ce57ea0fa fix(canvas): render Figma mask stacks 2026-05-22 21:05:35 +03:00
Danila Poyarkov 8e1d5d40e7 fix(canvas): render Figma blend modes 2026-05-22 21:00:34 +03:00
Danila Poyarkov 8f4f7a47e9 fix(canvas): filter retained backing previews
- Keep stale scene backings available during zoom for smooth interaction

- Draw scaled backings with linear filtering to avoid blocky text artifacts
2026-05-22 14:44:16 +03:00
Danila Poyarkov a49f626e3e fix(canvas): render stroked container shadows from bounds
- Use container bounds for stroked frames with drop shadows

- Keep stroke-geometry shadows for childless stroke-only shapes

- Cover the shadcn dropdown menu case
2026-05-22 13:39:29 +03:00
Danila Poyarkov 1c22b3f7a9 test(canvas): align shadow cleanup checks
- Keep explicit color filter deletion checks compatible with cleanup guards

- Verify text inner-shadow restore balancing through the restore-count loop

Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
2026-05-22 13:17:04 +03:00
Danila Poyarkov f6e31be707 fix(canvas): delete renderer label resources
- Dispose parent outline paint during renderer teardown

- Dispose section and component label fonts with other renderer-owned fonts

- Cover renderer teardown for label resources

Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
2026-05-22 13:15:35 +03:00
Danila Poyarkov 420c61e004 fix(canvas): guard retained backing surfaces
- Fall back to live rendering when CanvasKit cannot allocate the backing surface

- Match retained backing metadata against the current graph preview version

- Cover null-surface and stale-preview backing regressions

Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
2026-05-22 12:51:00 +03:00
Danila Poyarkov 9f67a1086d fix(canvas): restore shadow render state on errors
- Restore canvas save layers and shared paints from shadow effect paths when rendering fails

- Delete temporary paths and color filters through error paths without suppressing failures

- Cover drop-shadow and text inner-shadow cleanup regressions

Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
2026-05-22 12:47:33 +03:00
Danila Poyarkov 0b4fcc9f77 fix(canvas): render shadows from path shapes
- Use polygon, star, and vector paths for shadows when geometry blobs are unavailable
- Apply shadow spread to copied geometry paths without mutating caches
- Clip and cut out inner shadows with the same path geometry

Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
2026-05-22 12:37:00 +03:00
Danila Poyarkov fadb17b108 fix(canvas): clean up gradient text layers
- Delete gradient text paragraphs through the exception path
- Reset shared effect layer paint after gradient text rendering

Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
2026-05-22 12:24:14 +03:00
Danila Poyarkov 2fc67e7b6a fix(canvas): clean up boolean render paths
- Delete boolean operation paths even when drawing fails
- Reset fill shaders while preserving the existing render path

Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
2026-05-22 12:19:14 +03:00
Danila Poyarkov 3850be9512 build: publish node-compatible packages 2026-05-21 17:03:19 +03:00
Danila Poyarkov 24ac31d4ab fix(fig): restore lazy badge visibility overrides 2026-05-21 14:54:18 +03:00
Danila Poyarkov d3e82fba44 fix(fig): preserve source metadata during lazy import 2026-05-21 14:54:17 +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 302ed838f5 fix(fig): sanitize preserved payload enums 2026-05-21 14:54:17 +03:00
Danila Poyarkov 749585d737 refactor(fig): group source roundtrip metadata 2026-05-21 14:54:17 +03:00
Danila Poyarkov d78bcb3b40 fix(fig): render headless export thumbnails 2026-05-21 14:54:16 +03:00
Danila Poyarkov c85e06466c fix(fig): preserve imported canvas strokes 2026-05-21 14:54:16 +03:00
Danila Poyarkov dd0a5317fd fix(fig): preserve imported node ordering 2026-05-21 14:54:16 +03:00
Danila Poyarkov 8eedaba84f fix(fig): preserve imported canvas guids 2026-05-21 14:54:16 +03:00
Danila Poyarkov 2ef237f5e1 fix(fig): preserve imported text and paint fallbacks 2026-05-21 14:54:16 +03:00
Danila Poyarkov b784882e88 fix(fig): preserve component prop reference maps
- Export component sets with Figma-compatible frame state-group metadata
- Emit internal component definitions before page instances
- Preserve prop-ref variable maps while continuing to strip unsafe alias maps
2026-05-21 14:54:15 +03:00
Danila Poyarkov 2897e0b20f fix(fig): preserve component prop preferred values
- Add current Kiwi component prop fields used by Figma exports
- Preserve empty instance-swap preferred value arrays instead of dropping them during encoding
2026-05-21 14:54:15 +03:00
Danila Poyarkov e6508c191b fix(fig): preserve import edit metadata
- Add EditInfo to the export schema so preserved raw Figma edit metadata is encoded
- Emit false symbol publishability for components to match imported Figma payloads
2026-05-21 14:54:15 +03:00
Danila Poyarkov 5dff0d4285 fix(fig): keep variable maps inside instance payloads
- Continue stripping top-level variable maps that crash Figma import
- Preserve nested variable maps in symbol overrides, component assignments, and derived symbol data for better instance reconstruction
2026-05-21 14:54:15 +03:00
Danila Poyarkov 450ca16b28 fix(fig): preserve component prop default values
- Add ComponentPropDef.varValue to the static Kiwi schema
- Keep imported boolean component defaults instead of degrading them to empty strings
2026-05-21 14:54:14 +03:00
Danila Poyarkov 35b146b4c6 fix(fig): preserve component variant metadata
- Preserve raw component property definitions, refs, variant specs, and source library metadata
- Add current Figma schema entries needed to encode variantPropSpecs and modern component prop types
2026-05-21 14:54:14 +03:00
Danila Poyarkov ef802b4681 fix(fig): skip unresolved paint variables
- Drop preserved colorVar and opacityVar payload fields together with variable maps
- Keep concrete paint colors as fallbacks so Figma does not render unresolved variables as missing content
2026-05-21 14:54:14 +03:00
Danila Poyarkov 6586b497bb fix(fig): skip variable maps in preserved payloads
- Keep preserving style IDs and paint variable metadata
- Drop variableConsumptionMap and parameterConsumptionMap on export because Figma imports enter invalid Slides rail state with these raw maps
2026-05-21 14:54:14 +03:00
Danila Poyarkov 307b271259 fix(fig): mark exported canvases as design pages
- Add the current Figma pageType field and EditorType enum values
- Write pageType DESIGN on exported CANVAS records so Figma initializes design-mode page state
2026-05-21 14:54:13 +03:00
Danila Poyarkov 25430b1479 fix(kiwi): restore export-stable schema fields
- Keep live clipboard-derived numbers only for fields emitted by preserved payloads
- Restore unused glyph/layout fields to the schema shape Figma imports without triggering Slides state
2026-05-21 14:54:13 +03:00
Danila Poyarkov 82499b8678 fix(kiwi): keep layout fields in schema order
- Move stackWrap and stackCounterSpacing beside adjacent live Figma field IDs
- Preserve clipboard-derived field numbers without appending them after newer high IDs
2026-05-21 14:54:13 +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 81fa529332 fix(fig): preserve raw Figma override metadata
- Preserve raw paint variables, style ids, text line metadata, and variable maps
- Keep raw node paint/geometry/effect fields for imported Figma nodes
- Extend the Kiwi schema for current Figma override and variable fields
2026-05-21 14:54:12 +03:00
Danila Poyarkov 513d630653 fix(fig): preserve variable-backed override fields
- Add missing style and variable map fields to the Kiwi schema
- Preserve TEXT_DATA consumption maps and style ids inside instance overrides
- Keep Figma's component override payloads closer to clipboard output
2026-05-21 14:54:12 +03:00
Danila Poyarkov 844b904844 fix(fig): preserve instance component assignments
- Keep top-level componentPropAssignments from imported Figma instances
- Re-emit those assignments with preserved variable values for Figma import
- Fix datepicker instances losing configured component property values
2026-05-21 14:54:12 +03:00
Danila Poyarkov f4ad80d789 fix(fig): preserve imported geometry and prop values
- Keep raw Figma size and transform values for imported nodes during export
- Add current Kiwi schema fields for component prop varValue and symbol id variable values
- Preserve component source geometry used by Figma to reconstruct instances
2026-05-21 14:54:12 +03:00
Danila Poyarkov 1c0122b485 fix(fig): preserve derived instance payloads
- Store imported derivedSymbolData on scene nodes with blob bytes remapped for export
- Re-emit derivedSymbolData and layout versions for Figma instances
- Skip unsupported metadata fields that the current Kiwi encoder cannot write
2026-05-21 14:54:11 +03:00
Danila Poyarkov 40ee1b83d4 fix(fig): preserve instance override payloads
- Keep imported Figma node guids so override paths and symbol references remain stable
- Serialize imported symbolOverrides and uniform scale factors for instances
- Strip unsupported variable consumption maps from preserved overrides before encoding
2026-05-21 14:54:11 +03:00