Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

#37

Celebrate a landed change request with a confetti burst

merged · by keenan 13d ago · merged into main at c8fa5759 by keenan 13d ago

keenan opened this 13d ago

Landing a change request is the payoff for the review loop, and until now the page it landed on looked exactly like any other view.

A successful landing redirects with ?merged=1. static/app.js reads that parameter once, removes it with replaceState, fetches static/confetti.browser.js, and fires a single burst. Nothing else loads the library: a reload, a bookmark, a shared link, or any other page is unchanged and pays nothing.

Where it departs from the issue

The issue estimated 10.8 KB from the minified file on the jsDelivr CDN. That file is generated by the CDN, not published upstream. The 1.9.3 npm tarball contains only dist/confetti.browser.js, so the vendored asset is 24.9 KB raw / 6.9 KB gzipped, byte-for-byte from the tarball whose sha512 matches the registry’s dist.integrity (sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g==). Minifying it ourselves would make the committed bytes depend on a tool that is not in the repository, so the honest artifact wins.

That size is acceptable only because of the lazy load. Static() serves through http.FileServerFS with no gzip middleware, so a script in the page shell would cost every page load 24.9 KB; on the landing redirect it costs one reader, once.

Changes

  • static/confetti.browser.js and static/canvas-confetti.LICENSE: vendored like htmx and Lucide, so script-src 'self' is untouched. useWorker is left off, so no blob: worker is created and default-src needs no relaxation.
  • writes.go: the merge redirect carries ?merged=1. Refusal paths, including the HTMX fragment reply, are unchanged.
  • static/app.js: the reader of the parameter. disableForReducedMotion: true and reset() before firing, so a reduced-motion visitor gets the same page with no animation and a back/forward-cache restore cannot stack canvases.
  • templates.go and docs/ui-plan.md: record why one asset is fetched on demand when nothing else is.
  • Tests: the merge redirect and the merged page behind it; the asset is served from the binary, app.js names it once, and no shell page mentions it.

Closes #01M5XZ7T4R88BA9KV1KTSV7ZXP

Discussion (0)

No discussion yet.