Personal homepage generator. Users answer a short wizard, pick a theme, and download their complete static site as a zip (index.html + style.css + assets + a hand-holding deploy README). Everything runs in the browser - the Cloudflare Worker serves static assets only, no server code, no accounts, no tracking. Photos never leave the user's device.
src/engine/- pure, DOM-free render engine (also runs in Node for tests).renderSite(data, theme)->{html, css}. Deterministic: same inputs, byte-identical output (fixed zip mtime, no clock/randomness).src/themes/- theme packs as data: onetheme.tsper theme (structural CSS string + palettes + system font stacks). Registry insrc/themes/index.ts. Every palette must pass the WCAG AA contrast test.src/app/- two bundles, no framework.main.ts->app.jsis the wizard at/make(4 steps: You / Look / Style / Download; draft in localStorage; zip built client-side with fflate).landing.ts->landing.jsis the shop window at/, which renders every theme live from the same engine.src/static/- page shells, copied verbatim todist/.index.html= the landing at/,make.html= the builder at/make(Workers Assets resolves the extensionless path). The landing forwards any fragment that is not one of its own anchors to/make, so pre-landing share links (/#s=...) and the theme workbench (/#gallery) keep working.
npm test # vitest: snapshots, escaping, zip contents, determinism, palette contrast
npm run typecheck
npm run build # esbuild -> dist/
npm run dev # esbuild watch + serve on :8787 (static copies not watched)
npm run sample # render the full.json fixture to stdout (--out DIR writes files)
npm run deploy # local/operator testing only; production deploys from merged main
src/themes/<id>/theme.tsexporting aThemePack(copy slate as the pattern).- Register it in
src/themes/index.ts. npm test- snapshots for the new theme are created, contrast test must pass.- Eyeball every palette at
/#gallery(theme workbench, renders the full fixture in all combinations).
Assets-only worker (wrangler.toml has no main). Production deploys main to
pageforge.mtclab.net via deploy-production.yml; smoke uses workers.dev and
/version must report the deployed commit.