Initial implementation of latent: film-effects editor + develop-later server
All checks were successful
Docker / build-and-push (push) Successful in 3m29s
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:
60
README.md
Normal file
60
README.md
Normal 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 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.
|
||||
Reference in New Issue
Block a user