Digital Contact Sheet
A fast, keyboard-first contact sheet for your photos. Scan, cull, tag, and export thousands of JPEGs without opening a heavy editor.
Status: alpha. Expect rough edges in the UI.
You just got back from a trip with three thousand photos. You don't want to edit them yet. You want to look through them, throw out the bad ones, keep the good ones, and pull your favourites into a folder to share. That's the job dcs does, and it does it fast. Originals are never touched; everything you do lives in a small, readable project file next to your photos.
- Fast and native. Runs on macOS, Linux, and Windows, and stays smooth with thousands of photos.
- Keyboard-first. Accept, reject, tag, crop, search, and undo from the keyboard. Shortcuts are remappable.
- Never touches your originals. Verdicts and tags are saved alongside your photos, and stick even if you rename or move the files.
- Crop and straighten with fixed ratios, free crop, and a straighten slider.
- Automatic grouping. Photos organize themselves by day, time, and bursts.
- Freeform board. Drag photos onto a canvas and arrange them by hand.
- Search by describing. Find photos by what's in them ("temple", "red car"), entirely on your machine. See Semantic search.
- Export your keepers to a folder. Copies only, never overwrites.
- Print contact sheets. Turn your grid into a physical sheet on paper. See Contact sheets.
- Undo that lasts. Undo and redo keep working after you close and reopen.
Make the digital contact sheet physical again: print your grid on paper.
Frames come out numbered in a film-rebate style with monospace captions, on the paper size you choose (A4, A3, Letter, or Legal), against a black or white background, with optional filename and exposure captions. Filters apply, so you print exactly the set you're looking at, and the live preview is what gets rendered. It saves to a multi-page PDF or prints straight through your system viewer, so you can cull on paper the old-fashioned way, or show off a set you've already picked.
Type what you're looking for ("temple", "red car", "people laughing") and dcs returns the photos that match the meaning, not file names or tags.
It works by running a local SigLIP image-text model. Every photo and your query are turned into vectors in one shared space; the matches are the photos nearest your query. The whole thing runs on your machine, fully offline. No API, no account, nothing uploaded.
A few things worth knowing:
- It's optional and per project. Search is off by default. You turn it on for a given project, and that choice is saved with the project.
- It needs to index first. When enabled, dcs builds an index of your photos in the background at the lowest priority, so it never slows down loading or scrolling. Search gets better as indexing finishes. The index is a disposable cache (about 3 KB per photo); it's never part of your owned project data.
- Indexing can be GPU-accelerated. Indexing and queries run on the GPU where available: Metal on macOS (on by default), CUDA on Nvidia, with a CPU fallback everywhere else. Queries are fast (sub-100ms) even on CPU; expect slower indexing on CPU.
- The model ships inside the app. No separate download at runtime, so it works out of the box. This is what makes the binary large (see below).
Grab a prebuilt binary from the Releases page.
cargo build --workspace # build everything
cargo run -p dcs-ui # launch the app (binary name: dcs)Release build:
cargo build --release -p dcs-ui --bin dcsThe first build downloads the search model (~800 MB, once).
build.rsfetches the pinned SigLIP model, checks its SHA-256, converts it to fp16, and bakes it into the binary. The embedded model adds about 390 MB to the executable. It's cached per revision undertarget/, so only the first build (or a build aftercargo clean) pays the download.
- Rust stable (
rustuprecommended). - NASM and CMake, because
turbojpegbuilds libjpeg-turbo's SIMD from source. CMake ships on most systems; install NASM through your package manager. - Linux only, the GUI dev headers:
sudo apt-get install -y libgtk-3-dev libxkbcommon-dev libwayland-dev \ libx11-dev libxcursor-dev libxrandr-dev libxi-dev \ libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev pkg-config
Inference picks the best backend automatically, with a CPU fallback:
| Platform | Backend | How |
|---|---|---|
| macOS | Metal | automatic (on by default) |
| Linux / Windows + Nvidia | CUDA | --features cuda (needs the CUDA toolkit) |
| anything else | CPU | automatic fallback |
cargo build --release -p dcs-ui --bin dcs --features cuda # NvidiaPut the three files (config.json, tokenizer.json, model.safetensors from
the pinned revision) in a directory and point build.rs at it, with no
download:
DCS_MODEL_DIR=/path/to/model cargo build --release -p dcs-ui --bin dcsTo update the model, edit the pinned commit in
crates/dcs-io/model_revision.txt (read by both build.rs and CI). The next
build prints the new SHA-256 hashes; paste them into crates/dcs-io/build.rs to
lock them against drift.
cargo fmt --all --check
cargo clippy --workspace -- -D warnings
cargo test --workspaceFour crates, dependencies pointing downward only:
| Crate | Role |
|---|---|
dcs-ui |
egui binary: grid / gallery / crop / board views, contact-sheet dialog, ephemeral UI state |
dcs-app |
conductor: session, command registry, dispatch, undo |
dcs-io |
infrastructure behind traits: imaging, scan, persistence, embeddings |
dcs-domain |
pure core: types and pure functions (no I/O, no async, no egui) |
The authoritative design lives in spec.md.
- dcs is licensed under MIT OR Apache-2.0, at your option.
- The embedded SigLIP model and tokenizer (
google/siglip-base-patch16-384) are © Google, licensed under Apache-2.0. Because every build ships the model, distributions must include the model attribution and the Apache-2.0 license text. SeeTHIRD_PARTY_NOTICES.md. The weights are converted to fp16 for embedding; no other change is made.

