Self-hosted emergence-engineering/pcbjam (browser KiCad WASM) — CMMS embed fork. Upstream tracked as remote "upstream".
  • TypeScript 49.1%
  • C++ 36%
  • Shell 4.2%
  • C 2.9%
  • JavaScript 2.6%
  • Other 5.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Viktor Vaczi 63ed1f3c1f e2e/CI: dual-engine suites, per-engine screenshots, SwiftShader retired, prod web suite, CI-coverage gate
Squash of experiment/ff-big-modules vs main.

Big-module routing removed: native-EH shrank kicad_editor below
SpiderMonkey's x86-64 code budget (runs 29355049705/29356152413 green on
stock Firefox), so BIG_MODULE_SPECS routing and the baseline-only-JIT
crutch are gone — kicad-firefox and kicad-chromium both run the full
suite, with the module compiled the way real users' browsers compile it.

Per-engine screenshots end to end: stableShot/shotPath write
test-results/<engine>/<name>.png; baselines move to
baseline-screenshots/{chromium,firefox}/ and the whole tools/screenshots
pipeline (compare/promote/manifest/spec-map/changelog/Discord) keys on
<engine>/<name>. Previously Firefox and Chromium renders of one spec
overwrote each other and Firefox renders were never actually gated.
Seeded from CI run 29421380806 (92 new firefox baselines, +24 chromium
web-suite shots); manifest generated from the baseline tree.

One merged playwright.config.ts (kicad/asyncify/coroutine/perf as
projects); ~25 dead npm scripts dropped. The web suite is gated in CI for
the first time ever (4 rotted specs fixed, 5 broken lib-bridge specs
triaged as fixme in docs/features/web-e2e-rot/); cheap lint step after
npm ci; last 26 blind-sleep violations fixed.

SwiftShader retired: CI Chromium renders WebGL on ANGLE → Mesa llvmpipe
(--use-gl=angle --use-angle=gl --ignore-gpu-blocklist; the blocklist flag
is mandatory — llvmpipe is blocklisted and WebGL is silently unavailable
without it) in BOTH configs. Under WORKERS=4 congestion SwiftShader
transiently failed the first post-board-load draw and the recovery
cascade ended in a silent permanent Cairo fallback — that engine flip was
the "~1.2% changedRatio both directions" occ-export baseline flake.
Validated 160/160 across two 80-repeat rigs; full analysis in
docs/features/wx-parity-bugs/occ-export-context-eviction.md. Chromium
baselines shift slightly on llvmpipe — promote once from the first green
run. Deflakes the new coverage exposed: presence baselines settle before
capture; presence fixtures declare current file formats; perf gets its
own outputDir so CI evidence survives; occ-export settles the board paint
before the export dialog; menu-item waits (waitForRenderedByLabel before
clickMenuItem) in 4 specs + the TESTING.md rule.

Web suite runs the PROD build, in parallel: webServer becomes backend
`start` + the standalone's e2e:preview (build-preview.mjs: link-wasm →
stash the public/wasm symlink aside during vite build, build-demo.mjs's
move — then vite preview as the persistent server). The wasm middleware
serves /wasm/* in preview and emits COOP/COEP/CORP itself (a pthread
worker script's own response must carry COEP or Chrome kills it with
ERR_BLOCKED_BY_RESPONSE). VITE_* flags bake at build time;
VITE_ALLOW_USER_OVERRIDE joins turbo globalEnv. fullyParallel + default
workers: 5.2m → 1.4m. Determinism fixes the parallel run exposed:
shared-page specs become serial groups; locks.spec grabs alice's exact
item via the new kicadCollabTestSelectByUuid hook (cross-tab "first
footprint" order is not a ysync invariant); quit specs poll page.url()
(quit supersedes its own navigation — NS_BINDING_ABORTED on Firefox).
Suite: 51 passed / 12 skipped / 0 failed in 1.6m.

CI-coverage gate (lint:ci-coverage): every tests/**/*.spec.ts must be
reachable from the npm scripts the workflows invoke — scraped from
.github/workflows/, resolved through package.json, coverage asked from
playwright --list itself. Rules: uncovered-spec + orphan-project (with a
documented LOCAL_ONLY_PROJECTS allowlist). Gating next to
lint:determinism; 138 spec files / 13 projects accounted for.

Product fixes kept from the investigations (reachable on real GPUs too):
wx 7799fd1be5 — paint flags clear before dispatch + Invalidate always
propagates; kicad 3dcfea5e45 — SwiftShader pass-boundary flush +
per-instance font texture + first-frame GL-error drain (GAL recovery
recovers instead of falling back to Cairo) + the user-facing eeschema
switch navigates again under __EMSCRIPTEN__ (project-sync's
FaceRegistered gate had rerouted it into the hidden sync player; caught
by the newly-gated web suite).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018eUxiPApHgGiu9NFyQfhAq
2026-07-17 12:21:54 +02:00
.claude docs(git-workflow): add binaryen to git-feature SKILL.md instructions 2026-06-30 10:21:16 +02:00
.github/workflows e2e/CI: dual-engine suites, per-engine screenshots, SwiftShader retired, prod web suite, CI-coverage gate 2026-07-17 12:21:54 +02:00
binaryen@1d40cf5a8f docs(hoist): pass-simplification dossier; bump binaryen (FindAll/BranchUtils refactor) 2026-07-01 16:52:17 +02:00
deploy/demo feat(demo): demo.pcbjam.com deploy — versioned WASM CDN + static gallery + tag CI 2026-06-19 11:39:09 +02:00
docker tasks-runner 0001 R2: kicad_tools joins the CI build set + lint gates 2026-07-14 19:02:13 +02:00
docs e2e/CI: dual-engine suites, per-engine screenshots, SwiftShader retired, prod web suite, CI-coverage gate 2026-07-17 12:21:54 +02:00
features feat(site): 🫙 PCBJam landing revisions — branding, accuracy, positioning graphic 2026-06-07 17:14:19 +02:00
kicad@3dcfea5e45 e2e/CI: dual-engine suites, per-engine screenshots, SwiftShader retired, prod web suite, CI-coverage gate 2026-07-17 12:21:54 +02:00
logs Added logs .gitignore. 2026-01-03 13:52:34 +01:00
scripts standalone-hardening 0006: redirect non-editor routes to the mgmt app 2026-07-16 17:24:37 +02:00
site harden the marketing site: gate demo overrides, rate-limit + redact waitlist 2026-07-16 12:46:17 +02:00
tests e2e/CI: dual-engine suites, per-engine screenshots, SwiftShader retired, prod web suite, CI-coverage gate 2026-07-17 12:21:54 +02:00
wasm e2e/CI: dual-engine suites, per-engine screenshots, SwiftShader retired, prod web suite, CI-coverage gate 2026-07-17 12:21:54 +02:00
web e2e/CI: dual-engine suites, per-engine screenshots, SwiftShader retired, prod web suite, CI-coverage gate 2026-07-17 12:21:54 +02:00
wxwidgets@7799fd1be5 e2e/CI: dual-engine suites, per-engine screenshots, SwiftShader retired, prod web suite, CI-coverage gate 2026-07-17 12:21:54 +02:00
.ci-cache-epoch tasks-runner 0001 R2: kicad_tools joins the CI build set + lint gates 2026-07-14 19:02:13 +02:00
.dockerignore Add Docker build environment for KiCad WASM 2025-12-08 12:07:01 +01:00
.gitignore test(3d): screenshot-baseline TDD suite for the 3D viewer OpenGL->WebGL port — 47 native goldens + red-state WebGL harness 2026-07-03 15:45:58 +02:00
.gitmodules feat(wasm-eh): migrate the WASM build to native wasm exceptions (+ 3D viewer default-on) 2026-06-30 09:40:26 +02:00
CLAUDE.md e2e/CI: dual-engine suites, per-engine screenshots, SwiftShader retired, prod web suite, CI-coverage gate 2026-07-17 12:21:54 +02:00
LICENSE Add GNU General Public License v3 2026-06-11 12:54:52 +02:00
README.md feat(tests): screenshot regression + Discord review, perf-tracked 2026-07-01 18:17:20 +02:00

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 (binaryen)
└── 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 four submodules (kicad, wxwidgets, binaryen, 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 binaryen 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 binaryen 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 / bound wasm-opt RAM, cap parallelism and skip the slow release optimization:

KICAD_DOCKER_CPUS=4 BINARYEN_CORES=4 BINARYEN_OPT_LEVEL=-O1 \
  ./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 committed baselines and posts the diff (plus the runtime-perf numbers) to Discord. To update baselines after an intended render change, promote a CI run's render — only meaningfully-changed images restage, so it stays churn-free:

cd tests
npm run screenshots:check                          # local gate: current vs baselines
npm run screenshots:promote -- --run <ci-run-id>   # adopt a CI run's render, then commit

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:

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.