figma-transformer: decode raw vectorNetwork blobs + compose boolean-op vectors to SVG (#247)#275
Merged
Merged
Conversation
) Vector decode is the dominant remaining .fig fidelity gap. On a real fixture matrix run (David Perell) the transform left placeholders with reasons unsupported_vector_network_blob (24) and unsupported_boolean_operation_children (~14), and the quality/matrix summary undercounted vector success (generated_svg_count: 0 while 141 paths actually rendered). ScenegraphNormalizer: add a general vectorNetwork blob decoder that parses the raw buffer (header counts, 20-byte vertex table, segment table, per-region directed segment loops) into real SVG paths. Straight segments emit L; segments carrying bezier tangents emit a cubic C from vertex+tangent control points. Segment stride (16 without tangents, 24 with) is auto-detected by requiring a fully consistent parse that consumes the buffer exactly and references only valid indices, so a wrong layout guess is rejected rather than emitted as garbage. Region winding rule is carried through to fill-rule. This runs as a fallback after the existing exact-match decoders, so legacy shapes are unchanged. StaticHtmlEmitter: compose BOOLEAN_OPERATION nodes from child vector geometry into one <svg>. UNION (and unknown) overlay the child paths (visually correct for the common icon case); SUBTRACT/INTERSECT/EXCLUDE approximate hole-cutting with a single fill-rule:evenodd path when children share the operation origin, otherwise fall back to the overlay. booleanOperation is carried through the Kiwi field policy. Diagnostics: wire the quality/matrix summary rollup to reflect actual rendered_paths so generated_svg_count stops reporting 0 when paths were emitted; expose the externalized-asset count separately as externalized_svg_asset_count; surface vector_network_decoded and boolean_operations_composed outcome counts in the vectors aggregate, decode coverage, single-page summary, and the multi-page matrix summary. Tests: add contract coverage for a curved vectorNetwork blob decoding to a real cubic-curve path (counted as network-decoded by both the coverage diagnostic and the summary rollup), a UNION boolean op composing two child paths, and a SUBTRACT boolean op producing an evenodd composite. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Closes the dominant remaining
.figfidelity gap in thefigma-transformerpackage: raw FigmavectorNetworkBlobgeometry andBOOLEAN_OPERATIONnodes, plus a vector-success undercount in the diagnostics summary. Tracking issue: #247.Data motivation
On a fixture-matrix run over real
.figdesigns (David Perell), the transform left placeholders with reasonsunsupported_vector_network_blob(24) andunsupported_boolean_operation_children(~14). Separately, the matrix/quality summary reportedgenerated_svg_count: 0/vector_placeholders: 38even though the result artifact showed 141 paths actually rendered — the summary was reading the externalized-SVG-file count, not the rendered-path count.Changes
vectorNetwork → SVG (
ScenegraphNormalizer)L; segments with non-zero tangents emit a cubicCusingvertex + tangentcontrol points. Region winding rule (NONZERO/EVENODD) is carried through tofill-rule.readUint32/readFloatPair/vectorNetworkCounts).Boolean operations (
StaticHtmlEmitter)BOOLEAN_OPERATIONnodes are composed from their child vector geometry into one<svg>. UNION (and unknown ops) overlay the child paths — visually correct for the common icon case. SUBTRACT/INTERSECT/EXCLUDE approximate hole-cutting with a singlefill-rule:evenoddpath when children share the operation origin; otherwise they fall back to the overlay.data-figma-boolean-operationrecords the op.booleanOperationis carried through the Kiwi field policy so real files get the correct op type.Diagnostics undercount fix (
FigmaTransformer+StaticHtmlEmitter)generated_svg_countfrom actualrendered_paths, with the externalized-asset count exposed separately asexternalized_svg_asset_count.vector_network_decodedandboolean_operations_composedoutcome counts across the vectors aggregate, decode coverage, and both summary surfaces; the multi-page summary now also carriesvector_nodes/vector_decoded_to_svg/vector_decode_coverage_ratio.Tests
Added focused contract coverage in
tests/contract/run.php:vectorNetwork(3 vertices, one curved segment, one region) decodes to a real<svg><path d="M0 0L10 0C…Z">(not a placeholder) and is counted as network-decoded by both the coverage diagnostic and the summary rollup;BOOLEAN_OPERATIONcomposes two child paths into one svg;BOOLEAN_OPERATIONproduces a singlefill-rule:evenoddcomposite.cd figma-transformer && php tests/contract/run.php→ "Figma Transformer contract tests passed." Synthetic fixtures only; the large local.figfiles were not run.Honest caveats
.figblob in this session (large local fixtures were intentionally not run). The auto-detection requires an exactly-consuming, index-valid parse, so a wrong layout is rejected to a placeholder rather than mis-rendered — but blobs whose real layout differs from this model will still fall back honestly.AI assistance