Skip to content

fix(import): make emitted ui.js self-contained (relative asset paths)#6413

Merged
shipyard-local[bot] merged 1 commit into
mainfrom
fix/import-selfcontained-assets
Jul 21, 2026
Merged

fix(import): make emitted ui.js self-contained (relative asset paths)#6413
shipyard-local[bot] merged 1 commit into
mainfrom
fix/import-selfcontained-assets

Conversation

@shipyard-local

@shipyard-local shipyard-local Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Item #3 of the Figma-import hardening plan (planning/2026-07-20-figma-import-hardening-plan.md).

Exported ui.js referenced decode-time temp asset paths ($TMPDIR/pulp-fig-*/assets/…) that are deleted at run end — so re-rendering the export silently lost every image/font. --validate only passed because it renders before cleanup.

Fix (general — every JS-emitting lane)

  • Emit side: new localize_ir_assets copies referenced images+fonts into an assets/ dir next to --output and rewrites the IR to output-relative paths (collision-suffixed; copy failure degrades to a warning, never fails the import).
  • Render side: new WidgetBridge::set_script_base_dir / resolve_script_relative resolves relative fs paths at the asset-taking APIs against the script's dir (unset = historical CWD behavior; deliberately not the sandboxing set_asset_roots). Wired into --validate, pulp-screenshot, pulp-design-tool.
  • Leak: make_scratch_dir now sweeps stale pulp-* scratch dirs >24h (drained a 161-dir backlog from killed runs; live imports untouched).

Verification

  • Real A Channel FX import: 16 setImageSource → relative assets/… (dedup'd texture copied alongside), zero functional /var/folders refs (the one left is a // Source: provenance comment). Re-rendered standalone from / → content renders (assets resolve via base-dir, not CWD).
  • ctest -R "import|design|asset|codegen|native" 617/617; -R "bridge|widget|screenshot|font" 408/408. New tests pin the self-contained artifact (survives decode-dir deletion), the scratch-dir sweep, and base-dir resolution.

🤖 Generated with Claude Code


🔎 Provenance

Agent claude
Machine m5
Workspace w1
Directory ~/Code/fig-fix
Session fd0e374f-d5dc-4e2a-bb33-6fa8b66124a0

Resume

claude --resume fd0e374f-d5dc-4e2a-bb33-6fa8b66124a0

Jump to this tab

cmux surface focus B1B434D3-85F6-4937-8806-96D59886F574

Relaunch (any agent)

cmux surface resume get --surface B1B434D3-85F6-4937-8806-96D59886F574

Restore URLhttps://claude.ai/code/session_014e8kbMn8Sf4mF8ozsy1Jot

stamped 2026-07-20 22:40 UTC

The import CLI stamped decode-time ABSOLUTE paths into the generated
JS (setImageSource/setKnobSpriteStrip/registerFont): for `--from fig`
these point into the per-run $TMPDIR/pulp-fig-* scratch dir, which is
deleted when the run exits, so re-rendering the export later silently
lost every image; `--validate` only worked because it renders before
cleanup. Other lanes kept paths into whatever directory the envelope
happened to be decoded in — broken as soon as it moved.

Fix, general to every JS-emitting lane:

- `localize_ir_assets` (sprite_skins.cpp) runs after asset resolution
  and before codegen: it copies each referenced image/font into
  `assets/` next to the `--output` file and rewrites the IR references
  to output-relative `assets/<file>` paths. Skipped for --dry-run and
  baked emits.
- `WidgetBridge::set_script_base_dir` resolves those relative paths
  against the script's own directory at the path-taking bridge APIs,
  regardless of process CWD. Unset base keeps the historical CWD
  behavior, and unlike set_asset_roots it never restricts loadAsset.
  The `--validate` render, pulp-screenshot, and pulp-design-tool set
  it from the script location.
- `make_scratch_dir` now sweeps stale (>24h) `pulp-<tag>-*` siblings:
  runs killed mid-decode never reach their cleanup destructor, and
  ~160 leaked scratch dirs had accumulated in $TMPDIR. The age floor
  leaves concurrent live imports untouched.

Tests: self-containment pin (relative paths emitted, assets copied,
export intact after the decode dir is deleted), scratch-cleanup +
stale-sweep pin, script-base-dir resolution unit sections, and the
ZIP-sidecar test updated to the new relative contract.

Hotspot-Grow: core/view/include/pulp/view/widget_bridge.hpp reason="script-base-dir resolution API needed for self-contained import artifacts"
Hotspot-Grow: tools/import-design/pulp_import_design.cpp reason="wire asset localization + validate-render base dir (+10 LOC)"
Compat-Update: skip prefix=canvas2d reason="host-side script-base-dir path resolution API; no web-compat surface change"
Compat-Update: skip prefix=css reason="host-side script-base-dir path resolution API; no web-compat surface change"
Compat-Update: skip prefix=html reason="host-side script-base-dir path resolution API; no web-compat surface change"
Compat-Update: skip prefix=imports reason="host-side script-base-dir path resolution API; no web-compat surface change"
Compat-Update: skip prefix=react reason="host-side script-base-dir path resolution API; no web-compat surface change"
Compat-Update: skip prefix=rn reason="host-side script-base-dir path resolution API; no web-compat surface change"
Compat-Update: skip prefix=yoga reason="host-side script-base-dir path resolution API; no web-compat surface change"
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014e8kbMn8Sf4mF8ozsy1Jot
@shipyard-local
shipyard-local Bot merged commit d8d9a5d into main Jul 21, 2026
20 of 29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant