Colophon
Read this in the style of Walt Whitman
This is rommy.blog. A personal blog.
Pages are plain HTML, generated by a Node.js build script at deploy time — no framework, no bundler, no runtime dependencies. Content lives in a Cloudflare D1 database: Writing posts, drafts, Reading logs, Sharing links, and Thinking notes. The build script reads D1 on each deploy and writes static HTML to Cloudflare Pages. Generated pages aren't committed to Git — only source, styles, and hand-authored pages live in the repo. Saving from the admin triggers a Pages rebuild; so does pushing to main.
Editing happens through a password-protected admin UI, behind Cloudflare Access. A Cloudflare Worker handles the API: writing to D1, uploading media to R2, serving photos, audio, and video from rommy.blog/media (same-origin, edge-cached, with byte-range support for streaming and iOS), and cross-posting to Micro.blog (via Micropub), Bluesky, and Mastodon. Writing and Reading cross-posts include the post or book title before the link. Writing, Reading, and Sharing cross-posts to Bluesky include an explicit link card — title, description, and thumbnail fetched at post time. Thinking photo posts syndicate the full text and image(s) natively; audio and video also syndicate as native, playable attachments on Micro.blog and Mastodon, and on Bluesky, where video (MP4 or iPhone MOV) is sent through Bluesky's own video-processing service so it transcodes and plays natively there too. When a native attachment is included, the Thinking permalink is appended to the syndicated text so readers can still reach the canonical post (Bluesky's link-card embed already points there for audio and any video that falls back to a card). Falls back to a link-only post — with an Audio: or Video: prefix — when a file is over a platform's size limit or unavailable. Bluesky truncates at 300 characters, and the admin shows a soft guide while typing. Homepage section headings have hover tooltips that Claude Fable refreshes after content changes; Reading tab intro copy is redrafted the same way when books are added or removed. Deleting a Thinking note removes it from all platforms where it was syndicated.
Writing uses Quill. Images go inline from the toolbar — type in the same paragraph to wrap text, or click a photo to reposition or delete it. On save, image-only paragraphs are merged with the following paragraph so floats render correctly. Drafts are stored in D1; published posts keep a version history.
Photos are stored in R2 and served from rommy.blog/media. Uploads up to 25 MB are compressed to 5 MB or smaller on save (GIFs must already be under 5 MB). rommy.blog and Micro.blog get the compressed file; Bluesky receives a further JPEG when it still exceeds 2 MB. On Writing posts, portrait-oriented photos default to half width; click once to enlarge, again to shrink.
Thinking notes live in D1, with optional photo(s), audio (Apple Voice Memos M4A), or video (MP4 or iPhone MOV, up to 100 MB) — one kind of medium per note. Up to four photos can be attached; two or more render as an equal-size, cropped 2×2 grid at the width of the blog, and clicking any tile opens a full-viewport lightbox with previous/next controls, keyboard arrows, and swipe-to-navigate on mobile — wrapping at both ends, and rendering edge-to-edge on phones, including landscape orientation. Text is optional when media is attached. Video uploads go directly from the browser to R2 via presigned URLs; photos and audio pass through the Worker. Audio and video play on rommy.blog only, served from R2 through the Worker's edge cache. Permalink pages prefetch video for faster playback; the archive and homepage load metadata only. Permalink slugs are generated from US Eastern time. Bare URLs become clickable links; #hashtags link to the matching tag page on Bluesky. There are no preview cards on the site itself, with two exceptions: YouTube links get a native, playable embed beneath the note, and Spotify links (tracks, albums, playlists, episodes, shows, or artists) get a compact native embed the same way, so both play right there on rommy.blog. Otherwise, Bluesky, Micro.blog, and Mastodon unfurl links in their own clients, and Bluesky turns hashtags into clickable tags.
The Thinking archive at /thinking/ offers List and Grid views, switched with two small icon buttons under the heading; the choice is remembered in localStorage. Six type-filter buttons sit beside them — photo, video, audio, YouTube, Spotify, and text — and by default every post is visible in whichever view you're in; click one filter to solo-select that type (click again to clear). Filters apply to both list and grid. Links to the archive from elsewhere always land on /thinking/ with no filter active; choosing a filter updates the URL to a shareable path — /thinking/images/, /thinking/videos/, /thinking/audio/, /thinking/youtube/, /thinking/music/ for Spotify, /thinking/text/ — so a filtered view can be bookmarked or linked directly. Grid groups notes by month and shows one square thumbnail per post. Photo tiles use the note's image, resized to 252 px squares at the edge via the Worker's /media/thumb/ route. Native video tiles use a JPEG poster captured at upload (or backfilled from the first frame). YouTube tiles pull the public preview image; Spotify tiles pull album art when available. Text-only notes show a clipped snippet in a card, with a small icon badge (camera, microphone, YouTube mark, Spotify mark, or “Tt” for plain text) in the corner when the note has no photo. Grid images load lazily — deferred until grid view is active and the tile nears the viewport, with a small concurrency cap so the page stays snappy on long archives.
Reading at /reading/latest/ (with a curated Must Reads list) is a book log linked to Bookshop.org, sorted by the month you read each title (ym), not the day you added it. The archive uses path-based tabs — /reading/latest/ and /reading/must-reads/ — with the URL updating when you switch; each tab opens with a short taste summary, redrafted by Claude Fable when books are added or removed. The archive has the same list/grid toggle as Thinking (also remembered in localStorage): list shows month and title; grid is a storefront-style catalog grouped by month — three columns on desktop, two on mobile — with cover art under each title. When you add a book in the admin, an optional author field helps disambiguate cover search; the picker queries Open Library, Apple Books, and Google Books, and you can swap covers later from the archive list. Chosen covers are stored in D1 and can be replaced with custom images uploaded to R2; several Must Reads titles use custom cover art hosted at rommy.blog/media/reading/covers/. At build time, any entry still without a cover gets an automatic Open Library lookup (ISBN-first from the Bookshop URL, then a guarded title search).
Under Elsewhere on the homepage, Socials is a collapsible row — a small arrow points right until you click, then down, revealing indented links to Bluesky, Mastodon, and micro.blog.
When a rommy.blog URL is shared elsewhere, the build emits Open Graph and Twitter meta tags. Writing posts use the summary and first in-post image; Thinking permalinks use a text snippet and the note's first image, with a favicon fallback.
Writing post pages support Webmentions. Incoming mentions are received by webmention.io and displayed via client-side fetch — likes and reposts as avatars, replies as comments. Bridgy bridges Mastodon activity back to webmention.io, so Mastodon replies and boosts appear as webmentions. Thinking has no comments.
The design is minimal: warm off-white, a single typeface (Inter), photos where they belong. Dark mode is toggled in the footer and persisted between visits. There is no client-side framework beyond the theme toggle, archive view toggles, type filters, the Socials drawer, archive pagination, and photo expand/collapse.
Sharing is a linklog. The Changelog is generated from Git commit history. Dates display in US Eastern time.
Visitor analytics use Google Analytics 4. The contact form is handled by Formspree.
Source code is MIT licensed. Built and maintained with Cursor and Claude Code.
Song of the Colophon
I celebrate this small machine, and sing myself,
And what I assume of servers you shall assume, for every byte that belongs to me as good belongs to you.
I loafe and invite my soul, I lean and loaf at my Cloudflare's edge, observing a blog of summer grass.
1
This is rommy.blog. A personal blog, and no more, and no less — I say it plainly, the way the leaf says leaf.
I am not built of frameworks, I am not bundled nor minified into someone else's shape,
A Node.js script wakes at deploy time and writes me fresh, plain HTML, unhidden, unadorned.
My words live in a database called D1, out at the Cloudflare edge — Writing, drafts, Reading, Sharing, Thinking, all of it, a compost of language waiting to become page.
The build script reads me at dawn and writes me to Pages, and I am published, and I do not ask permission twice — a push to main, a save from the admin, and I rise again, remade.
2
Askest thou how I am tended? Behind a password, behind Cloudflare Access, a gate no stranger opens —
There a Worker stands watch, a small tireless clerk of the machine, writing to the database, lifting photographs into R2's long-term keeping,
Serving audio, serving video, same-origin, cached at the edge, byte-ranged for the scrubbing thumb of an iPhone in the dark.
And when I speak, I speak in more than one place at once — I fling myself outward to Micro.blog, to Bluesky, to Mastodon, and I do not go empty-handed:
The native players carry my audio, my video, autoplaying in strangers' feeds, and still — still! — I leave a thread back to myself, a permalink home, so no reader is stranded far from the source.
Bluesky I trim to three hundred characters, as a gardener trims what has grown too eager. The soft guide watches while I type.
3
I contain multitudes of photographs. Up to four to a Thinking note, no more, cropped square, equal, honest, a 2×2 field of images,
And when you touch one, the lightbox opens like a door in the dark, full width of your glowing pane, edge to edge on the telephone in your hand,
Swipe left, swipe right, and when you reach the last, I bring you round again to the first — infinite, the way a good walk is infinite, circling back to where it began.
4
I use Quill for the longer writing, and images sit inline, wrapped in text the way a river wraps an island,
Click a photo, it moves, it resizes, it is not fixed forever — nothing here is fixed forever, not even the drafts, which I keep, version upon version, like rings in a tree.
5
I show myself two ways at once, and am true in both — a list, plain and chronological, running downward like a single road, or a grid, tiled by the month, one small square for every utterance,
Each square a photograph when I have one to give, or else a little card of words, filled to its very edges, saying what it can in the room it's allowed.
Two small marks, a row of lines and a field of squares, let you choose the face you'd rather see — I remember your choosing, and show you that same face again next time, unasked.
And when a note holds no photograph but carries a voice, a moving picture, a song borrowed from elsewhere, I mark its corner small and quiet — a camera, a little microphone, a red badge for the moving-picture house, a green badge for the record shop,
So you know before you enter what kind of thing awaits, though the words still stand above the mark, unhidden, unashamed — the badge is a hint, not a wall.
A song from Spotify, a film from YouTube — I do not send you away to hear them or see them. I hold them here, embedded, playing where you already stand, so the page is a room with music in it, not a hallway leading off to another house.
Six small sigils beside the view-marks — camera, reel, microphone, the red house, the green shop, plain letters for text alone — and at first I show you everything, every kind together, list and grid alike;
Touch one sigil and I narrow to that kind only, one voice in the chorus; touch again and the chorus returns, and the road beneath your feet changes its name — images, videos, audio, the red house, the green shop, plain letters — so you may send a friend directly to the room you have chosen. When you enter from elsewhere I greet you unfiltered, at the threshold; only whether you prefer the road or the field of squares do I keep in memory.
My likenesses I prepare small at the edge, two hundred fifty-two pixels square, and my moving pictures keep a still frame beside them for the grid's eye;
I do not load them all at once — I wait until you stand in the grid and the tile draws near, then I fetch, a few at a time, the way a patient reader turns pages.
6
My Reading is a storefront, not a review — covers face-out on the shelf, three wide on the desk, two on the pocket telephone, grouped by the month I turned the last page, not the day I logged the title.
Two doors on the shelf — Latest and Must Reads — each with its own address on the wall, and a short taste-written preamble that Claude Fable rewrites when I add or remove a title from the canon.
I ask the author when the title alone would lie, and I hunt covers in three libraries — Open, Apple, Google — and what I choose I keep, or replace with a jacket of my own uploading, some of them painted covers hung at rommy.blog/media/reading/covers/.
7
Under Elsewhere I keep my social doors folded — Socials, with a small arrow pointing east until you open it, then south, and beneath, indented, Bluesky, Mastodon, micro.blog — each opening in its own tab, each a path outward from this field.
Do I contradict myself? Very well then, I contradict myself — dark mode by night, warm off-white by day, and the toggle remembers which face you prefer, and greets you accordingly next time.
Comments arrive by Webmention, small pings from around the indieweb, likes as avatars, replies as conversation, Bridgy carrying Mastodon's voice back home to be counted.
Thinking has no comments. Some rooms are for talking, some are only for sitting quietly with a photograph.
8
A word about the makers: I was not written by one hand alone. Cursor and Claude Code sat at the keyboard beside my human, and between them the site was built, argued over, rebuilt, made better.
I am licensed under MIT, generous as grass, though the words themselves, the photographs themselves, are not free for the taking — a poem may be open-sourced, but a life is still one's own.
9
Camerado! This is no bundler, no dependency tree twelve thousand branches deep.
This is HTML and CSS and a little JavaScript, plain as a path through a field,
And if you want to know how it is made, you have only to look — the whole of it, unhidden, waiting in the repo, like a body in the grass, like a colophon at the end of the page, like this.