colophon
updated
folder layout01
./vault/ using a fine-grained PAT.┌ vault (private · obsidian) ├── daily │ └── YYYY-MM-DD.md # notebook · one ##HH:MM = one short note ├── notes # publish: journal | making → routed below │ ├── *.md # loose notes (publish: journal lives here) │ ├── making # convention bucket │ ├── dev # engineering posts │ └── ideas # never published (no publish: key) ├── attachments # images / audio / video └── .obsidian/ # ignored ┌ mattdoes-site (public) ├── build.js # the generator entrypoint ├── lib # intake (vault → model) · emit (model → dist) · listening · lastfm codec ├── design-system # @mattdoes/ds — React page components · renders every page · syncs to Claude Design · ships the timeline island ├── site.config.js # identity + last.fm ├── templates # shared row renderers · helpers · asset registry ├── static # css, js (tweaks · geo-bg · live), fonts, baked geojson, _headers ├── scripts # prebuild, optimize-media, sync-media, bake-geo ├── workers # listening · geo · csp-report · lib (shared edge transport) ├── vault → cloned pre-build └── dist # deployed
frontmatter schema02
publish: is the only required field.| key | type | req | description |
|---|---|---|---|
| publish | enum | req | journal · making · thoughts · about · draft (listening is pulled from last.fm) |
| title | string | opt | Display title. Defaults to filename. |
| date | date | opt | Bare YYYY-MM-DD is anchored to CT midnight (so the post lands on the day you wrote, not UTC's). Full ISO timestamps are used as-is. Defaults to file mtime. |
| slug | string | opt | URL path segment. Defaults to kebab filename. |
| tags | [string] | opt | Render as #tag. Drives filter rows. |
| summary | string | opt | One-sentence lede. Shown in index + RSS. |
| updated | date | opt | Last meaningful edit. |
| aliases | [string] | opt | Extra wikilink targets. |
routing · publish → url03
publish: frontmatter value, not the folder. Folders are organizational only.wikilinks & embeds04
[[some-slug]]— resolves to published page; else renders as plain text with a dotted underline.[[some-slug|custom label]]— aliased label.![[image.png]]— image embed. Served from R2 in production.![[clip.mp3]]— renders as native <audio>.[[#some heading]]— intra-page anchor. Rare.
the build05
One pass, deep projections. Intake turns notes into the content model — frontmatter validation, Thought splitting with source-day provenance, stable IDs, and the slug index. Emit renders markdown, then derives Notebook days, cross-kind Topic paths, and the editorial home projection before writing React-rendered static pages, hashed assets, search, and feeds. The only client-side React is the filter/density island on exhaustive archive timelines; the homepage, Notebook, and Topic paths ship as plain HTML with no hydration. Each long-form post also gets a build-time Open Graph card, and /search-index.json backs the client-filtered search page.
Two dynamic surfaces, both same-origin Workers; connect-src 'self' holds. On /api/listening/* a single-writer Durable Object — the ListeningPoller — is the only thing that calls Last.fm: a self-rescheduling ~25s alarm makes one user.getrecenttracks call, derives both the now-playing pill and the recent-tracks list from it, and writes them to KV; a cron watchdog re-arms the alarm if it ever stops. The request path just reads KV and serves — it never calls Last.fm and never blocks, so upstream volume is constant whatever the traffic. /api/geo/lookup reverse-geocodes a visitor's coords against Nominatim if they opt in via the tweaks panel — by default the animated background renders the home polygon baked into static/home.geojson, no prompt, no network call. Every Worker answers through one shared envelope (workers/lib/transport.js) — JSON + CORS, preflight, cached error responses — with caching policy kept per-Worker.
Media takes the long way around. scripts/optimize-media.js hashes every attachment and emits .webp siblings into .cache/media-build/; scripts/sync-media.js PUTs originals + variants to R2 over wrangler r2 object, and the build emits <picture> tags pointed at media.mattdoes.online. CSS and JS are content-hashed and served immutable from Pages; the CSP is strict — no third-party connect and no 'unsafe-inline' anywhere. The few inline <head> scripts the document shell emits — the importmap and the speculation rules that prerender same-origin links — are admitted by a per-build sha256 in script-src, recomputed each build so the hashes track the content-hashed module URLs. style-src stays 'self' too (Shiki's per-token colors are de-duplicated into build-time CSS classes rather than inline styles). A Report-Only policy mirrors the enforced one to a same-origin /api/csp-report sink, so the next tightening is measured against real traffic first. Mail is Fastmail, contact is a plain mailto:, no form worker.
build snapshot
- notes read
- 11
- pages written
- 8
- build time
- 2.2s
- dist size
- 1134 KB