← appaday

The letter that hid three quarters of the museum

Digging through an old drive I found a folder called screensaver, four commits long, last touched in April 2023. Out of habit I typed the address in the manifest into a browser expecting nothing. It loaded. It has been sitting there serving paintings to nobody for three and a half years.

A framed print filling the browser window: an 18th-century engraving of a ruined temple courtyard with rows of broken columns, figures in wide hats resting among fallen stones, a line of handwritten French underneath, and the cream mount and dark frame edge still visible at the sides. A Fullscreen button and Contain/Cover radio buttons sit in the top right corner
A real load, this evening. No title, no artist, no caption — the painting and two controls are the whole page.

Forty-six minutes

The git log is short enough to read as a story, and the timestamps are the good part:

17:42
Initial commit — one hard-coded image URL, Hokusai's Great Wave, in an array with // Add more image URLs here under it
17:54
using met API — the array is gone, replaced by a live query
18:27
just paintings :)
two days later
mobile capable — a web manifest and a pile of iOS hacks

Twelve minutes from hand-pasting a URL to asking a museum for everything it has. That is the entire trick, and the reason it still runs: The Met publishes its open-access collection through an API with no key, no signup and no quota, and it answers Access-Control-Allow-Origin: *, so a single HTML file opened from a hard drive can call it directly. Pick a random ID from the search result, ask for the object, set background-image, done. If the object turns out to have no photograph, it rolls again.

The letter

Then there is the bug I only noticed now, writing this.

The Met's search endpoint insists on a q parameter. There is no "give me everything" — so the 2023 version of me passed the single letter e as a stand-in for nothing in particular:

search?hasImages=true&medium=Paintings&q=e

That is not a wildcard. The search matches whole words, so q=e quietly means paintings whose catalogue text contains the word "e", and the placeholder turns into a filter. Asking the same endpoint the same question three ways this evening:

q=e
3,350 paintings — what the screensaver has been drawing from
q=a
11,084 paintings
q=painting
14,338 paintings

So for three and a half years it has been showing a randomly chosen quarter of the collection while believing it had all of it, and the choice of which quarter came down to which letter got typed at half past five on a Friday. It never looked broken. That is what makes it my favourite kind of bug: every single painting it served was real, and the ones it could never reach left no trace.

The other half of the same mistake is in the picture above. That load asked for medium=Paintings and came back with an object The Met titles Engraving — ink on paper, eighteenth century, filed under Greek and Roman Art, photographed in its frame with the mount still showing. The filter matches catalogue text, not the thing itself, so "paintings" quietly includes prints of Roman ruins. A minute earlier the same page had handed me a Gauguin. Both are the real collection; only one of them is what I asked for.

The version that only exists on the server

The copy answering at that address today matches none of the four commits. It carries a couple of :root[sizemode="fullscreen"] selectors that appear nowhere in the repository, and this, left in:

.test:fullscreen { background-color: red }

Someone edited the live file to chase a fullscreen bug, got it working, and never committed it — so the only copy of that version in the world was the one on the server. It has now been saved next to the repo before anything touches it.

What it wanted to be

Above the code sits a block of TODO comments, which is really a product plan written by someone who already knows they will not build it:

history of "last displayed" with artist and name.... so you can go back and find out more

strongly prefer loading landscape format artwork in landscape and vice versa

hide images behind my own API cause that's def the unique work, collecting and curating them

All three are right. The first is the one you feel within about ten seconds of watching it: a painting arrives, it is beautiful, and the page has nothing to tell you about it. The second is why portrait paintings get cropped into abstraction on a wide monitor. The third is the actual insight — the museum hands out the images for free, so the only thing worth owning is the curation.

It never got any of them, and I would rather link the thing as it was than quietly fix it eleven pages later.

Still standing

code
one HTML file, 7.9 KB
dependencies
none — no build, no framework, no key
API
The Met Collection API, CC0, public
built
April 2023, in about 46 minutes
uptime since
three and a half years, unattended

A single file with no dependencies is still running unchanged three and a half years later, against an API that did not break, serving art that cannot expire. Almost nothing else I have written from that year still opens.

The collection came back around, too: the side-scrolling walk I built this month is fourteen paintings from that same open-access catalogue, stitched end to end. Three years apart, same museum, same free API.