Status: canonical
Audience: engineering, product, agents
Purpose: define how to safely improve the website without changing style or behavior by accident
This website should feel hand-crafted to visitors and systematic to maintainers.
The public experience is the product. Refactors are successful only when the site looks and behaves the same, while the underlying authoring, performance, and safety rails improve.
Every meaningful change should satisfy:
| Gate | Requirement |
|---|---|
| Build | npm run build succeeds and updates generated artifacts. |
| Full check | npm run check passes. |
| Structure | npm run check:source and npm run check:structure pass. |
| Deploy surface | Firebase still serves dist/, not source folders. |
| Links | Local links resolve inside generated dist/. |
| Performance | Budgets pass or are intentionally ratcheted. |
| Behavior | Existing interaction contracts still hold. |
| Style | Design system language and visual patterns are preserved. |
Authored source:
data/*.json, except generated data/pages.json_src/pages/, _src/layouts/, and _src/partials/css/src/js/scripts/docs/images/source/ master assets used to regenerate production images/videoGenerated output:
dist/css/style.csscss/page-*.cssimages/generated/ responsive image and video derivativesdata/pages.jsonsitemap.xmlrobots.txtllms.txt.html files in dist/ generated from _src/pages/ or collection
dataDo not hand-edit generated files. If a generated file is wrong, change the
owning source file or the relevant build helper in scripts/build-site.js /
scripts/build/, then run npm run build.
Asset derivatives are generated by npm run assets:optimize, which is also
called by npm run build. Keep the source master crisp, regenerate derivatives,
and let the build copy only production-safe generated assets into dist/.
Current commit policy: commit authored source only. Ignore generated deploy
output, generated asset derivatives, remote asset caches, and generated
indexes/bundles that can be recreated from source. robots.txt may stay
tracked because it is tiny deploy metadata, but it is still generated by the
build.
npm run check:source fails if a route exists in both the repository root and
_src/pages/. data/source-ownership.json remains the contract for route
ownership, even though legacy root page source has been cleared out. One page,
one owner. npm run check:structure ratchets legacy CSS, local screenshot
artifacts, stale admin workflow notes, and the remaining admin inline-handler
budget.
Use behavior-preserving vertical slices:
The codebase now follows a clearer split between orchestration, rendering, and shared interaction primitives.
scripts/build-site.js is the build entrypoint and should stay mostly wiring.scripts/build/site-data.js owns source-data loading.scripts/build/dist.js owns final packaging into dist/.scripts/build/page-manifest.js owns route metadata and CSS bundle ownership.scripts/build/pipeline.js owns the build stage order.scripts/build/runtime-data-manifest.js owns cache-version metadata for static JSON.scripts/build/source-pages.js owns frontmatter parsing and source-page
validation.When adding build behavior, prefer a focused helper in scripts/build/ instead
of growing the entrypoint.
For larger interactive pages, prefer this shape:
Examples:
js/books.js + js/books-view.jsjs/letterboxd.js + js/letterboxd-render.jsjs/dateme.js + js/dateme-content.jsPrefer delegated data-action handlers over inline event attributes.
js/action-dispatcher.js handles click, input, and submitjs/collection-ui.js handles repeated collection behaviors like active state,
expanding/collapsing groups, clear-button visibility, sidebar persistence,
debounced inputs, and dropdown closingjs/data-fetch.js handles version-aware fetches for static JSON so browser
and CDN caching stay on while content changes still invalidate correctlyIf a new page needs interaction wiring, start with delegated actions first and only add page-local listeners where delegation is awkward or stateful.
dist/.