Fredrik JohanssonandClaude Sonnet 5 bee81187fb
Docker / build-and-push (push) Successful in 4m54s
Fix upload jumping straight to camera on mobile
The file input's capture="environment" attribute forces mobile browsers
to open the camera directly, skipping the OS file picker entirely -- so
there was no way to pick an existing photo from the phone, only take a
new one. Dropping capture restores the normal camera-or-library chooser
on mobile; desktop drag-and-drop is unaffected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 19:09:15 +02:00
2026-07-16 15:29:34 +02:00

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 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 2–48h).
  • 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.

S
Description
No description provided
Readme
86 KiB
Languages
JavaScript 69.5%
CSS 16.2%
HTML 12.8%
Dockerfile 1.5%