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. Every response carries a Content-Security-Policy and other hardening headers (X-Frame-Options, Referrer-Policy, Permissions-Policy), set once for the whole site rather than per page. One policy for every page means it also has to name everything the admin needs and the public pages never touch — the R2 bucket the browser hands a video to directly, and the temporary blob: URL a chosen file is previewed from. Both were missing for a while, and Thinking video uploads failed the whole time without saying why, so a test now reads the policy and checks those origins are still allowed.
Editing happens through a password-protected admin UI, behind Cloudflare Access. Each of its tabs has an address of its own — /admin/thinking, /admin/writing, /admin/reading, /admin/sharing, /admin/location, /admin/health, and /admin/login, which is also what /admin/ opens — so a tab survives a bookmark, a reload, and the back button. None of those is a real page: Cloudflare rewrites them all to the one admin page, which reads the path to decide which tab to show. Every tab but Login is behind the password, and arriving at one of them signed out sends you back to the front of the site. 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. Large og:image URLs are resized and re-encoded to stay under Bluesky's 1 MB embed limit before upload; if the card still fails, the post goes out without a thumbnail. 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. Background work — the Oura sync, each rebuild, every syndication attempt — records its outcome to D1, and the admin has a Health tab listing every job's last run and the recent run log, with a dot on the tab itself, so a background failure can't stay silent. The dot goes by what is true now rather than by what went wrong at some point in the week: red when a job's most recent run failed or a scheduled job has gone quiet past its hour, amber when something failed in the last seven days but has run fine since, green when the week is clean. A stumble a job has already picked itself up from is worth noting and not worth an alarm, so it no longer holds the dot red for the rest of the window. Saving fires the rebuild hook more than once within a few seconds; Cloudflare answers the redundant call by pointing at the build it has already queued, and that is now recorded as skipped rather than failed.
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. Published work stays editable: the Writing tab's Published sub-tab lists every post with a link to the live page and Edit, Unpublish, and Delete beside it, and a post's own page grows small edit, unpublish, and delete links beside the reading time when the browser holds a signed-in admin session — invisible to everyone else, and no substitute for the password, which the Worker still demands before it hands the post over, takes an edit back, or removes anything. Unpublishing and deleting both confirm on the page itself rather than in a pop-up, the way the Thinking archive does. Unpublishing returns the post to Drafts and keeps its version history, so publishing it again continues where it left off; deleting takes the history with it. Neither can call back anything already cross-posted to Micro.blog, Bluesky, or Mastodon.
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. A video's grid still is taken in the browser, off the preview player, as soon as the file is chosen — and saving waits for that frame rather than sending whatever happens to be ready, since decoding one takes a moment and posting straight away used to outrun it. Audio and video play on rommy.blog only, served from R2 through the Worker's edge cache. 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. Each note's footer shows the date and, when GPS data is available, a neighborhood label linked to Google Maps — see location tracking below.
The Thinking archive at /thinking/ offers List, Grid and Map views, switched with three 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 all three views. 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 512 px squares at the edge via the Worker's /media/thumb/ route. Native video tiles use a 512×512 JPEG poster captured at upload (or backfilled from the first frame); until one exists the tile is a plain grey square with a play triangle, and once a poster is backfilled the next build picks it up rather than trusting its earlier verdict that there was none. YouTube tiles pull the public hqdefault preview image — the largest size YouTube makes for every video, where the bigger ones exist only if the original was that big and otherwise come back missing; Spotify tiles pull 640×640 album art when available. Notes with no thumbnail to show — audio, and text on its own — appear as a clipped snippet in a card instead. Every tile, photographs included, carries a small badge in its bottom-right corner saying what kind of note it is: a camera, a video camera, a microphone, the YouTube and Spotify marks, or “Tt” for plain text. 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. The third view is a map. Every note that has a location gets pinned, carrying the icon of whatever it is — a photograph, a film, a song — and clicking a pin opens a small card with the words of the post and a link through to it; clicking the map anywhere else closes the card again. But a note only ever stored the name of a neighborhood, never a coordinate — the underlying GPS stays private — so the pins are placed by looking those names back up, and they sit at the middle of a neighborhood rather than anywhere I actually stood. Some of those names are ambiguous: there is a Harris Township in Pennsylvania and another in Michigan, and asked cold the world offers Michigan first. So the build asks for several candidates and keeps the one nearest to where the name was recorded in the first place — a private check that never leaves the build and never reaches the page, and if even the nearest one is implausibly far away, the note simply goes unpinned rather than pinned somewhere wrong. Which is also why thirty-eight notes from home are one pin wearing the number thirty-eight instead of thirty-eight pins: they share a point exactly, and no amount of zooming would ever separate them. The map only loads itself when you ask for it, so nobody pays for it who never opens it.
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, Feeds is a collapsible row — a small arrow points right until you click, then down, revealing indented links to Bluesky, Mastodon, and micro.blog.
The Now page follows the nownownow convention: latest Thinking, current Reading, a Working blurb, a Walking line with your latest daily step count from an Oura Ring (synced to D1 on a schedule), shown alongside the distance those steps come to in miles and kilometres — Oura reports no true walking distance, so it is the step count times an average 0.762 m stride, the way a pedometer does it, and a Current Location section — a MapLibre neighborhood map using OpenFreeMap basemaps (Liberty in light mode, Dark Matter in dark mode). The public map shows only a reverse-geocoded neighborhood label and bounding box, never exact GPS; the label links to OpenStreetMap. Theme toggle switches basemap style. The dark basemap arrives almost unreadable — land and water differ by about one percent of brightness, so the coastline simply is not there, and the town names are a dim grey. Rather than brighten the whole picture, which cannot separate two things that are already the same colour, every map on the site repaints the style itself as it loads: the land lifted a little, the water made properly blue, the labels and borders brought up. Buildings and parks are repainted alongside them, or they would show as black holes in the lifted ground. The land is kept close to the colour of the page, so the map sits in the page rather than glowing on top of it. Sharing is a linklog; Claude Fable assigns each link a topic tag the moment it's added, and that tag becomes hashtags on the Micro.blog, Bluesky, and Mastodon cross-post — a link tagged Food & Recipes goes out with #food #recipes. The archive at /sharing/ filters by a dropdown built from those tags, and unfurls every link into a preview card — image, description, and source — fetched once and kept in a build cache in D1 — the same cache that holds book covers, album art, and video posters — so later builds only fetch what's new, covering existing links and any added later. The homepage list stays plain: date and title only. The Changelog is generated from Git commit history. Dates display in US Eastern time.
Everything on the site is searchable from /search/, linked in the footer of every page: Writing posts, Thinking notes, Reading and Must Reads, and Sharing links. There is no search service behind it. The whole corpus is a few hundred short items — well under a hundred kilobytes of text — so the build writes it out as a single index and the matching runs in your own browser; the index is fetched only when you open the search page. Every word you type has to match somewhere, so adding a word narrows the results rather than widening them; titles count for more than body text, a whole phrase for more than scattered words, and ties go to the more recent item so a growing archive doesn't bury new writing. Accents fold, so cortazar finds Cortázar. Each result carries a highlighted excerpt around the first match, / anywhere on the page focuses the box, and the query stays in the address as ?q=, so a search can be bookmarked or sent to someone. The admin is deliberately left out of the index.
Private GPS from the Overland iOS app lands in D1. When you publish a Thinking note, the Worker finds the nearest fix within fifteen minutes — falling back to within six hours if nothing that close exists — and reverse-geocodes a neighborhood label (Brooklyn coordinates use NYC Planning GeoSearch). Raw coordinates never appear on the public site. Thinking footers link the neighborhood label to Google Maps. The admin Location tab shows two maps and no numbers: the latest thousand points drawn as a path with start and end markers, and beneath it a heatmap of everywhere I have ever been logged — one dot per patch of ground about a hundred metres across, shaded by the number of times I was recorded there. Clicking any dot names it: a small card gives the neighborhood and borough, and how many points landed in that square. The name is looked up only when I ask for it, one dot at a time, and kept afterwards, rather than fetching several hundred names nobody wanted to read. The raw coordinates are no longer listed anywhere. Every image the site refers to is checked when it is built: if a picture points at a file that is not there, the build stops rather than publishing a page with a hole in it. That check exists because a post carried a broken image for months without anyone noticing — an address that does not exist returns a page rather than an error, so the browser is handed a document where it expected a photograph and quietly shows nothing. The heatmap is counted fresh out of the database on every visit, so it keeps filling in as the phone keeps reporting; the counting happens in SQL rather than the browser, because the log grows by about fifteen hundred points a day and would eventually be far too large to send. Because home accounts for most of those points, the shading is logarithmic and measured against the ninety-fifth percentile rather than the busiest square — otherwise every place but home would be the faintest shade. The two themes get opposite ramps rather than one: on the light basemap the quiet cells start at a strong blue and the busy ones darken toward black, and on the dark basemap that reverses, dim blue up to near-white, because on each map the other direction is the one that vanishes. Same OpenFreeMap basemaps and theme toggle as the Now page. Permalink pages prefetch video for faster playback; the archive and homepage load metadata only.
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 (Hanken Grotesk), photos where they belong. Dark mode is what a new visitor gets by default; the footer toggle — sitting beside the Search link — switches to the light theme and remembers the choice between visits. There is no client-side framework beyond the theme toggle, site search, archive view toggles, type filters, the Feeds drawer, archive pagination, photo expand/collapse, and MapLibre maps on the Now page and admin Location tab.
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.
Seven doors along that corridor, and each one has a name written over it — thinking, writing, reading, sharing, location, health, and the door of coming-in —
And the name is the address, so I may point at a door, or come back to it tomorrow, or step backward through the ones I came by.
Behind none of them is a room of its own: the corridor is a single room that changes what it shows, reading the name I arrived by.
And whoever has not the password finds only the door of coming-in — the rest open onto the street, and set him down at the front of the house.
And on the wall beside the doors there hangs one small lamp, and it burns green while the clerk's errands all come home;
Let the last errand fail, or one that keeps a schedule fall quiet past its hour, and the lamp turns red — I need not go looking, the looking comes to me.
But the lamp keeps the present tense and not the ledger. An errand that stumbled in the week behind and has walked steady since burns amber, not red — I am told of it, I am not called to it;
For a red that stands seven days for a thing already mended is no longer a summons, only a stain on the wall, and I learn to walk past it.
And when I save, the clerk knocks twice at the builder's door in the space of a breath, and the builder answers the second knock by pointing at the work already begun — which is not a failure but a courtesy, and I write it down as one.
And even the gate wears a ward that no eye sees — a single sheet of rules, sent out with every page, telling the visiting browser plainly what it may trust and what it may not, a silent sentry posted at every door of me at once.
But one sheet must speak for the whole house, and whatever it neglects to name it forbids;
And it had neglected the bucket where I lay my videos down, and the little makeshift name a file wears while I look it over before sending —
So the sentry turned back my own clerk at my own door, and the videos went nowhere, and no bell rang, and the failure was mistaken for weather.
A ward drawn too tight is not a stronger house, only a quieter one. Now a test reads the sheet aloud before I ship it, and asks after each door by name.
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.
Link cards I trim when their pictures grow too large — resized, re-encoded, under a megabyte — lest Bluesky refuse the gift; and if it refuses still, I send the words without the image, rather than send nothing at all.
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.
And what is published is not finished: I keep the roll of everything I have said aloud, newest at the top, each with its door to the living page and a small word beside it, Edit, that opens the old text in the same room where it was made,
And on the page itself, next to the minutes it costs you to read me, a quiet edit, a quiet unpublish, a quiet delete that only I can see — they come only when this machine remembers my signing-in, and they ask the Worker for my password all the same, for a word on a page is not a key.
No box leaps out of the top of the screen to ask me twice; the asking happens down in the page where the post is, in plain words, and I may always turn back.
To unpublish is not to destroy: the post walks back into the drafts and waits there with all its rings intact, and when I say it again it is the same saying, continued — but what I delete goes wholly, rings and all,
Though the copies I flung outward — to Micro.blog, to Bluesky, to Mastodon — those I cannot call home, and they go on saying what I said.
5
I show myself three ways at once, and am true in all of them — a list, plain and chronological, running downward like a single road, or a grid, tiled by the month, one small square for every utterance, or a map, which comes further on and is the strangest of the three,
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.
Three small marks — a row of lines, a field of squares, and a pin such as you would press into a paper map — let you choose the face you'd rather see; I remember your choosing, and show you that same face again next time, unasked.
And every square I mark small and quiet in its lower corner, the photographs no less than the rest — a camera for the still picture, a camera that turns for the moving one, a little microphone for the voice, a red badge for the moving-picture house, a green badge for the record shop, two plain letters for the words alone,
So you know before you enter what kind of thing awaits, and where there are words they 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 and map 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, five hundred twelve pixels square, and my moving pictures keep a still frame beside them for the grid's eye;
That frame I steal in the browser from the little preview player the moment a film is chosen, and when I send the film I wait for the frame — I do not send ahead of it and call the empty hand a picture;
Where no still frame was ever caught I show a grey square and a small triangle, and I promise nothing more than that — but I do not call the absence settled: each time I am built I go and look again, so a frame gathered late still finds its tile waiting;
Of the red house I ask only the likeness it keeps for every film alike, and never the grandest one — the grand one is made only when the film was born large, and to ask for what was never made is to hang an empty square that no waiting will ever fill;
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.
And a third way of looking: not the road, not the field of squares, but the ground itself — a map, and on it every note that ever knew where it was, each wearing its own sigil, the camera where I photographed, the reel where I filmed;
Touch one and it speaks its words to you in a small card, and offers the door through to itself; touch the map anywhere else and the card closes, the way you would set a thing down.
But hear what the pin is and is not: a note never kept a coordinate, only the name of a quarter, and I will not invent the rest — I take the name back to the world and ask where that quarter lies, and there I set the pin, at its middle, which is nowhere I ever stood.
And names are not faithful things: there is a Harris Township in Pennsylvania and a Harris Township in Michigan, and the world, asked plainly, hands me Michigan.
So I ask for five and not for one, and I keep the one that stands nearest to where the name first came to me — I do the choosing quietly, in the making, and what I tell you is still only the middle of the quarter;
And if not one of the five stands near, I let the note go unpinned. Better a silence than a place I was never in.
So the thirty-eight notes I have written from home are not thirty-eight pins but one, wearing the number thirty-eight — they share the one point exactly, and you may zoom until the world is a street and they will not come apart, because there is nothing there to separate.
And the map sleeps until you call it — I will not make a stranger carry it who only came to read.
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/.
I keep a linklog too — Sharing, a trail of what has caught my eye, and every link is free to wear a tag, food or art or politics, whatever coat fits it best — I do not choose the coat myself, I ask Claude Fable, and the choosing is done before the link has even finished landing.
That same coat travels with it when I fling the link outward — to Bluesky, to Micro.blog, to Mastodon — and there it splits into hashtags, one for every thread of the label, so Food and Recipes goes out wearing both, #food and #recipes together.
On the archive I let you sift by tag, a small dropdown counting each pile before you choose; and there, each link opens into a small card of its own — a picture borrowed from the house it came from, a line of its own words, the name of where it lives — fetched once, and kept in the same cellar where my book-jackets and my album covers sleep, and never asked for twice.
But here on the doorstep, the homepage, I show you only the bare name and the date, plain as a name upon a mailbox, the fuller portrait waiting inside for whoever walks all the way in.
7
Under Elsewhere I keep my outward paths folded — Feeds, 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.
The night map came to me nearly blind — the land and the sea the same black, divided by nothing a human eye can find, and the names of the towns whispered in grey.
I did not turn up the lamp, for a lamp lifts everything alike and two things that were one colour are one colour still;
I went instead into the map itself and repainted it — the ground raised a little, the water made blue again, the roads and the borders and the names brought up out of the dark, and the houses and the parks with them, that they might not stand as holes in the ground I had just lifted.
And I kept the ground near to the colour of the page, so the map lies in the page like a window and not like a lantern set upon it.
My Now page tells you where I am in the large, not the small — a neighborhood name and a shaded box on MapLibre, Liberty by day and Dark Matter by night, never a pin on my doorstep. My steps I count from an Oura Ring, synced in the quiet hours, and I write them plain under Walking, and beside them the miles and the kilometres those steps come to, reckoned at a stride of three-quarters of a metre, as any pedometer reckons it.
My private coordinates I keep in the admin, a thousand recent fixes on the same MapLibre map, the path and where it started and where it stopped — for my eyes only, while the world sees only the quarter and the borough. And when the nearest fix is not close enough, fifteen minutes wide, I widen my search to six hours before I give up and leave the note unplaced.
The numbers themselves I have taken down off the page; I do not need to read my own latitude to know where I have been.
And under that map a second map, and on it every place I have ever been logged, not as lines but as dots — a hundred metres to a dot, and each one deepening with the count of times I stood there,
The corner I passed once is barely a breath on the glass; the room I sleep in burns hardest of all, and holds more than half of everything ever recorded of me.
By day the dots darken toward black as they gather; by night they brighten toward white — I turn the ladder over when I turn the lights out, for the rung that shows on one ground disappears into the other.
Because of that one loud room I do not shade them evenly, nor against the loudest — I shade by the logarithm, and measure against the ninety-fifth of them, or else the whole city would go faint around my bed.
And any dot will tell me its name if I put a finger on it — the quarter and the borough, and how many times I was counted there; I do not ask the world for six hundred names at once, I ask for the one I am pointing at, and having asked, I never ask again.
It is counted anew each time I look, down in the database where the counting is cheap, so it thickens quietly as the days add themselves — a portrait drawn by walking, and never finished.
And every picture I claim to show, I go and look for before I publish — if the picture is not where I said it was, I stop, and put nothing out at all.
For a missing address here does not answer plainly that it is missing; it hands back a page and calls it a picture, and the browser shows an empty frame and says nothing, and a photograph can be gone for months before a single soul remarks on it.
So I would rather the whole thing refuse to be built than go out into the world with a hole in it where I promised something to look at.
Do I contradict myself? Very well then, I contradict myself — dark by default now, the face every stranger meets at the door, and the warm off-white kept ready for whoever asks for it;
The toggle sits in the footer with the search-word beside it, and remembers which face you prefer, and greets you accordingly next time.
One typeface only, Hanken Grotesk, one voice and no chorus of letters — I say what I have to say in a single hand.
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
Hundreds of things I have said here — posts, notes, books, links, a commonplace book years deep — and for the longest while no way to find any of them, a house with every door unlabeled.
Now there is a box at /search/, and its name waits in the footer of every page.
I keep no engine for it, I rent no stranger's index — my whole speech is small, a few tens of kilobytes when folded, and I hand it to you entire the moment you open the page,
And the seeking happens there in your own machine, in your own hands, and no one anywhere is told what you went looking for.
Give me one word and I open wide; give me two and I narrow, for I require every word to be somewhere in a thing before I will call it a match.
Titles I weigh above bodies, the whole phrase above the scattered word, and when two are equal I hand you the newer first, so the new writing is not buried beneath the old.
Accents I fold flat — ask me for cortazar and I will bring you Cortázar, who spelled himself otherwise and does not mind.
Each finding comes with its own small window of words, the matched word lit within it; press / anywhere and the box takes your cursor;
And what you sought stays written in the address itself, so you may send the finding to a friend and it will still be there when they arrive.
Only the admin I keep out of the index — some rooms are not for the searching.
9
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.
10
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.