Commit graph

602 commits

Author SHA1 Message Date
Viktor Vaczi
c005e1ba73 feat(ci): e2e failure no longer suppresses the screenshot report
An e2e failure used to skip everything downstream: a wx failure skipped the
asyncify suite (&&-chain) and the kicad suite, and any failure skipped the
screenshot check + Discord report entirely — leaving only the bare text notice
even though the rendered screenshots were already on disk.

Now the three suites run as separate steps gated on !cancelled() + "previous
stage wasn't skipped" (build failures still skip all tests), and the screenshot
report runs whenever the suites ran, posting with an --e2e pass/fail badge
computed from the step outcomes — so a wrong or MISSING screenshot (spec died
before page.screenshot() => classified "removed") is visible on Discord on red
builds too. The text-only failure notice becomes a fallback for when the rich
report didn't post (build broke before tests, or the report errored) — no
duplicate ping. A failing suite still fails the job; gating is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTxTrY9on6A8gLvogFbGiy
2026-07-02 17:30:15 +02:00
Viktor Vaczi
e01256b54d fix(ci): binaryen tools cache also needs lib/ — bin-only restore broke every post-process
The binopt cache from b4cb10b saved only binaryen-hoist-build/bin, but the
tools dynamically link lib/libbinaryen.so, so the first cache HIT (run
28585074335) failed all 7 tools' finalize with a loader error. Cache bin/ +
lib/, bump the key to binopt-v2 (Ubicloud never re-saves an exact-key hit, so
the poisoned v1 entry can't be repaired in place), and make the
BINARYEN_TRUST_PREBUILT guard exec both tools with --version instead of -x
existence checks so an incomplete restore falls through to a source build.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTxTrY9on6A8gLvogFbGiy
2026-07-02 14:29:20 +02:00
Istvan Matejcsok
7630c7e521 fix: 🐛 raytrace deadlock - pre-warm 2N+8 pthread Workers 2026-07-02 13:01:02 +02:00
Viktor Vaczi
b4cb10b1c6 perf(ci): cache the per-run toolchain + test-app work (binaryen, emsdk, apps, browsers)
Four new caches in wasm-build.yml, keyed on their real inputs:

- Binaryen post-process tools (bin/ only, keyed on the submodule SHA): on a
  hit BINARYEN_TRUST_PREBUILT=1 tells build-wasm-opt.sh to skip cmake+ninja
  and trust the restored binaries (~46s/run). The guard is env-gated so local
  pass iteration (uncommitted sources, same SHA) is unaffected.
- Built wx test apps (tests/apps minus kicad/ staging + gal-webgl/): skips
  the whole build step on a hit (~3 min — the post-link hoist+asyncify over
  ~74 apps dominates). Key covers wx SHA + kicad SHA (some apps compile real
  KiCad sources: thread_pool.cpp, libcontext), binaryen SHA, tracked app
  sources, and the build/post-link scripts + shims. Gated on a wx cache HIT:
  the app build creates the libwx_*.a symlinks the GAL link needs, so on a
  wx rebuild the apps must rebuild too.
- Host emsdk (tools/emsdk, keyed on the pinned EMSCRIPTEN_VERSION): mostly
  availability insurance — a fresh install is only ~23s but pulls ~340 MB
  from github.com + storage.googleapis.com on every run. downloads/ tarballs
  are pruned before the post-job save.
- Playwright browsers (~/.cache/ms-playwright keyed on tests/package-lock).

Warm-cache runs should drop from ~12 min to ~8-8.5 min (e2e suites are the
floor). Measured baselines from runs 28577824366 / 28520845242.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeiSRRScdaox5jBueJNcyG
2026-07-02 12:40:22 +02:00
Viktor Vaczi
0702192fed fix(ci): screenshot report is report-only again — never fail the build on drift
Per request: a screenshot difference shouldn't fail CI; the Discord post is the
signal. Revert the enforcing gate (3efcdcf): drop `--fail-on-change` + the
exit-status gating and restore `continue-on-error` on the on-success report step
(compare.ts exits 0 without the flag). Remove the now-moot fail-notice guard.
Build/e2e failures still post the "CI failed" notice; changed/added/removed still
post the captioned Discord report + perf.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 12:22:19 +02:00
Viktor Vaczi
9787efc2c9 feat(tests): caption posted screenshots (name + spec); raise drift floor to 0.5%
Bake a caption strip onto every posted screenshot composite — status + name +
the spec that produces it — for changed, added, and removed; removed now shows
the old baseline image (was a text-only line). Zero native-dep: an embedded
public-domain 8x8 bitmap font (font8x8.ts) rendered by image-ops `withBottomLabel`;
the name→spec attribution is factored out of gen-manifest into a shared
`spec-map.ts` resolver. Bottom strip, colour per status (green/red/orange).
Applies in both compare (drift gate) and changelog (git-history diff), and
post-discord now attaches the captioned removed images.

Also raise the per-engine drift floor 0.2% → 0.5% (changedRatio) to absorb the
sub-1% inter-run flakiness seen after the re-baseline, while still catching real
localized changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 12:07:41 +02:00
Gergő Törcsvári
4330c9344e
feat(3d): live models CDN — 10.0.3 publish wiring + wrl→step fallback
- kicad-packages3D is STEP-only from the 10.x tags: ensureModelInMemfs
  falls back from a missing .wrl to the same-stem .step, written and
  answered under the .step path (the returned path's extension picks
  the parsing plugin — no C++ awareness). Verified against the live
  CDN with the gallery demo board (4/4 wrl refs served as step).
- upload-models-r2.sh: rclone/S3 bulk upload of a local publish layout
  (wrangler-per-object can't move ~14k blobs); published 10.0.3 —
  105 libs / 7,238 models, 3.4GB raw → 500MB brotli — to pcbjam-cdn.
- deploy-demo.yml MODELS_TAG=10.0.3 → build-demo --models-tag →
  VITE_MODELS_MANIFEST_URL (matches LIB_TAG: model refs come from the
  footprints at that release).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014AT7gVHRktDYoQ68S4x6A4
2026-07-02 11:35:37 +02:00
Gergő Törcsvári
6f3f3bcf00
feat(3d): lazy 3D model delivery R2→IDB→WASM
- cdnModelsSource: sparse per-lib stacks over the models CDN layout
  (libs/kicad-models/<tag>/<lib>/manifest + content-addressed blobs)
- models-bridge: board prescan ((model …) scan → prefetch, 4/4 in 74ms
  on the demo board) + the kind=model3d 'ensure' op answering absolute
  MEMFS paths; only board-referenced bodies ever enter IDB
- boot/runner/config/WasmTool wiring (VITE_MODELS_MANIFEST_URL,
  KICAD*_3DMODEL_DIR seeding, prefetch badge)
- StorageUsageCard on HomePage: per-kind cached sizes + delete-3D-cache
- publish-models.ts (brotli content-addressed publish, 606→93MB for the
  pic_programmer lib set) + dev-demo --models-tag/--models-local
- e2e: 3d-viewer-models.spec.ts (bridge normalize/dedup + STEP/WRL
  render); submodule bumps: kicad (static 3D plugins + ensure hook),
  pcbjam-shared (sparse sync layer)

Spec + findings: docs/features/3d-models (private repo).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014AT7gVHRktDYoQ68S4x6A4
2026-07-02 11:35:36 +02:00
Viktor Vaczi
3efcdcf91c fix(tests): enforce screenshot gate; drop shadow dir, flaky retinascale, 12 stale
Finalize the screenshot review system after the first Linux re-baseline
(that run showed 355/356 stable — the placeholder floor is fine as-is):

- ENFORCE the gate: `screenshots:check --fail-on-change` now fails the build on any
  changed/added/removed vs baselines (it still posts the drift report first, so the
  failure is actionable; a real render change → re-promote). The generic "CI failed"
  notice is suppressed for gate failures so we don't double-post on drift.
- Exclude retinascale-01-loaded: a fullPage HiDPI test whose captured height + DPR
  scaling vary run-to-run (~60% inter-run diff) — a flaky test, not render noise.
  IGNORE_SCREENSHOTS in config.ts; compare/promote/gen-manifest skip it; baseline removed.
- Kill the baseline-dir shadowing: drop e2e/baseline-screenshots/ from BASELINE_DIRS +
  delete its 3 files (grid-tab-final, wxgrid-controls, wxgrid-dedicated-page) that
  duplicated names in baseline-screenshots/ with different bytes.
- Prune 12 stale baselines (renamed/removed specs: wizard-01..04, gerbview-wizard-01..04,
  zoom-pl_editor-*, popup-03-palette).
- Delete the dead compare-screenshots.sh / update-baseline-screenshots.sh.
- Regenerate screenshot-manifest.json (355 entries).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 11:30:33 +02:00
Viktor Vaczi
348596c515 perf(build): use all cores in host builds — wx lib, test apps, gal-webgl
env.sh exports a docker-safe JOBS=1 default, and every host build silently
inherited it (the docker kicad path dodges it by passing -j explicitly):

- build-wx-wasm.sh: the intended "${JOBS:-nproc}" fallback sat BELOW the
  env.sh source, so it was dead code — full wx builds ran make -j1 on the
  Mac and on CI. Compute the all-cores default before env.sh instead
  (explicit JOBS/PARALLEL_JOBS still wins); also -j the PCRE pre-build.
- build-wasm-test.sh: same default fix, plus fan the post-link
  hoist+asyncify loop out across JOBS with xargs -P. Per-app wasm-opt
  can't feed many cores (small modules), so serial stays ~4min even with
  BINARYEN_CORES=16; fanning across the 74 independent apps is what
  scales. Safe: apply-asyncify is in-place per wasm, injector tmp is
  per-js, HOIST_WASMOPT resolved once up front.
- build-gal-webgl-test.sh: make had no -j at all.

Measured on a 16-core M4 Max, clean test-app build: 15m36s (-j1) → 2m08s,
peak RAM 10.7 GB summed across all build processes (64 GB machine; CI
runners have 120 GB). Core counts are always derived from nproc at
runtime — nothing hardcoded, CI workers differ.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeiSRRScdaox5jBueJNcyG
2026-07-02 10:54:14 +02:00
Viktor Vaczi
616bbbf67c test(screenshots): adopt Linux CI baselines (first re-baseline)
Promote the first green CI run built with the outputDir fix (b270507, run
28572705121) — the run that keeps test-results across the sequential suites.
Overwrites the Mac-rendered baselines with CI's Linux render (churn-free,
verbatim bytes):

- 335 updated  — Mac->Linux font/AA rendering (expected, not regressions)
- 14 added     — new specs (modal, notebook, pcbnew-move, 3d-viewer, dark-mode, ...)
- 7 unchanged  — blank/loading screens identical across platforms

Renders eyeballed (pcbnew / eeschema / wx controls) — all correct UI. From here
the baselines are the Linux source of truth; the next run compares Linux-vs-Linux.

12 stale baselines (renamed specs, e.g. wizard-01 -> wizard-01-loaded) are left in
place pending confirmation — prune separately.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 10:44:40 +02:00
Viktor Vaczi
f49d536f95 fix(build): wx 'zlib.h not found' CI flake — self-heal zlib port + deterministic cache touch
Two fixes for the intermittent wx-build failure on CI (zipstrm.cpp: fatal
error: 'zlib.h' file not found, surviving the serial retry):

- build-wx-wasm.sh: --with-zlib=sys resolves to the Emscripten zlib PORT,
  which only `embuilder build zlib` installs — and that ran only in the
  configure branch. A pre-configured build dir (CI cache) + fresh emsdk
  therefore died on any recompile of a zlib-using TU. Ensure the port
  before every make; --force because embuilder stamps the port on libz.a
  alone, so a half-populated cache would no-op.

- wasm-build.yml: the cache-restore `touch {} +` stamped files ns-apart in
  readdir order; GNU make 4.x compares ns mtimes, so objects touched before
  a generated header they depend on (wx/setup.h, pcre2.h via .deps/*.d)
  recompiled — a random subset per run, which is what made the failure
  flaky. Use one shared timestamp instead: equal mtimes = up to date.

Reproduced + validated locally (remove sysroot zlib.h + one .o → exact CI
failure; with fix, self-heals in 0.5s; Linux make ns/equal-mtime behavior
verified in a container).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeiSRRScdaox5jBueJNcyG
2026-07-02 09:59:32 +02:00
Viktor Vaczi
b270507505 fix(tests): keep test-results across CI suites; loud pipeline alert
The screenshot report went silent on green CI runs. CI runs four sequential
`playwright test` invocations (wx, asyncify, kicad, perf) that all default their
outputDir to `test-results`; Playwright clears the whole outputDir at the start
of every run, so each suite wiped the previous suite's screenshots. By the time
`compare` ran, only perf-*.json remained -> all 354 baselines read as "removed"
-> the no-render guard stayed silent.

- Gate Playwright's outputDir off test-results/ in CI only
  (process.env.CI ? 'pw-artifacts/<suite>' : 'test-results') in the wx / asyncify
  / kicad configs, so the committed-baseline screenshots (page.screenshot to
  'test-results/...') accumulate in test-results/ across the suites for compare.
  Local single-suite behavior is unchanged.
- post-discord: replace the silent no-render guard with a loud, image-less
  pipeline alert ("No screenshots produced this run") when 0 render; genuine
  partial removals still post as the normal capped REMOVED list.
- gitignore pw-artifacts/; upload tests/pw-artifacts/** as a CI artifact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 09:20:35 +02:00
Gergő Törcsvári
9b41d7321f feat(site): link the live demo + serve the gerber demo from the versioned CDN
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>
2026-07-02 07:40:30 +02:00
Viktor Vaczi
13551f4f22 feat(tests): screenshot regression + Discord review, perf-tracked
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>
2026-07-01 18:17:20 +02:00
Viktor Vaczi
05127af431 docs(hoist): pass-simplification dossier; bump binaryen (FindAll/BranchUtils refactor)
Adds docs/features/hoist-cpp-catches-simplification/ (diagnosis + Layer 1 result) and bumps the binaryen submodule to 1d40cf5a8 (FindAll/BranchUtils refactor + describe-as-is comments of HoistCppCatches). Validated end-to-end: full pcbnew build through the refactored wasm-opt + Firefox pcbnew e2e 6/6.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 16:52:17 +02:00
Istvan Matejcsok
8ff05e137d fix(3d-viewer): resize deadlock — defer GL-window repaint (bump wxwidgets)
Bumps the wxwidgets submodule to the resize-deadlock fix: wx_window_resize no
longer forces a synchronous wxTheApp->Paint() for a window hosting a wxGLCanvas
(the 3D viewer). That synchronous, nested paint ran the multi-threaded CPU
raytracer from inside the resize call and deadlocked when it had to boot an
on-demand pthread Worker — the 236s mouse.move freeze that reddened CI. The GL
window now repaints via the normal event-loop pump, like a camera move, where the
Worker can boot; dialogs keep the synchronous repaint.

Verified locally against a fresh native-EH BUILD_3D_VIEWER=ON build: 3d-viewer.spec
4/4 green with all four tests in ONE shared serial worker (the frozen scenario);
resize 19.9s. CI green end-to-end.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 15:23:07 +02:00
Viktor Vaczi
3e5791774b test(perf): track-only runtime-perf E2E for eeschema + pcbnew
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>
2026-07-01 14:43:54 +02:00
Viktor Vaczi
7eb65f5b6a docs(wasm-eh): add native-EH vs JS-EH runtime benchmark report
Benchmark of the WASM exception migration (native -fwasm-exceptions vs
legacy JS-EH) for eeschema + pcbnew, O1/O2, headed/headless: native-EH is
~22%/26% smaller gzip, ~30-35% faster load, and faster ops/FPS; ship the
post-link wasm-opt tail at -O1, not -O2. Full tables + methodology in the doc.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 14:43:54 +02:00
Gergő Törcsvári
b5ee3da92c
perf(cdn): publish demo WASM as brotli-q11 + no-transform
release.yml's publish-wasm job now uploads .wasm/.js with
`--compress br --quality 11` instead of gzip-6, and IMMUTABLE
content-addressed blobs carry `no-transform` so Cloudflare's edge
can't decompress + re-serve them at its on-the-fly br-4 (and the
original Content-Length passes through).

~15-20% smaller wasm on cdn.pcbjam.com. Forward-only: tool folders
already published stay gzip until their source changes (identity is
hashed over uncompressed bytes, so the compressor switch never
re-versions or re-uploads existing folders).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 12:21:54 +02:00
Gergő Törcsvári
e7640d0a97
build(wasm): standardize asyncify wasm-opt tail to -O1 everywhere
The Binaryen wasm-opt shrink after Asyncify was the only -O2 in the
pipeline: -O2 by default (local + tag release) but -O1 in main CI. The
C++/wx/deps compile is already -O1 everywhere (DEBUG_BUILD defaults to 1;
nothing passes --release in CI/release). Pin the tail to -O1 too:

- apply-asyncify.sh: BINARYEN_OPT_LEVEL default -O2 -> -O1
- release.yml: opt_level -O2 -> -O1 (demo now ships -O1)
- ci-ubicloud.yml / wasm-build.yml / docker/build.sh: refresh stale -O2 comments

Because both callers now build at -O1, the FINAL cache key converges, so a
tag release FINAL-cache-hits main's build and skips the asyncify-tail
rebuild entirely (previously the ~1-2h -O2 wasm-opt was rerun per release).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 12:18:57 +02:00
Gergő Törcsvári
89a433fda9
fix(trace): make ?trace= work by merging Module.ENV in the glue
The emscripten glue's `var ENV = {};` never merged Module.ENV, so boot.ts's
Module.ENV.KICAD_TRACE was a silent no-op — and since environ_get on a pthread
proxies to the main thread, the app/UI thread's getenv read the (empty) main
ENV. Net: KICAD_TRACE never arrived and every KI_TRACE was a no-op.

scripts/common/patch-env-shim.mjs post-processes each generated <app>.js to
merge Module.ENV into ENV (idempotent; runtime no-op when unset), wired into
docker/build.sh's per-app host post-process next to the dyncall-shim inject.
Replaces a fragile manual glue edit re-applied after every build. Verified:
symbol-editor eager load now emits KI_TRACE_SYM_CHOOSER fatLoad timing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 11:01:10 +02:00
Gergő Törcsvári
88aaba99c9
feat(libs): react load overlay + progress bar; mimalloc mallinfo stub; framed tests
- WasmTool/source.ts: LIB_LOADING_EVENT brackets the fat-load; full-cover
  overlay ('Loading <kind> libraries…') with a per-lib progress bar (done/total
  from listLibs), show-on-first / hide-after-last coalescing.
- mallinfo stub (wasm/shims/mallinfo_stub.c + build-kicad-target.sh): -sMALLOC=
  mimalloc doesn't export glibc mallinfo() that OpenCASCADE OSD_MemInfo (pcbnew
  3D) needs; zeroed no-op unblocks the pcbnew link.
- source/cdn-source tests: updated to the framed Uint8Array 'bodies' contract.
- bump kicad -> e8db3d3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 09:56:32 +02:00
Gergő Törcsvári
4025b05218
feat(libs): parallel s-expr parse + mimalloc + copy-as-is transport — symbol chooser cold 274s→44s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 07:58:30 +02:00
Gergő Törcsvári
ffd1cb1fc3
wip: symbol chooser load — no-clone enumerate + KI_TRACE instrumentation + ?trace= harness
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 20:08:57 +02:00
Viktor Vaczi
71807db734 feat(wasm,3d-viewer): run upstream multi-threaded CPU raytracer
Bumps the kicad submodule to the threading revert (the 3D-viewer raytracer's
WASM single-threaded #ifdef fallbacks + the bs_thread_pool inline shim are gone;
those four files are now byte-identical to upstream KiCad).

Links wasm/shims/nanosleep_yield.c into every app (mirrors the gl_ffp_stub
pattern): the now-upstream raw-thread raytracer joins via a main-thread
sleep_for busy-wait, and this shim makes that nanosleep Asyncify-yield to the JS
event loop instead of deadlocking on on-demand pthread-Worker creation. Its
EM_ASYNC_JS yield is already covered by env.__asyncjs__* in asyncify-imports.txt.
This is what lets upstream's multi-threaded code run on WASM under native-EH.

Also documents isolated-worktree + submodule-branch creation in the README.

Result: ~11x faster 3D raytrace (21.3s -> 1.9s, 16 threads), pixel-correct
render, full kicad e2e green (63 passed / 0 failed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 18:17:56 +02:00
Istvan Matejcsok
3628a090dd feat: 🎸 wxWidgets dialog/frame header/drag/resize 2026-06-30 15:46:52 +02:00
Istvan Matejcsok
cf1fdf5c3d feat: 🎸 wxWidgets dialog/frame DOM header 2026-06-30 15:46:49 +02:00
Viktor Vaczi
917d03c22f fix(wasm-eh): native-EH link flags for the GAL WebGL test app
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>
2026-06-30 13:25:00 +02:00
Viktor Vaczi
714b0a816b fix(wasm-eh): build wasm-emscripten-finalize from the Binaryen submodule (unbreak CI)
The native-EH migration pointed apply-finalize.sh at emsdk's bundled
wasm-emscripten-finalize (${EMSDK:-tools/emsdk}/upstream/bin), which exists on a
dev machine (tools/emsdk persists from a prior build) but never on the ephemeral
CI host — emsdk lives only inside the Docker image, and nothing on the host
post-process path provisions it. So the host post-process died at finalize for
every app once the binaryen-SHA cache re-key forced it to actually run. (Not the
missing-ninja theory — ninja was installed; the run never reached the wasm-opt
build, which is downstream of finalize.)

Finish the "Binaryen submodule everywhere" migration: build-wasm-opt.sh now also
builds wasm-emscripten-finalize, and apply-finalize.sh takes it from that build
(next to wasm-opt). The host post-process is now emsdk-free (dyncall=node,
finalize+asyncify=submodule v130) and finalize/wasm-opt share one Binaryen
version (previously finalize was emsdk's v121, wasm-opt the submodule's v130).
get-wasm-opt.sh stays for bench only; dropped it from the wasm cache key and
added build-wasm-opt.sh.

Also surface the from-source Binaryen build as a "Build Binaryen" stage in
build-monitor.sh (it had no marker), emitted at the pipelined pre-warm sites.

Validated: a clean from-scratch `docker/build.sh calculator --build-deps` (deps +
compile + finalize via the submodule binary + asyncify + -O2) succeeded
end-to-end; finalize resolved to build-wasm/tools/binaryen-hoist-build/bin.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 11:55:52 +02:00
Gergő Törcsvári
c7d7189c65
docs(git-workflow): add binaryen to git-feature SKILL.md instructions
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 10:21:16 +02:00
Gergő Törcsvári
6414036580
chore: add binaryen submodule to git-workflow
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 10:06:34 +02:00
Gergő Törcsvári
269449da46
fix(collab): dedupe yjs so @pcbjam/shared + standalone link ONE instance
Two pnpm workspaces (root globs pcbjam-shared; pcbjam/web has it too) each install yjs, so shared's collab code (kicad-y) and the app's yjs were two physical copies → a Y.Map rejects the other instance's Y types ('Unexpected content type'). resolve.dedupe:['yjs'] in vite + vitest forces a single copy. Not a test-only artifact: the same two copies bundle into the editor and would break collab on doc seed. Full standalone suite now 55/55 (was 47/55).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 09:54:50 +02:00
Gergő Törcsvári
fe0bec9909
feat(scopes): migrate GPL open backend + web e2e to scope grammar
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>
2026-06-30 09:54:50 +02:00
Gergő Törcsvári
ff9b966109
docs(site): dev blog updates (w26 + webgl-porting post)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 09:54:50 +02:00
Gergő Törcsvári
344a36799a
chore: add dev:demo script (web) + refresh site lockfile
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 09:54:49 +02:00
Gergő Törcsvári
7bc5260bc7
fix(scopes): standalone project list label showed old /p/<slug> instead of scope/projects/<slug>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 09:54:49 +02:00
Gergő Törcsvári
234e5fe189
feat(scopes): phase 0003 — standalone scope routing, tool inference, scoped API client, Demo/Local/Cloud badges
Routes → /:scope/projects/:name/* (+ -/:tool) and /:scope/libs/:name; tool inferred from file ext / lib kind (?tool= override); currentScope()/userSlug() in config; SCOPE/USER headers + scoped paths through project + libs sources; @local/demo scopes on constructed projects; badge relabel (drop scary read-only).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 09:54:49 +02:00
Gergő Törcsvári
e28e5e8e57
chore: bump pcbjam-shared (scopes 0001 — shared scope grammar)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 09:54:49 +02:00
Viktor Vaczi
c1ef489cfa feat(wasm-eh): migrate the WASM build to native wasm exceptions (+ 3D viewer default-on)
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>
2026-06-30 09:40:26 +02:00
Istvan Matejcsok
b8c8dee355 fix(wasm): blank foreign-editor Preferences pages
Bump kicad to the KiFACE()-returns-nullptr fix so eeschema's Preferences
stops showing blank Footprint/PCB/3D/Gerber panels for editors not present
in a single-app build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 12:56:25 +02:00
Istvan Matejcsok
13cac06778 fix(wasm): radio groups no longer merge into one
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>
2026-06-29 12:54:35 +02:00
Gergő Törcsvári
39cb04b127
feat(standalone): demo follow-ups — waitlist, analytics, move-to-local, file tree, load progress
- Waitlist signup form on the home page (between Projects and Tools),
  cross-posting to the landing site's /api/waitlist (CORS + OPTIONS added there,
  gated by WAITLIST_ALLOWED_ORIGINS).
- Version badge gains a pcbjam.com landing-page link (VITE_LANDING_URL).
- Optional Plausible analytics from VITE_PLAUSIBLE_DOMAIN (off by default);
  wired into build-demo + both deploy workflows via vars.PLAUSIBLE_DOMAIN.
- Opening a read-only gallery project auto-"moves to local": it forks into a
  writable browser-local project at the same slug, shadowing the gallery row.
- Project + local-folder views use the same iconed tool launcher (ToolGrid)
  and a navigable directory FileTree instead of a flat file list.
- Boot overlay shows real wasm download progress (Module.instantiateWasm +
  streaming byte counter) and a "taking too long" state after 60s.
- Home Libraries section lists the active libs source (the read-only R2/CDN
  set in the demo) with a name filter; useLibs now reads libsSourceConfig.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPJYx4urFVhdMjEmYfMCMD
2026-06-27 07:59:09 +02:00
Gergő Törcsvári
6c6f889ef5
chore: bump kicad (lazy footprint load fixes pcbnew WASM boot hang)
Bumps kicad submodule fef0343 -> 9285d52:
- fix(wasm): lazy footprint library load — no-op enumerateLibrary + on-demand
  GetFootprints (mirror of the symbol lazy-load). Fixes the standalone PCB
  editor never opening: boot enumerated every global footprint library inline
  on the main thread (each a CDN fetch + parse) before first paint, freezing
  the tab. Footprints now load on demand (Add-Footprint chooser / footprint
  editor tree). eeschema was already lazy; footprint editor boots faster too.

Verified in the local demo: PCB editor and footprint editor both render; the
Add-Footprint chooser lists all ~222 libraries with footprint content fetched
on chooser-open, not at boot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Eu9CbU7EybM8NEjDZD3hq7
2026-06-26 18:25:43 +02:00
Gergő Törcsvári
a77f7ae346
fix(standalone): bump KICAD_VERSION_DIR 9.99 -> 10.0 so seeded lib tables are read
After the kicad fork was rebased onto KiCad 10.0.4, GetMajorMinorVersion() (and
thus PATHS::GetUserSettingsPath()'s version subdir) became "10.0", but the
standalone still seeded the global sym-lib-table / config under
~/.config/kicad/kicad/9.99/. The WASM read .../10.0/ and found nothing, so
LIBRARY_MANAGER loaded 0 symbol-table rows and the Add Symbol / Add Power
choosers came up empty ("0 items loaded") with no library list requests.

Aligning KICAD_VERSION_DIR with the build's version makes the chooser load all
222 CDN libraries (19,779 symbols) again. Verified in the local demo against live
R2 (libs/kicad/10.0.3). The footprint editor / pcbnew read the same dir, so this
fixes their libraries too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 13:50:55 +02:00
Gergő Törcsvári
e8d964d871
feat(demo): local dev-demo runner — R2 libs + example gallery, no backend/partykit
scripts/deploy/dev-demo.mjs (+ `pnpm dev:demo`) is the dev sibling of
build-demo.mjs: it runs the standalone via `vite dev` in the no-backend demo
configuration so a local WASM build can be exercised against the live R2 CDN.

  - libraries: live R2 CDN (VITE_LIBS_SOURCE=cdn, libs/kicad/<lib-tag>, default
    10.0.3) — IDB-cached, read-only; the lazy/fat lib-load path
  - projects: the read-only example gallery (deploy/demo/gallery.json → the same
    "Demo Board") built locally via publish-content.mjs and served same-origin at
    /content/<gallery-tag>/; --content-tag pins the live CDN gallery instead;
    --no-gallery falls back to local-folder + IDB only
  - no partykit (VITE_YJS_PROVIDER=broadcastchannel), no REST backend
    (offline.invalid → local-folder loader), browser-local IDB projects
  - WASM: local fresh build at /wasm (default) or --wasm r2

The generated gallery (public/content symlink, web/standalone/.demo-cdn) is
gitignored, mirroring the public/wasm dev symlink.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 08:16:43 +02:00
Gergő Törcsvári
d6ce380458
fix(wasm): add MODEL_SUBSTITUTION no-op stub for 3D-disabled pcbnew/footprint build
Provides wasm/stubs/model_substitution_stub.cpp — no-op IsWrlExtension /
STEP_CATALOG::Build / FindMatchFor — so pcbnew and footprint_editor link when the
3D viewer is off (KICAD_BUILD_3D_VIEWER_WASM=OFF). The KiCad 10 rebase made
dialog_migrate_3d_models.cpp reference these, which live in the unlinked 3D
library. The browser build has no 3D viewer, so model migration finds no
substitutions. Bumps kicad to the matching CMake wiring (fef0343).

Verified: pcbnew + footprint_editor compile and link clean (eeschema/symbol_editor
unaffected).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 08:14:47 +02:00
Gergő Törcsvári
30645dbae5
feat(libs): fat-list provider + getAllItems + parallel lib pre-sync; re-land onto KiCad 10 wasm-port
Replays the symbol-editor fast-lib-load work after the kicad fork was rebased
onto KiCad 10.0.4 and wasm-port was force-pushed. Carries the standalone libs
TS code (fat-list provider, getAllItems, parallel lib pre-sync) and bumps the
submodule pointers to the re-applied tips:

- kicad      -> c63009046 (lazy load on expand + chooser preview + fat-load enumerate)
- wxwidgets  -> 5d40228   (flush events + repaint after modal button click)
- pcbjam-shared -> c6a7e00 (bulk readAll for fat-load lib warm-up)

The 824e8cc build-kicad-target.sh sym-converter-contamination fix is omitted:
the KiCad 10 integration (ce344da) already pins KICAD_SYM_CONVERTER_WASM=OFF for
non-sym_convert targets. Verified: eeschema WASM kiface compiles + links; libs
unit tests 10/10.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:31:25 +02:00
Istvan Matejcsok
ce344da2dc upgrade: ⬆️ bump kicad 2026-06-25 09:57:42 +02:00
Istvan Matejcsok
a7cdafbb39 upgrade: ⬆️ bump kicad + wxwidgets 2026-06-25 09:33:04 +02:00