Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
184 commits
Select commit Hold shift + click to select a range
b7504ce
figma-transformer: improve FSE responsive parity
chubes4 Jul 2, 2026
1ab1b6c
figma-transformer: explain clone and asset omissions
chubes4 Jul 2, 2026
3095d91
figma-transformer: preserve clone source offsets
chubes4 Jul 2, 2026
46b3374
figma-transformer: improve static site viability
chubes4 Jul 2, 2026
d7aeec4
figma-transformer: harden static HTML semantics
chubes4 Jul 2, 2026
e161821
figma-transformer: improve static layout parity
chubes4 Jul 2, 2026
45941f2
figma-transformer: preserve list and text override fidelity
chubes4 Jul 2, 2026
45e6bfb
figma-transformer: abstract conversion pattern recognition
chubes4 Jul 2, 2026
654505c
figma-transformer: preserve semantic list layout
chubes4 Jul 2, 2026
183b8f2
figma-transformer: improve FSE content fidelity
chubes4 Jul 2, 2026
faf5a42
figma-transformer: improve arbitrary fig page structure
chubes4 Jul 2, 2026
e7eb5fe
figma-transformer: keep page roots full bleed
chubes4 Jul 2, 2026
38c812d
figma-transformer: sanitize emitted layout gaps
chubes4 Jul 3, 2026
57ae192
figma-transformer: flag invalid css artifacts
chubes4 Jul 3, 2026
2ea3d34
figma-transformer: extract layout frame role classifier
chubes4 Jul 3, 2026
7c8fbf5
figma-transformer: materialize typography tokens
chubes4 Jul 3, 2026
413fcec
figma-transformer: centralize image visual evidence
chubes4 Jul 3, 2026
70dd786
figma-transformer: recognize responsive centered shells
chubes4 Jul 3, 2026
5d39608
figma-transformer: include materialized font families in diagnostics
chubes4 Jul 3, 2026
22cd306
figma-transformer: diagnose emitted mask sources
chubes4 Jul 3, 2026
8e56820
figma-transformer: report implicit route evidence
chubes4 Jul 3, 2026
d9d3db1
figma-transformer: link visual nodes to emitted artifacts
chubes4 Jul 3, 2026
d6462db
figma-transformer: resolve Apple system font families
chubes4 Jul 3, 2026
f5cd9ec
figma-transformer: guard implicit entrypoint routes
chubes4 Jul 3, 2026
e15684c
figma-transformer: suppress mask source operators
chubes4 Jul 3, 2026
4ccce83
figma-transformer: trace aggregate visual nodes to pages
chubes4 Jul 3, 2026
52883bc
figma-transformer: use flow height for vertical fluid frames
chubes4 Jul 3, 2026
8d5e431
figma-transformer: center responsive fluid shells
chubes4 Jul 3, 2026
02f1222
figma-transformer: preserve responsive freeform footer flow
chubes4 Jul 3, 2026
27d780b
figma-transformer: preserve clone text typography
chubes4 Jul 3, 2026
5c8b84e
figma-transformer: add mobile responsive safety fallbacks
chubes4 Jul 3, 2026
1d19fea
figma-transformer: compose nested vector containers
chubes4 Jul 3, 2026
9fb48d5
figma-transformer: hydrate offset text segments
chubes4 Jul 3, 2026
963e3a5
figma-transformer: preserve layered image effects
chubes4 Jul 3, 2026
78d4e59
figma-transformer: tighten responsive node parity matching
chubes4 Jul 3, 2026
ffd4ff1
figma-transformer: add source-loss coverage diagnostics
chubes4 Jul 3, 2026
5e29f51
figma-transformer: render normalized per-corner radii
chubes4 Jul 3, 2026
6e49066
figma-transformer: preserve nested source text lists
chubes4 Jul 3, 2026
cb779a6
figma-transformer: compose simple mask clip paths
chubes4 Jul 3, 2026
c7027bc
figma-transformer: summarize visual node map evidence
chubes4 Jul 3, 2026
29c84b8
figma-transformer: filter duplicate route drafts
chubes4 Jul 3, 2026
16f3751
figma-transformer: sanitize invalid layout CSS tokens
chubes4 Jul 3, 2026
a9e27af
figma-transformer: resolve token-only and SF system fonts
chubes4 Jul 3, 2026
56204ba
figma-transformer: account for mask-source clone suppression
chubes4 Jul 3, 2026
0b1f0d4
figma-transformer: align token-only font contract
chubes4 Jul 3, 2026
8953140
figma-transformer: center standalone canvas shells
chubes4 Jul 3, 2026
db8e9eb
figma-transformer: ignore non-rendering vector scaffolds
chubes4 Jul 3, 2026
f68bb75
figma-transformer: keep top chrome above hero layers
chubes4 Jul 3, 2026
eebce35
figma-transformer: let page roots fill viewport
chubes4 Jul 3, 2026
06d4e6e
figma-transformer: preserve fixed social icon widths
chubes4 Jul 3, 2026
6b2dbf6
figma-transformer: isolate canvas shell decisions
chubes4 Jul 3, 2026
d8c9aa3
figma-transformer: clarify layer stack roles
chubes4 Jul 3, 2026
5dfce2d
figma-transformer: isolate breakpoint width policy
chubes4 Jul 3, 2026
0c0fe60
figma-transformer: remove duplicate clone geometry helpers
chubes4 Jul 3, 2026
767a1a8
figma-transformer: isolate positioning style decisions
chubes4 Jul 3, 2026
2aa4a1d
figma-transformer: explain component clone geometry choices
chubes4 Jul 3, 2026
8aae5fa
figma-transformer: isolate chrome role classification
chubes4 Jul 3, 2026
63523c9
figma-transformer: expose transform decision reasons
chubes4 Jul 3, 2026
621b37d
figma-transformer: repair stale clone CTA offsets
chubes4 Jul 3, 2026
8c2464b
figma-transformer: suppress root off-canvas variant clusters
chubes4 Jul 3, 2026
d1ba18d
figma-transformer: preserve footer chrome layout
chubes4 Jul 3, 2026
31e69b3
figma-transformer: compose social icon masks
chubes4 Jul 3, 2026
a440065
figma-transformer: center absolute breakpoint widths
chubes4 Jul 3, 2026
2c4108a
figma-transformer: align visual diagnostics with emitted CSS geometry
chubes4 Jul 3, 2026
b32015e
figma-transformer: align suppressed offset diagnostics
chubes4 Jul 3, 2026
19001f8
figma-transformer: generalize responsive top chrome safety
chubes4 Jul 3, 2026
00b3f7f
figma-transformer: generalize mobile chrome breakpoints
chubes4 Jul 3, 2026
0845fd0
figma-transformer: tighten social icon output
chubes4 Jul 3, 2026
540a0e5
figma-transformer: demote preserved style diagnostics
chubes4 Jul 3, 2026
b076a86
figma-transformer: merge mobile chrome safety policies
chubes4 Jul 3, 2026
5c25f79
figma-transformer: extract visual geometry resolver
chubes4 Jul 3, 2026
300a524
figma-transformer: centralize full-bleed width policy
chubes4 Jul 3, 2026
587e91b
figma-transformer: centralize stacking context policy
chubes4 Jul 3, 2026
b3b4279
figma-transformer: expose responsive breakpoint contracts
chubes4 Jul 3, 2026
8903d77
figma-transformer: expose source frame planning evidence
chubes4 Jul 3, 2026
9678b97
figma-transformer: extract clip mask style resolver
chubes4 Jul 3, 2026
35d0c45
figma-transformer: centralize geometry diagnostics
chubes4 Jul 3, 2026
b11a2c5
figma-transformer: isolate asset composition decisions
chubes4 Jul 3, 2026
899830c
figma-transformer: use visual geometry for reflected full-bleed
chubes4 Jul 3, 2026
867ac04
figma-transformer: fluidize root absolute canvas children
chubes4 Jul 3, 2026
ea7e454
figma-transformer: make flow z-index effective
chubes4 Jul 3, 2026
f375fd7
figma-transformer: preserve mobile header source height
chubes4 Jul 3, 2026
a192717
figma-transformer: expose geometry decision diagnostics
chubes4 Jul 3, 2026
d5ec419
figma-transformer: preserve page tokens and paint stacks
chubes4 Jul 3, 2026
72037d0
figma-transformer: align mobile header chrome flow
chubes4 Jul 3, 2026
351613a
figma-transformer: clamp mobile centered hero text
chubes4 Jul 3, 2026
361d6dd
figma-transformer: suppress duplicate icon state layers
chubes4 Jul 3, 2026
6635c55
figma-transformer: infer labeled comment textarea controls
chubes4 Jul 3, 2026
736743d
figma-transformer: suppress wrapped vector state duplicates
chubes4 Jul 3, 2026
da22992
figma-transformer: extract paint stack resolver
chubes4 Jul 3, 2026
03fa391
figma-transformer: extract child layer composition resolver
chubes4 Jul 3, 2026
5438dbf
figma-transformer: clarify vector asset rendering paths
chubes4 Jul 3, 2026
015bd3a
figma-transformer: extract static html semantics classifier
chubes4 Jul 3, 2026
1baf180
figma-transformer: extract responsive safety policy
chubes4 Jul 3, 2026
b60dc08
figma-transformer: centralize decision traces
chubes4 Jul 3, 2026
d8c117c
figma-transformer: clarify page route grouping helpers
chubes4 Jul 3, 2026
71477b3
figma-transformer: refactor contract assertion helpers
chubes4 Jul 3, 2026
c9aab24
figma-transformer: render zero-height vector separators
chubes4 Jul 3, 2026
f901a08
figma-transformer: suppress near-overlap vector states
chubes4 Jul 3, 2026
4fd3eab
figma-transformer: resolve Avenir as local system font
chubes4 Jul 3, 2026
fd71363
figma-transformer: suppress zero-area vector placeholders
chubes4 Jul 3, 2026
cf3b99f
figma-transformer: surface vector placeholder metric
chubes4 Jul 3, 2026
0c6d9ad
figma-transformer: suppress empty zero-area vector scaffolds
chubes4 Jul 3, 2026
34f8472
figma-transformer: suppress missing-dimension vector scaffolds
chubes4 Jul 3, 2026
f291eee
figma-transformer: align zero-area vector diagnostics
chubes4 Jul 3, 2026
0bd5644
figma-transformer: preserve text list continuations
chubes4 Jul 3, 2026
229a119
figma-transformer: compose layered button backgrounds
chubes4 Jul 3, 2026
823ebcf
figma-transformer: infer spatial newsletter fields
chubes4 Jul 3, 2026
b80f78f
figma-transformer: layer freeform decorative underlays
chubes4 Jul 3, 2026
5c63e4c
figma-transformer: align full-bleed hero chrome geometry
chubes4 Jul 3, 2026
2623dde
figma-transformer: fix mirrored full-bleed anchoring
chubes4 Jul 3, 2026
596affe
figma-transformer: break out overscan section bands
chubes4 Jul 3, 2026
f055475
figma-transformer: rank decorative underlay stacks
chubes4 Jul 3, 2026
88deb83
figma-transformer: reserve transformed chrome bounds
chubes4 Jul 3, 2026
5e185fd
figma-transformer: surface positional parity diagnostics
chubes4 Jul 3, 2026
1d4accd
figma-transformer: trace absolute positioning decisions
chubes4 Jul 3, 2026
81f7f30
figma-transformer: isolate stacking context policy
chubes4 Jul 3, 2026
0f5d8d9
figma-transformer: trace transformed reserve bounds
chubes4 Jul 3, 2026
cc95648
figma-transformer: explain full-bleed breakout evidence
chubes4 Jul 3, 2026
85403ea
figma-transformer: sample positional decision traces
chubes4 Jul 3, 2026
24fa2d1
figma-transformer: rank overlapping chrome above hero
chubes4 Jul 3, 2026
2139564
figma-transformer: preserve matched header breakpoints
chubes4 Jul 3, 2026
6391695
figma-transformer: preserve vector band paints
chubes4 Jul 3, 2026
ac4b90c
figma-transformer: preserve full-bleed breakpoint bands
chubes4 Jul 3, 2026
a9541cf
figma-transformer: group border shell cards locally
chubes4 Jul 3, 2026
806fe39
figma-transformer: layer local vector tracks under markers
chubes4 Jul 3, 2026
bb85d90
figma-transformer: flow footer chrome on mobile
chubes4 Jul 3, 2026
7338bfb
figma-transformer: preserve responsive full-bleed breakout
chubes4 Jul 3, 2026
5eacd46
figma-transformer: split packed route text
chubes4 Jul 3, 2026
b9f8bb8
figma-transformer: aggregate positional diagnostics
chubes4 Jul 3, 2026
3b66e2f
figma-transformer: classify cloned top headers as chrome
chubes4 Jul 3, 2026
14a80fe
figma-transformer: stabilize handout header nav layering
chubes4 Jul 3, 2026
849bb5b
figma-transformer: scope reverse stack z-index
chubes4 Jul 3, 2026
4988b47
figma-transformer: block responsive chrome safety leaks
chubes4 Jul 3, 2026
af12090
figma-transformer: preserve packed route text
chubes4 Jul 3, 2026
e6dabb1
figma-transformer: group compact border cards
chubes4 Jul 3, 2026
6e3573e
figma-transformer: prefix numeric shared classes
chubes4 Jul 3, 2026
156b584
figma-transformer: ignore decorative hairline offsets
chubes4 Jul 3, 2026
6b6c2af
figma-transformer: suppress invisible zero-area scaffolds
chubes4 Jul 3, 2026
927a7e2
figma-transformer: scope mobile safety breakpoints
chubes4 Jul 3, 2026
fdcbdd0
figma-transformer: diagnose clone transform preservation
chubes4 Jul 3, 2026
e2757b5
figma-transformer: demote decorative vector clusters
chubes4 Jul 3, 2026
03e447b
figma-transformer: link packed nav text
chubes4 Jul 3, 2026
6339329
figma-transformer: classify top-anchored headers
chubes4 Jul 3, 2026
3d65e94
figma-transformer: preserve field control chrome
chubes4 Jul 3, 2026
935ce74
figma-transformer: add html artifact quality diagnostics
chubes4 Jul 3, 2026
5cb0fbb
figma-transformer: label static page roots
chubes4 Jul 3, 2026
5e74abc
figma-transformer: prefer explicit route identities
chubes4 Jul 3, 2026
301c864
figma-transformer: layer hero media above chrome strips
chubes4 Jul 3, 2026
3828459
figma-transformer: preserve list body typography
chubes4 Jul 3, 2026
bb24f55
figma-transformer: filter internal page scaffolds
chubes4 Jul 3, 2026
55d7877
figma-transformer: expand node trace geometry diagnostics
chubes4 Jul 3, 2026
c9e9214
blocks-engine: diagnose generated HTML quality gaps
chubes4 Jul 3, 2026
411fcff
figma-transformer: diagnose vector network blob gaps
chubes4 Jul 3, 2026
f3d10bf
figma-transformer: trace clone transform override fields
chubes4 Jul 3, 2026
0d2629a
figma-transformer: clamp mobile safety max widths
chubes4 Jul 3, 2026
8739544
figma-transformer: demote explicit body text headings
chubes4 Jul 3, 2026
52ae3d4
figma-transformer: suppress intentional source loss gaps
chubes4 Jul 3, 2026
5ab4ccb
figma-transformer: normalize wrapped list body casing
chubes4 Jul 3, 2026
b623140
figma-transformer: scope list body casing overrides
chubes4 Jul 3, 2026
26ef4f9
figma-transformer: override shared list body casing
chubes4 Jul 3, 2026
ee1fca1
figma-transformer: override list paragraph shared casing
chubes4 Jul 3, 2026
969acec
figma-transformer: normalize paragraph list casing
chubes4 Jul 3, 2026
4b6c224
figma-transformer: remove stale paragraph uppercase
chubes4 Jul 3, 2026
06958ec
figma-transformer: extract static HTML CSS rule set
chubes4 Jul 3, 2026
f0f389c
figma-transformer: narrow text style extraction
chubes4 Jul 3, 2026
d9a765a
figma-transformer: replace link emitter callbacks
chubes4 Jul 3, 2026
01be9f8
figma-transformer: extract static html diagnostics
chubes4 Jul 3, 2026
6a173c3
figma-transformer: fix emitter refactor integration
chubes4 Jul 3, 2026
96e4fd2
Improve Figma node trace component clone evidence
chubes4 Jul 4, 2026
903f3f6
figma-transformer: integrate wave29 diagnostics data
chubes4 Jul 4, 2026
4c8330c
figma-transformer: suppress contained offset diagnostics
chubes4 Jul 4, 2026
8362e1b
figma-transformer: clamp non-finite layout dimensions
chubes4 Jul 4, 2026
808b992
figma-transformer: trace responsive offset decisions
chubes4 Jul 4, 2026
fa4ecec
figma-transformer: extract source loss coverage builder
chubes4 Jul 4, 2026
eb1f04c
figma-transformer: account for suppressed off-canvas text
chubes4 Jul 4, 2026
7060a77
figma-transformer: classify background bleed diagnostics
chubes4 Jul 4, 2026
4da2c70
figma-transformer: harden large fig data mining
chubes4 Jul 4, 2026
a8d00b1
figma-transformer: add route identity report
chubes4 Jul 4, 2026
9d6e875
figma-transformer: classify residual geometry diagnostics
chubes4 Jul 4, 2026
738fde3
figma-transformer: add gated kiwi decode planning
chubes4 Jul 4, 2026
bc23e95
blocks-engine: update report diagnostics expectation
chubes4 Jul 4, 2026
fc04cd3
figma-transformer: harden page fidelity diagnostics
chubes4 Jul 4, 2026
fdc52a1
figma-transformer: fix responsive page paths
chubes4 Jul 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,406 changes: 4,406 additions & 0 deletions artifacts/wave31-peter-route-identity/route-identity-report.json

Large diffs are not rendered by default.

39 changes: 39 additions & 0 deletions docs/contracts/figma-transformer-result.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,43 @@ Required parity fields:
- `diff_summary`: optional compact diff summary such as changed pixels, threshold, or ratio
- `metrics`: optional runner metrics

## Transform Diagnostics

`source_reports.figma.html.transform_diagnostics` uses schema `blocks-engine/figma-transformer/transform-diagnostics/v1`. It is a development/parity diagnostics envelope, not a rendering contract. It explains source nodes that were decoded but not materially emitted so visual gaps can be triaged without papering over output.

`source_reports.figma.html.visual_node_map` is the aggregate source-to-artifact evidence map. Each emitted visual node entry includes `id`, `rect`, `page_path`, optional `emitted_class`/`emitted_tag`, and multi-page provenance fields `source_page_index` and `source_page_frame_id`. The same traced entries are preserved in each `source_reports.figma.html.pages[].visual_node_map` page report so arbitrary `.fig` scale output can be traced from aggregate JSON to the generated page HTML and shared CSS selector.

Text coverage lives at `transform_diagnostics.text` with schema `blocks-engine/figma-transformer/text-coverage/v1`:

- `decoded_text_node_count`: non-empty decoded text nodes considered for emission.
- `emitted_text_node_count`: decoded text nodes whose `data-figma-node-id` appears in generated HTML.
- `missing_emitted_text_node_count`: decoded non-empty text nodes not found in generated HTML.
- `missing_emitted_text_reason_categories`: stable counts by reason.
- `missing_emitted_text_nodes[]`: sample nodes with `node_id`, `name`, `type`, `class`, `page_id`, `page_name`, `character_count`, and `reason`.

Asset coverage lives at `transform_diagnostics.images`:

- `node_refs`: raw nodes carrying an explicit asset reference or image paint.
- `asset_nodes[]`: sample nodes with `node_id`, `name`, `type`, `class`, `emitted`, `reason`, optional `path`, and `refs`.
- `asset_node_reason_categories`: stable counts by reason.
- `missing_assets[]`: asset-bearing node samples with no resolved archive asset path.

Initial omission reasons include `hidden`, `zero_area`, `parent_omitted`, `decorative`, `no_archive_asset`, `no_archive_asset_hash`, `clipped_masked`, `converted_to_background`, `converted_to_form_control`, and `not_emitted`.

Positional parity coverage lives at `transform_diagnostics.layout.positional_parity` with schema `blocks-engine/figma-transformer/positional-parity/v1`. It summarizes emitted CSS and layout evidence that can affect arbitrary `.fig` visual parity without changing runtime behavior:

- `full_bleed_viewport_width_count`: emitted `width:100vw` declarations.
- `full_bleed_breakout_count`: emitted viewport breakout declarations using `left:50%` plus `margin-left:±50vw`.
- `mirrored_transform_count`: emitted CSS matrix transforms with a negative horizontal or vertical scale component.
- `reflected_full_bleed_count`: emitted full-bleed reflected nodes using `margin-left:50vw` plus a mirrored matrix.
- `fixed_over_root_width_underlay_count`: decorative underlay samples whose fixed source width exceeds parent/root width.
- `fixed_over_root_width_underlays[]`: bounded samples with page, node, parent, geometry, and class evidence.
- `chrome_overflow_count`: off-canvas visual nodes associated with header/footer chrome.
- `chrome_overflow_nodes[]`: bounded samples with page, node, parent, geometry, and class evidence.
- `root_stacking_trace_count`: count of recorded stacking-context decision traces.
- `root_stacking_reason_counts`: stable stacking/z-index/overlap decision reason counts when present.
- `decision_trace_samples[]`: bounded positional decision trace samples derived from `decision_traces.samples` for effective geometry, stacking context, transform viewport, and responsive decisions. Samples include stable node/page/class identity plus compact source geometry, emitted CSS geometry, full-bleed/canvas-shell, stacking, transform, or responsive declaration evidence when present.

Status meanings:

- `not_run`: no parity runner has executed for this transform.
Expand All @@ -51,6 +88,8 @@ Status meanings:

Arbitrary `.fig` files are not fully decoded by the PHP-native package yet. Current `.fig` support safely opens `.fig` files or wrapper ZIPs, identifies nested `.fig` entries, reports `fig-kiwi` prelude/version/chunk metadata, inventories embedded files/assets, and records compression diagnostics.

The bounded Kiwi skipped-field inventory reports skipped fields in `fields`/`summary` and selected decoded paint-variable/interpolation diagnostics in `decoded_fields`/`decoded_summary`. Decoded paint diagnostics currently cover `Paint.colorVar`, `Paint.stopsVar`, color-stop variable bindings, and gradient interpolation/color-space fields so large real files can be audited without full visual rendering.

Next decoder milestones are schema chunk parsing, Zstandard message decoding when supported by the runtime, mapping decoded Kiwi messages into normalized IR, and expanding layout/paint/text/component/asset coverage against external real-file evidence.

## Fixture Strategy
Expand Down
13 changes: 13 additions & 0 deletions figma-transformer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,19 @@ add_filter(

No pure-PHP Zstandard decoder is bundled today. Unsupported runtimes report `figma_transformer_zstd_extension_missing` or adapter failure diagnostics and continue parsing the rest of the archive metadata.

### Large `.fig` Memory Profiles

Large production `.fig` exports should default to bounded inspection before full scenegraph materialization. Keep the library defaults conservative: the eager Kiwi message decode limit is 16 MB, the selective decode preflight limit is 32 MB, and the zstd inflated chunk limit is 64 MB. With those defaults, oversized modern Kiwi messages are reported with `figma_transformer_kiwi_message_decode_skipped_preflight` instead of risking a PHP fatal.

Recommended operator profiles:

- Archive/gate inspection: run with `--inspect-kiwi-gate`, `--omit-asset-content` when asset bytes are not needed, and a 512 MB PHP memory limit.
- Skipped-field inventory: run `scripts/figma-kiwi-skipped-field-inventory.php` with an explicit `--zstd-command` when the host lacks `ext-zstd`; 512 MB is expected to be enough for bounded inventory scans.
- Parser parity dry run: keep `--max-kiwi-message-decode-bytes=1` for the safe preflight/default path. Raise `--max-kiwi-selective-message-decode-bytes` only for an intentional selective decode experiment on a high-memory worker.
- Full transform: do not raise `--max-kiwi-selective-message-decode-bytes` for untrusted or fatal-scale files unless the process budget has been measured against that file. `--max-nodes` limits normalized output size, but it does not avoid the current cost of decoding and indexing the source graph.

When a real file exceeds the default selective decode ceiling, prefer `--inspect-kiwi-gate` and skipped-field inventory to identify the page/frame scope before allocating a larger transform worker. Treat memory budgets that finish within a few percent of the configured PHP limit as unsafe defaults; use them only for one-off operator runs.

## Output Contract

Successful transforms produce a static website artifact:
Expand Down
43 changes: 41 additions & 2 deletions figma-transformer/bin/figma-transformer
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ if ( is_readable($autoload) ) {

$path = $argv[1] ?? '';
if ( '' === $path || '--help' === $path || '-h' === $path ) {
fwrite(STDERR, "Usage: figma-transformer <path-to-fig-or-scenegraph-json> [--inspect-frames[=<limit>]] [--multi-page] [--frame-ids=<id,id>] [--entry-frame-id=<id>] [--max-pages=<count>] [--output-dir=<dir>] [--omit-asset-content] [--max-nodes=<count>] [--max-kiwi-message-decode-bytes=<bytes>] [--zstd-command=<path>] [--frame-id=<id>] [--font-css=<css>] [--font-css-file=<path>] [--font-family-css=<family>:<css>] [--font-family-css-file=<family>:<path>] [--render-text-glyph-paths] [--parity-status=<status>] [--parity-report-path=<path>] [--parity-source-screenshot-url=<url>] [--parity-source-screenshot-path=<path>] [--parity-generated-screenshot-artifact=<artifact>] [--parity-diff-image-artifact=<artifact>] [--parity-pixel-mismatch-count=<count>] [--parity-pixel-mismatch-ratio=<ratio>] [--parity-threshold=<ratio>] [--parity-viewport=<width>x<height>] [--parity-dom-boxes-path=<path>] [--parity-layout-report-path=<path>] [--parity-render-evidence-path=<path>] [--parity-layout-mismatch-count=<count>]\n");
fwrite(STDERR, "Usage: figma-transformer <path-to-fig-or-scenegraph-json> [--inspect-frames[=<limit>]] [--inspect-kiwi-gate] [--kiwi-gated-decode] [--multi-page] [--frame-ids=<id,id>] [--entry-frame-id=<id>] [--max-pages=<count>] [--output-dir=<dir>] [--omit-asset-content] [--max-canvas-bytes=<bytes>] [--max-nested-fig-bytes=<bytes>] [--max-archive-asset-content-bytes=<bytes>] [--max-zstd-inflated-bytes=<bytes>] [--max-nodes=<count>] [--max-kiwi-message-decode-bytes=<bytes>] [--max-kiwi-selective-message-decode-bytes=<bytes>] [--zstd-command=<path>] [--frame-id=<id>] [--font-css=<css>] [--font-css-file=<path>] [--font-family-css=<family>:<css>] [--font-family-css-file=<family>:<path>] [--render-text-glyph-paths] [--parity-status=<status>] [--parity-report-path=<path>] [--parity-source-screenshot-url=<url>] [--parity-source-screenshot-path=<path>] [--parity-generated-screenshot-artifact=<artifact>] [--parity-diff-image-artifact=<artifact>] [--parity-pixel-mismatch-count=<count>] [--parity-pixel-mismatch-ratio=<ratio>] [--parity-threshold=<ratio>] [--parity-viewport=<width>x<height>] [--parity-dom-boxes-path=<path>] [--parity-layout-report-path=<path>] [--parity-render-evidence-path=<path>] [--parity-layout-mismatch-count=<count>]\n");
exit(1);
}

$options = array();
$zstdCommand = getenv('FIGMA_TRANSFORMER_ZSTD_COMMAND') ?: null;
$outputDir = null;
$inspectKiwiGateMode = false;
foreach ( array_slice($argv, 2) as $argument ) {
if ( ! str_starts_with($argument, '--') ) {
continue;
Expand Down Expand Up @@ -46,6 +47,17 @@ foreach ( array_slice($argv, 2) as $argument ) {
continue;
}

if ( 'inspect-kiwi-gate' === $name ) {
$options['inspect_kiwi_gate'] = true;
$inspectKiwiGateMode = true;
continue;
}

if ( 'kiwi-gated-decode' === $name ) {
$options['inspect_kiwi_gate'] = true;
continue;
}

if ( 'inspect-frame-limit' === $name ) {
$options['frame_inspection_limit'] = max(1, (int) $value);
continue;
Expand All @@ -61,6 +73,31 @@ foreach ( array_slice($argv, 2) as $argument ) {
continue;
}

if ( 'max-kiwi-selective-message-decode-bytes' === $name ) {
$options['max_kiwi_selective_message_decode_bytes'] = max(0, (int) $value);
continue;
}

if ( 'max-canvas-bytes' === $name ) {
$options['max_canvas_bytes'] = max(0, (int) $value);
continue;
}

if ( 'max-nested-fig-bytes' === $name ) {
$options['max_nested_fig_bytes'] = max(0, (int) $value);
continue;
}

if ( 'max-archive-asset-content-bytes' === $name ) {
$options['max_archive_asset_content_bytes'] = max(0, (int) $value);
continue;
}

if ( 'max-zstd-inflated-bytes' === $name ) {
$options['max_zstd_inflated_bytes'] = max(0, (int) $value);
continue;
}

if ( 'max-nodes' === $name ) {
$options['max_nodes'] = max(0, (int) $value);
continue;
Expand Down Expand Up @@ -195,7 +232,9 @@ if ( isset($options['parity']['render_evidence_path']) && is_scalar($options['pa
}

$transformer = blocks_engine_figma_transformer_cli_transformer(is_string($zstdCommand) && '' !== $zstdCommand ? $zstdCommand : null);
if ( true === ($options['inspect_frames'] ?? false) ) {
if ( $inspectKiwiGateMode && ! str_ends_with(strtolower($path), '.json') ) {
$result = $transformer->inspectKiwiGateFile($path, $options);
} elseif ( true === ($options['inspect_frames'] ?? false) ) {
if ( str_ends_with(strtolower($path), '.json') ) {
$decoded = json_decode((string) file_get_contents($path), true);
$result = $transformer->inspectFramesScenegraph(is_array($decoded) ? $decoded : array(), $options);
Expand Down
47 changes: 30 additions & 17 deletions figma-transformer/scripts/figma-kiwi-skipped-field-inventory.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,25 @@
} else {
require_once __DIR__ . '/../figma-transformer.php';
}
require_once __DIR__ . '/figma-script-utils.php';

$options = blocks_engine_figma_kiwi_inventory_options($argv);
if ( blocks_engine_figma_script_bool_option($options['self_check'] ?? false) ) {
blocks_engine_figma_script_self_check();
exit(0);
}
if ( true === ($options['help'] ?? false) || '' === ($options['input'] ?? '') ) {
blocks_engine_figma_kiwi_inventory_usage(true === ($options['help'] ?? false) ? STDOUT : STDERR);
exit(true === ($options['help'] ?? false) ? 0 : 1);
}

$zstdCommand = $options['zstd_command'] ?? (getenv('FIGMA_TRANSFORMER_ZSTD_COMMAND') ?: null);
$result = blocks_engine_figma_kiwi_inventory((string) $options['input'], is_string($zstdCommand) && '' !== $zstdCommand ? $zstdCommand : null);
$json = json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";
$outputPath = $options['output'] ?? null;
if ( is_string($outputPath) && '' !== $outputPath ) {
if ( false === file_put_contents($outputPath, $json) ) {
fwrite(STDERR, "Failed to write skipped-field inventory output to {$outputPath}\n");
exit(1);
}
fwrite(STDOUT, json_encode(array(
'schema' => 'blocks-engine/figma-transformer/kiwi-skipped-field-inventory-output/v1',
'output' => $outputPath,
'summary' => $result['summary'] ?? array(),
), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n");
} else {
fwrite(STDOUT, $json);
try {
$input = blocks_engine_figma_script_require_input_path((string) $options['input']);
$result = blocks_engine_figma_kiwi_inventory($input, is_string($zstdCommand) && '' !== $zstdCommand ? $zstdCommand : null);
blocks_engine_figma_script_output_json($result, isset($options['output']) ? (string) $options['output'] : null, $result['summary'] ?? array());
} catch (Throwable $error) {
blocks_engine_figma_script_fail($error);
}
exit(empty($result['diagnostics']) ? 0 : 0);

Expand All @@ -62,7 +58,7 @@ function blocks_engine_figma_kiwi_inventory_options(array $argv): array

function blocks_engine_figma_kiwi_inventory_usage(mixed $stream): void
{
fwrite($stream, "Usage: figma-kiwi-skipped-field-inventory.php <path-to-fig> [--zstd-command=/opt/homebrew/bin/zstd] [--output=/tmp/inventory.json]\n");
fwrite($stream, "Usage: figma-kiwi-skipped-field-inventory.php <path-to-fig> [--zstd-command=/opt/homebrew/bin/zstd] [--output=/tmp/inventory.json] [--self-check]\n");
}

/**
Expand Down Expand Up @@ -187,16 +183,33 @@ function blocks_engine_figma_kiwi_inventory_payload(string $payload, ZstdCapabil
function blocks_engine_figma_kiwi_inventory_file_summary(array $inventories): array
{
$byRole = array();
$decodedByRole = array();
$fieldCount = 0;
$decodedFieldCount = 0;
$occurrences = 0;
$decodedOccurrences = 0;
foreach ( $inventories as $inventory ) {
$summary = is_array($inventory['summary'] ?? null) ? $inventory['summary'] : array();
$fieldCount += (int) ($summary['field_count'] ?? 0);
$occurrences += (int) ($summary['occurrences'] ?? 0);
foreach ( is_array($summary['by_role'] ?? null) ? $summary['by_role'] : array() as $role => $count ) {
$byRole[(string) $role] = ($byRole[(string) $role] ?? 0) + (int) $count;
}
$decodedSummary = is_array($inventory['decoded_summary'] ?? null) ? $inventory['decoded_summary'] : array();
$decodedFieldCount += (int) ($decodedSummary['field_count'] ?? 0);
$decodedOccurrences += (int) ($decodedSummary['occurrences'] ?? 0);
foreach ( is_array($decodedSummary['by_role'] ?? null) ? $decodedSummary['by_role'] : array() as $role => $count ) {
$decodedByRole[(string) $role] = ($decodedByRole[(string) $role] ?? 0) + (int) $count;
}
}
arsort($byRole);
return array('field_count' => $fieldCount, 'occurrences' => $occurrences, 'by_role' => $byRole);
arsort($decodedByRole);
return array(
'field_count' => $fieldCount,
'occurrences' => $occurrences,
'by_role' => $byRole,
'decoded_field_count' => $decodedFieldCount,
'decoded_occurrences' => $decodedOccurrences,
'decoded_by_role' => $decodedByRole,
);
}
Loading
Loading