Initial implementation of latent: film-effects editor + develop-later server
All checks were successful
Docker / build-and-push (push) Successful in 3m29s

Canvas-based client-side editor (grain, vignette, halation, procedural
light leaks, color-cast presets) plus a small Express/SQLite server for
the two paths that need persistence: instant share links and delayed
"send to develop" links with a randomized reveal time.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Fredrik Johansson
2026-07-16 15:19:48 +02:00
commit 5a5c0da8a6
20 changed files with 2611 additions and 0 deletions

60
README.md Normal file
View File

@@ -0,0 +1,60 @@
# latent
A phone-photo editor with a "develop it later" option. Upload a photo,
apply film-style effects (grain, light leaks, vignette, halation, color
cast) entirely in the browser, then either download it right away or send
it off to "develop" — the server holds it behind a randomized delay
(hours to days) before the link actually resolves to the image. Getting
your photos back later, on purpose, for no practical reason except that
it's a fun mechanic.
Named after the *latent image*, the photographic term for the picture
that already exists on exposed film but is invisible until developed.
See [PROPOSAL.md](PROPOSAL.md) for the original design writeup.
## Two finishing paths off one editor
1. **Instant** — edit, then download directly, entirely client-side.
Optionally generate a share link (explicit action, not automatic).
2. **Delayed** — edit, then "send to develop": uploads to server storage,
assigns a random `develop_at` within a configured range, and gives back
a link immediately — it just won't resolve to the actual image until
that time passes.
## Running locally
```
npm install --prefix server
npm start --prefix server
```
Then open http://localhost:3000. `DATA_DIR` defaults to `./data`
(gitignored) for the SQLite db and image blobs.
## Deploying
`docker compose up` using the provided `docker-compose.yml` /
`.env.example` (copy `.env.example` to `.env` and adjust). CI builds and
pushes the image on push to `main` via `.gitea/workflows/docker.yml`.
## Config
All via env vars, see `.env.example`:
- `DEVELOP_MIN_HOURS` / `DEVELOP_MAX_HOURS` — randomized delay range for
the "send to develop" path (default 248h).
- `INSTANT_TTL_HOURS` — retention for share links off the instant path
(default 24h; deliberately shorter than the delayed path since it's a
more casual "just give me a link" flow).
- `DELAYED_VIEW_WINDOW_HOURS` — how long a delayed image stays available
*after* `develop_at` passes, before the TTL sweep deletes it (default
168h / 7 days).
- `MAX_UPLOAD_BYTES`, `RATE_LIMIT_PER_HOUR` — basic abuse limits; no
accounts or auth on any endpoint, the link itself is the credential.
## Non-goals
No accounts, no galleries, no e2e encryption (nothing here is sensitive —
the whole point is a link other people can open), no collaborative
editing.