feat: ✨ lazily-loaded Gerber viewer demo in the blog, served from R2

Embed KiCad's gerbview WASM in the graphics-to-WebGL blog post as a
click-to-load demo that opens the tiny_tapeout board entirely in-browser.

- GerberDemo.astro: lazy iframe embed + cross-origin-isolation reload guard
  + WebGL2/SharedArrayBuffer feature-detect with a poster fallback
- public/gerber-demo/{index.html,boot.js}: self-contained gerbview boot
  harness (config seed, MEMFS board preload, argv auto-open)
- board/ tiny_tapeout layers + poster.png committed; wasm/ glue JS committed
  (served same-origin — pthread worker can't be cross-origin), while
  gerbview.wasm + kicad-resources.bin are git-ignored and served from
  Cloudflare R2 (assets.pcbjam.com)
- COOP/COEP require-corp scoped to the post + /gerber-demo routes
  (dev: astro.config.mjs + middleware.ts; prod: vercel.json)
- post converted to MDX (@astrojs/mdx) so it can embed the component
- scripts/: sync-demo-wasm.sh, r2-deploy.sh, r2-cors.json

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Viktor Vaczi 2026-06-17 10:28:06 +02:00
commit 57f1f53d26
36 changed files with 242845 additions and 9 deletions

View file

@ -0,0 +1,38 @@
# Gerber viewer blog 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.
## 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. |
| `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`. |
## 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 />`. |
| `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. |
## Run / update
```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
# after a new gerbview build: refresh local mirror, then push binaries to R2
scripts/sync-demo-wasm.sh && scripts/r2-deploy.sh
```
The live viewer needs SharedArrayBuffer + WebGL2 (Chrome/Edge/Firefox, Safari 15.2+);
other browsers get `poster.png`.