2026-06-09 12:35:46 +02:00
|
|
|
import type { Tool } from "@pcbjam/shared";
|
2026-06-01 16:30:29 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* KiCad config/version dir baked into the WASM build. The File→Open dialog
|
|
|
|
|
* starts in MEMFS_PROJECTS_DIR; we mirror each project under a subfolder of it.
|
|
|
|
|
*
|
|
|
|
|
* NOTE (spec §11.1): this path is KiCad-version dependent and confirmed by
|
|
|
|
|
* tests/kicad/load-pcb-probe.spec.ts. If the build's version dir changes, this
|
|
|
|
|
* must change too — a candidate for reading from the module at runtime later.
|
|
|
|
|
*/
|
|
|
|
|
export const KICAD_VERSION_DIR = "9.99";
|
|
|
|
|
export const MEMFS_PROJECTS_DIR = `/home/kicad/documents/kicad/${KICAD_VERSION_DIR}/projects`;
|
|
|
|
|
|
|
|
|
|
/** Where KiCad expects images.tar.gz (compiled-in KICAD_DATA path). */
|
|
|
|
|
export const RESOURCE_PATH =
|
|
|
|
|
"/workspace/build-wasm/sysroot/share/kicad/resources";
|
|
|
|
|
|
fix(web): boot KiCad WASM in-document (no iframe) and fix eeschema frame sizing
Replace the same-origin iframe in WasmTool with a direct in-document boot
(src/wasm/boot.ts): build the global Emscripten Module + preRun steps and
inject wx.js + <tool>.js into the page, the same artifacts the e2e harness
uses. The build is non-modularized (global Module/FS) and pthread-based, so
locateFile/mainScriptUrlOrBlob are set so the wasm + worker load regardless
of the SPA route, and only one tool runs per page load.
Two bugs found during in-browser verification:
- This build does not export Module.FS (touching it aborts); use the global
window.FS like the harness does.
- The wasm reads top-level frame geometry from a global `mainWindow`
(offsetWidth/offsetHeight/offsetTop), falling back to a hardcoded 1280x720
when undefined. The harness sets it via `var mainWindow = ...`; we must too,
or the frame mismatches the viewport and the whole AUI layout breaks
(missing toolbars, transparent/ghosted panels). Expose the #main-window
element as window.mainWindow.
Verified: eeschema renders the full UI (menus, toolbars, panels, schematic)
matching the e2e baseline. pcbnew remains pre-existing-broken at the build
level (raw pcbnew.html harness is equally broken: empty registry, dynCall
"ii signature" errors), independent of this change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 13:30:32 +02:00
|
|
|
/**
|
|
|
|
|
* argv[0] each tool's DEBUG check expects. These MUST match the values the
|
|
|
|
|
* proven harness HTMLs set as `Module.thisProgram` (tests/apps/kicad/<tool>.html)
|
|
|
|
|
* — notably the calculator binary is `pcb_calculator`, not `calculator`.
|
|
|
|
|
*/
|
2026-06-01 16:30:29 +02:00
|
|
|
export const TOOL_ARGV0: Record<Tool, string> = {
|
|
|
|
|
pcbnew: "/usr/bin/pcbnew",
|
|
|
|
|
eeschema: "/usr/bin/eeschema",
|
fix(web): boot KiCad WASM in-document (no iframe) and fix eeschema frame sizing
Replace the same-origin iframe in WasmTool with a direct in-document boot
(src/wasm/boot.ts): build the global Emscripten Module + preRun steps and
inject wx.js + <tool>.js into the page, the same artifacts the e2e harness
uses. The build is non-modularized (global Module/FS) and pthread-based, so
locateFile/mainScriptUrlOrBlob are set so the wasm + worker load regardless
of the SPA route, and only one tool runs per page load.
Two bugs found during in-browser verification:
- This build does not export Module.FS (touching it aborts); use the global
window.FS like the harness does.
- The wasm reads top-level frame geometry from a global `mainWindow`
(offsetWidth/offsetHeight/offsetTop), falling back to a hardcoded 1280x720
when undefined. The harness sets it via `var mainWindow = ...`; we must too,
or the frame mismatches the viewport and the whole AUI layout breaks
(missing toolbars, transparent/ghosted panels). Expose the #main-window
element as window.mainWindow.
Verified: eeschema renders the full UI (menus, toolbars, panels, schematic)
matching the e2e baseline. pcbnew remains pre-existing-broken at the build
level (raw pcbnew.html harness is equally broken: empty registry, dynCall
"ii signature" errors), independent of this change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 13:30:32 +02:00
|
|
|
calculator: "/usr/bin/pcb_calculator",
|
feat(web): wire pl_editor + symbol_editor tools (open, wizard-skip, UI)
Add the two newly WASM-ported editors to the web app the same way as the
existing tools:
- pl_editor (drawing-sheet, .kicad_wks): PL_EDITOR_FRAME overrides
OpenProjectFiles, so it gets the generic kicadOpenFile embind hook
(wasm/bindings/pl_editor_embind.cpp) for deterministic open. Mapped
.kicad_wks -> pl_editor in EXTENSION_TOOL.
- symbol_editor (symbol library): SYMBOL_EDIT_FRAME does NOT override
OpenProjectFiles, so it's treated as file-less (boot standalone, opens
libraries via its own UI). Added to FILELESS_TOOLS.
Both boot through single_top.cpp's STARTWIZARD, so both seed config to skip the
first-run wizard (TOOL_NEEDS_CONFIG_SEED) and get a /usr/bin/<binary> argv0.
contract: add to TOOLS, plus a TOOL_LABELS map for friendly names. The project
UI now renders file-less launch links generically from FILELESS_TOOLS and
per-file "Open in <label>" links from EXTENSION_TOOL (auto file-type detection),
so adding a tool needs no UI edits.
Verified in-browser: pl_editor opens a .kicad_wks (renders the sheet),
symbol_editor boots wizard-free; both with 0 console errors.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 21:49:04 +02:00
|
|
|
pl_editor: "/usr/bin/pl_editor",
|
|
|
|
|
symbol_editor: "/usr/bin/symbol_editor",
|
2026-06-14 06:22:40 +02:00
|
|
|
footprint_editor: "/usr/bin/footprint_editor",
|
feat(web): wire gerbview tool (file-less launch, wizard-skip, UI)
Register the newly WASM-ported Gerber Viewer in the web app the same way as
the other tools — registry entries only, no UI edits (ProjectDetailPage renders
launch links generically from FILELESS_TOOLS).
GERBVIEW_FRAME opens gerber/drill files through its own File→Open UI and projects
carry no gerber files to auto-open, so it's treated as file-less (boot standalone),
mirroring symbol_editor. It boots through single_top.cpp's STARTWIZARD, so it seeds
config to skip the first-run wizard (TOOL_NEEDS_CONFIG_SEED) and gets a
/usr/bin/gerbview argv0.
- contract: add "gerbview" to TOOLS, TOOL_LABELS ("Gerber Viewer"), FILELESS_TOOLS
- frontend: add gerbview to TOOL_ARGV0 and TOOL_NEEDS_CONFIG_SEED
- e2e: add file-less gerbview case to tools-open.spec.ts (title "Gerber Viewer",
canvas painted, wizard-free, no WASM abort)
Verified in-browser via npm run test:web: gerbview boots wizard-free with the
viewer chrome (toolbars + layers manager), 0 console errors.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 16:47:23 +02:00
|
|
|
gerbview: "/usr/bin/gerbview",
|
2026-06-01 16:30:29 +02:00
|
|
|
};
|
|
|
|
|
|
fix(web): boot KiCad WASM in-document (no iframe) and fix eeschema frame sizing
Replace the same-origin iframe in WasmTool with a direct in-document boot
(src/wasm/boot.ts): build the global Emscripten Module + preRun steps and
inject wx.js + <tool>.js into the page, the same artifacts the e2e harness
uses. The build is non-modularized (global Module/FS) and pthread-based, so
locateFile/mainScriptUrlOrBlob are set so the wasm + worker load regardless
of the SPA route, and only one tool runs per page load.
Two bugs found during in-browser verification:
- This build does not export Module.FS (touching it aborts); use the global
window.FS like the harness does.
- The wasm reads top-level frame geometry from a global `mainWindow`
(offsetWidth/offsetHeight/offsetTop), falling back to a hardcoded 1280x720
when undefined. The harness sets it via `var mainWindow = ...`; we must too,
or the frame mismatches the viewport and the whole AUI layout breaks
(missing toolbars, transparent/ghosted panels). Expose the #main-window
element as window.mainWindow.
Verified: eeschema renders the full UI (menus, toolbars, panels, schematic)
matching the e2e baseline. pcbnew remains pre-existing-broken at the build
level (raw pcbnew.html harness is equally broken: empty registry, dynCall
"ii signature" errors), independent of this change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 13:30:32 +02:00
|
|
|
/**
|
2026-06-02 17:22:51 +02:00
|
|
|
* Every standalone tool here boots through common/single_top.cpp, which runs
|
|
|
|
|
* STARTWIZARD::CheckAndRun() — the first-run "KiCad Setup" wizard. It shows
|
|
|
|
|
* whenever any provider (SETTINGS / LIBRARIES / PRIVACY) reports
|
|
|
|
|
* NeedsUserInput(), which is always true on our ephemeral MEMFS with no config,
|
|
|
|
|
* and its modal loop crashes Asyncify. So for all of them we seed a default
|
|
|
|
|
* KiCad config before main() (kicad_common.json privacy flags + the lib-tables
|
|
|
|
|
* the providers check) so NeedsUserInput() is false and the wizard is skipped.
|
fix(web): boot KiCad WASM in-document (no iframe) and fix eeschema frame sizing
Replace the same-origin iframe in WasmTool with a direct in-document boot
(src/wasm/boot.ts): build the global Emscripten Module + preRun steps and
inject wx.js + <tool>.js into the page, the same artifacts the e2e harness
uses. The build is non-modularized (global Module/FS) and pthread-based, so
locateFile/mainScriptUrlOrBlob are set so the wasm + worker load regardless
of the SPA route, and only one tool runs per page load.
Two bugs found during in-browser verification:
- This build does not export Module.FS (touching it aborts); use the global
window.FS like the harness does.
- The wasm reads top-level frame geometry from a global `mainWindow`
(offsetWidth/offsetHeight/offsetTop), falling back to a hardcoded 1280x720
when undefined. The harness sets it via `var mainWindow = ...`; we must too,
or the frame mismatches the viewport and the whole AUI layout breaks
(missing toolbars, transparent/ghosted panels). Expose the #main-window
element as window.mainWindow.
Verified: eeschema renders the full UI (menus, toolbars, panels, schematic)
matching the e2e baseline. pcbnew remains pre-existing-broken at the build
level (raw pcbnew.html harness is equally broken: empty registry, dynCall
"ii signature" errors), independent of this change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 13:30:32 +02:00
|
|
|
*/
|
|
|
|
|
export const TOOL_NEEDS_CONFIG_SEED: Record<Tool, boolean> = {
|
2026-06-02 17:22:51 +02:00
|
|
|
pcbnew: true,
|
fix(web): boot KiCad WASM in-document (no iframe) and fix eeschema frame sizing
Replace the same-origin iframe in WasmTool with a direct in-document boot
(src/wasm/boot.ts): build the global Emscripten Module + preRun steps and
inject wx.js + <tool>.js into the page, the same artifacts the e2e harness
uses. The build is non-modularized (global Module/FS) and pthread-based, so
locateFile/mainScriptUrlOrBlob are set so the wasm + worker load regardless
of the SPA route, and only one tool runs per page load.
Two bugs found during in-browser verification:
- This build does not export Module.FS (touching it aborts); use the global
window.FS like the harness does.
- The wasm reads top-level frame geometry from a global `mainWindow`
(offsetWidth/offsetHeight/offsetTop), falling back to a hardcoded 1280x720
when undefined. The harness sets it via `var mainWindow = ...`; we must too,
or the frame mismatches the viewport and the whole AUI layout breaks
(missing toolbars, transparent/ghosted panels). Expose the #main-window
element as window.mainWindow.
Verified: eeschema renders the full UI (menus, toolbars, panels, schematic)
matching the e2e baseline. pcbnew remains pre-existing-broken at the build
level (raw pcbnew.html harness is equally broken: empty registry, dynCall
"ii signature" errors), independent of this change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 13:30:32 +02:00
|
|
|
eeschema: true,
|
2026-06-02 17:22:51 +02:00
|
|
|
calculator: true,
|
feat(web): wire pl_editor + symbol_editor tools (open, wizard-skip, UI)
Add the two newly WASM-ported editors to the web app the same way as the
existing tools:
- pl_editor (drawing-sheet, .kicad_wks): PL_EDITOR_FRAME overrides
OpenProjectFiles, so it gets the generic kicadOpenFile embind hook
(wasm/bindings/pl_editor_embind.cpp) for deterministic open. Mapped
.kicad_wks -> pl_editor in EXTENSION_TOOL.
- symbol_editor (symbol library): SYMBOL_EDIT_FRAME does NOT override
OpenProjectFiles, so it's treated as file-less (boot standalone, opens
libraries via its own UI). Added to FILELESS_TOOLS.
Both boot through single_top.cpp's STARTWIZARD, so both seed config to skip the
first-run wizard (TOOL_NEEDS_CONFIG_SEED) and get a /usr/bin/<binary> argv0.
contract: add to TOOLS, plus a TOOL_LABELS map for friendly names. The project
UI now renders file-less launch links generically from FILELESS_TOOLS and
per-file "Open in <label>" links from EXTENSION_TOOL (auto file-type detection),
so adding a tool needs no UI edits.
Verified in-browser: pl_editor opens a .kicad_wks (renders the sheet),
symbol_editor boots wizard-free; both with 0 console errors.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 21:49:04 +02:00
|
|
|
pl_editor: true,
|
|
|
|
|
symbol_editor: true,
|
2026-06-14 06:22:40 +02:00
|
|
|
footprint_editor: true,
|
feat(web): wire gerbview tool (file-less launch, wizard-skip, UI)
Register the newly WASM-ported Gerber Viewer in the web app the same way as
the other tools — registry entries only, no UI edits (ProjectDetailPage renders
launch links generically from FILELESS_TOOLS).
GERBVIEW_FRAME opens gerber/drill files through its own File→Open UI and projects
carry no gerber files to auto-open, so it's treated as file-less (boot standalone),
mirroring symbol_editor. It boots through single_top.cpp's STARTWIZARD, so it seeds
config to skip the first-run wizard (TOOL_NEEDS_CONFIG_SEED) and gets a
/usr/bin/gerbview argv0.
- contract: add "gerbview" to TOOLS, TOOL_LABELS ("Gerber Viewer"), FILELESS_TOOLS
- frontend: add gerbview to TOOL_ARGV0 and TOOL_NEEDS_CONFIG_SEED
- e2e: add file-less gerbview case to tools-open.spec.ts (title "Gerber Viewer",
canvas painted, wizard-free, no WASM abort)
Verified in-browser via npm run test:web: gerbview boots wizard-free with the
viewer chrome (toolbars + layers manager), 0 console errors.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 16:47:23 +02:00
|
|
|
gerbview: true,
|
fix(web): boot KiCad WASM in-document (no iframe) and fix eeschema frame sizing
Replace the same-origin iframe in WasmTool with a direct in-document boot
(src/wasm/boot.ts): build the global Emscripten Module + preRun steps and
inject wx.js + <tool>.js into the page, the same artifacts the e2e harness
uses. The build is non-modularized (global Module/FS) and pthread-based, so
locateFile/mainScriptUrlOrBlob are set so the wasm + worker load regardless
of the SPA route, and only one tool runs per page load.
Two bugs found during in-browser verification:
- This build does not export Module.FS (touching it aborts); use the global
window.FS like the harness does.
- The wasm reads top-level frame geometry from a global `mainWindow`
(offsetWidth/offsetHeight/offsetTop), falling back to a hardcoded 1280x720
when undefined. The harness sets it via `var mainWindow = ...`; we must too,
or the frame mismatches the viewport and the whole AUI layout breaks
(missing toolbars, transparent/ghosted panels). Expose the #main-window
element as window.mainWindow.
Verified: eeschema renders the full UI (menus, toolbars, panels, schematic)
matching the e2e baseline. pcbnew remains pre-existing-broken at the build
level (raw pcbnew.html harness is equally broken: empty registry, dynCall
"ii signature" errors), independent of this change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 13:30:32 +02:00
|
|
|
};
|
|
|
|
|
|
2026-06-14 06:22:40 +02:00
|
|
|
/**
|
|
|
|
|
* Which library kind a tool consumes — drives which lib-table boot populates
|
|
|
|
|
* from the lib source (symbol → sym-lib-table; footprint → fp-lib-table). A
|
|
|
|
|
* user lib is a kind-agnostic container, so the same lib id can land in both
|
|
|
|
|
* tables depending on the tool. `null` = the tool uses no libraries.
|
|
|
|
|
*/
|
|
|
|
|
export const TOOL_LIB_KIND: Record<Tool, "symbol" | "footprint" | null> = {
|
|
|
|
|
pcbnew: "footprint",
|
|
|
|
|
eeschema: "symbol",
|
|
|
|
|
calculator: null,
|
|
|
|
|
pl_editor: null,
|
|
|
|
|
symbol_editor: "symbol",
|
|
|
|
|
footprint_editor: "footprint",
|
|
|
|
|
gerbview: null,
|
|
|
|
|
};
|
|
|
|
|
|
fix(web): boot KiCad WASM in-document (no iframe) and fix eeschema frame sizing
Replace the same-origin iframe in WasmTool with a direct in-document boot
(src/wasm/boot.ts): build the global Emscripten Module + preRun steps and
inject wx.js + <tool>.js into the page, the same artifacts the e2e harness
uses. The build is non-modularized (global Module/FS) and pthread-based, so
locateFile/mainScriptUrlOrBlob are set so the wasm + worker load regardless
of the SPA route, and only one tool runs per page load.
Two bugs found during in-browser verification:
- This build does not export Module.FS (touching it aborts); use the global
window.FS like the harness does.
- The wasm reads top-level frame geometry from a global `mainWindow`
(offsetWidth/offsetHeight/offsetTop), falling back to a hardcoded 1280x720
when undefined. The harness sets it via `var mainWindow = ...`; we must too,
or the frame mismatches the viewport and the whole AUI layout breaks
(missing toolbars, transparent/ghosted panels). Expose the #main-window
element as window.mainWindow.
Verified: eeschema renders the full UI (menus, toolbars, panels, schematic)
matching the e2e baseline. pcbnew remains pre-existing-broken at the build
level (raw pcbnew.html harness is equally broken: empty registry, dynCall
"ii signature" errors), independent of this change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 13:30:32 +02:00
|
|
|
/** KiCad user settings dir for this build (PATHS::GetUserSettingsPath()). */
|
|
|
|
|
export const KICAD_CONFIG_DIR = `/home/kicad/.config/kicad/kicad/${KICAD_VERSION_DIR}`;
|
|
|
|
|
|
2026-06-01 16:30:29 +02:00
|
|
|
export function memfsProjectDir(slug: string): string {
|
|
|
|
|
return `${MEMFS_PROJECTS_DIR}/${slug}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function memfsFilePath(slug: string, relPath: string): string {
|
|
|
|
|
return `${memfsProjectDir(slug)}/${relPath}`;
|
|
|
|
|
}
|