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>
2.3 KiB
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
- Instant — edit, then download directly, entirely client-side. Optionally generate a share link (explicit action, not automatic).
- Delayed — edit, then "send to develop": uploads to server storage,
assigns a random
develop_atwithin 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 afterdevelop_atpasses, 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.