Refer to demo.pcbjam.com from the landing: an accent "Live demo" link in the
header nav, an "Open the live editor" hero link, a note in the gerber section,
and a "Try the live demo now" line in the final CTA.
Rework the embedded gerber viewer (public/gerber-demo/boot.js) to source the
WASM from the deploy pipeline's versioned CDN instead of the hand-synced
assets.pcbjam.com bucket: resolve gerbview's content-addressed folder at runtime
from the release manifest (manifest-latest -> tag -> manifest-<tag> -> gerbview),
load all assets (glue + wasm + images.tar.gz) from cdn.pcbjam.com, and load the
cross-origin pthread worker via a same-origin blob importScripts shim (mirrors
web/standalone/src/wasm/boot.ts). Bump the config-seed KICAD_VERSION_DIR
9.99 -> 10.0 to match the deployed build. Drop the now-obsolete committed glue
mirror and the old assets.pcbjam.com sync/r2-deploy scripts.
Collapse the header nav to the hamburger below 1025px — the added demo link no
longer fits the 1024px-capped bar on a single row.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New tooling in tests/tools/screenshots/ (TypeScript via tsx):
- compare.ts: one pixelmatch engine (AA-excluded), connected-component
"where to look" boxes, old|new+boxes|heatmap triptych, per-engine floors.
- promote.ts: churn-free updater — overwrite a baseline only when decoded
pixels differ beyond the floor, copying CI bytes verbatim (no re-encode
churn); pulls a CI run via `gh run download` or a local --from dir.
- post-discord.ts: always-on CI-on-main report (SHA + e2e status + the
track-only runtime-perf table), then screenshot triptychs, batched +
size-capped + flood-collapsed + 429-aware.
- perf-report.ts: perf table with Δ vs the previous main run (via gh).
- changelog.ts: no-build git-history baseline differ (Discord trigger B).
- noise.ts / gen-manifest.ts: calibration + manifest generation.
CI wiring:
- wasm-build.yml: post-test step runs the gate + report on the already-
produced test-results (no extra build); report-only (continue-on-error),
posts only on push to main, inert without DISCORD_WEBHOOK_URL.
- ci-ubicloud.yml: secrets: inherit (pass the webhook through).
- screenshot-changelog.yml: ~30s no-build changelog on baseline changes.
screenshot-manifest.json: canonical 354-name set + best-effort engine tags
(313 chromium-swiftshader / 41 firefox-llvmpipe).
Normalize scale:'device'->'css' across 18 spec files (no-op at CI DSF=1)
so committed baselines are uniformly css-scaled.
Design: CI's Linux render is the single source of truth; no pinned
container (accept rare env drift -> re-promote); dev commits via promote.
Replaces the byte-cmp compare-screenshots.sh + file-size-proxy
update-baseline-screenshots.sh (kept for now until the first re-baseline).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Measures the current build's cold load, open+render, and pan/zoom FPS
(1x/4x/6x CPU-throttle sweep) for both editors, writing
tests/test-results/perf-*.json. Track-only: asserts only that the app booted
and the document opened — no perf thresholds, so it never gates CI.
Runs on a new Chromium `perf` Playwright project (CDP throttling; pcbnew needs
V8 anyway) via `npm run test:perf`, and is wired into wasm-build.yml as a
continue-on-error step so the numbers are captured/uploaded without flaking the
gate. Reuses the existing fixtures, ready-signal, fs-inject, and board-ready
helpers; FPS counter is cancel-able so a throttle sweep on one page doesn't
accumulate rAF loops.
.gitignore: ignore /benchmark-builds/ (disposable prebuilt-WASM + standalone
harness bundle used to reproduce the native-vs-JS-EH comparison locally).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The native-EH migration left tests/gal-regression/wasm/Makefile on the old
Emscripten JS-exception model (-sNO_DISABLE_EXCEPTION_CATCHING, no
-fwasm-exceptions). The wxWidgets libs it links are now built with
-fwasm-exceptions, so wasm-ld couldn't resolve __cpp_exception / __c_longjmp and
the "Build GAL WebGL test app" CI step failed. This was masked until now because
the host post-process (finalize) bug killed every run before this step ran.
Compile and link with DEPS_EH_FLAGS (-fwasm-exceptions -sSUPPORT_LONGJMP=wasm
-sWASM_LEGACY_EXCEPTIONS=1), honoring the value build-gal-webgl-test.sh exports
via env.sh with a Makefile ?= fallback — matching the wxWidgets test-app build.
Drop the now-incompatible -sNO_DISABLE_EXCEPTION_CATCHING.
Verified locally: ./scripts/build-gal-webgl-test.sh links clean against the
native-EH wx libs and produces gal_webgl_test.{js,wasm}.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
backend-example (open ref backend): USER_HEADER, scope on the project DTO, raw routes under /api/scopes/:scope, no-op reportDrift + DOM lib (was red on main → now typecheck-green). GPL web specs (tools-open, symbol/footprint-write-remote, global-setup-web): /p/demo/:tool/* → /:scope/projects/demo/(file | -/:tool), direct API fetches scoped + x-pcbjam-owner → x-pcbjam-user. Reference backend keeps lib type 'user' (cosmetic vs closed 'org').
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the legacy Emscripten JS-exceptions model with native wasm-EH (legacy
encoding) across the whole build, keeping Asyncify coroutines working via a
from-source Binaryen --hoist-cpp-catches pre-pass. Net result: native-EH is the
only build mode, the 3D viewer is on by default, and pcbnew shrinks substantially.
Highlights:
- Binaryen submodule everywhere + --hoist-cpp-catches integration in apply-asyncify;
post-link Asyncify covers every app wasm (not just standalone test wasm).
- Build deps (incl. OpenCASCADE without OCC_CONVERT_SIGNALS) and all KiCad apps
with -fwasm-exceptions; emscripten_sleep added to the post-link asyncify-imports.
- libcontext fiber entry wired under native exceptions; while-loop main loop +
currData shim injected into all wx apps.
- Native-EH collab apply fixed: DEBUG-define the embind TU + match all out-of-CMake
C++ TUs' ABI flags to the core, fixing the vtable-layout skew / mis-dispatch.
- 3D viewer enabled by default (real raytracer linked, not the stub).
- Retire the EH-spike scaffolding; flip the asyncify-races ablation pins to
shim-redundancy pins (native-EH stays clean with the legacy shims ablated).
- Fix the asyncify-races quiescence check to not require Asyncify.currData==0:
under the native-EH per-frame-yield top loop the main stack is asyncify-suspended
every frame, so currData legitimately churns (a freed-but-not-yet-nulled buffer,
not a leak). Refresh the pcbnew toolbar screenshot baseline for the new kicad.
- CI: drop the obsolete binaryen_version input/env (the build uses the binaryen
submodule fork's wasm-opt, not a version download); key the wasm-output cache on
the binaryen submodule SHA instead.
Bumps the wxwidgets + binaryen submodules to their squashed feature commits.
Validated green: all 7 apps native-EH (real 3D in pcbnew); KiCad e2e 63/63
Firefox + Chromium (3D viewer renders); wx 336; coroutine 34/34 both engines;
asyncify 7/7 both engines.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bump wxwidgets to the %p->%zu radio-group name fix and add a standalone
wxWidgets harness plus an e2e regression that asserts three radio groups
in one window select independently. Build artifacts are gitignored; only
radiogroups_test.cpp is tracked.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The crosshair toolbar group-cycle (ACTION_TOOLBAR::onToolEvent) was
expected-to-fail because the kicad submodule was a pre-10.0 (9.99.0)
snapshot that lacked it. The KiCad 10.0.4 rebase on this branch restores
the behavior, so the test now passes and Playwright flagged it as
"Expected to fail, but passed". Remove the test.fail annotation as the
test's own comment instructed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
KiCad 10.0.4 added two trailing optional params (std::optional<VECTOR2I>
aMousePos, wxString* aActiveUrl) to the out-of-line FONT::Draw declaration
in font/font.h. The hand-written stub in the GAL WebGL test app still
declared the old 6-arg form, so it matched no declaration and failed the
CI "Build GAL WebGL test app" step. Update the stub signature to match.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Builds KiCad's 3D viewer for the browser (opt in with BUILD_3D_VIEWER=ON) and
wires up the legacy-GL emulation it needs.
- build-kicad-target.sh / docker/build.sh: BUILD_3D_VIEWER →
-DKICAD_BUILD_3D_VIEWER_WASM=ON + -sLEGACY_GL_EMULATION + the GL js-library.
- wasm/shims/gl_immediate_shim.js: display-list emulation (record/replay board
layers), fixed-function + GLU stubs, throw-guards for unsupported pnames, and
per-context GLImmediate init for the viewer's SECOND WebGL context.
- tests/kicad/3d-viewer.spec.ts + utils/pcbnew-ready.ts: open View → 3D Viewer.
- bumps the kicad submodule (EMSCRIPTEN-guarded GL changes).
WIP: the viewer window + UI render and geometry draws (glError=0x0), but the
board is not yet visibly rendered — GLImmediate's FFP shader program isn't
linked on the viewer's 2nd WebGL context. Full status + next steps in
features/feat/add-3d-view/notes.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The web tool-open smoke booted 6 of the 7 standalone tools; add the
footprint_editor case so every tool the editor exposes is exercised. It
boots file-less (like symbol_editor/gerbview) and asserts its frame title.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rework HomePage into KiCad-launcher-style zones: local file-load, a Tools grid,
backend projects, and a backend libraries listing (useLibs over the shared
listLibs). The Tools grid shows all seven tools in KiCad's standalone order
(Schematic/Symbol/PCB/Footprint editors, Gerber Viewer, Calculator, Drawing
Sheet); clicking a tool or a library launches the editor with no project
(launchedTool → WasmTool slug=local) — file-less editors browse backend libs,
document editors open blank. Harden the web e2e global-setup to assert the
self-provisioned origin libs (Device, Resistor_SMD) are present, failing fast.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Standalone wx test apps (contextmenu, scrollbar) + e2e specs proving the
wxScrollBar control, the wxScrolledWindow gutter, and DoPopupMenu.
- KiCad in-app specs: pl_editor + pcbnew canvas right-click context menus and
scrolled-panel scrollbar gutters, with baseline screenshots.
- build-wx-wasm.sh: serial -j1 fallback when the parallel build trips the
intermittent clean-build race (a generated header read mid-rewrite by
concurrent compiles; never happens at -j1). Recovery resumes from built
objects; a genuine error still fails the serial pass.
- Bump wxwidgets submodule (context menus + draggable scrollbars).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bump wxwidgets (8814ddb) for the two DOM-port fixes and add their reproductions:
- tests/apps/standalone/{textctrl-reentry,tooltip-lifetime}: standalone wx repro
apps + Makefile.wasm targets (textctrl links -fexceptions to throw from a
wxEVT_TEXT handler), driven by tests/e2e/dom-port-bugs.spec.ts. Each app is
deterministic and self-contained (no UB, ASAN, or timing dependence).
- docs/features/wx-dom-port/branch-review.md: branch review with findings #2/#3
marked fixed and a "Bug reproductions and fixes" section, including the
asyncify + legacy-EH gotcha (catch/destructor landing pads are unreliable
while unwinding through asyncify frames).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Submodule pointer bump for the wxMenuBar dangling-child fix that resolved the 18 DOM-port kicad e2e failures. Also adds the async-debug dossier (docs/features/async/08-10) root-causing the 'indirect call to null' / 'signature mismatch' family to the menu-bar use-after-free, and folds the asyncify harness into 'npm test' (new test:wx for wx-only); tests/README + WHATWORKS updated to match.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- wxwidgets -> 25281178d2: wxClipboard::IsSupported answered via a 2 s
Asyncify suspend on KiCad's idle path; overlapping suspensions
corrupted Asyncify.currData ('indirect call to null'/'signature
mismatch' storms after every document load — bug 2 of features/async).
It now answers synchronously. The storms and 2 s UI stalls are gone.
- 58 kicad screenshot baselines regenerated from the green run (the old
set was canvas-only and died with the canvas port).
- visual-notes: bug 29 + the known-red list — the 10 file-loading kicad
specs (load-pcb, collab bridges, eeschema-ui keyboard/dialog) remain
red on the unfixed asyncify substrate (bug 3, per-context currData
authority). Bisect-verified pre-existing: binaries built from the
pre-consolidation wx tree fault identically. Greening them is the
async feature's exit criterion, deliberately out of scope here.
Gates: wx e2e 292/0/1 skipped; kicad 32 passed / 10 known-red / 2
skipped (parity +1 with pre-consolidation, minus the timeout storms).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
One-time refresh from a fully green run (292/0/1): the client-origin
projection fix moved every notebook's tab strip to its true position
(content shifted by the strip height), and many baselines predated the
DOM-native notebook entirely. 10 new screenshots (gal/menu/spinctrl
flows that previously never ran green), 159 updated, 100 untouched.
compare-screenshots.sh is clean against the gate run.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pure file moves: the canvas baseline set (331 PNGs) is deleted, the DOM
set becomes tests/baseline-screenshots/, and the DOM pcbnew reference
image becomes wizard-04-finish-headless.png. 73 kicad-flow baselines
existed only on the canvas side; they are regenerated from a green DOM
run in a follow-up commit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The canvas (wxUniversal) mode is gone (wxwidgets submodule); remove every
piece of side-by-side plumbing so there is exactly one build and one test
flow:
- scripts/build-wxuniversal-wasm.sh -> scripts/build-wx-wasm.sh; no
--dom/--enable-universal; builds into build-wasm/wxwidgets
- build-wasm-test.sh: no DOM_BUILD / apps-dom rsync mirror / PORT=dom;
apps build straight into tests/apps (Makefile.wasm PORT conditionals
collapsed; wx.js + wx-dom.js always pre-js)
- docker/build.sh, build-kicad-target.sh, env.sh: WX_PORT / -dom /
-universal suffixes removed; kicad builds to kicad-<app>, outputs to
output/; wx.js/wx-dom.js copied from the real source path
(/workspace/wxwidgets/build/wasm — the old build-wasm path never
existed and silently failed)
- setup-kicad-wasm.sh: single target dir; the perl wx-dom.js injection is
gone — the 7 checked-in kicad pages now reference wx-dom.js directly
- playwright configs serve apps/; fixtures drop the test-results/dom and
logs/wxwidgets/dom namespacing; boot.spec asserts wxDomPort
unconditionally; pcbnew.spec uses one reference image;
appearance.spec assertions unconditional
- compare/update-baseline-screenshots.sh: --port removed
- tests/gal-regression/wasm/Makefile: links build-wasm/wxwidgets and
carries wx-dom.js as a second pre-js — the gal-webgl suite (30 specs)
now actually builds and runs here (it needed host-side boost+glm via
scripts/deps; the bundle had been missing, timing the whole spec out)
- tests: clickCanvas() dispatches via page.mouse (DOM widgets
legitimately cover the canvas; locator actionability refused the
click); the comprehensive spec drives wxChoice through its native
<select> (browser-owned popup cannot be coordinate-clicked)
- docs: README/CLAUDE.md/build.md script names and dirs;
features/wx-dom-port README reframed (DOM is THE port), visual-notes
bugs 26-28; FindwxWidgets.cmake config label drops 'wasmuniv'
- wxwidgets submodule -> 9dbacc9448 (DOM-only port, fork diff shrunk)
Gate: full wx e2e suite 292 passed / 1 skipped / 0 failed — first run
ever with the gal-webgl specs green (28 scenarios + load + sequential).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New tests/kicad/appearance.spec.ts: tab cycle through Layers/Objects/
Nets and back (with blank-rows regression assertion), wheel scrolling
in Layers (movement + exact scroll-back restoration) and Objects, with
screenshots per state. All 3 pass against the DOM pcbnew.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>