Skip to content
← All work
Replay — "The shape of your time.", with a year scrubber marking the months a trip falls in

Replay

A local-first timeline that turns a camera roll back into trips and days.

Year
2025
Role
Design and engineering
Stack
TypeScript · Electron · SQLite

The problem

A camera roll is chronological and nothing else. The structure you actually remember — the trip, the day, the afternoon something happened — exists in your head and nowhere in the file system.

The approach

Replay reads a photo and video library on Windows and reconstructs that structure locally. Nothing is uploaded; the library never leaves the machine.

What was hard

Clustering is easy to make work on your own library and hard to make work on someone else's. Threshold-tuning that felt correct on a dense London camera roll fell apart on a sparse one.

What I'd change

The clustering is tuned, not learned, and tuned against my own library — which is dense, urban and heavily photographed. On a sparse library the same thresholds produce either one enormous bundle or a hundred singletons. The fix is not better constants; it is deriving the thresholds from the library's own density before clustering anything, so the parameters are a property of the collection rather than of mine.

Local-first was the right constraint and it cost more than I expected. No sync means no second device, and the moment someone has a phone and a laptop the model quietly stops matching how people actually keep photographs. I would keep the default and add optional, explicit sync rather than pretending the need is not there.

I never measured it against a genuinely large library. Electron and SQLite are fine at the sizes I tested, and "fine at the sizes I tested" is exactly the sentence that precedes a performance problem.