- 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
- 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
- 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
- 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
- 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
- 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
- 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
- Add semantic raw verifier for componentPropDefs
- Keep derived text raw checks focused on stable metadata
- Split raw verifier helpers to keep roundtrip test utilities small
- 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
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.