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>
61 lines
2.3 KiB
Markdown
61 lines
2.3 KiB
Markdown
# 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 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.
|