# pathways
A photo viewer that walks your library as a maze. You start on one random
picture; every photo secretly holds up to four paths — its biggest memberships
across labels, keywords, camera, and lens — one per direction. Press a
direction (arrow keys, or the buttons that appear when you hover) and the next
photo of that path locks into the grid beside you, in the direction you moved.
The visited pictures accumulate into a mosaic you can pan around and step back
through.
The live instance lives at and reads the PhotoPrism
database directly (read-only) on the same machine. PhotoPrism's admin UI
stays behind basic auth at ; pathways is public.
## How the paths work
- Every photo's paths are its member groups: label(s), keyword(s), camera,
lens. They're ranked by member count; the top four (one per direction) become
its exits.
- Paths with a single member are skipped; a photo with fewer than four usable
paths is topped up with a "library" path (all photos), so every direction
always leads somewhere.
- Each path is an ordered cycle (by taken date, then id): walking "grey" goes
grey → grey → … and wraps around. Assignment is deterministic, so revisiting
a photo always offers the same four exits.
- Movement is spatial: pressing a direction lands you on whatever photo already
occupies that cell — you walk through photos you've placed before rather than
over them. New photos are only added when you step into a genuinely empty
cell. If the path's next photo is already placed elsewhere, focus jumps to
it, so the mosaic never holds two copies of a photo.
## Run it
```bash
npm install
DB_HOST=127.0.0.1 DB_USER=photoprism DB_PASSWORD=… DB_NAME=photoprism \
PORT=3100 THUMBS_ROOT=/srv/photoprism/storage/cache/thumbnails \
node server.mjs
```
On NixOS the box runs it as a systemd unit (`systemd.services.pathways`),
started after `mysql.service`, as user `dax`.
## API
- `GET /api/paths` — every photo (id, thumb, title, date) plus the facets
(groups with ≥3 members)
- `GET /api/random` — one random photo
- `GET /api/exits/:id` — a photo plus its four exits; each exit has the path
it follows (`type`, `name`, `count`) and the `next` photo in that path's cycle
- `GET /api/health` — liveness probe
Thumbnails are served as static files by Caddy from
`/srv/photoprism/storage/cache/thumbnails/{a}/{b}/{c}/{hash}_{size}.jpg`
(`720x720_fit` for tiles).
## Layout
```
server.mjs API + static file serving
public/index.html splash + the walkable stage
public/app.css tiles, hover exits, lock-in animation
public/app.js grid state, exits, pan/click/keyboard, cycling walk
```
The thumbnail path sharding matches PhotoPrism: directory = first three
characters of the file hash. Note `file_hash` comes back from MariaDB as a
binary Buffer, so it is decoded to a string before building URLs.
