# whiteboard-render

Local sidecar for whiteboard frame mode -- see `server.js`'s own header
comment for the full "why Node, why not a headless browser" reasoning.
Not an independently deployed service: it runs as a second process
inside the main server's container (`../Dockerfile` installs Node,
`../start.sh` launches this in the background before `exec`-ing
uvicorn), reachable only at `127.0.0.1:3001` from the Python process in
that same container.

**Not runtime-tested against a real `npm install` during development**
-- this environment had no Node.js/npm available, only the npm registry
API (used to verify the dependency versions/licenses in `package.json`
actually exist and resolve). The code is written carefully against each
library's documented API (`@excalidraw/utils`'s `exportToSvg`,
`@resvg/resvg-js`'s `Resvg` class), but `docker compose build`+actually
running it is the first time this has executed end to end -- and the
first real run did in fact crash: `@excalidraw/utils`'s bundle touches
bare browser globals (`devicePixelRatio`, `location`, `matchMedia`, ...)
the same way inline `<script>` code in a real page would, not as
`window.foo` -- jsdom only puts those *on* `dom.window`, so only
copying `window`/`document`/`navigator` onto Node's `global` (the
original version of this file) left everything else undefined. Fixed
by copying jsdom's entire `window` onto `global` plus a `matchMedia`
stub (jsdom doesn't implement it at all). If another crash like this
shows up, it's almost certainly the same shape -- another bare global
the bundle expects that this file hasn't stubbed yet. One other gap
worth knowing about going in: jsdom's `<canvas>` has no real 2D
rendering context (no `node-canvas` installed), so if Excalidraw's text
measurement path depends on `canvas.getContext('2d').measureText(...)`
rather than pure SVG/font-metrics math, that could be a next thing to
watch for -- not something confirmed broken, just not yet exercised.

## Local development (if you have Node 20.19+/22.13+ installed)

```sh
cd render-service
npm install
npm start          # listens on 127.0.0.1:3001
curl -X POST http://127.0.0.1:3001/render \
  -H "Content-Type: application/json" \
  -d '{"elements": [], "width": 800}' \
  -o /tmp/test.png  # an empty scene -- just checks the service comes up and returns a valid PNG
```
