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.
- Use container bounds for stroked frames with drop shadows
- Keep stroke-geometry shadows for childless stroke-only shapes
- Cover the shadcn dropdown menu case
- 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>
- 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>
- 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>
- 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>
- 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>
- 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>
- 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>