Files
DarkRoom/docs/manual/README.md
T
dtourolle 5b4ad11853
Benchmarks / CPU and I/O (per commit) (push) Failing after 6m16s
Benchmarks / Frame budget (on demand) (push) Skipped
Build and test / Desktop (Linux) (push) Failing after 42s
🐳 Android image / Build and push (push) Successful in 1s
Build and test / android-image (push) Successful in 1s
🐳 Windows image / Build and push (push) Successful in 1s
Build and test / windows-image (push) Successful in 2s
Build and test / Layer separation (push) Successful in 26s
Traceability / Requirement traces (push) Failing after 38s
Build and test / Android (aarch64) (push) Failing after 2m20s
Build and test / Windows (x86_64, cross) (push) Failing after 3m3s
Manual: nested collections, and the ghost drawn as it should be
A scene that makes a parent, nests two collections in it by drag and by
the menu, files frames into a child and opens the parent to see it count
both; stills of the tree and of the menu. The collections recording is
re-made now that the bitmap under the cursor is the photograph.

drive.py grows a multi-leg drag: a diagonal with much vertical in it is
taken by the grid's Flickable as a scroll before the DragArea can claim
it, so a drag to the sidebar goes sideways first.
2026-09-20 16:27:18 +02:00

241 lines
10 KiB
Markdown

# DarkRoom, shown
A tour of what the application does, one picture per thing. Every image on
this page was captured from the desktop build driving itself — nothing is a
mock-up, and nothing has been retouched outside DarkRoom. Where a feature is
better seen moving, it moves.
The requirements behind each feature are in [requirements.md](../requirements.md);
the reasoning is in the design documents linked from each section. This page
is only about what you see.
The photographs are the author's. None show a person.
## Opening a library
DarkRoom opens on a library: a folder on this machine, a folder a sync
client keeps, or a Nextcloud account. A folder needs no password and uploads
nothing.
![The launch screen: a server field, a folder field, and which formats to scan for](media/launch.png)
Once a folder is named, it is the library — you are not asked for it again,
and `Open library` opens it whole. `Subfolder…` narrows the scan to part of
it. The formats ticked are what the scan looks for; RAW is on and JPEG off
by default, because a RAW editor's sensible default is the file the camera
wrote first.
![A folder chosen: the library, whether to scan a subfolder, and the formats](media/launch-folder.png)
## The library
![The grid: collections on the left, the timeline beside it, the roll of thumbnails, and the filter bar above](media/library.png)
Photographs are ordered by capture time, with a month heading where each
begins. The strip on the left is the timeline — drag it to jump to a year.
The bar above the grid filters by rating, flag and where the file is (on this
device, or only on the server).
### Rating and flagging
Hover a cell and the stars appear; click one. The filter chips above the grid
count what each rating holds, and clicking `3+` shows only those.
![Rating two photographs, then filtering the grid to three stars and more](media/library-rating.gif)
### Getting about
Drag the timeline to scrub through years; Ctrl and the wheel resize the
thumbnails.
![Scrubbing the timeline](media/library-timeline.gif)
![Resizing the thumbnails with Ctrl and the wheel](media/library-thumbsize.gif)
### Selecting several
`Select` in the header — or Ctrl-click — starts a selection. Shift-click picks
a range. The bar at the foot of the grid is everything a selection can be done
to: collections, keywords, presets, export, and merging to a panorama.
![Twelve photographs selected, with the selection bar along the foot of the grid](media/library-selection.png)
`Keywords` on that bar opens a sheet; type a word and press return, and it
is on every photograph selected. The list below the field is every keyword
the library has, ticked where the selection carries it.
![Keywording twelve frames](media/library-keywords.gif)
### Collections
`+` at the head of the sidebar makes one. Drag a photograph — or the whole
selection — onto its row to file it there; click the row to see it. A
photograph can be in several, and the badge on its cell counts them.
![Filing photographs in a collection by dragging them onto it](media/library-collections.gif)
Collections nest. Drag one onto another to put it inside; `+` with a
collection selected — or `New collection inside` from its menu — makes a
child. A parent shows everything its children hold, and its count says so.
Right-click a row (hold it, on a tablet) for the menu: rename, nest,
move back to the top level, keep it offline, delete.
![Making Trips, nesting Alps and New York inside it, and opening the parent](media/library-nesting.gif)
![Trips showing both of its children's photographs](media/library-nesting.png)
![The menu on a collection](media/library-collection-menu.png)
## Developing a photograph
Click a thumbnail to open it. The column on the right is every adjustment;
the strip at its head narrows it to one group.
![The develop view: the photograph, the histogram, and the adjustment column](media/develop.png)
![Switching between the Optics, Light, Colour, Effects and Detail groups](media/develop-groups.gif)
### Light
Exposure, contrast, highlights, shadows, blacks, whites and a tone curve.
Hold `Before` to see the photograph as it was.
![Raising exposure, pulling the highlights, lifting the shadows, then holding Before](media/develop-light.gif)
### Looking closer
Double-click for 1:1; drag to move about; double-click again to fit. The
wheel zooms to any amount in between.
![Zooming to 1:1, panning, and back](media/develop-zoom.gif)
### White balance from the photograph
Press `pick` in the White Balance group, then click something neutral —
a white wall, a grey card, the air conditioner here. The picker sets the
sliders from the photograph, not from where they were: below, the frame
is dragged cold first and one click puts it right. A blown highlight is
refused, since a clipped pixel has no colour left to balance.
![Cooling the frame with the slider, then picking a white air conditioner to set the white balance](media/develop-wb.gif)
### Composing
Crop by dragging the frame's corners, straighten with the slider, lock a
ratio from the chips. `Done composing` returns to the photograph.
![Cropping, straightening and choosing a ratio](media/compose.gif)
### Local adjustments
`Local` in the rail turns the column into a mask stack. `Find subjects` runs a
segmentation model over the photograph; what it recognises appears as a list
of categories with how much of the frame each covers. Click one and it is a
mask — then every slider below edits only that region.
![What the model found in an urban scene: ground, architecture, sky, vegetation](media/local-categories.png)
![The sky chosen: tinted on the photograph, and the column now scoped to it](media/local-segment.png)
A mask is a stack of parts. Paint into it, subtract a gradient from it, grow
or shrink its edge, choose how it falls off. `Show masks as` draws the mask
tinted, as alpha, or as an outline; the eye on its row switches it off.
![Looking at the mask three ways, painting into it, then growing its edge](media/local-paint.gif)
Linear and radial gradients, a tone range and a colour range are the other
ways to make one; each can be combined with any other.
### Repair
`Repair` in the rail: click a mark and it is covered from a source DarkRoom
chooses beside it. Drag either circle to move it; the size, feather and
opacity are in the panel. Heal blends; clone copies.
![Covering marks on a road](media/repair.gif)
### Film
The `Film` chooser at the head of Adjust applies a spectral simulation of a
named stock; below it, the print exposure and push controls a film has and a
sensor does not.
![Choosing Velvia, then holding Before](media/film.gif)
### History, snapshots, presets
Every change is a step; `Undo` and the History panel walk them. `Snapshot`
keeps the current state under a name. `Presets…` saves the settings to
apply elsewhere, and imports `.xmp` from other applications.
![The presets sheet](media/presets.png)
## Merging a panorama
Select the frames, then `Merge to panorama` from the selection bar. The
frames are read, aligned, and drawn on the suggested projection with each one
outlined where it landed — twelve hand-held portrait frames across an alpine
valley, here. Change the projection (a 150° sweep on a flat perspective is
what the middle of the film shows, and why cylindrical is suggested), ask for
the border to be filled rather than cropped, then `Merge`. The composite is
written beside its sources as a DNG and appears in the grid with the merge
as the first step in its history.
![Twelve frames aligned, the projections tried, and the border filled](media/panorama.gif)
![The alignment on a cylinder, each frame outlined where it landed](media/panorama-aligned.png)
![The same, with the ragged border filled by the model rather than cropped away](media/panorama-filled.png)
## Export
`Export` in the develop header, or `Export N` from a selection. Format,
size, colour space, sharpening, naming and where the file goes are in
Settings, and apply to every export until changed. An export with no folder
set is refused, and the header says so.
![Export defaults in Settings](media/settings-export.png)
## Settings
![The settings page: background activity, indexing, storage, display](media/settings.png)
Background activity with progress, thumbnail and face indexing, storage on
this device, display and colour, export defaults, what is written to XMP
sidecars, and a diagnostics bundle for a bug report.
## People
Face detection and identity run over the library and group faces by person;
the `Identity` page is where suggestions are confirmed, rejected and split,
and `People` on the filter bar narrows the grid to someone. Not pictured
here, for the obvious reason — [faces.md](../faces.md) has the design.
## Where things are written down
| Feature | Design |
|---|---|
| Local masks and segmentation | [segmentation.md](../segmentation.md), [mask-editing.md](../mask-editing.md) |
| Repair | [spot-removal.md](../spot-removal.md) |
| Panorama | [panorama.md](../panorama.md) |
| Faces and identity | [faces.md](../faces.md) |
| Gestures, generated from the code | [gestures.md](../gestures.md) |
| Navigation and layout | [ui-navigation.md](../ui-navigation.md) |
| Sync and storage | [storage.md](../storage.md) |
## How this page is made
[`tools/manual/`](../../tools/manual/README.md) drives the desktop build on
a private X server and records each scene; `record.sh <library>` re-makes
every picture here. Run it after a change to the interface and commit what
changed. The pictures are in LFS.
Making it the first time turned up nine faults, each fixed in its own
commit before the pictures were taken: the folder picker could not choose
the top level, month headings overprinted each other, a category mask
widened the column off the window, the mask tint outlived its mode, the
first sync uploaded an empty thumbnail shard, a merge that ran out of GPU
memory left the page on Stop for ever, the export settings promised to ask
for a folder and did not, the keyword sheet sent its keys to the grid, and
an empty trash told you to check your library folder.