- TypeScript 49.1%
- C++ 36%
- Shell 4.2%
- C 2.9%
- JavaScript 2.6%
- Other 5.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
A review of the group-E fixes found 13 further defects; ten were introduced by
those fixes, two pre-existed and were merely relocated, one is deferred.
Services / transport
E-10 retireWorker synthesized no bg/exit frame, so sharedspice's s_bgRunning
mirror stayed latched true after a mid-run worker death: Run stayed
disabled and the promised fresh-worker restart was unreachable for the
whole session. Retirement now dispatches a synthetic controlled-exit
straight to the installed handler (never through dispatchEvt — a
fabricated frame must not touch the credit ledger). Driving the repro
exposed two further defects, both fixed here: a replacement worker
trapped on pre-init engine reads, and the rerun's cm_input_path/circ hit
that uninitialized engine before KiCad's validate() re-init (the native
flow assumes a crashed engine survives in-process — true for the dll,
false for a dead worker). Reads now answer their empty shapes pre-init,
writes lazy-init, and init is idempotent per worker engine.
E-19 dispatchEvt acked only AFTER handler(evt) returned, and the sharedspice
client deliberately rethrows non-trap errors — so each throw leaked one
unit of the 64-frame credit window until the stream died with a
misattributed "transport exceeded". The ack moves to a finally in both
service copies; the throw still propagates (the trap machinery needs it).
E-20 the oversize-line path promises to transfer the accepted prefix, but
with the window full that flush only DEFERS, and stopEventStream wiped
the deferred queue — losing the diagnostics that explain the failure.
The terminal notice now carries them as pendingEvents; both hosts
deliver them in order, unacked (the fatal frame is outside the credit
protocol).
E-21 the 30s prefetch deadline discarded every model already collected and
reported nothing. A caller-owned progress sink ships the partials and
the omission reaches the export report. (Awaiting the aborted collection
was rejected: an in-flight source fetch is not abortable — E-4's
original disease.) Plus a serving-candidate memo, so a .wrl ref served
by its .step fallback stops re-probing the miss on every export.
Scheduler
E-14 _terminalizeNativeTrap classified by message substring, so any plain JS
error QUOTING 'Aborted(' or 'out of bounds' permanently bricked a
healthy instance. Now structural only: instanceof RuntimeError plus a
duck-typed name check (verified in this build's glue that abort() throws
a genuine RuntimeError both pre- and post-runtime-init). Module.onAbort
now latches the gate — the authoritative notification, previously
ignored.
E-15 the shim half: _pumpResume gates on terminal (catching wakes already
queued at latch time) and resolveWait refuses on terminal WITHOUT
consuming the entry, so a frame stays visibly parked rather than
resuming inside a trapped module.
E-16 the E-5 handler read the realm-global scheduler at dispatch instead of
its installing module's; also frees the per-line buffer on the non-trap
rethrow path.
E-11 get_vec trusted the worker's res.length over the transferred arrays.
Observed death shape: a 4 GiB std::vector threw an unhandled
std::length_error that exited the editor's main loop. Now clamped, with
the buffers freed on every failure path.
Guardrails (replacing two deferred refactors: e2e→production-code injection and
collapsing the four copies of the worker-lifecycle machinery)
E-18 the source contract asserted comment-string counts — rewording failed
CI while moving a guard outside its #ifdef passed. It now parses the
#ifdef regions and asserts on code.
service-stub-parity.ts pins what the four lifecycle copies must share:
credit-window equality parsed from source, the finally-ack, boot
deadlines, terminal-notice consumption. The transport numbers are now
single-sourced from the worker.
CI actually runs the gates: the web/standalone vitest suites (which had
NEVER run in CI), the reducer, the source contract and the parity tool —
with a NON_PLAYWRIGHT_GATES check so deleting a step re-fails the lint.
E-22 the e2e occ stub's 60s boot watchdog, deleted in a66e109, is restored in
the ngspice-stub shape with a wedgeNextBoot() repro hook.
Every behavioral fix has red-then-green evidence (the reds were captured first).
E-17 (a stale RUNNING cross-stamping the next run's generation under E-6's
transport deferral) is DEFERRED with its analysis recorded — a real fix needs
run identity on the bg frames.
Test hygiene: the dwell lint now requires the mandated ": <why>" and all 47 bare
markers carry their reason; three export-report dwells became modal-lease polls;
exact-ledger assertions became relative deltas; the dead data-wx-dom-id branch,
an unused fault hook and unused receipt plumbing are gone; abort scans, wx
dialog drivers, the sim harness and the vitest FakeWorker are each one copy now.
Bumps kicad and wxwidgets to their findings-group-e tips.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
| .claude | ||
| .github/workflows | ||
| deploy | ||
| docker | ||
| docs | ||
| features | ||
| kicad@56678639ee | ||
| logs | ||
| scripts | ||
| site | ||
| sourcetrail | ||
| tests | ||
| wasm | ||
| web | ||
| workers/cdn | ||
| wxwidgets@4e6cc5a441 | ||
| .ci-cache-epoch | ||
| .dockerignore | ||
| .gitignore | ||
| .gitmodules | ||
| CLAUDE.md | ||
| LICENSE | ||
| README.md | ||
KiCad WebAssembly Port
Run KiCad PCBnew in the browser using WebAssembly.
Quick Start
Full Build (KiCad + All Tests)
# 1. Initialize submodules
git submodule update --init --recursive
# 2. Build KiCad WASM (Docker, ~10 min incremental, ~1-2 hours full)
./docker/build.sh
# 3. Build wxWidgets for local testing
./scripts/build-wx-wasm.sh
# 4. Build wxWidgets test apps
./scripts/build-wasm-test.sh
# 5. Run all tests
cd tests && npm install
npm test # wxWidgets tests (256 tests)
npm run test:kicad # KiCad tests (2 tests)
wxWidgets Only (No Docker)
# Requires: Node.js 18+ (Emscripten SDK auto-installed on first build)
./scripts/build-wx-wasm.sh
./scripts/build-wasm-test.sh
cd tests && npm install && npm test
Project Structure
kicad-wasm/
├── kicad/ # KiCad source (git submodule)
├── wxwidgets/ # wxWidgets source (git submodule)
├── wasm/ # WASM compatibility layer
│ ├── bindings/ # Embind bindings for JavaScript
│ ├── cmake/ # CMake find modules
│ ├── kiplatform/ # Platform abstraction (app, UI, printing)
│ ├── libcontext/ # Coroutine/fiber implementation
│ ├── shims/ # Runtime JavaScript shims
│ └── stubs/ # Stub implementations (libgit2, curl)
├── scripts/ # Build scripts
│ ├── build-wx-wasm.sh # Build wxWidgets for WASM
│ ├── build-wasm-test.sh # Build wxWidgets test apps
│ ├── deps/ # Dependency build scripts
│ ├── kicad/ # KiCad build scripts
│ ├── common/ # Shared utilities
│ └── config/ # Build config wrappers
├── docker/ # Docker build environment
├── tests/ # Playwright E2E tests
│ ├── e2e/ # Test specs
│ └── apps/ # WASM test applications
├── tools/ # External tools (local emsdk install)
└── output/ # Build output (pcbnew.js, pcbnew.wasm)
Feature Branches
Curated design docs and research notes for each feature live in
docs/features/<branch-name>/ (committed).
./scripts/create-feature-patches.sh [branch-name] generates per-branch patches
(root.patch, kicad.patch, wxwidgets.patch) into a local features/<branch-name>/
scratch dir. That dir is gitignored — the patches are local history, not committed.
Two Build Workflows
1. KiCad Build (Docker)
Full KiCad PCBnew build using Docker:
# Build KiCad WASM
./docker/build.sh
# Copy output to test directory
./tests/scripts/setup-kicad-wasm.sh
# Run KiCad tests
cd tests && npm install && npm run test:kicad
Output: output/pcbnew.js, output/pcbnew.wasm
See docs/build.md for detailed build documentation.
Creating an isolated worktree (with submodule branches)
For an experiment or feature you can work in a disposable git worktree so the
main checkout stays pristine. This repo has three submodules
(kicad, wxwidgets, web/pcbjam-shared); a new worktree starts
with them empty, so initialize and branch each one:
# 1. Create the worktree on a new branch (off main), at a sibling path
git worktree add -b experiment/my-thing ../kicad-wasm-my-thing main
# 2. Check out the submodules INSIDE the worktree (working trees only;
# git objects are shared with the main checkout)
cd ../kicad-wasm-my-thing
git submodule update --init kicad wxwidgets web/pcbjam-shared
# 3. Create a matching branch in each submodule (they start at detached HEAD)
git checkout -b experiment/my-thing # root already on it via -b above
for sm in kicad wxwidgets web/pcbjam-shared; do
git -C "$sm" checkout -b experiment/my-thing
done
Then build from inside the worktree. Use an isolated Docker project — do NOT
set COMPOSE_PROJECT_NAME to another branch's project (e.g. kicad-wasm-main),
which can collide with other workflows; docker/build.sh auto-derives an isolated
project name from the worktree branch. The first build provisions deps
(wxWidgets + OCC) from scratch. To keep the machine responsive, cap
parallelism:
KICAD_DOCKER_CPUS=4 ./docker/build.sh pcbnew -j 4
Tear down afterward with git worktree remove ../kicad-wasm-my-thing (and
docker compose -p <project> down -v to drop the isolated volumes).
Fresh worktree provisioning
Some test artifacts are gitignored and are NOT produced by the build pipeline,
so they don't carry into a newly-created git worktree — without them the
gal-webgl tests 404 ("Loading WASM...") and the collab specs fail with
Could not resolve "@pcbjam/shared". After building (docker/build.sh +
scripts/build-wx-wasm.sh) and cd tests && npm i, run once per worktree:
./scripts/setup-worktree.sh # idempotent: sysroot headers, gal-webgl harness, web/ pnpm install, collab bundle
2. wxWidgets Test Apps (Local)
Build standalone wxWidgets test apps for feature testing:
# Build wxWidgets for WASM
./scripts/build-wx-wasm.sh
# Build test apps
./scripts/build-wasm-test.sh
# Run wxWidgets tests
cd tests && npm install && npm test
Output: tests/apps/standalone/
Prerequisites
For KiCad Build (Docker)
- Docker Desktop with 16GB+ RAM allocated
- 10+ GB disk space for build cache
For wxWidgets Build (Local)
- Node.js 18+ (for tests)
- Emscripten SDK (auto-installed on first build)
# Initialize submodules
git submodule update --init --recursive
# Install Emscripten SDK (auto-runs on first build, or run manually)
./scripts/setup-emsdk.sh
Testing
cd tests
npm install
# Run all tests
npm test
# Run specific tests
npm run test:kicad # KiCad tests only
npx playwright test menu # Menu tests only
See tests/README.md for test documentation.
Screenshots
CI's Linux render is the source of truth for baseline screenshots. On each main
push, CI compares its render against the baselines (pinned by the R2-hosted
manifest — nothing screenshot-related is committed) and posts the diff (plus the
runtime-perf numbers) to Discord. To update baselines after an intended render
change, promote the CI run's screenshots in the morelli review app
(https://pcbjam-morelli-staging.pcbjam-staging.workers.dev) — pick the run,
review the diffs, bulk-select, Promote. CI uploads every run's renders to R2
for that purpose (30-day retention).
cd tests
npm run screenshots:fetch-manifest && npm run screenshots:fetch # materialize baselines
npm run screenshots:check # local gate: current vs baselines
See tests/tools/screenshots/README.md.
Current Status
- wxWidgets WASM: Core widgets working (menus, dialogs, grids, trees, OpenGL)
- KiCad PCBnew: Builds and loads in browser, canvas rendering working
- In Progress: Testing wxWidgets features used by KiCad
Documentation
See docs/README.md for the full documentation map. Highlights:
- Build System - Docker build details
- Docker README - Container setup
- Debugging Guide - Asyncify/WASM debugging
- Tests README - Test infrastructure
Landing page / website
The marketing site and landing page live in site/ (Astro), deployed as
static assets to Cloudflare R2.
On every release, bump the build SHA. site/src/components/Footer.astro has a
hardcoded BUILD_SHA constant that is shown in the footer and links to the
corresponding commit. Because the main-repo commit pins the KiCad and wxWidgets
submodule revisions implicitly, this is our GPLv3 corresponding-source pointer
(surfaced on /licenses). The site is static, so nothing sets it automatically —
update BUILD_SHA by hand to the deployed pcbjam commit each time you release.
License
KiCad is GPL-3.0. This project follows the same license.
The site combines KiCad (GPLv3) with the wxWidgets fork; the wxWidgets WebAssembly
port files are LGPL v2 (without the wxWindows binary exception). See the
/licenses page (site/src/content/legal/licenses.md) for the full breakdown and
the corresponding-source offer.