pcbjam/tests/kicad/utils/occ-service.ts

174 lines
8.8 KiB
TypeScript
Raw Normal View History

feat(wasm): occ-split — lazy occ_service worker; kicad_editor drops OCC (−31%) Move OpenCASCADE out of the merged editor image into occ_service: a separate emscripten module (-sASYNCIFY=0, MODULARIZE, in-container -Oz finalize, 2N+8 pre-warmed pthread pool) booted lazily in a dedicated Web Worker on the first STEP export or STEP/IGES model parse. kicad_editor.wasm ~190 MB -> 130 MB; sessions that never touch OCC never fetch its 57 MB. STEP export works in the browser for the first time: the unchanged desktop dialog runs EXPORTER_STEP, whose wasm shadow suspends into globalThis.occService and the export bytes go straight to a browser download (never entering the editor heap). STEP/IGES 3D models parse in the worker via the oce shadow (S3D WriteCache/ReadCache wire). - wasm/occ-service/: service CMake target (hooked from the kicad fork's top-level CMakeLists, wasm/editor pattern), embind entry (occExport/occLoadModel), wxConfig pre-js. - wasm/stubs/{exporter_step,oce_plugin}_stub.cpp: EM_ASYNC_JS worker bridges (callee-shadowing; no caller #ifdefs). - web/standalone: provider installed whenever the kicad_editor bundle boots (cross-face safe); ONE shared worker-boot source occ-worker.js (vite ?raw; the e2e stub reads the same file) — blob worker with locateFile absolutized against the glue URL; export download-name guard. - deps: OCC builds with RapidJSON so its glTF/GLB writer exists — pinned to the vcpkg master snapshot 2025-02-26 (24b5e7a8b27f), the same code official KiCad consumes via vcpkg.json's opencascade[rapidjson]; rapidjson's latest tag (v1.1.0, 2016) is ill-formed under modern clang. - tests: occ-export dialog e2e (lazy-fetch boundary + STEP download bytes), occ-probe incl. a 9-format matrix (step/stpz/brep/xao/ply/stl/glb/u3d/pdf), 3d-viewer-models hard-asserts the worker parse; occ provider stub installed ambiently by the kicad fixtures. Validated against desktop kicad-cli 10.0.4: geometric exact equality (bbox delta 0 um, volume delta 0.0000%) for STEP/GLB/STL/BREP/STPZ across three boards and option sweeps — with desktop OCC 7.9 vs wasm OCC 7.8; PLY/XAO/PDF structurally equal; U3D same-size (quantizer float LSBs differ). Full kicad e2e green on Firefox and Chromium; standalone verified end to end (lazy fetch only on the Export click; export.step 60,628 B ISO-10303-21; loadModel 700 KB STEP -> 569 KB scenegraph cache). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:39:58 +02:00
import * as fs from 'fs';
import * as path from 'path';
import type { Page } from '@playwright/test';
/**
* Install a REAL `globalThis.occService` provider into a harness page the
* same worker-backed occ_service boot the standalone app does, minus the CDN
* manifest resolution: the harness serves occ_service.{js,wasm} same-origin
* next to the tool page (tests/scripts/setup-kicad-wasm.sh copies them from
* output/).
*
* The worker-side wrapper is the SHARED source of truth
* (web/standalone/src/wasm/occ-worker.js the standalone imports it via vite
* `?raw`; the harness reads it off disk and injects it verbatim), so the
* trap-prone boot logic (blob worker + locateFile absolutization + pthread
* mainScriptUrlOrBlob) cannot drift between app and tests.
*
* Differences from the app provider, for assertability:
* - export results are captured into window.__occExports (name, size, magic
feat(occ): ship board 3D model bodies with STEP/GLB exports (3d-models 0007) The occ_service export worker has its own MEMFS — the editor's lazily-fetched lib models were invisible there, so every export was a bare board (54 "Could not add 3D model" warnings on pic_programmer, 2 STEP products). - models-bridge: collectBoardModelFiles(boardText) — scan refs, ensure via the 0004 sparse source (IDB/R2, wrl->step fallback), read staged bytes back, dedupe by real staged path. - occ-service.ts: attach the collected models to every export request (best-effort — prefetch failure still exports, misses reported by the exporter); transfer the body buffers. - occ-worker.js (shared app/harness): pass req.models through to occExport. - occ_service_main.cpp: occExport(board, params, models) stages each entry under PCBJAM_3D::MODELS_MEMFS_ROOT (path-sanitized) for the exporter's staged-model probe (kicad 83645275ac), removed again after the export. - tests: harness occ stub mirrors the prefetch against the page kicadLibs provider + captures report/productCount; new occ-export-models.spec.ts guards the delivery (green companion pins preconditions; guard asserts 0 missing lib models + component PRODUCTs). pic_programmer: 17/17 staged, 87 products @ 13.3 MB (was 2 @ 402 KB). models-bridge unit tests 13/13. Known remainder (0007 step 4): project-local ${KIPRJMOD} refs still drop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017UjpnviP3ZDxTM1Ap63Sqv
2026-07-10 08:44:55 +02:00
* prefix, the exporter's report text, and a PRODUCT-entity count for STEP
* bodies the per-component geometry signal) instead of triggering a
* browser download;
* - the app's export model prefetch (occ-service.ts models-bridge
* collectBoardModelFiles) is mirrored against the page's `kicadLibs`
* provider: lib refs scanned from the board text are ensured (kind
* "model3d"), read back from the editor MEMFS, and shipped as the
* request's `models` array. Specs without a kicadLibs stub ship none
* the pre-delivery behavior.
feat(wasm): occ-split — lazy occ_service worker; kicad_editor drops OCC (−31%) Move OpenCASCADE out of the merged editor image into occ_service: a separate emscripten module (-sASYNCIFY=0, MODULARIZE, in-container -Oz finalize, 2N+8 pre-warmed pthread pool) booted lazily in a dedicated Web Worker on the first STEP export or STEP/IGES model parse. kicad_editor.wasm ~190 MB -> 130 MB; sessions that never touch OCC never fetch its 57 MB. STEP export works in the browser for the first time: the unchanged desktop dialog runs EXPORTER_STEP, whose wasm shadow suspends into globalThis.occService and the export bytes go straight to a browser download (never entering the editor heap). STEP/IGES 3D models parse in the worker via the oce shadow (S3D WriteCache/ReadCache wire). - wasm/occ-service/: service CMake target (hooked from the kicad fork's top-level CMakeLists, wasm/editor pattern), embind entry (occExport/occLoadModel), wxConfig pre-js. - wasm/stubs/{exporter_step,oce_plugin}_stub.cpp: EM_ASYNC_JS worker bridges (callee-shadowing; no caller #ifdefs). - web/standalone: provider installed whenever the kicad_editor bundle boots (cross-face safe); ONE shared worker-boot source occ-worker.js (vite ?raw; the e2e stub reads the same file) — blob worker with locateFile absolutized against the glue URL; export download-name guard. - deps: OCC builds with RapidJSON so its glTF/GLB writer exists — pinned to the vcpkg master snapshot 2025-02-26 (24b5e7a8b27f), the same code official KiCad consumes via vcpkg.json's opencascade[rapidjson]; rapidjson's latest tag (v1.1.0, 2016) is ill-formed under modern clang. - tests: occ-export dialog e2e (lazy-fetch boundary + STEP download bytes), occ-probe incl. a 9-format matrix (step/stpz/brep/xao/ply/stl/glb/u3d/pdf), 3d-viewer-models hard-asserts the worker parse; occ provider stub installed ambiently by the kicad fixtures. Validated against desktop kicad-cli 10.0.4: geometric exact equality (bbox delta 0 um, volume delta 0.0000%) for STEP/GLB/STL/BREP/STPZ across three boards and option sweeps — with desktop OCC 7.9 vs wasm OCC 7.8; PLY/XAO/PDF structurally equal; U3D same-size (quantizer float LSBs differ). Full kicad e2e green on Firefox and Chromium; standalone verified end to end (lazy fetch only on the Export click; export.step 60,628 B ISO-10303-21; loadModel 700 KB STEP -> 569 KB scenegraph cache). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:39:58 +02:00
* - installed as an init script (kicad fixtures do this for every page), so
* it exists from document start on every navigation standalone parity,
* where boot.ts installs the provider whenever the editor bundle boots.
*
* The worker fetches occ_service.js lazily on the FIRST request specs can
* assert the lazy-load boundary by watching network requests.
*/
const OCC_WORKER_SRC = fs.readFileSync(
path.resolve(__dirname, '..', '..', '..',
'web', 'standalone', 'src', 'wasm', 'occ-worker.js'),
'utf8');
export async function installOccServiceStub(page: Page): Promise<void> {
await page.addInitScript((workerSrc: string) => {
if ((globalThis as any).occService) return;
(window as any).__occExports = [];
let workerP: Promise<Worker> | null = null;
const pending = new Map<number, (res: any) => void>();
let nextId = 1;
const ensureWorker = (): Promise<Worker> => {
if (!workerP) {
workerP = (async () => {
const glue = new URL('occ_service.js', window.location.href).href;
console.log(`[TEST-OCC] booting occ_service from ${glue}`);
const worker = new Worker(URL.createObjectURL(new Blob(
[`self.OCC_GLUE_URL = ${JSON.stringify(glue)};\n`, workerSrc],
{ type: 'text/javascript' })));
worker.onmessage = (e) => {
const { id, res } = e.data ?? {};
if (typeof id !== 'number') return;
const resolve = pending.get(id);
if (resolve) { pending.delete(id); resolve(res); }
};
jspi: fix the dead-tools ownership bug, emscripten-6 fallout, and green the full suite on Playwright 1.62 Live-app fix (Place Footprints / routing dead in Chrome): submodule bumps carry the coroutine ownership fix (kicad 012d95ecb4) and the handler-exception survival fix (wxwidgets 1b5f0e31f4). Emscripten-6 fallout: - occ/ngspice worker wrappers: mainScriptUrlOrBlob was removed upstream; pthread children re-run the wrapper blob, so an em-pthread realm now importScripts the glue and gets out of the way (before: recursive service boots, pool never fills, silent 180s boot hangs — every occ spec and ngspice bg_run). - Makefile.wasm: -sASYNCIFY frankenlinks on the no-wx coroutine repro targets ported to -sJSPI (the JSPI-only libcontext crashed at first yield under them); mainloop/gl repro pages drive their tick through a promising export (emscripten_set_main_loop callbacks cannot suspend); retired inject-dyncall-shims lines removed (targets were unbuildable since Phase 8); $stringToNewUTF8 force-included (the EM_ASM value bridge aborted the runtime on the first decoded exception). - fiber-park levers: neither embind shape can drive suspending levers (plain throws on strict-JSPI Firefox; emscripten::async() re-executes its invoker on settle) — kept sync for manual Chromium probing, spec coverage moved to the jspi-coroutine harness (18 cases). Suite work: - Playwright 1.61.1 -> 1.62.1 (Firefox 153: JSPI on by default). - fiber-resume-park.spec retired -> coroutine-lifecycle.spec: census gate over boot / board load / chooser open / cancel (deterministically red on the pre-fix build). - Blind asyncify-era pins re-keyed: quasimodal-strand + wait-beacons beacon regexes, footprint-chooser-close liveness -> wx parking-timer heartbeat (scheduler counters idle flat on Firefox). - occ/ngspice test providers: 60s boot timeout + worker error surfacing (a worker death used to be a silent 180s timeout). - Harness pages: stale 9.99 config dir -> 10.0 (library_manager wxCHECK noise, chooser had no libraries). - gal-webgl harness: missing artifacts rebuilt (boost/glm extracted to the host sysroot), PgmOrNull stub added for the rebased GAL. - jspi-scheduler: clean-shutdown console line restored (app-quit contract), quarantine never yanks SP from a live window. Gates: test:e2e 699 passed / 0 failed (wx-chromium, kicad-firefox, kicad-chromium, jspi-firefox, coroutine-firefox); web ff/cr/mobile 71 passed; lint:ci-coverage 166, lint:determinism 163, screenshots manifest 492 current, corpus 7/7, tools:contract green. Offline screenshot baselines show expected mass drift from the engine bump — re-baseline (screenshots:noise -> promote) is a follow-up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016X9eh1s5sTx1o9Em9KBuwR
2026-08-13 17:41:28 +02:00
// Legible boot: the old handshake could never reject on a
// worker DEATH (importScripts throw, pthread spawn wedge,
// OOM-kill) — the promise just hung until the spec's 180s
// timeout with zero evidence. Surface worker errors and
// bound the boot.
feat(wasm): occ-split — lazy occ_service worker; kicad_editor drops OCC (−31%) Move OpenCASCADE out of the merged editor image into occ_service: a separate emscripten module (-sASYNCIFY=0, MODULARIZE, in-container -Oz finalize, 2N+8 pre-warmed pthread pool) booted lazily in a dedicated Web Worker on the first STEP export or STEP/IGES model parse. kicad_editor.wasm ~190 MB -> 130 MB; sessions that never touch OCC never fetch its 57 MB. STEP export works in the browser for the first time: the unchanged desktop dialog runs EXPORTER_STEP, whose wasm shadow suspends into globalThis.occService and the export bytes go straight to a browser download (never entering the editor heap). STEP/IGES 3D models parse in the worker via the oce shadow (S3D WriteCache/ReadCache wire). - wasm/occ-service/: service CMake target (hooked from the kicad fork's top-level CMakeLists, wasm/editor pattern), embind entry (occExport/occLoadModel), wxConfig pre-js. - wasm/stubs/{exporter_step,oce_plugin}_stub.cpp: EM_ASYNC_JS worker bridges (callee-shadowing; no caller #ifdefs). - web/standalone: provider installed whenever the kicad_editor bundle boots (cross-face safe); ONE shared worker-boot source occ-worker.js (vite ?raw; the e2e stub reads the same file) — blob worker with locateFile absolutized against the glue URL; export download-name guard. - deps: OCC builds with RapidJSON so its glTF/GLB writer exists — pinned to the vcpkg master snapshot 2025-02-26 (24b5e7a8b27f), the same code official KiCad consumes via vcpkg.json's opencascade[rapidjson]; rapidjson's latest tag (v1.1.0, 2016) is ill-formed under modern clang. - tests: occ-export dialog e2e (lazy-fetch boundary + STEP download bytes), occ-probe incl. a 9-format matrix (step/stpz/brep/xao/ply/stl/glb/u3d/pdf), 3d-viewer-models hard-asserts the worker parse; occ provider stub installed ambiently by the kicad fixtures. Validated against desktop kicad-cli 10.0.4: geometric exact equality (bbox delta 0 um, volume delta 0.0000%) for STEP/GLB/STL/BREP/STPZ across three boards and option sweeps — with desktop OCC 7.9 vs wasm OCC 7.8; PLY/XAO/PDF structurally equal; U3D same-size (quantizer float LSBs differ). Full kicad e2e green on Firefox and Chromium; standalone verified end to end (lazy fetch only on the Export click; export.step 60,628 B ISO-10303-21; loadModel 700 KB STEP -> 569 KB scenegraph cache). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:39:58 +02:00
await new Promise<void>((resolve, reject) => {
jspi: fix the dead-tools ownership bug, emscripten-6 fallout, and green the full suite on Playwright 1.62 Live-app fix (Place Footprints / routing dead in Chrome): submodule bumps carry the coroutine ownership fix (kicad 012d95ecb4) and the handler-exception survival fix (wxwidgets 1b5f0e31f4). Emscripten-6 fallout: - occ/ngspice worker wrappers: mainScriptUrlOrBlob was removed upstream; pthread children re-run the wrapper blob, so an em-pthread realm now importScripts the glue and gets out of the way (before: recursive service boots, pool never fills, silent 180s boot hangs — every occ spec and ngspice bg_run). - Makefile.wasm: -sASYNCIFY frankenlinks on the no-wx coroutine repro targets ported to -sJSPI (the JSPI-only libcontext crashed at first yield under them); mainloop/gl repro pages drive their tick through a promising export (emscripten_set_main_loop callbacks cannot suspend); retired inject-dyncall-shims lines removed (targets were unbuildable since Phase 8); $stringToNewUTF8 force-included (the EM_ASM value bridge aborted the runtime on the first decoded exception). - fiber-park levers: neither embind shape can drive suspending levers (plain throws on strict-JSPI Firefox; emscripten::async() re-executes its invoker on settle) — kept sync for manual Chromium probing, spec coverage moved to the jspi-coroutine harness (18 cases). Suite work: - Playwright 1.61.1 -> 1.62.1 (Firefox 153: JSPI on by default). - fiber-resume-park.spec retired -> coroutine-lifecycle.spec: census gate over boot / board load / chooser open / cancel (deterministically red on the pre-fix build). - Blind asyncify-era pins re-keyed: quasimodal-strand + wait-beacons beacon regexes, footprint-chooser-close liveness -> wx parking-timer heartbeat (scheduler counters idle flat on Firefox). - occ/ngspice test providers: 60s boot timeout + worker error surfacing (a worker death used to be a silent 180s timeout). - Harness pages: stale 9.99 config dir -> 10.0 (library_manager wxCHECK noise, chooser had no libraries). - gal-webgl harness: missing artifacts rebuilt (boost/glm extracted to the host sysroot), PgmOrNull stub added for the rebased GAL. - jspi-scheduler: clean-shutdown console line restored (app-quit contract), quarantine never yanks SP from a live window. Gates: test:e2e 699 passed / 0 failed (wx-chromium, kicad-firefox, kicad-chromium, jspi-firefox, coroutine-firefox); web ff/cr/mobile 71 passed; lint:ci-coverage 166, lint:determinism 163, screenshots manifest 492 current, corpus 7/7, tools:contract green. Offline screenshot baselines show expected mass drift from the engine bump — re-baseline (screenshots:noise -> promote) is a follow-up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016X9eh1s5sTx1o9Em9KBuwR
2026-08-13 17:41:28 +02:00
const fail = (msg: string) => {
clearTimeout(timer);
reject(new Error(msg));
};
const timer = setTimeout(
() => fail('[TEST-OCC] occ_service boot timed out after 60s '
+ '(no ready/bootError from the worker)'), 60000);
feat(wasm): occ-split — lazy occ_service worker; kicad_editor drops OCC (−31%) Move OpenCASCADE out of the merged editor image into occ_service: a separate emscripten module (-sASYNCIFY=0, MODULARIZE, in-container -Oz finalize, 2N+8 pre-warmed pthread pool) booted lazily in a dedicated Web Worker on the first STEP export or STEP/IGES model parse. kicad_editor.wasm ~190 MB -> 130 MB; sessions that never touch OCC never fetch its 57 MB. STEP export works in the browser for the first time: the unchanged desktop dialog runs EXPORTER_STEP, whose wasm shadow suspends into globalThis.occService and the export bytes go straight to a browser download (never entering the editor heap). STEP/IGES 3D models parse in the worker via the oce shadow (S3D WriteCache/ReadCache wire). - wasm/occ-service/: service CMake target (hooked from the kicad fork's top-level CMakeLists, wasm/editor pattern), embind entry (occExport/occLoadModel), wxConfig pre-js. - wasm/stubs/{exporter_step,oce_plugin}_stub.cpp: EM_ASYNC_JS worker bridges (callee-shadowing; no caller #ifdefs). - web/standalone: provider installed whenever the kicad_editor bundle boots (cross-face safe); ONE shared worker-boot source occ-worker.js (vite ?raw; the e2e stub reads the same file) — blob worker with locateFile absolutized against the glue URL; export download-name guard. - deps: OCC builds with RapidJSON so its glTF/GLB writer exists — pinned to the vcpkg master snapshot 2025-02-26 (24b5e7a8b27f), the same code official KiCad consumes via vcpkg.json's opencascade[rapidjson]; rapidjson's latest tag (v1.1.0, 2016) is ill-formed under modern clang. - tests: occ-export dialog e2e (lazy-fetch boundary + STEP download bytes), occ-probe incl. a 9-format matrix (step/stpz/brep/xao/ply/stl/glb/u3d/pdf), 3d-viewer-models hard-asserts the worker parse; occ provider stub installed ambiently by the kicad fixtures. Validated against desktop kicad-cli 10.0.4: geometric exact equality (bbox delta 0 um, volume delta 0.0000%) for STEP/GLB/STL/BREP/STPZ across three boards and option sweeps — with desktop OCC 7.9 vs wasm OCC 7.8; PLY/XAO/PDF structurally equal; U3D same-size (quantizer float LSBs differ). Full kicad e2e green on Firefox and Chromium; standalone verified end to end (lazy fetch only on the Export click; export.step 60,628 B ISO-10303-21; loadModel 700 KB STEP -> 569 KB scenegraph cache). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:39:58 +02:00
const onFirst = (e: MessageEvent) => {
jspi: fix the dead-tools ownership bug, emscripten-6 fallout, and green the full suite on Playwright 1.62 Live-app fix (Place Footprints / routing dead in Chrome): submodule bumps carry the coroutine ownership fix (kicad 012d95ecb4) and the handler-exception survival fix (wxwidgets 1b5f0e31f4). Emscripten-6 fallout: - occ/ngspice worker wrappers: mainScriptUrlOrBlob was removed upstream; pthread children re-run the wrapper blob, so an em-pthread realm now importScripts the glue and gets out of the way (before: recursive service boots, pool never fills, silent 180s boot hangs — every occ spec and ngspice bg_run). - Makefile.wasm: -sASYNCIFY frankenlinks on the no-wx coroutine repro targets ported to -sJSPI (the JSPI-only libcontext crashed at first yield under them); mainloop/gl repro pages drive their tick through a promising export (emscripten_set_main_loop callbacks cannot suspend); retired inject-dyncall-shims lines removed (targets were unbuildable since Phase 8); $stringToNewUTF8 force-included (the EM_ASM value bridge aborted the runtime on the first decoded exception). - fiber-park levers: neither embind shape can drive suspending levers (plain throws on strict-JSPI Firefox; emscripten::async() re-executes its invoker on settle) — kept sync for manual Chromium probing, spec coverage moved to the jspi-coroutine harness (18 cases). Suite work: - Playwright 1.61.1 -> 1.62.1 (Firefox 153: JSPI on by default). - fiber-resume-park.spec retired -> coroutine-lifecycle.spec: census gate over boot / board load / chooser open / cancel (deterministically red on the pre-fix build). - Blind asyncify-era pins re-keyed: quasimodal-strand + wait-beacons beacon regexes, footprint-chooser-close liveness -> wx parking-timer heartbeat (scheduler counters idle flat on Firefox). - occ/ngspice test providers: 60s boot timeout + worker error surfacing (a worker death used to be a silent 180s timeout). - Harness pages: stale 9.99 config dir -> 10.0 (library_manager wxCHECK noise, chooser had no libraries). - gal-webgl harness: missing artifacts rebuilt (boost/glm extracted to the host sysroot), PgmOrNull stub added for the rebased GAL. - jspi-scheduler: clean-shutdown console line restored (app-quit contract), quarantine never yanks SP from a live window. Gates: test:e2e 699 passed / 0 failed (wx-chromium, kicad-firefox, kicad-chromium, jspi-firefox, coroutine-firefox); web ff/cr/mobile 71 passed; lint:ci-coverage 166, lint:determinism 163, screenshots manifest 492 current, corpus 7/7, tools:contract green. Offline screenshot baselines show expected mass drift from the engine bump — re-baseline (screenshots:noise -> promote) is a follow-up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016X9eh1s5sTx1o9Em9KBuwR
2026-08-13 17:41:28 +02:00
if (e.data?.ready) {
worker.removeEventListener('message', onFirst);
clearTimeout(timer);
resolve();
} else if (e.data?.bootError) {
fail(`[TEST-OCC] occ_service bootError: ${e.data.bootError}`);
}
feat(wasm): occ-split — lazy occ_service worker; kicad_editor drops OCC (−31%) Move OpenCASCADE out of the merged editor image into occ_service: a separate emscripten module (-sASYNCIFY=0, MODULARIZE, in-container -Oz finalize, 2N+8 pre-warmed pthread pool) booted lazily in a dedicated Web Worker on the first STEP export or STEP/IGES model parse. kicad_editor.wasm ~190 MB -> 130 MB; sessions that never touch OCC never fetch its 57 MB. STEP export works in the browser for the first time: the unchanged desktop dialog runs EXPORTER_STEP, whose wasm shadow suspends into globalThis.occService and the export bytes go straight to a browser download (never entering the editor heap). STEP/IGES 3D models parse in the worker via the oce shadow (S3D WriteCache/ReadCache wire). - wasm/occ-service/: service CMake target (hooked from the kicad fork's top-level CMakeLists, wasm/editor pattern), embind entry (occExport/occLoadModel), wxConfig pre-js. - wasm/stubs/{exporter_step,oce_plugin}_stub.cpp: EM_ASYNC_JS worker bridges (callee-shadowing; no caller #ifdefs). - web/standalone: provider installed whenever the kicad_editor bundle boots (cross-face safe); ONE shared worker-boot source occ-worker.js (vite ?raw; the e2e stub reads the same file) — blob worker with locateFile absolutized against the glue URL; export download-name guard. - deps: OCC builds with RapidJSON so its glTF/GLB writer exists — pinned to the vcpkg master snapshot 2025-02-26 (24b5e7a8b27f), the same code official KiCad consumes via vcpkg.json's opencascade[rapidjson]; rapidjson's latest tag (v1.1.0, 2016) is ill-formed under modern clang. - tests: occ-export dialog e2e (lazy-fetch boundary + STEP download bytes), occ-probe incl. a 9-format matrix (step/stpz/brep/xao/ply/stl/glb/u3d/pdf), 3d-viewer-models hard-asserts the worker parse; occ provider stub installed ambiently by the kicad fixtures. Validated against desktop kicad-cli 10.0.4: geometric exact equality (bbox delta 0 um, volume delta 0.0000%) for STEP/GLB/STL/BREP/STPZ across three boards and option sweeps — with desktop OCC 7.9 vs wasm OCC 7.8; PLY/XAO/PDF structurally equal; U3D same-size (quantizer float LSBs differ). Full kicad e2e green on Firefox and Chromium; standalone verified end to end (lazy fetch only on the Export click; export.step 60,628 B ISO-10303-21; loadModel 700 KB STEP -> 569 KB scenegraph cache). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:39:58 +02:00
};
worker.addEventListener('message', onFirst);
jspi: fix the dead-tools ownership bug, emscripten-6 fallout, and green the full suite on Playwright 1.62 Live-app fix (Place Footprints / routing dead in Chrome): submodule bumps carry the coroutine ownership fix (kicad 012d95ecb4) and the handler-exception survival fix (wxwidgets 1b5f0e31f4). Emscripten-6 fallout: - occ/ngspice worker wrappers: mainScriptUrlOrBlob was removed upstream; pthread children re-run the wrapper blob, so an em-pthread realm now importScripts the glue and gets out of the way (before: recursive service boots, pool never fills, silent 180s boot hangs — every occ spec and ngspice bg_run). - Makefile.wasm: -sASYNCIFY frankenlinks on the no-wx coroutine repro targets ported to -sJSPI (the JSPI-only libcontext crashed at first yield under them); mainloop/gl repro pages drive their tick through a promising export (emscripten_set_main_loop callbacks cannot suspend); retired inject-dyncall-shims lines removed (targets were unbuildable since Phase 8); $stringToNewUTF8 force-included (the EM_ASM value bridge aborted the runtime on the first decoded exception). - fiber-park levers: neither embind shape can drive suspending levers (plain throws on strict-JSPI Firefox; emscripten::async() re-executes its invoker on settle) — kept sync for manual Chromium probing, spec coverage moved to the jspi-coroutine harness (18 cases). Suite work: - Playwright 1.61.1 -> 1.62.1 (Firefox 153: JSPI on by default). - fiber-resume-park.spec retired -> coroutine-lifecycle.spec: census gate over boot / board load / chooser open / cancel (deterministically red on the pre-fix build). - Blind asyncify-era pins re-keyed: quasimodal-strand + wait-beacons beacon regexes, footprint-chooser-close liveness -> wx parking-timer heartbeat (scheduler counters idle flat on Firefox). - occ/ngspice test providers: 60s boot timeout + worker error surfacing (a worker death used to be a silent 180s timeout). - Harness pages: stale 9.99 config dir -> 10.0 (library_manager wxCHECK noise, chooser had no libraries). - gal-webgl harness: missing artifacts rebuilt (boost/glm extracted to the host sysroot), PgmOrNull stub added for the rebased GAL. - jspi-scheduler: clean-shutdown console line restored (app-quit contract), quarantine never yanks SP from a live window. Gates: test:e2e 699 passed / 0 failed (wx-chromium, kicad-firefox, kicad-chromium, jspi-firefox, coroutine-firefox); web ff/cr/mobile 71 passed; lint:ci-coverage 166, lint:determinism 163, screenshots manifest 492 current, corpus 7/7, tools:contract green. Offline screenshot baselines show expected mass drift from the engine bump — re-baseline (screenshots:noise -> promote) is a follow-up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016X9eh1s5sTx1o9Em9KBuwR
2026-08-13 17:41:28 +02:00
worker.addEventListener('error', (e: any) => fail(
`[TEST-OCC] occ_service worker error: ${e?.message ?? e} `
+ `(${e?.filename ?? '?'}:${e?.lineno ?? '?'})`));
worker.addEventListener('messageerror', () => fail(
'[TEST-OCC] occ_service worker messageerror (structured clone failed)'));
feat(wasm): occ-split — lazy occ_service worker; kicad_editor drops OCC (−31%) Move OpenCASCADE out of the merged editor image into occ_service: a separate emscripten module (-sASYNCIFY=0, MODULARIZE, in-container -Oz finalize, 2N+8 pre-warmed pthread pool) booted lazily in a dedicated Web Worker on the first STEP export or STEP/IGES model parse. kicad_editor.wasm ~190 MB -> 130 MB; sessions that never touch OCC never fetch its 57 MB. STEP export works in the browser for the first time: the unchanged desktop dialog runs EXPORTER_STEP, whose wasm shadow suspends into globalThis.occService and the export bytes go straight to a browser download (never entering the editor heap). STEP/IGES 3D models parse in the worker via the oce shadow (S3D WriteCache/ReadCache wire). - wasm/occ-service/: service CMake target (hooked from the kicad fork's top-level CMakeLists, wasm/editor pattern), embind entry (occExport/occLoadModel), wxConfig pre-js. - wasm/stubs/{exporter_step,oce_plugin}_stub.cpp: EM_ASYNC_JS worker bridges (callee-shadowing; no caller #ifdefs). - web/standalone: provider installed whenever the kicad_editor bundle boots (cross-face safe); ONE shared worker-boot source occ-worker.js (vite ?raw; the e2e stub reads the same file) — blob worker with locateFile absolutized against the glue URL; export download-name guard. - deps: OCC builds with RapidJSON so its glTF/GLB writer exists — pinned to the vcpkg master snapshot 2025-02-26 (24b5e7a8b27f), the same code official KiCad consumes via vcpkg.json's opencascade[rapidjson]; rapidjson's latest tag (v1.1.0, 2016) is ill-formed under modern clang. - tests: occ-export dialog e2e (lazy-fetch boundary + STEP download bytes), occ-probe incl. a 9-format matrix (step/stpz/brep/xao/ply/stl/glb/u3d/pdf), 3d-viewer-models hard-asserts the worker parse; occ provider stub installed ambiently by the kicad fixtures. Validated against desktop kicad-cli 10.0.4: geometric exact equality (bbox delta 0 um, volume delta 0.0000%) for STEP/GLB/STL/BREP/STPZ across three boards and option sweeps — with desktop OCC 7.9 vs wasm OCC 7.8; PLY/XAO/PDF structurally equal; U3D same-size (quantizer float LSBs differ). Full kicad e2e green on Firefox and Chromium; standalone verified end to end (lazy fetch only on the Export click; export.step 60,628 B ISO-10303-21; loadModel 700 KB STEP -> 569 KB scenegraph cache). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:39:58 +02:00
});
console.log('[TEST-OCC] occ_service ready');
return worker;
})().catch((e) => { workerP = null; throw e; });
}
return workerP;
};
feat(occ): ship board 3D model bodies with STEP/GLB exports (3d-models 0007) The occ_service export worker has its own MEMFS — the editor's lazily-fetched lib models were invisible there, so every export was a bare board (54 "Could not add 3D model" warnings on pic_programmer, 2 STEP products). - models-bridge: collectBoardModelFiles(boardText) — scan refs, ensure via the 0004 sparse source (IDB/R2, wrl->step fallback), read staged bytes back, dedupe by real staged path. - occ-service.ts: attach the collected models to every export request (best-effort — prefetch failure still exports, misses reported by the exporter); transfer the body buffers. - occ-worker.js (shared app/harness): pass req.models through to occExport. - occ_service_main.cpp: occExport(board, params, models) stages each entry under PCBJAM_3D::MODELS_MEMFS_ROOT (path-sanitized) for the exporter's staged-model probe (kicad 83645275ac), removed again after the export. - tests: harness occ stub mirrors the prefetch against the page kicadLibs provider + captures report/productCount; new occ-export-models.spec.ts guards the delivery (green companion pins preconditions; guard asserts 0 missing lib models + component PRODUCTs). pic_programmer: 17/17 staged, 87 products @ 13.3 MB (was 2 @ 402 KB). models-bridge unit tests 13/13. Known remainder (0007 step 4): project-local ${KIPRJMOD} refs still drop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017UjpnviP3ZDxTM1Ap63Sqv
2026-07-10 08:44:55 +02:00
// Mirror of the app's collectBoardModelFiles, against the page's
// kicadLibs provider (the specs' model stub): scan lib refs, ensure
// each into the editor MEMFS, read the staged bytes back.
const collectModels = async (boardText: string) => {
const hook = (globalThis as any).kicadLibs;
const FS = (window as any).FS;
if (!hook?.request || !FS) return [];
const ROOT = '/pcbjam/3dmodels';
const refs = new Set<string>();
const re = /\(\s*model\s+"((?:[^"\\]|\\.)*)"/g;
for (let m = re.exec(boardText); m; m = re.exec(boardText)) {
const raw = m[1].replace(/\\(.)/g, '$1');
const lib = raw.match(/^\$[{(](?:[^})]*3DMODEL_DIR|KISYS3DMOD)[})][/\\]+(.+)$/);
if (lib) refs.add(lib[1]);
}
const models: Array<{ path: string; bytes: Uint8Array }> = [];
const seen = new Set<string>();
for (const ref of refs) {
const abs = await hook.request('ensure', '', ref, 'model3d');
if (typeof abs !== 'string' || !abs.startsWith(`${ROOT}/`) || seen.has(abs)) continue;
seen.add(abs);
models.push({ path: abs.slice(ROOT.length + 1), bytes: FS.readFile(abs) });
}
console.log(`[TEST-OCC] shipping ${models.length} board model(s) with the export`);
return models;
};
feat(wasm): occ-split — lazy occ_service worker; kicad_editor drops OCC (−31%) Move OpenCASCADE out of the merged editor image into occ_service: a separate emscripten module (-sASYNCIFY=0, MODULARIZE, in-container -Oz finalize, 2N+8 pre-warmed pthread pool) booted lazily in a dedicated Web Worker on the first STEP export or STEP/IGES model parse. kicad_editor.wasm ~190 MB -> 130 MB; sessions that never touch OCC never fetch its 57 MB. STEP export works in the browser for the first time: the unchanged desktop dialog runs EXPORTER_STEP, whose wasm shadow suspends into globalThis.occService and the export bytes go straight to a browser download (never entering the editor heap). STEP/IGES 3D models parse in the worker via the oce shadow (S3D WriteCache/ReadCache wire). - wasm/occ-service/: service CMake target (hooked from the kicad fork's top-level CMakeLists, wasm/editor pattern), embind entry (occExport/occLoadModel), wxConfig pre-js. - wasm/stubs/{exporter_step,oce_plugin}_stub.cpp: EM_ASYNC_JS worker bridges (callee-shadowing; no caller #ifdefs). - web/standalone: provider installed whenever the kicad_editor bundle boots (cross-face safe); ONE shared worker-boot source occ-worker.js (vite ?raw; the e2e stub reads the same file) — blob worker with locateFile absolutized against the glue URL; export download-name guard. - deps: OCC builds with RapidJSON so its glTF/GLB writer exists — pinned to the vcpkg master snapshot 2025-02-26 (24b5e7a8b27f), the same code official KiCad consumes via vcpkg.json's opencascade[rapidjson]; rapidjson's latest tag (v1.1.0, 2016) is ill-formed under modern clang. - tests: occ-export dialog e2e (lazy-fetch boundary + STEP download bytes), occ-probe incl. a 9-format matrix (step/stpz/brep/xao/ply/stl/glb/u3d/pdf), 3d-viewer-models hard-asserts the worker parse; occ provider stub installed ambiently by the kicad fixtures. Validated against desktop kicad-cli 10.0.4: geometric exact equality (bbox delta 0 um, volume delta 0.0000%) for STEP/GLB/STL/BREP/STPZ across three boards and option sweeps — with desktop OCC 7.9 vs wasm OCC 7.8; PLY/XAO/PDF structurally equal; U3D same-size (quantizer float LSBs differ). Full kicad e2e green on Firefox and Chromium; standalone verified end to end (lazy fetch only on the Export click; export.step 60,628 B ISO-10303-21; loadModel 700 KB STEP -> 569 KB scenegraph cache). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:39:58 +02:00
const request = async (req: any) => {
feat(occ): ship board 3D model bodies with STEP/GLB exports (3d-models 0007) The occ_service export worker has its own MEMFS — the editor's lazily-fetched lib models were invisible there, so every export was a bare board (54 "Could not add 3D model" warnings on pic_programmer, 2 STEP products). - models-bridge: collectBoardModelFiles(boardText) — scan refs, ensure via the 0004 sparse source (IDB/R2, wrl->step fallback), read staged bytes back, dedupe by real staged path. - occ-service.ts: attach the collected models to every export request (best-effort — prefetch failure still exports, misses reported by the exporter); transfer the body buffers. - occ-worker.js (shared app/harness): pass req.models through to occExport. - occ_service_main.cpp: occExport(board, params, models) stages each entry under PCBJAM_3D::MODELS_MEMFS_ROOT (path-sanitized) for the exporter's staged-model probe (kicad 83645275ac), removed again after the export. - tests: harness occ stub mirrors the prefetch against the page kicadLibs provider + captures report/productCount; new occ-export-models.spec.ts guards the delivery (green companion pins preconditions; guard asserts 0 missing lib models + component PRODUCTs). pic_programmer: 17/17 staged, 87 products @ 13.3 MB (was 2 @ 402 KB). models-bridge unit tests 13/13. Known remainder (0007 step 4): project-local ${KIPRJMOD} refs still drop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017UjpnviP3ZDxTM1Ap63Sqv
2026-07-10 08:44:55 +02:00
if (req.kind === 'export')
req.models = await collectModels(new TextDecoder().decode(req.board));
feat(wasm): occ-split — lazy occ_service worker; kicad_editor drops OCC (−31%) Move OpenCASCADE out of the merged editor image into occ_service: a separate emscripten module (-sASYNCIFY=0, MODULARIZE, in-container -Oz finalize, 2N+8 pre-warmed pthread pool) booted lazily in a dedicated Web Worker on the first STEP export or STEP/IGES model parse. kicad_editor.wasm ~190 MB -> 130 MB; sessions that never touch OCC never fetch its 57 MB. STEP export works in the browser for the first time: the unchanged desktop dialog runs EXPORTER_STEP, whose wasm shadow suspends into globalThis.occService and the export bytes go straight to a browser download (never entering the editor heap). STEP/IGES 3D models parse in the worker via the oce shadow (S3D WriteCache/ReadCache wire). - wasm/occ-service/: service CMake target (hooked from the kicad fork's top-level CMakeLists, wasm/editor pattern), embind entry (occExport/occLoadModel), wxConfig pre-js. - wasm/stubs/{exporter_step,oce_plugin}_stub.cpp: EM_ASYNC_JS worker bridges (callee-shadowing; no caller #ifdefs). - web/standalone: provider installed whenever the kicad_editor bundle boots (cross-face safe); ONE shared worker-boot source occ-worker.js (vite ?raw; the e2e stub reads the same file) — blob worker with locateFile absolutized against the glue URL; export download-name guard. - deps: OCC builds with RapidJSON so its glTF/GLB writer exists — pinned to the vcpkg master snapshot 2025-02-26 (24b5e7a8b27f), the same code official KiCad consumes via vcpkg.json's opencascade[rapidjson]; rapidjson's latest tag (v1.1.0, 2016) is ill-formed under modern clang. - tests: occ-export dialog e2e (lazy-fetch boundary + STEP download bytes), occ-probe incl. a 9-format matrix (step/stpz/brep/xao/ply/stl/glb/u3d/pdf), 3d-viewer-models hard-asserts the worker parse; occ provider stub installed ambiently by the kicad fixtures. Validated against desktop kicad-cli 10.0.4: geometric exact equality (bbox delta 0 um, volume delta 0.0000%) for STEP/GLB/STL/BREP/STPZ across three boards and option sweeps — with desktop OCC 7.9 vs wasm OCC 7.8; PLY/XAO/PDF structurally equal; U3D same-size (quantizer float LSBs differ). Full kicad e2e green on Firefox and Chromium; standalone verified end to end (lazy fetch only on the Export click; export.step 60,628 B ISO-10303-21; loadModel 700 KB STEP -> 569 KB scenegraph cache). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:39:58 +02:00
let worker: Worker;
try {
worker = await ensureWorker();
} catch (e) {
return { ok: false, report: `occ_service unavailable: ${e}` };
}
const id = nextId++;
feat(occ): ship board 3D model bodies with STEP/GLB exports (3d-models 0007) The occ_service export worker has its own MEMFS — the editor's lazily-fetched lib models were invisible there, so every export was a bare board (54 "Could not add 3D model" warnings on pic_programmer, 2 STEP products). - models-bridge: collectBoardModelFiles(boardText) — scan refs, ensure via the 0004 sparse source (IDB/R2, wrl->step fallback), read staged bytes back, dedupe by real staged path. - occ-service.ts: attach the collected models to every export request (best-effort — prefetch failure still exports, misses reported by the exporter); transfer the body buffers. - occ-worker.js (shared app/harness): pass req.models through to occExport. - occ_service_main.cpp: occExport(board, params, models) stages each entry under PCBJAM_3D::MODELS_MEMFS_ROOT (path-sanitized) for the exporter's staged-model probe (kicad 83645275ac), removed again after the export. - tests: harness occ stub mirrors the prefetch against the page kicadLibs provider + captures report/productCount; new occ-export-models.spec.ts guards the delivery (green companion pins preconditions; guard asserts 0 missing lib models + component PRODUCTs). pic_programmer: 17/17 staged, 87 products @ 13.3 MB (was 2 @ 402 KB). models-bridge unit tests 13/13. Known remainder (0007 step 4): project-local ${KIPRJMOD} refs still drop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017UjpnviP3ZDxTM1Ap63Sqv
2026-07-10 08:44:55 +02:00
const transfer = req.kind === 'export'
? [req.board.buffer, ...(req.models ?? []).map((m: any) => m.bytes.buffer)]
: [req.bytes.buffer];
feat(wasm): occ-split — lazy occ_service worker; kicad_editor drops OCC (−31%) Move OpenCASCADE out of the merged editor image into occ_service: a separate emscripten module (-sASYNCIFY=0, MODULARIZE, in-container -Oz finalize, 2N+8 pre-warmed pthread pool) booted lazily in a dedicated Web Worker on the first STEP export or STEP/IGES model parse. kicad_editor.wasm ~190 MB -> 130 MB; sessions that never touch OCC never fetch its 57 MB. STEP export works in the browser for the first time: the unchanged desktop dialog runs EXPORTER_STEP, whose wasm shadow suspends into globalThis.occService and the export bytes go straight to a browser download (never entering the editor heap). STEP/IGES 3D models parse in the worker via the oce shadow (S3D WriteCache/ReadCache wire). - wasm/occ-service/: service CMake target (hooked from the kicad fork's top-level CMakeLists, wasm/editor pattern), embind entry (occExport/occLoadModel), wxConfig pre-js. - wasm/stubs/{exporter_step,oce_plugin}_stub.cpp: EM_ASYNC_JS worker bridges (callee-shadowing; no caller #ifdefs). - web/standalone: provider installed whenever the kicad_editor bundle boots (cross-face safe); ONE shared worker-boot source occ-worker.js (vite ?raw; the e2e stub reads the same file) — blob worker with locateFile absolutized against the glue URL; export download-name guard. - deps: OCC builds with RapidJSON so its glTF/GLB writer exists — pinned to the vcpkg master snapshot 2025-02-26 (24b5e7a8b27f), the same code official KiCad consumes via vcpkg.json's opencascade[rapidjson]; rapidjson's latest tag (v1.1.0, 2016) is ill-formed under modern clang. - tests: occ-export dialog e2e (lazy-fetch boundary + STEP download bytes), occ-probe incl. a 9-format matrix (step/stpz/brep/xao/ply/stl/glb/u3d/pdf), 3d-viewer-models hard-asserts the worker parse; occ provider stub installed ambiently by the kicad fixtures. Validated against desktop kicad-cli 10.0.4: geometric exact equality (bbox delta 0 um, volume delta 0.0000%) for STEP/GLB/STL/BREP/STPZ across three boards and option sweeps — with desktop OCC 7.9 vs wasm OCC 7.8; PLY/XAO/PDF structurally equal; U3D same-size (quantizer float LSBs differ). Full kicad e2e green on Firefox and Chromium; standalone verified end to end (lazy fetch only on the Export click; export.step 60,628 B ISO-10303-21; loadModel 700 KB STEP -> 569 KB scenegraph cache). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:39:58 +02:00
const res: any = await new Promise((resolve) => {
pending.set(id, resolve);
worker.postMessage({ id, req }, transfer);
});
if (req.kind === 'export') {
if (res.ok && res.bytes?.length) {
const magic = new TextDecoder().decode(res.bytes.slice(0, 16));
feat(occ): ship board 3D model bodies with STEP/GLB exports (3d-models 0007) The occ_service export worker has its own MEMFS — the editor's lazily-fetched lib models were invisible there, so every export was a bare board (54 "Could not add 3D model" warnings on pic_programmer, 2 STEP products). - models-bridge: collectBoardModelFiles(boardText) — scan refs, ensure via the 0004 sparse source (IDB/R2, wrl->step fallback), read staged bytes back, dedupe by real staged path. - occ-service.ts: attach the collected models to every export request (best-effort — prefetch failure still exports, misses reported by the exporter); transfer the body buffers. - occ-worker.js (shared app/harness): pass req.models through to occExport. - occ_service_main.cpp: occExport(board, params, models) stages each entry under PCBJAM_3D::MODELS_MEMFS_ROOT (path-sanitized) for the exporter's staged-model probe (kicad 83645275ac), removed again after the export. - tests: harness occ stub mirrors the prefetch against the page kicadLibs provider + captures report/productCount; new occ-export-models.spec.ts guards the delivery (green companion pins preconditions; guard asserts 0 missing lib models + component PRODUCTs). pic_programmer: 17/17 staged, 87 products @ 13.3 MB (was 2 @ 402 KB). models-bridge unit tests 13/13. Known remainder (0007 step 4): project-local ${KIPRJMOD} refs still drop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017UjpnviP3ZDxTM1Ap63Sqv
2026-07-10 08:44:55 +02:00
// STEP is a text format: `#n=PRODUCT('name',…)` entities count the
// distinct model bodies in the assembly (a bare board exports 12;
// component models add one each). The anchored `=PRODUCT(` match
// excludes PRODUCT_DEFINITION/PRODUCT_CONTEXT relatives.
let productCount = -1;
if (magic.startsWith('ISO-10303-21')) {
const text = new TextDecoder().decode(res.bytes);
productCount = (text.match(/=\s*PRODUCT\s*\(/g) ?? []).length;
}
feat(wasm): occ-split — lazy occ_service worker; kicad_editor drops OCC (−31%) Move OpenCASCADE out of the merged editor image into occ_service: a separate emscripten module (-sASYNCIFY=0, MODULARIZE, in-container -Oz finalize, 2N+8 pre-warmed pthread pool) booted lazily in a dedicated Web Worker on the first STEP export or STEP/IGES model parse. kicad_editor.wasm ~190 MB -> 130 MB; sessions that never touch OCC never fetch its 57 MB. STEP export works in the browser for the first time: the unchanged desktop dialog runs EXPORTER_STEP, whose wasm shadow suspends into globalThis.occService and the export bytes go straight to a browser download (never entering the editor heap). STEP/IGES 3D models parse in the worker via the oce shadow (S3D WriteCache/ReadCache wire). - wasm/occ-service/: service CMake target (hooked from the kicad fork's top-level CMakeLists, wasm/editor pattern), embind entry (occExport/occLoadModel), wxConfig pre-js. - wasm/stubs/{exporter_step,oce_plugin}_stub.cpp: EM_ASYNC_JS worker bridges (callee-shadowing; no caller #ifdefs). - web/standalone: provider installed whenever the kicad_editor bundle boots (cross-face safe); ONE shared worker-boot source occ-worker.js (vite ?raw; the e2e stub reads the same file) — blob worker with locateFile absolutized against the glue URL; export download-name guard. - deps: OCC builds with RapidJSON so its glTF/GLB writer exists — pinned to the vcpkg master snapshot 2025-02-26 (24b5e7a8b27f), the same code official KiCad consumes via vcpkg.json's opencascade[rapidjson]; rapidjson's latest tag (v1.1.0, 2016) is ill-formed under modern clang. - tests: occ-export dialog e2e (lazy-fetch boundary + STEP download bytes), occ-probe incl. a 9-format matrix (step/stpz/brep/xao/ply/stl/glb/u3d/pdf), 3d-viewer-models hard-asserts the worker parse; occ provider stub installed ambiently by the kicad fixtures. Validated against desktop kicad-cli 10.0.4: geometric exact equality (bbox delta 0 um, volume delta 0.0000%) for STEP/GLB/STL/BREP/STPZ across three boards and option sweeps — with desktop OCC 7.9 vs wasm OCC 7.8; PLY/XAO/PDF structurally equal; U3D same-size (quantizer float LSBs differ). Full kicad e2e green on Firefox and Chromium; standalone verified end to end (lazy fetch only on the Export click; export.step 60,628 B ISO-10303-21; loadModel 700 KB STEP -> 569 KB scenegraph cache). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:39:58 +02:00
(window as any).__occExports.push({
name: req.fileName || res.fileName,
size: res.bytes.length,
magic,
feat(occ): ship board 3D model bodies with STEP/GLB exports (3d-models 0007) The occ_service export worker has its own MEMFS — the editor's lazily-fetched lib models were invisible there, so every export was a bare board (54 "Could not add 3D model" warnings on pic_programmer, 2 STEP products). - models-bridge: collectBoardModelFiles(boardText) — scan refs, ensure via the 0004 sparse source (IDB/R2, wrl->step fallback), read staged bytes back, dedupe by real staged path. - occ-service.ts: attach the collected models to every export request (best-effort — prefetch failure still exports, misses reported by the exporter); transfer the body buffers. - occ-worker.js (shared app/harness): pass req.models through to occExport. - occ_service_main.cpp: occExport(board, params, models) stages each entry under PCBJAM_3D::MODELS_MEMFS_ROOT (path-sanitized) for the exporter's staged-model probe (kicad 83645275ac), removed again after the export. - tests: harness occ stub mirrors the prefetch against the page kicadLibs provider + captures report/productCount; new occ-export-models.spec.ts guards the delivery (green companion pins preconditions; guard asserts 0 missing lib models + component PRODUCTs). pic_programmer: 17/17 staged, 87 products @ 13.3 MB (was 2 @ 402 KB). models-bridge unit tests 13/13. Known remainder (0007 step 4): project-local ${KIPRJMOD} refs still drop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017UjpnviP3ZDxTM1Ap63Sqv
2026-07-10 08:44:55 +02:00
report: String(res.report ?? ''),
productCount,
feat(wasm): occ-split — lazy occ_service worker; kicad_editor drops OCC (−31%) Move OpenCASCADE out of the merged editor image into occ_service: a separate emscripten module (-sASYNCIFY=0, MODULARIZE, in-container -Oz finalize, 2N+8 pre-warmed pthread pool) booted lazily in a dedicated Web Worker on the first STEP export or STEP/IGES model parse. kicad_editor.wasm ~190 MB -> 130 MB; sessions that never touch OCC never fetch its 57 MB. STEP export works in the browser for the first time: the unchanged desktop dialog runs EXPORTER_STEP, whose wasm shadow suspends into globalThis.occService and the export bytes go straight to a browser download (never entering the editor heap). STEP/IGES 3D models parse in the worker via the oce shadow (S3D WriteCache/ReadCache wire). - wasm/occ-service/: service CMake target (hooked from the kicad fork's top-level CMakeLists, wasm/editor pattern), embind entry (occExport/occLoadModel), wxConfig pre-js. - wasm/stubs/{exporter_step,oce_plugin}_stub.cpp: EM_ASYNC_JS worker bridges (callee-shadowing; no caller #ifdefs). - web/standalone: provider installed whenever the kicad_editor bundle boots (cross-face safe); ONE shared worker-boot source occ-worker.js (vite ?raw; the e2e stub reads the same file) — blob worker with locateFile absolutized against the glue URL; export download-name guard. - deps: OCC builds with RapidJSON so its glTF/GLB writer exists — pinned to the vcpkg master snapshot 2025-02-26 (24b5e7a8b27f), the same code official KiCad consumes via vcpkg.json's opencascade[rapidjson]; rapidjson's latest tag (v1.1.0, 2016) is ill-formed under modern clang. - tests: occ-export dialog e2e (lazy-fetch boundary + STEP download bytes), occ-probe incl. a 9-format matrix (step/stpz/brep/xao/ply/stl/glb/u3d/pdf), 3d-viewer-models hard-asserts the worker parse; occ provider stub installed ambiently by the kicad fixtures. Validated against desktop kicad-cli 10.0.4: geometric exact equality (bbox delta 0 um, volume delta 0.0000%) for STEP/GLB/STL/BREP/STPZ across three boards and option sweeps — with desktop OCC 7.9 vs wasm OCC 7.8; PLY/XAO/PDF structurally equal; U3D same-size (quantizer float LSBs differ). Full kicad e2e green on Firefox and Chromium; standalone verified end to end (lazy fetch only on the Export click; export.step 60,628 B ISO-10303-21; loadModel 700 KB STEP -> 569 KB scenegraph cache). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:39:58 +02:00
});
feat(occ): ship board 3D model bodies with STEP/GLB exports (3d-models 0007) The occ_service export worker has its own MEMFS — the editor's lazily-fetched lib models were invisible there, so every export was a bare board (54 "Could not add 3D model" warnings on pic_programmer, 2 STEP products). - models-bridge: collectBoardModelFiles(boardText) — scan refs, ensure via the 0004 sparse source (IDB/R2, wrl->step fallback), read staged bytes back, dedupe by real staged path. - occ-service.ts: attach the collected models to every export request (best-effort — prefetch failure still exports, misses reported by the exporter); transfer the body buffers. - occ-worker.js (shared app/harness): pass req.models through to occExport. - occ_service_main.cpp: occExport(board, params, models) stages each entry under PCBJAM_3D::MODELS_MEMFS_ROOT (path-sanitized) for the exporter's staged-model probe (kicad 83645275ac), removed again after the export. - tests: harness occ stub mirrors the prefetch against the page kicadLibs provider + captures report/productCount; new occ-export-models.spec.ts guards the delivery (green companion pins preconditions; guard asserts 0 missing lib models + component PRODUCTs). pic_programmer: 17/17 staged, 87 products @ 13.3 MB (was 2 @ 402 KB). models-bridge unit tests 13/13. Known remainder (0007 step 4): project-local ${KIPRJMOD} refs still drop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017UjpnviP3ZDxTM1Ap63Sqv
2026-07-10 08:44:55 +02:00
console.log(`[TEST-OCC] export captured: ${req.fileName} ${res.bytes.length}B "${magic}" products=${productCount}`);
feat(wasm): occ-split — lazy occ_service worker; kicad_editor drops OCC (−31%) Move OpenCASCADE out of the merged editor image into occ_service: a separate emscripten module (-sASYNCIFY=0, MODULARIZE, in-container -Oz finalize, 2N+8 pre-warmed pthread pool) booted lazily in a dedicated Web Worker on the first STEP export or STEP/IGES model parse. kicad_editor.wasm ~190 MB -> 130 MB; sessions that never touch OCC never fetch its 57 MB. STEP export works in the browser for the first time: the unchanged desktop dialog runs EXPORTER_STEP, whose wasm shadow suspends into globalThis.occService and the export bytes go straight to a browser download (never entering the editor heap). STEP/IGES 3D models parse in the worker via the oce shadow (S3D WriteCache/ReadCache wire). - wasm/occ-service/: service CMake target (hooked from the kicad fork's top-level CMakeLists, wasm/editor pattern), embind entry (occExport/occLoadModel), wxConfig pre-js. - wasm/stubs/{exporter_step,oce_plugin}_stub.cpp: EM_ASYNC_JS worker bridges (callee-shadowing; no caller #ifdefs). - web/standalone: provider installed whenever the kicad_editor bundle boots (cross-face safe); ONE shared worker-boot source occ-worker.js (vite ?raw; the e2e stub reads the same file) — blob worker with locateFile absolutized against the glue URL; export download-name guard. - deps: OCC builds with RapidJSON so its glTF/GLB writer exists — pinned to the vcpkg master snapshot 2025-02-26 (24b5e7a8b27f), the same code official KiCad consumes via vcpkg.json's opencascade[rapidjson]; rapidjson's latest tag (v1.1.0, 2016) is ill-formed under modern clang. - tests: occ-export dialog e2e (lazy-fetch boundary + STEP download bytes), occ-probe incl. a 9-format matrix (step/stpz/brep/xao/ply/stl/glb/u3d/pdf), 3d-viewer-models hard-asserts the worker parse; occ provider stub installed ambiently by the kicad fixtures. Validated against desktop kicad-cli 10.0.4: geometric exact equality (bbox delta 0 um, volume delta 0.0000%) for STEP/GLB/STL/BREP/STPZ across three boards and option sweeps — with desktop OCC 7.9 vs wasm OCC 7.8; PLY/XAO/PDF structurally equal; U3D same-size (quantizer float LSBs differ). Full kicad e2e green on Firefox and Chromium; standalone verified end to end (lazy fetch only on the Export click; export.step 60,628 B ISO-10303-21; loadModel 700 KB STEP -> 569 KB scenegraph cache). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:39:58 +02:00
}
return { ok: res.ok, report: res.report, fileName: res.fileName };
}
return res;
};
(globalThis as any).occService = { request };
}, OCC_WORKER_SRC);
}