- TypeScript 49.1%
- C++ 36%
- Shell 4.2%
- C 2.9%
- JavaScript 2.6%
- Other 5.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The 3d-webgl merge (kicad eb13ff3bdc: the viewer now defaults to the real OpenGL renderer via wasm/gl1, and occ-split moves STEP parsing into the occ_service worker) made the raytracer-era orchestration on this branch moot — main's chromium-ci phase is green at 15-way parallelism (28666407570 / 28698861536). Drop what no longer earns its complexity, keep the diagnostics, fix main's live flake, and make the deadlock spec test what it was written for. - REVERT the chromium-ci-3d serial project, the two-phase test:kicad:ci, the SwiftShader GPU-process flags, and the resize-drag/models skips: config and package.json are byte-for-byte back to main's shape. The raytracer contention they guarded is no longer on the CI path. - FIX main's live flake: run 28698861536 is green only via retry (3d-viewer.spec:26 flaky) and 28666407570's deadlock red sampled an ALL-ZERO pixel signature — the viewer's first frame lags the canvas's creation on software WebGL under parallel load, and sampling too early reads an all-black backbuffer. New waitForThreeDRender() gates render assertions on actual pixels (1s-interval full-frame CPU reads) instead of fixed sleeps, used by 3d-viewer.spec:26 and the models render tail. - KEEP the storm-proofed samplers (one full-frame getImageData on a willReadFrequently canvas replacing 256 per-pixel GPU round-trips per sample — the "GPU stall due to ReadPixels" trigger) and the logThreeDDiag instrumentation: engine-independent, and they de-risk every remaining software-GL pixel read. - models spec: bridge assertions stay front-loaded (the protocol regression signal is independent of the render); the occ_service parse verdict is now POLLED — it lands async relative to the bridge ensures, so asserting it immediately raced the worker; the render tail runs again everywhere. (The pre-webgl raytracer+models renderer-death documented in a17f3be does not affect the OpenGL default path — the raytracer-toggle+models combination remains untested product surface, tracked outside this branch.) - deadlock spec: the deadlock it guards is raytracer-specific and the viewer now defaults to OpenGL — on the GL engine it either passes vacuously (fast renders make every liveness assertion trivial, 28698861536) or fails on the black first frame (28666407570). It now flips the engine via the "Use raytracing" toolbar toggle (loud assert if the toggle moved) and cross-checks engagement by requiring the canvas pixels to CHANGE after the flip with no input in between (the raytraced frame is lit differently; a GL re-render reproduces identical pixels; heap growth is unusable — mimalloc satisfies the raytracer from freed arena pages). That guard immediately caught a REAL defect: on the webgl-era wasm build the toggle is INERT (the click lands and "Reload time" updates, but the canvas never changes — suspects: DoRePaint's silent catch(runtime_error) freezing the canvas after a raytracer Redraw throw, or ToggleRaytracing writing m_boardAdapter.m_Cfg while RenderEngineChanged() reads GetAppSettings<…>(), possibly different instances in the merged bundle). The spec is therefore test.skip-annotated as a KNOWN ISSUE with the full engine-force machinery in place — unskipping it self-validates the product fix. The CI-skip also stays (raytracer liveness needs real-GPU pacing; the Worker-boot deadlock mechanism is covered on CI by the standalone wx harnesses). - 180s viewer-open waits kept as pure CI headroom (never slow a passing run). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
| .claude | ||
| .github/workflows | ||
| binaryen@1d40cf5a8f | ||
| deploy/demo | ||
| docker | ||
| docs | ||
| features | ||
| kicad@eb13ff3bdc | ||
| logs | ||
| scripts | ||
| site | ||
| tests | ||
| wasm | ||
| web | ||
| wxwidgets@b3f0a09d43 | ||
| .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 (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:
- 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.