feat(site): link the live demo + serve the gerber demo from the versioned CDN
Refer to demo.pcbjam.com from the landing: an accent "Live demo" link in the header nav, an "Open the live editor" hero link, a note in the gerber section, and a "Try the live demo now" line in the final CTA. Rework the embedded gerber viewer (public/gerber-demo/boot.js) to source the WASM from the deploy pipeline's versioned CDN instead of the hand-synced assets.pcbjam.com bucket: resolve gerbview's content-addressed folder at runtime from the release manifest (manifest-latest -> tag -> manifest-<tag> -> gerbview), load all assets (glue + wasm + images.tar.gz) from cdn.pcbjam.com, and load the cross-origin pthread worker via a same-origin blob importScripts shim (mirrors web/standalone/src/wasm/boot.ts). Bump the config-seed KICAD_VERSION_DIR 9.99 -> 10.0 to match the deployed build. Drop the now-obsolete committed glue mirror and the old assets.pcbjam.com sync/r2-deploy scripts. Collapse the header nav to the hamburger below 1025px — the added demo link no longer fits the 1024px-capped bar on a single row. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
13551f4f22
commit
9b41d7321f
15 changed files with 407 additions and 17539 deletions
|
|
@ -1,38 +1,65 @@
|
|||
# Gerber viewer blog demo
|
||||
# Gerber viewer demo
|
||||
|
||||
KiCad's `gerbview` compiled to WebAssembly, embedded (lazily) in the blog post.
|
||||
Click → it streams the WASM and renders the bundled tiny_tapeout board in-browser.
|
||||
KiCad's `gerbview` compiled to WebAssembly, embedded (lazily) in the landing page
|
||||
and the blog post. Click → it streams the WASM and renders the bundled
|
||||
tiny_tapeout board in-browser.
|
||||
|
||||
The WASM is **not** kept here — `boot.js` loads it from the versioned CDN
|
||||
(`cdn.pcbjam.com`), the same artifacts the demo/app deploy publishes. It resolves
|
||||
gerbview's immutable, content-addressed folder at runtime from the release
|
||||
manifest, so this page always shows the **latest deployed** gerbview with no
|
||||
manual sync:
|
||||
|
||||
```
|
||||
manifest-latest.json -> { tag }
|
||||
manifest-<tag>.json -> tools.gerbview -> <ver>
|
||||
base = https://cdn.pcbjam.com/wasm/gerbview/<ver>
|
||||
```
|
||||
|
||||
See `docs/features/demo-deploy/0001-wasm-cdn-versioning.md` (in `pcbjam-private`)
|
||||
for the CDN layout, manifest shapes, and header matrix.
|
||||
|
||||
## Files here (`site/public/gerber-demo/`)
|
||||
|
||||
| Path | What it does |
|
||||
|------|--------------|
|
||||
| `index.html` | The iframe target — minimal page with the `#main-window` / `#window-container` the WASM needs. |
|
||||
| `boot.js` | Boot harness: configures Emscripten `Module`, seeds KiCad config, preloads the board into MEMFS, auto-opens it via `Module.arguments`, and injects `wx.js → wx-dom.js → gerbview.js`. Holds `R2_BASE` + the dev/prod asset-base switch. |
|
||||
| `index.html` | The iframe/standalone target — minimal page with the `#main-window` / `#window-container` the WASM needs. |
|
||||
| `boot.js` | Boot harness: resolves gerbview's CDN folder from the manifest, configures Emscripten `Module`, seeds KiCad config, preloads the board into MEMFS, auto-opens it via `Module.arguments`, and injects `wx.js → wx-dom.js → gerbview.js` from the CDN. |
|
||||
| `board/` | The tiny_tapeout Gerber layers (committed) the demo opens. |
|
||||
| `poster.png` | Static fallback shown to browsers that can't run the live viewer. |
|
||||
| `wasm/` | `wx.js`/`wx-dom.js`/`gerbview.js` (committed, served same-origin) + `gerbview.wasm`/`kicad-resources.bin` (git-ignored; served from R2 in prod, local in dev). Synced from `/output`. |
|
||||
|
||||
The folder is cross-origin to this page (which is COEP `require-corp`); the CDN
|
||||
sends `Cross-Origin-Resource-Policy: cross-origin` + `Access-Control-Allow-Origin: *`,
|
||||
and the cross-origin pthread worker is loaded via a same-origin `blob:`
|
||||
`importScripts` shim (`new Worker(<cross-origin URL>)` is a SecurityError). This
|
||||
mirrors the standalone editor's `web/standalone/src/wasm/boot.ts`.
|
||||
|
||||
## Related pieces (elsewhere in `site/`)
|
||||
|
||||
| Path | What it does |
|
||||
|------|--------------|
|
||||
| `src/components/GerberDemo.astro` | The embed: lazy click-to-load iframe, cross-origin-isolation reload guard, feature-detect + poster fallback. |
|
||||
| `src/content/blog/porting-kicad-graphics-to-webgl-with-claude.mdx` | The post that renders `<GerberDemo />`. |
|
||||
| `src/sections/GerberDemoSection.astro` | The landing-page showcase: a poster + launch button that opens `/gerber-demo/` in a new tab (the landing itself is not cross-origin isolated). |
|
||||
| `src/components/GerberDemo.astro` | The blog embed: lazy click-to-load iframe, cross-origin-isolation reload guard, feature-detect + poster fallback. |
|
||||
| `astro.config.mjs` + `src/middleware.ts` | Dev cross-origin-isolation headers (COOP/COEP `require-corp`). |
|
||||
| `vercel.json` | Prod COOP/COEP, scoped to the post + `/gerber-demo/` routes. |
|
||||
| `scripts/sync-demo-wasm.sh` | Copy fresh WASM from `/output` into `wasm/` (run after a gerbview rebuild). |
|
||||
| `scripts/r2-deploy.sh` + `scripts/r2-cors.json` | Upload the heavy binaries to Cloudflare R2 (`pcbjam-assets` → `assets.pcbjam.com`) and set CORS. |
|
||||
| `vercel.json` | Prod COOP/COEP, scoped to the blog post + `/gerber-demo/` routes. |
|
||||
|
||||
## Run / update
|
||||
## Dev overrides
|
||||
|
||||
```bash
|
||||
# local dev (serves wasm/ from the local mirror)
|
||||
scripts/sync-demo-wasm.sh && npm run dev # /blog/porting-kicad-graphics-to-webgl-with-claude
|
||||
`boot.js` reads query params so you can point it elsewhere without a rebuild:
|
||||
|
||||
# after a new gerbview build: refresh local mirror, then push binaries to R2
|
||||
scripts/sync-demo-wasm.sh && scripts/r2-deploy.sh
|
||||
```
|
||||
| Param | Effect |
|
||||
|-------|--------|
|
||||
| `?tag=<tag>` | Pin a specific release instead of following `manifest-latest.json`. |
|
||||
| `?cdn=<root>` | Swap the CDN root (e.g. a local mirror serving `manifest-*.json` + `gerbview/<ver>/`). |
|
||||
| `?base=<folder>` | Use a tool folder verbatim (e.g. a fresh local build) — skips manifest resolution. |
|
||||
|
||||
The live viewer needs SharedArrayBuffer + WebGL2 (Chrome/Edge/Firefox, Safari 15.2+);
|
||||
other browsers get `poster.png`.
|
||||
other browsers get `poster.png`.
|
||||
|
||||
## Updating `KICAD_VERSION_DIR`
|
||||
|
||||
`boot.js` seeds KiCad config under a version dir (currently `"10.0"`) to suppress
|
||||
the first-run wizard. It **must** match the deployed build's
|
||||
`GetMajorMinorVersion()`. If a future deploy bumps KiCad's major.minor, update the
|
||||
`KICAD_VERSION_DIR` constant in `boot.js` (same coupling as
|
||||
`web/standalone/src/wasm/constants.ts`).
|
||||
|
|
|
|||
|
|
@ -1,44 +1,51 @@
|
|||
/*
|
||||
* Self-contained boot harness for the KiCad Gerber viewer (gerbview) WASM,
|
||||
* embedded in the blog post via an <iframe>. Adapted from the proven test
|
||||
* harness (tests/apps/kicad/gerbview.html) and the React port
|
||||
* (web/standalone/src/wasm/boot.ts) — same global `Module`, same preRun steps,
|
||||
* same wx.js -> wx-dom.js -> gerbview.js injection order.
|
||||
* embedded in the landing page / blog post via an <iframe>. A faithful port of
|
||||
* the standalone React boot (web/standalone/src/wasm/boot.ts) — same global
|
||||
* `Module`, same preRun steps, same wx.js -> wx-dom.js -> gerbview.js order.
|
||||
*
|
||||
* Classic script (NOT a module): the non-modularized WASM glue reads a GLOBAL
|
||||
* `var Module` and a GLOBAL `mainWindow`, and publishes `FS` onto the global
|
||||
* scope. Top-level `var`/`const` here share that global scope.
|
||||
* scope. `window.Module = ...` is what makes the glue see our config.
|
||||
*
|
||||
* Asset layout, split because the pthread worker script MUST be same-origin
|
||||
* (a Worker can't be created from a cross-origin URL). So the small glue stays
|
||||
* on the site origin and only the big binaries move to Cloudflare R2:
|
||||
* GLUE_BASE : wx.js, wx-dom.js, gerbview.js, mainScriptUrlOrBlob (same-origin)
|
||||
* BINARY_BASE : gerbview.wasm, kicad-resources.bin (R2 in prod, local in dev)
|
||||
* ── Assets come from the versioned CDN (cdn.pcbjam.com) — the SAME artifacts the
|
||||
* demo/app deploy publishes, not a hand-synced copy. We resolve gerbview's
|
||||
* immutable, content-addressed folder at runtime from the release manifest:
|
||||
*
|
||||
* BINARY_BASE auto-switches by hostname: localhost → the local mirror (./wasm),
|
||||
* any other host → R2_BASE below. Override either base with ?glue=/?bin=.
|
||||
* To point at R2, set R2_BASE to your bucket's public URL — either a custom
|
||||
* domain (https://assets.pcbjam.com) or the managed https://<id>.r2.dev URL.
|
||||
* manifest-latest.json -> { tag }
|
||||
* manifest-<tag>.json -> tools.gerbview -> <ver>
|
||||
* base = <CDN_ROOT>/gerbview/<ver>
|
||||
*
|
||||
* so the landing always shows the LATEST deployed gerbview with no manual sync.
|
||||
* A tool folder is self-contained + ABI-matched: gerbview.wasm, gerbview.js,
|
||||
* wx.js, wx-dom.js, images.tar.gz. See docs/features/demo-deploy/0001-*.
|
||||
*
|
||||
* The folder is CROSS-ORIGIN to this page (which is COEP `require-corp`); the CDN
|
||||
* sends `Cross-Origin-Resource-Policy: cross-origin` + `Access-Control-Allow-Origin: *`
|
||||
* so the <script>/fetch loads are permitted. The one thing a cross-origin base
|
||||
* breaks is the pthread worker — `new Worker(<cross-origin URL>)` is a
|
||||
* SecurityError — so `mainScriptUrlOrBlob` is a SAME-ORIGIN `blob:` worker that
|
||||
* `importScripts()` the cross-origin glue (a blob URL inherits the page origin;
|
||||
* a classic worker's importScripts is allowed cross-origin under CORP).
|
||||
*
|
||||
* Dev overrides (query string): ?base=<folder> uses that folder verbatim (e.g. a
|
||||
* local build); ?tag=<tag> pins a specific release; ?cdn=<root> swaps the CDN root.
|
||||
*/
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
// R2 bucket public URL (no trailing slash). Custom domain for the
|
||||
// pcbjam-assets bucket (the managed URL https://pub-cecc0239e6f74d99ba7d06630bd87c64.r2.dev
|
||||
// also still works).
|
||||
var R2_BASE = "https://assets.pcbjam.com";
|
||||
// Versioned WASM CDN root (no trailing slash). Overridable with ?cdn=.
|
||||
var CDN_ROOT = "https://cdn.pcbjam.com/wasm";
|
||||
|
||||
var params = new URLSearchParams(location.search);
|
||||
var isLocal = /^(localhost|127\.0\.0\.1|\[?::1\]?)$/.test(location.hostname);
|
||||
var GLUE_BASE = (params.get("glue") || "./wasm").replace(/\/+$/, "");
|
||||
var BINARY_BASE = (params.get("bin") || (isLocal ? "./wasm" : R2_BASE)).replace(
|
||||
/\/+$/,
|
||||
""
|
||||
);
|
||||
|
||||
// KiCad paths baked into the WASM build (see web/standalone/src/wasm/constants.ts).
|
||||
var KICAD_VERSION_DIR = "9.99";
|
||||
// KICAD_VERSION_DIR MUST match the deployed build's GetMajorMinorVersion() — the
|
||||
// config we seed to suppress the first-run wizard is only read from THIS dir.
|
||||
// The KiCad 10.0.x rebase bumped it from "9.99" to "10.0"; bump it here if a
|
||||
// future deploy changes KiCad's major.minor.
|
||||
var KICAD_VERSION_DIR = "10.0";
|
||||
var KICAD_CONFIG_DIR =
|
||||
"/home/kicad/.config/kicad/kicad/" + KICAD_VERSION_DIR;
|
||||
var RESOURCE_PATH =
|
||||
|
|
@ -99,49 +106,35 @@
|
|||
var mainWindow = document.getElementById("main-window");
|
||||
window.mainWindow = mainWindow;
|
||||
|
||||
// ── Prefetch the heavy, non-wasm assets in parallel with the wasm download ──
|
||||
// images.tar.gz (compiled-in KiCad resources) and the board layers. Both are
|
||||
// ~10x smaller than gerbview.wasm, so they land before preRun runs; a run
|
||||
// dependency guards the rare case where the wasm wins the race.
|
||||
var resourceData = null;
|
||||
// Served without a .gz extension on purpose (see sync-demo-wasm.sh) so no
|
||||
// server adds Content-Encoding: gzip. Written into MEMFS as images.tar.gz.
|
||||
fetch(BINARY_BASE + "/kicad-resources.bin")
|
||||
.then(function (r) {
|
||||
if (!r.ok) throw new Error("HTTP " + r.status);
|
||||
return r.arrayBuffer();
|
||||
})
|
||||
.then(function (buf) {
|
||||
resourceData = new Uint8Array(buf);
|
||||
console.log("[KICAD] prefetched images.tar.gz (" + resourceData.length + " bytes)");
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.warn("[KICAD] images.tar.gz prefetch failed:", err.message);
|
||||
// ── Resolve gerbview's versioned CDN folder from the release manifest ────────
|
||||
function fetchJson(url) {
|
||||
// manifest-*.json are served `no-store` so a rollback takes effect next load.
|
||||
return fetch(url, { cache: "no-store" }).then(function (r) {
|
||||
if (!r.ok) throw new Error("HTTP " + r.status + " for " + url);
|
||||
return r.json();
|
||||
});
|
||||
}
|
||||
|
||||
var boardData = null; // { name: Uint8Array }
|
||||
var boardPromise = Promise.all(
|
||||
BOARD_FILES.map(function (name) {
|
||||
return fetch("./board/" + name)
|
||||
.then(function (r) {
|
||||
if (!r.ok) throw new Error("HTTP " + r.status + " for " + name);
|
||||
return r.arrayBuffer();
|
||||
})
|
||||
.then(function (buf) {
|
||||
return [name, new Uint8Array(buf)];
|
||||
function resolveBase() {
|
||||
var override = params.get("base");
|
||||
if (override) return Promise.resolve(override.replace(/\/+$/, ""));
|
||||
var root = (params.get("cdn") || CDN_ROOT).replace(/\/+$/, "");
|
||||
var tagParam = params.get("tag");
|
||||
var tagP = tagParam
|
||||
? Promise.resolve(tagParam)
|
||||
: fetchJson(root + "/manifest-latest.json").then(function (m) {
|
||||
if (!m || !m.tag) throw new Error("manifest-latest.json has no tag");
|
||||
return m.tag;
|
||||
});
|
||||
})
|
||||
)
|
||||
.then(function (pairs) {
|
||||
boardData = {};
|
||||
pairs.forEach(function (p) {
|
||||
boardData[p[0]] = p[1];
|
||||
return tagP.then(function (tag) {
|
||||
return fetchJson(root + "/manifest-" + tag + ".json").then(function (m) {
|
||||
var ver = m && m.tools && m.tools.gerbview;
|
||||
if (!ver) throw new Error("no gerbview version in manifest-" + tag);
|
||||
console.log("[KICAD] gerbview " + ver + " (release " + tag + ")");
|
||||
return root + "/gerbview/" + ver;
|
||||
});
|
||||
console.log("[KICAD] prefetched " + pairs.length + " board files");
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error("[KICAD] board prefetch failed:", err.message);
|
||||
});
|
||||
}
|
||||
|
||||
// ── preRun steps ────────────────────────────────────────────────────────────
|
||||
function createCanvas() {
|
||||
|
|
@ -166,16 +159,6 @@
|
|||
console.log("[KICAD] canvas " + window.innerWidth + "x" + window.innerHeight);
|
||||
}
|
||||
|
||||
function writeResources() {
|
||||
FS.mkdirTree(RESOURCE_PATH);
|
||||
if (resourceData) {
|
||||
FS.writeFile(RESOURCE_PATH + "/images.tar.gz", resourceData);
|
||||
console.log("[KICAD] wrote images.tar.gz");
|
||||
} else {
|
||||
console.warn("[KICAD] images.tar.gz not ready at preRun");
|
||||
}
|
||||
}
|
||||
|
||||
// Suppress the first-run setup wizard (its modal loop crashes Asyncify on our
|
||||
// ephemeral MEMFS): make every settings provider report NeedsUserInput()==false.
|
||||
function seedKicadConfig() {
|
||||
|
|
@ -206,86 +189,174 @@
|
|||
console.log("[KICAD] seeded config (wizard suppressed)");
|
||||
}
|
||||
|
||||
// Write the board into MEMFS and point argv at it so gerbview auto-opens it.
|
||||
// argv must be set before main(); a run dependency keeps main() waiting if the
|
||||
// board fetch hasn't landed yet.
|
||||
function preloadBoard() {
|
||||
Module.arguments = OPEN_ARGS;
|
||||
var writeBoard = function () {
|
||||
if (!boardData) return;
|
||||
FS.mkdirTree(BOARD_DIR);
|
||||
Object.keys(boardData).forEach(function (name) {
|
||||
FS.writeFile(BOARD_DIR + "/" + name, boardData[name]);
|
||||
// Boot the tool once its CDN folder is resolved. `base` is the (cross-origin)
|
||||
// versioned folder; every asset — glue, wasm, images.tar.gz — lives under it.
|
||||
function boot(base) {
|
||||
// ── Prefetch the heavy, non-wasm assets in parallel with the wasm download ──
|
||||
// images.tar.gz (compiled-in KiCad resources) comes from the tool folder; the
|
||||
// board layers are same-origin fixtures. Both are far smaller than
|
||||
// gerbview.wasm, so they land before preRun runs; a run dependency guards the
|
||||
// rare case where the wasm wins the race.
|
||||
var resourceData = null;
|
||||
// The CDN stores images.tar.gz as raw gzip with NO Content-Encoding, so the
|
||||
// browser hands us the compressed bytes and KiCad's own gunzip succeeds.
|
||||
fetch(base + "/images.tar.gz")
|
||||
.then(function (r) {
|
||||
if (!r.ok) throw new Error("HTTP " + r.status);
|
||||
return r.arrayBuffer();
|
||||
})
|
||||
.then(function (buf) {
|
||||
resourceData = new Uint8Array(buf);
|
||||
console.log("[KICAD] prefetched images.tar.gz (" + resourceData.length + " bytes)");
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.warn("[KICAD] images.tar.gz prefetch failed:", err.message);
|
||||
});
|
||||
console.log("[KICAD] wrote board into " + BOARD_DIR + "; argv=" + OPEN_ARGS.length + " files");
|
||||
};
|
||||
if (boardData) {
|
||||
writeBoard();
|
||||
return;
|
||||
|
||||
var boardData = null; // { name: Uint8Array }
|
||||
var boardPromise = Promise.all(
|
||||
BOARD_FILES.map(function (name) {
|
||||
return fetch("./board/" + name)
|
||||
.then(function (r) {
|
||||
if (!r.ok) throw new Error("HTTP " + r.status + " for " + name);
|
||||
return r.arrayBuffer();
|
||||
})
|
||||
.then(function (buf) {
|
||||
return [name, new Uint8Array(buf)];
|
||||
});
|
||||
})
|
||||
)
|
||||
.then(function (pairs) {
|
||||
boardData = {};
|
||||
pairs.forEach(function (p) {
|
||||
boardData[p[0]] = p[1];
|
||||
});
|
||||
console.log("[KICAD] prefetched " + pairs.length + " board files");
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error("[KICAD] board prefetch failed:", err.message);
|
||||
});
|
||||
|
||||
function writeResources() {
|
||||
FS.mkdirTree(RESOURCE_PATH);
|
||||
if (resourceData) {
|
||||
FS.writeFile(RESOURCE_PATH + "/images.tar.gz", resourceData);
|
||||
console.log("[KICAD] wrote images.tar.gz");
|
||||
} else {
|
||||
console.warn("[KICAD] images.tar.gz not ready at preRun");
|
||||
}
|
||||
}
|
||||
var add = window.addRunDependency;
|
||||
var rm = window.removeRunDependency;
|
||||
if (typeof add === "function" && typeof rm === "function") {
|
||||
add("board-files");
|
||||
boardPromise.then(function () {
|
||||
|
||||
// Write the board into MEMFS and point argv at it so gerbview auto-opens it.
|
||||
// argv must be set before main(); a run dependency keeps main() waiting if the
|
||||
// board fetch hasn't landed yet.
|
||||
function preloadBoard() {
|
||||
Module.arguments = OPEN_ARGS;
|
||||
var writeBoard = function () {
|
||||
if (!boardData) return;
|
||||
FS.mkdirTree(BOARD_DIR);
|
||||
Object.keys(boardData).forEach(function (name) {
|
||||
FS.writeFile(BOARD_DIR + "/" + name, boardData[name]);
|
||||
});
|
||||
console.log("[KICAD] wrote board into " + BOARD_DIR + "; argv=" + OPEN_ARGS.length + " files");
|
||||
};
|
||||
if (boardData) {
|
||||
writeBoard();
|
||||
rm("board-files");
|
||||
});
|
||||
} else {
|
||||
// Best-effort fallback (board << wasm, so this path is unlikely to lose).
|
||||
boardPromise.then(writeBoard);
|
||||
return;
|
||||
}
|
||||
var add = window.addRunDependency;
|
||||
var rm = window.removeRunDependency;
|
||||
if (typeof add === "function" && typeof rm === "function") {
|
||||
add("board-files");
|
||||
boardPromise.then(function () {
|
||||
writeBoard();
|
||||
rm("board-files");
|
||||
});
|
||||
} else {
|
||||
// Best-effort fallback (board << wasm, so this path is unlikely to lose).
|
||||
boardPromise.then(writeBoard);
|
||||
}
|
||||
}
|
||||
|
||||
// The pthread worker "script" for Module.mainScriptUrlOrBlob. KiCad spawns
|
||||
// CLASSIC workers via `new Worker(...)`; a cross-origin URL is a SecurityError,
|
||||
// so for the CDN base we hand emscripten a SAME-ORIGIN blob worker that
|
||||
// importScripts the cross-origin glue (allowed because the CDN sends CORP).
|
||||
function pthreadWorkerScript() {
|
||||
var abs = new URL(base + "/gerbview.js", location.href);
|
||||
if (abs.origin === location.origin) return base + "/gerbview.js";
|
||||
return new Blob(["importScripts(" + JSON.stringify(abs.href) + ");"], {
|
||||
type: "text/javascript",
|
||||
});
|
||||
}
|
||||
|
||||
// ── Module config (global) ─────────────────────────────────────────────────
|
||||
var Module = {
|
||||
thisProgram: "/usr/bin/gerbview", // argv[0] for KiCad's DEBUG check
|
||||
arguments: OPEN_ARGS,
|
||||
preRun: [createCanvas, writeResources, seedKicadConfig, preloadBoard],
|
||||
postRun: [],
|
||||
print: function () {
|
||||
console.log("[KICAD_OUT] " + Array.prototype.join.call(arguments, " "));
|
||||
},
|
||||
printErr: function () {
|
||||
console.error("[KICAD_ERR] " + Array.prototype.join.call(arguments, " "));
|
||||
},
|
||||
setStatus: function (text) {
|
||||
if (text) console.log("[KICAD_STATUS] " + text);
|
||||
setStatusUI(text);
|
||||
},
|
||||
totalDependencies: 0,
|
||||
monitorRunDependencies: function (left) {
|
||||
this.totalDependencies = Math.max(this.totalDependencies, left);
|
||||
Module.setStatus(
|
||||
left
|
||||
? "Preparing… (" + (this.totalDependencies - left) + "/" + this.totalDependencies + ")"
|
||||
: "All downloads complete."
|
||||
);
|
||||
},
|
||||
onRuntimeInitialized: function () {
|
||||
console.log("[KICAD] runtime initialized");
|
||||
if (Module.canvas) Module.canvas.style.display = "block";
|
||||
hideStatus();
|
||||
},
|
||||
onAbort: function (what) {
|
||||
showError("aborted: " + (what === undefined ? "" : String(what)));
|
||||
},
|
||||
// Everything (the .wasm and the pthread worker's relative fetches) resolves
|
||||
// against the versioned CDN folder.
|
||||
locateFile: function (path) {
|
||||
return base + "/" + path;
|
||||
},
|
||||
// Pin the pthread worker: same-origin base → direct URL; cross-origin CDN →
|
||||
// a same-origin blob shim that importScripts the glue (see helper above).
|
||||
mainScriptUrlOrBlob: pthreadWorkerScript(),
|
||||
};
|
||||
window.Module = Module;
|
||||
|
||||
Module.setStatus("Downloading…");
|
||||
window.onerror = function (msg, url, line) {
|
||||
showError(msg + " @ " + url + ":" + line);
|
||||
return false;
|
||||
};
|
||||
|
||||
// ── Inject glue scripts in the required order ──────────────────────────────
|
||||
// wx.js → wx-dom.js → gerbview.js, all from the (cross-origin) CDN folder.
|
||||
loadScript(base + "/wx.js")
|
||||
.then(function () {
|
||||
return loadScript(base + "/wx-dom.js");
|
||||
})
|
||||
.then(function () {
|
||||
return loadScript(base + "/gerbview.js");
|
||||
})
|
||||
.then(function () {
|
||||
console.log("[KICAD] injected wx.js + wx-dom.js + gerbview.js (base=" + base + ")");
|
||||
})
|
||||
.catch(function (err) {
|
||||
showError(err.message);
|
||||
});
|
||||
}
|
||||
|
||||
// ── Module config (global) ───────────────────────────────────────────────────
|
||||
var Module = {
|
||||
thisProgram: "/usr/bin/gerbview", // argv[0] for KiCad's DEBUG check
|
||||
arguments: OPEN_ARGS,
|
||||
preRun: [createCanvas, writeResources, seedKicadConfig, preloadBoard],
|
||||
postRun: [],
|
||||
print: function () {
|
||||
console.log("[KICAD_OUT] " + Array.prototype.join.call(arguments, " "));
|
||||
},
|
||||
printErr: function () {
|
||||
console.error("[KICAD_ERR] " + Array.prototype.join.call(arguments, " "));
|
||||
},
|
||||
setStatus: function (text) {
|
||||
if (text) console.log("[KICAD_STATUS] " + text);
|
||||
setStatusUI(text);
|
||||
},
|
||||
totalDependencies: 0,
|
||||
monitorRunDependencies: function (left) {
|
||||
this.totalDependencies = Math.max(this.totalDependencies, left);
|
||||
Module.setStatus(
|
||||
left
|
||||
? "Preparing… (" + (this.totalDependencies - left) + "/" + this.totalDependencies + ")"
|
||||
: "All downloads complete."
|
||||
);
|
||||
},
|
||||
onRuntimeInitialized: function () {
|
||||
console.log("[KICAD] runtime initialized");
|
||||
if (Module.canvas) Module.canvas.style.display = "block";
|
||||
hideStatus();
|
||||
},
|
||||
onAbort: function (what) {
|
||||
showError("aborted: " + (what === undefined ? "" : String(what)));
|
||||
},
|
||||
// Route the .wasm to BINARY_BASE; everything else (the pthread worker) to GLUE_BASE.
|
||||
locateFile: function (path) {
|
||||
return (/\.wasm$/.test(path) ? BINARY_BASE : GLUE_BASE) + "/" + path;
|
||||
},
|
||||
// Pin the pthread worker to the same-origin glue (workers cannot be cross-origin).
|
||||
mainScriptUrlOrBlob: GLUE_BASE + "/gerbview.js",
|
||||
};
|
||||
window.Module = Module;
|
||||
|
||||
Module.setStatus("Downloading…");
|
||||
window.onerror = function (msg, url, line) {
|
||||
showError(msg + " @ " + url + ":" + line);
|
||||
return false;
|
||||
};
|
||||
|
||||
// ── Inject glue scripts in the required order ────────────────────────────────
|
||||
function loadScript(src) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var s = document.createElement("script");
|
||||
|
|
@ -298,17 +369,10 @@
|
|||
});
|
||||
}
|
||||
|
||||
loadScript(GLUE_BASE + "/wx.js")
|
||||
.then(function () {
|
||||
return loadScript(GLUE_BASE + "/wx-dom.js");
|
||||
})
|
||||
.then(function () {
|
||||
return loadScript(GLUE_BASE + "/gerbview.js");
|
||||
})
|
||||
.then(function () {
|
||||
console.log("[KICAD] injected wx.js + wx-dom.js + gerbview.js (glue=" + GLUE_BASE + ", bin=" + BINARY_BASE + ")");
|
||||
})
|
||||
setStatusUI("Resolving latest build…");
|
||||
resolveBase()
|
||||
.then(boot)
|
||||
.catch(function (err) {
|
||||
showError(err.message);
|
||||
showError("could not resolve gerbview build: " + err.message);
|
||||
});
|
||||
})();
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue