Print generic datasheets - every option a unit could take, the way the
official cards read - instead of a record of one particular list.
The three Python scripts that used to rewrite the .ros file before upload
are now transforms in src/transforms/, running in the browser between
DOMParser and the roster parser. Most of each script was machinery for
preserving the file byte for byte on the way back to disk; in the browser
the document is never serialised, so only the domain logic came across.
Because they run on the parsed document rather than the uploaded file,
flipping a transform off rebuilds from the original XML with no
re-upload. Saved rosters therefore hold the raw roster XML rather than
the parsed object, under new localStorage keys.
The scripts' output over four 11th-edition rosters is checked in as test
fixtures, so the port is measured against an independent implementation
that was verified by printing the cards; scripts/update-fixtures.mjs
refuses to overwrite those without --force.
Two parser call sites now use :scope> rather than repeating the scope
element's own name, which means the same thing in a browser and also
works under jsdom, where the old form matched nothing.
Also: served at the root rather than a GitHub Pages subpath, PostHog
analytics removed, and deploy/ carries an nginx site for
scribe.luxick.de plus an rsync deploy script.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>