# Fork cleanup: minimize divergence & re-enable web-feasible features

> **Status:** research / planning only. No code has been changed. Authored June 2026.
> All `file:line` references are against the `kicad` submodule at its current HEAD
> (`ac7d733787`), upstream merge-base `4bfed3f174`, and the root repo at the same time.
> Verify line numbers before editing — they drift.
>
> **⚠️ The baseline counts in this README are superseded** — doc 01 has since landed (commit
> `c39e8f8689`) and other work shifted the numbers. For the *current* divergence, the per-change
> revert/relocate/re-enable verdict, effort, and resulting diff, see
> [00-effort-and-current-state.md](00-effort-and-current-state.md) (measured at HEAD `cb82b64410`,
> 2026-06-17): **~2,795 churned lines / 88 modified files today → ~480–620 / ~50 files after
> ~16–28 engineer-days of cleanup.**

## Why this exists

Getting KiCad to build for the browser meant disabling, stubbing, and `#ifdef`-ing a
lot of things "because we had to." Two goals now pull in the same direction:

1. **Keep the `kicad` and `wxwidgets` forks as close to mainline as possible.** Where we
   add things, they should live in *new files/folders* (or build flags, runtime config,
   the `wasm/` layer) — not as edits to upstream source.
2. **Everything that *can* work in a browser should actually work.** The 3D viewer,
   importers, the symbol chooser — turn them back on. Only Python scripting and things
   that are genuinely impossible on the web stay off.

The key reframe that ties them together: **re-enabling features mostly *deletes* fork
code.** Almost everything disabled is disabled by a fork-added gate, stub, or exclusion.
Turning it back on removes that divergence. The two goals are one project.

## TL;DR — the baseline and the target

Fork state vs. merge-base `4bfed3f174` (24 commits):

| | Count |
|---|---|
| New files (policy-compliant) | 44 (~28k lines, mostly the WebGL GAL copy) |
| Modified upstream files | **104** |
| Changed lines in modified files | **~2,400** (~1,600 of it CMake) |

Estimated reachable end-state after the refactors below: **~15–20 modified files /
~150–250 lines**, with the WASM product *gaining* the 3D viewer, render-to-PNG jobs,
VRML export, five importers, the symbol browser, and optionally simulation, tooltips,
HTTP libraries, and working local history.

Three facts do most of the work:

- **Big chunks of the diff are dead code.** All `#ifdef KICAD_IPC_API` gating, the
  +189-line `kiglew.h` shim, and the `opengl_gal.cpp` refactor compile in configurations
  the shipping build never uses. See [01](01-revert-dead-code.md).
- **Several "disabled" features are disabled by stale mechanisms.** The Altium importer's
  blocker was fixed months ago (the fix is force-included into every TU); three
  build-script `-D` flags don't even exist as options in this KiCad version. See
  [08](08-importers.md) and [07](07-native-build-bugs-and-tooling.md).
- **The 3D viewer has a cheap path.** KiCad ships a pure-CPU raytracer that needs zero
  OpenGL, and the fork currently *nulls it out*. See [10](10-3d-viewer.md).

## Master inventory

Every disabled/divergent item, with verdict. Detail + recipes in the linked docs.

### Reduce divergence (shrink the submodule diff — no behavior change)

| Item | Mechanism | Action | Doc |
|---|---|---|---|
| `#ifdef KICAD_IPC_API` gates (18 files) | dead code (build sets `=ON`) | revert | [01](01-revert-dead-code.md) |
| `kiglew.h` +189, `opengl_gal.cpp` +32/−31 | dead (opengl GAL not built for wasm) | revert | [01](01-revert-dead-code.md) |
| `KI_DIAG_*` call sites (~30 lines) | debugging a solved crash | delete | [01](01-revert-dead-code.md) |
| ~600 lines of CMake reindent/duplication | wrap-and-reindent instead of additive | de-churn | [02](02-cmake-dechurn.md) |
| zoom warp, Backspace, timer, kiface init | `#ifdef` behavior changes | runtime config | [03](03-config-not-code.md) |
| fontconfig/libcontext/SpaceMouse stubs | in-file `#ifdef` | move to new TUs | [04](04-stub-tu-relocation.md) |
| scale factor, selection, header hygiene | wx-port quirks patched in KiCad | fix in wx fork | [05](05-wx-layer-fixes.md) |
| RTree fix, hotkey bug, `wxUSE_*` guards | upstreamable | send upstream | [06](06-upstreamable-patches.md) |
| 6 native-build regressions + diff tooling | fork bugs | fix | [07](07-native-build-bugs-and-tooling.md) |

### Re-enable (web-feasible — mostly deletes gates)

| Item | Blocker today | Verdict | Doc |
|---|---|---|---|
| Altium importer (sch+pcb) | stale exclusion (fix already active) | **re-enable now** | [08](08-importers.md) |
| Eagle/CADSTAR/LTspice/EasyEDA(Pro) sch | MVP-scoping exclusion | **re-enable now** | [08](08-importers.md) |
| Symbol chooser + viewer | empty lib tables (asset gap) | un-gate + asset pipeline | [09](09-symbol-libraries.md) |
| 3D viewer + render job + VRML export | `KICAD_BUILD_3D_VIEWER_WASM=OFF` + gates | port (raytracer first) | [10](10-3d-viewer.md) |
| SPICE simulator | ngspice dep stubbed | port (~1–2 wk) | [11](11-ngspice-simulator.md) |
| HTTP libraries / local history | curl & libgit2 stubbed | port | [12](12-network-stack.md) |
| Tooltips | wxUniversal never implemented them | port in wx fork | [05](05-wx-layer-fixes.md) |

### Keep off

- **Impossible:** SpaceMouse/navlib, ODBC database, nng/IPC transport, fswatcher, webview,
  dynamic KIFACE `dlopen`, OS keychain, pointer warping. (See [12](12-network-stack.md) for
  the full catalog and *why* each is impossible.)
- **Policy-off:** Python scripting (see [`../../../features/python/research.md`](../../../features/python/research.md)),
  PCM, update check, the `kicad` project-manager / `cvpcb` apps (never wasm targets).

## Suggested sequencing

1. **Quick wins + dead-code reverts** ([01](01-revert-dead-code.md), [07](07-native-build-bugs-and-tooling.md),
   [08](08-importers.md)) — one build, one e2e run; large diff reduction *and* new
   importers. Importers are configure-confident but runtime-untested → smoke-test with a
   sample Eagle + Altium file.
2. **3D viewer Route C** ([10](10-3d-viewer.md)) — raytracer + blit; brings render job and
   VRML export back nearly free.
3. **Symbol-library asset pipeline** ([09](09-symbol-libraries.md)).
4. **CMake de-churn + config-not-code + stub relocation + wx fixes** ([02](02-cmake-dechurn.md)–[05](05-wx-layer-fixes.md))
   — the bulk of the remaining line-count reduction.
5. **Upstream PRs** ([06](06-upstreamable-patches.md)) — divergence that vanishes on merge.
6. **3D Route B (WebGL2) and Tier-3 ports** ([10](10-3d-viewer.md)–[12](12-network-stack.md)) per product priority.

## Document index

| File | Contents |
|---|---|
| [00-effort-and-current-state.md](00-effort-and-current-state.md) | **Current state (2026-06-17): per-change revert/relocate/re-enable verdict, effort, and resulting diff math reconciled against a live file ledger. Read this first.** |
| [01-revert-dead-code.md](01-revert-dead-code.md) | Diff that compiles only in unused configs: IPC-API gates, `kiglew.h`, `opengl_gal.cpp`, diagnostics. ~480 lines, zero behavior change. **(DONE — `c39e8f8689`.)** |
| [02-cmake-dechurn.md](02-cmake-dechurn.md) | ~600 lines of CMake reindent/duplication → early-return guards, `list(REMOVE_ITEM)`, shader-hook, relocate `if(EMSCRIPTEN)` to `cmake/wasm/`. **(In-place de-dup A–F done — `6f82742e68`; CMake churn 1,702→1,019, build graph proven identical. Only Phase-B `cmake/wasm/` relocation remains.)** |
| [03-config-not-code.md](03-config-not-code.md) | Patches that re-implement existing settings: zoom pref, hotkeys file, `HAVE_CLOCK_GETTIME`, kiface init from the shell. |
| [04-stub-tu-relocation.md](04-stub-tu-relocation.md) | Move in-file `#else` stubs to new translation units: fontconfig, libcontext, SpaceMouse. |
| [05-wx-layer-fixes.md](05-wx-layer-fixes.md) | KiCad patches that belong in the wxWidgets wasm port: scale factor, selection, header self-sufficiency, **tooltips**. |
| [06-upstreamable-patches.md](06-upstreamable-patches.md) | Bug fixes & portability guards to send to KiCad/wxWidgets upstream so the diff disappears on merge. |
| [07-native-build-bugs-and-tooling.md](07-native-build-bugs-and-tooling.md) | 6 regressions the fork introduced into *native* builds + dead build-script flags + the broken `kicad-diff-stats.sh`. |
| [08-importers.md](08-importers.md) | Re-enable Altium + Eagle/CADSTAR/LTspice/EasyEDA(Pro). Net-negative diff. |
| [09-symbol-libraries.md](09-symbol-libraries.md) | Un-gate the symbol chooser/viewer + ship a starter library set to the browser FS. |
| [10-3d-viewer.md](10-3d-viewer.md) | Why it's off; Route C (CPU raytracer), Route B (WebGL2 port), Route A (rejected); model loading; render job; VRML export. |
| [11-ngspice-simulator.md](11-ngspice-simulator.md) | Static-link a wasm ngspice + the one `init_dll` branch; retest the model-data stubs. |
| [12-network-stack.md](12-network-stack.md) | curl→fetch shim, libgit2/local-history, and the catalog of genuinely-impossible features. |

## Related docs

- [`../async/README.md`](../async/README.md) — the Asyncify model these gates dance around.
- [`../wasm-exceptions/README.md`](../wasm-exceptions/README.md) — the EH-model work that shrinks the binary.
- [`../libraries/0001-library-management.md`](../libraries/0001-library-management.md) — why designs open without libraries (background for [09](09-symbol-libraries.md)).
- [`../../../features/python/research.md`](../../../features/python/research.md) — Python re-enable research (stays off; IPC API is the mainline path).
- [`../../../features/gl-article/README.md`](../../../features/gl-article/README.md) — the OpenGL→WebGL GAL migration history (context for [10](10-3d-viewer.md)).
