Files
DarkRoom/docs/manual/index.html
T
dtourolle c2cfacd7d3 Record the new Best in the spec and the manual
denoise.md §15: why Best became one network, how it compares with the
mixture and Medium on real photographs and the chart, the candidates that
fell short, the file names, the saved-edit numbering, and the timings on
the 3050 -- 0.51-0.54 s whole-frame, 0.95 s in tiles, against 2.60 s for
the mixture in tiles. The manual lists Bilinear, Fast and Best, says an
edit made with Medium opens with Best, and gives the new time; Medium's
close-up goes.
2026-10-07 07:14:52 -04:00

528 lines
40 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<!-- GENERATED FILE — do not edit by hand. -->
<!-- Source: docs/manual/README.md. Regenerate: cargo run -p traceability -- manual -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark">
<title>DarkRoom, shown</title>
<style>
:root {
--bg: #fbfaf8;
--ink: #1d1c1a;
--ink-dim: #5c5955;
--rule: #dedad4;
--accent: #8a4b12;
--panel: #f1eee9;
--mark: #f6e3c7;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #161514;
--ink: #e9e6e1;
--ink-dim: #a39e97;
--rule: #34312d;
--accent: #e8a25c;
--panel: #201e1c;
--mark: #43321f;
}
}
* { box-sizing: border-box; }
body {
margin: 0;
background: var(--bg);
color: var(--ink);
font: 17px/1.6 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
.page {
display: grid;
grid-template-columns: 15rem minmax(0, 46rem);
gap: 3rem;
justify-content: center;
padding: 2rem 1.5rem 4rem;
}
.toc {
position: sticky;
top: 1.5rem;
align-self: start;
max-height: calc(100vh - 3rem);
overflow-y: auto;
font-size: 0.9rem;
}
.toc-title {
margin: 0 0 0.5rem;
color: var(--ink-dim);
font-size: 0.75rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.toc ul { list-style: none; margin: 0; padding: 0; }
.toc ul ul { padding-left: 0.9rem; }
.toc li { margin: 0.2rem 0; }
.toc a { color: var(--ink-dim); text-decoration: none; }
.toc a:hover { color: var(--accent); }
main { min-width: 0; }
h1, h2, h3 { line-height: 1.25; scroll-margin-top: 1rem; }
h1 { font-size: 2.1rem; margin: 0 0 1rem; }
h2 { font-size: 1.5rem; margin: 2.6rem 0 0.8rem; padding-top: 1rem; border-top: 1px solid var(--rule); }
h3 { font-size: 1.15rem; margin: 1.8rem 0 0.6rem; }
h2:target, h3:target { background: var(--mark); border-radius: 4px; padding-left: 0.3rem; margin-left: -0.3rem; }
a { color: var(--accent); }
code {
font: 0.88em ui-monospace, "Cascadia Mono", "DejaVu Sans Mono", monospace;
background: var(--panel);
border: 1px solid var(--rule);
border-radius: 4px;
padding: 0.05em 0.3em;
}
figure { margin: 1.4rem 0; }
figure img, main img {
display: block;
width: 100%;
height: auto;
aspect-ratio: auto 16 / 11;
border-radius: 6px;
border: 1px solid var(--rule);
}
figcaption { margin-top: 0.4rem; color: var(--ink-dim); font-size: 0.9rem; }
table { border-collapse: collapse; width: 100%; font-size: 0.95rem; }
th, td { text-align: left; padding: 0.4rem 0.6rem; border-bottom: 1px solid var(--rule); vertical-align: top; }
th { color: var(--ink-dim); font-weight: 600; }
@media (max-width: 52rem) {
.page { grid-template-columns: minmax(0, 1fr); gap: 1rem; padding: 1rem 16px 3rem; }
.toc { position: static; max-height: none; border: 1px solid var(--rule); border-radius: 6px; padding: 0.8rem 1rem; background: var(--panel); }
body { font-size: 16px; }
}
</style>
</head>
<body>
<div class="page">
<nav class="toc" aria-label="Contents">
<p class="toc-title">Contents</p>
<ul>
<li><a href="#opening-a-library">Opening a library</a></li>
<li><a href="#the-library">The library</a>
<ul>
<li><a href="#rating-and-flagging">Rating and flagging</a></li>
<li><a href="#getting-about">Getting about</a></li>
<li><a href="#selecting-several">Selecting several</a></li>
<li><a href="#collections">Collections</a></li>
<li><a href="#bursts">Bursts</a></li>
<li><a href="#duplicate-originals">Duplicate originals</a></li>
</ul>
</li>
<li><a href="#developing-a-photograph">Developing a photograph</a>
<ul>
<li><a href="#light">Light</a></li>
<li><a href="#looking-closer">Looking closer</a></li>
<li><a href="#ai-denoise">AI denoise</a></li>
<li><a href="#moving-between-photographs">Moving between photographs</a></li>
<li><a href="#white-balance-from-the-photograph">White balance from the photograph</a></li>
<li><a href="#composing">Composing</a></li>
<li><a href="#local-adjustments">Local adjustments</a></li>
<li><a href="#repair">Repair</a></li>
<li><a href="#film">Film</a></li>
<li><a href="#history-snapshots-presets">History, snapshots, presets</a></li>
<li><a href="#copying-settings">Copying settings</a></li>
</ul>
</li>
<li><a href="#merging-a-panorama">Merging a panorama</a></li>
<li><a href="#export">Export</a></li>
<li><a href="#settings">Settings</a></li>
<li><a href="#people">People</a></li>
<li><a href="#where-things-are-written-down">Where things are written down</a></li>
<li><a href="#how-this-page-is-made">How this page is made</a></li>
</ul>
</nav>
<main>
<h1 id="darkroom-shown">DarkRoom, shown</h1>
<p>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.</p>
<p>The requirements behind each feature are in <a href="https://gitea.tourolle.paris/dtourolle/DarkRoom/src/branch/master/docs/dev/requirements.md">requirements.md</a>;
the reasoning is in the design documents linked from each section. This page
is only about what you see.</p>
<p>The photographs are the author's. None show a person.</p>
<h2 id="opening-a-library">Opening a library</h2>
<p>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. <code>Choose folder…</code> opens your desktop's own folder dialogue, which can
make a new folder too; the folder used last stays on the screen with
<code>Open folder</code> beside it, and <code>Choose another…</code> in place of <code>Choose folder…</code>.
On a Nextcloud account the library folder is chosen in a browser of the
server, whose <code>New folder</code> makes one there. (The browser is not pictured:
these recordings have no server behind them. Nor is the folder dialogue,
which is your desktop's rather than DarkRoom's.)</p>
<figure><img loading="lazy" src="media/launch.png" alt="The launch screen: a Nextcloud server or an app password, or the folder used last with Open folder beside it"><figcaption>The launch screen: a Nextcloud server or an app password, or the folder used last with Open folder beside it</figcaption></figure>
<p>Once a folder is named, it is the library — you are not asked for it again,
and <code>Open library</code> opens it whole. <code>Subfolder…</code> 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. <code>Change library</code>, at the foot of the sidebar, comes back here.</p>
<figure><img loading="lazy" src="media/launch-folder.png" alt="A folder chosen: the library, whether to scan a subfolder, and the formats"><figcaption>A folder chosen: the library, whether to scan a subfolder, and the formats</figcaption></figure>
<h2 id="the-library">The library</h2>
<figure><img loading="lazy" src="media/library.png" alt="The grid: collections on the left, the timeline beside it, the roll of thumbnails, and the filter bar above"><figcaption>The grid: collections on the left, the timeline beside it, the roll of thumbnails, and the filter bar above</figcaption></figure>
<p>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, colour label and where the
file is (on this device, or only on the server).</p>
<h3 id="rating-and-flagging">Rating and flagging</h3>
<p>Hover a cell and the stars appear; click one. The filter chips above the grid
count what each rating holds, and clicking <code>3+</code> shows only those. From the
keyboard, <code>0</code> to <code>5</code> set the stars on the photograph under the pointer or on
the selection; <code>P</code> picks, <code>X</code> rejects and <code>U</code> takes the flag off, and <code>Flag</code>
on the selection bar does the same with the pointer. In
develop the same keys judge the open photograph and stay on it, and the top
bar carries its stars and <code>Pick</code> and <code>Reject</code>; the roll marks each frame's
flag and stars.</p>
<figure><img loading="lazy" src="media/library-rating.gif" alt="Rating two photographs, then filtering the grid to three stars and more"><figcaption>Rating two photographs, then filtering the grid to three stars and more</figcaption></figure>
<p>Colour labels work as Lightroom's do: <code>6</code> red, <code>7</code> yellow, <code>8</code> green, <code>9</code>
blue, on the photograph under the pointer or on the selection, and the same
key again takes the label off. <code>Label</code> on the selection bar offers all five,
purple included, and <code>None</code>. Each label is drawn with its initial on it, so
it reads without telling the colours apart, and the filter bar has a chip for
each. In develop, the top bar names the open photograph's label and sets it,
and the same keys work there.</p>
<figure><img loading="lazy" src="media/library-labels.gif" alt="Labelling four frames with 6, 7, 8 and 9, taking one off with the same key, and filtering the grid to green"><figcaption>Labelling four frames with 6, 7, 8 and 9, taking one off with the same key, and filtering the grid to green</figcaption></figure>
<h3 id="getting-about">Getting about</h3>
<p>Drag the timeline to scrub through years; Ctrl and the wheel resize the
thumbnails. On a desktop a scrollbar beside the grid says how far through the
library the view is — drag its thumb, or click the track to move a page — and
the sidebar, the develop column and Settings have one too whenever they run
past the window. On a tablet they scroll by flick alone, and a thin line at
the right-hand edge shows where the view is while it moves, fading once it
stops; it is only a picture, and a flick that starts on it scrolls the list.</p>
<p>A panorama gets a wider cell: about twice as wide as it is tall and it spans
two columns, then three, then four for the widest — whichever leaves the least
of the cell empty — with a thumbnail made for that width. One that would not
fit in what is left of a row starts the next, so the grid still reads in the
order the photographs were taken; the arrows walk it in that order, and up and
down go to whatever is above or below. On a tablet, or with too few columns to
put it beside anything, a panorama takes the whole row.</p>
<p><code>Help</code> in the header, or <code>F1</code>, opens the controls and shortcuts: every key and
gesture, screen by screen, with <code>See it</code> beside those this page shows, and
<code>Manual</code> to open this page. In develop it is the <code>?</code> beside <code>Settings</code>.</p>
<figure><img loading="lazy" src="media/library-timeline.gif" alt="Scrubbing the timeline"><figcaption>Scrubbing the timeline</figcaption></figure>
<figure><img loading="lazy" src="media/library-thumbsize.gif" alt="Resizing the thumbnails with Ctrl and the wheel"><figcaption>Resizing the thumbnails with Ctrl and the wheel</figcaption></figure>
<h3 id="selecting-several">Selecting several</h3>
<p><code>Select</code> 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.</p>
<figure><img loading="lazy" src="media/library-selection.png" alt="Twelve photographs selected, with the selection bar along the foot of the grid"><figcaption>Twelve photographs selected, with the selection bar along the foot of the grid</figcaption></figure>
<p><code>Keywords</code> 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.</p>
<figure><img loading="lazy" src="media/library-keywords.gif" alt="Keywording twelve frames"><figcaption>Keywording twelve frames</figcaption></figure>
<h3 id="collections">Collections</h3>
<p><code>+</code> 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.</p>
<figure><img loading="lazy" src="media/library-collections.gif" alt="Filing photographs in a collection by dragging them onto it"><figcaption>Filing photographs in a collection by dragging them onto it</figcaption></figure>
<p>Collections nest. Drag one onto another to put it inside; <code>+</code> with a
collection selected — or <code>New collection inside</code> 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.</p>
<figure><img loading="lazy" src="media/library-nesting.gif" alt="Making Trips, nesting Alps and New York inside it, and opening the parent"><figcaption>Making Trips, nesting Alps and New York inside it, and opening the parent</figcaption></figure>
<figure><img loading="lazy" src="media/library-nesting.png" alt="Trips showing both of its children's photographs"><figcaption>Trips showing both of its children's photographs</figcaption></figure>
<figure><img loading="lazy" src="media/library-collection-menu.png" alt="The menu on a collection"><figcaption>The menu on a collection</figcaption></figure>
<h3 id="bursts">Bursts</h3>
<p>Frames taken a moment apart that look alike fold into one cell, with a badge
counting them. Click the badge — tap it, on a tablet — to open the burst in
the grid, and again to fold it back. A folded burst shows its earliest frame;
to have it show another, open it and click the ring on the frame you want.</p>
<p>With faces indexed, narrowing the grid to a person puts <code>Eyes open</code> beside
their name on the filter bar, which leaves out the frames where they blinked.</p>
<h3 id="duplicate-originals">Duplicate originals</h3>
<p>A library put together by hand often holds the same RAW more than once — a
dated folder, a <code>bck</code> folder beside it, a renamed copy another program
exported. When the catalog finds files with the same camera, capture time
and size in more than one place, <code>Duplicate originals</code> appears under the
trash in the sidebar with how many there are; Settings offers the same page
beside the other whole-library passes.</p>
<p>The page lists each group with its picture and its paths. One copy is
marked <code>Stays</code>: the one outside a folder named like a backup (<code>bck</code>,
<code>backup</code>, <code>copy</code>, <code>old</code>…), then the one still named the way the camera named
it (<code>_MG_4623</code>, <code>IMG_0001</code>, <code>DSC_0042</code>), then the one catalogued first. Tap
another path to keep that copy instead, and untick <code>Include</code> to leave a
group alone.</p>
<p>Nothing moves until <code>Check</code> has read the first and last megabyte of every
copy and each copy's sidecar. A group whose files differ, or whose copies
carry two different edits, is marked skipped and says why — two edits of
one frame are kept for virtual copies. What the check reads is kept, so a
second visit costs nothing. The line under each group says what the copy
that stays will gain: the highest rating, every keyword and collection, a
flag or label the copies agree on, faces and the names on them, and the
edit if only a copy had one. Where the copies disagree on a flag or a
label, the one that stays keeps its own and the line says so.</p>
<figure><img loading="lazy" src="media/duplicates.png" alt="Two frames with a copy each in a bck folder, checked and proved the same, the copy that stays marked on each"><figcaption>Two frames with a copy each in a bck folder, checked and proved the same, the copy that stays marked on each</figcaption></figure>
<p><code>Move N copies to trash</code> does it, one group at a time: each group is merged
and its spare copies moved together, or not at all. The copies go to the
trash, not away — select them in the trash view and <code>Restore</code> puts them
back where they were.</p>
<h2 id="developing-a-photograph">Developing a photograph</h2>
<p>Click a thumbnail to open it. The column on the right is every adjustment;
the strip at its head narrows it to one group.</p>
<figure><img loading="lazy" src="media/develop.png" alt="The develop view: the photograph, the histogram, and the adjustment column"><figcaption>The develop view: the photograph, the histogram, and the adjustment column</figcaption></figure>
<figure><img loading="lazy" src="media/develop-groups.gif" alt="Switching between the Optics, Light, Colour, Effects and Detail groups"><figcaption>Switching between the Optics, Light, Colour, Effects and Detail groups</figcaption></figure>
<h3 id="light">Light</h3>
<p>Exposure, contrast, highlights, shadows, blacks, whites and a tone curve.
Hold <code>Before</code> to see the photograph as it was.</p>
<figure><img loading="lazy" src="media/develop-light.gif" alt="Raising exposure, pulling the highlights, lifting the shadows, then holding Before"><figcaption>Raising exposure, pulling the highlights, lifting the shadows, then holding Before</figcaption></figure>
<p><code>Tone Mapping</code>, last in the group, is how the scene is fitted onto the
screen, and it runs after every other adjustment. <code>White Point</code> says how many
stops above middle grey reach white — raise it to bring a bright sky back
from white, lower it for a brighter, punchier picture — and <code>Contrast</code> sets
the slope of the curve between. Every adjustment above it works on the scene
as the camera recorded it, highlights beyond white included, so pulling the
highlights recovers what the sensor caught rather than what the screen could
show. A JPEG has been fitted to a screen already, by the camera, so on a
JPEG these two do nothing.</p>
<figure><img loading="lazy" src="media/develop-tonemap.gif" alt="Raising the white point to bring the clouds back from white, lowering it for a brighter picture, raising the contrast, then holding Before"><figcaption>Raising the white point to bring the clouds back from white, lowering it for a brighter picture, raising the contrast, then holding Before</figcaption></figure>
<h3 id="looking-closer">Looking closer</h3>
<p>Double-click for 1:1; drag to move about; double-click again to fit. The
wheel zooms to any amount in between. Past 1:1 the file's own pixels are
drawn as hard-edged blocks rather than smoothed, so what you see is what
the sensor recorded.</p>
<figure><img loading="lazy" src="media/develop-zoom.gif" alt="Zooming to 1:1 with a double-click, panning, then further in with the wheel"><figcaption>Zooming to 1:1 with a double-click, panning, then further in with the wheel</figcaption></figure>
<h3 id="ai-denoise">AI denoise</h3>
<p>How every raw is developed. <code>AI Denoise</code>, at the top of the Adjust panel,
replaces how the camera's raw data is turned into colour: a network trained
on this library's own photographs removes the noise and the blotches of
colour that come with it, while keeping the fine detail. Look at it at
1:1, where noise lives.</p>
<p><code>Method</code> chooses how:</p>
<ul>
<li><code>Best</code>, the default: clean skies and sharp lettering, edges kept as
crisp as the camera recorded them.</li>
<li><code>Fast</code>: a smaller network, taught the same way. Visibly noisier at very
high ISO than <code>Best</code>, but still far cleaner than none, and quicker.</li>
<li><code>Bilinear</code>: the camera's ordinary conversion, noise and all.</li>
</ul>
<p>A photograph last edited with <code>Medium</code>, which earlier versions offered,
opens with <code>Best</code>.</p>
<p>The photograph shows the camera's ordinary conversion while the network
works, with its progress in the bar at the top, and changes when it is
done — on a laptop's graphics card, about a second for a 20-megapixel
photograph with <code>Best</code>, reading the file included; longer on a processor
alone or on the tablet. After installing, the graphics card spends up to a
quarter of an hour preparing each network, once, in the background; the
photographs developed meanwhile take a little longer. The result is kept, so a photograph opened again,
or exported, does not wait a second time, and switching back to a method
already used is quick.
<code>Strength</code> eases it off: below 100 % it puts back some of what was removed,
as grain without colour, for a picture that does not look too smooth.</p>
<p>The lamp and railing of a night frame at ISO 8000, at 1:1, by each method:</p>
<table><thead><tr><th>Bilinear</th><th>Fast</th></tr></thead><tbody>
<tr><td><img src="media/develop-denoise-bilinear.png" alt="The railing and the lamp at ISO 8000, as the camera recorded them" /></td><td><img src="media/develop-denoise-fast.png" alt="The same, with the Fast network" /></td></tr>
<tr><td><strong>Best</strong></td><td></td></tr>
<tr><td><img src="media/develop-denoise-best.png" alt="The same, with the Best network" /></td><td></td></tr>
</tbody></table>
<p>It works on raw files from any camera with the usual colour pattern of
red, green and blue squares — not on JPEGs, and not yet on Fujifilm's
X-Trans. How noisy the camera is at each ISO was measured for the Canon
EOS 6D; for other cameras it is read from a DNG's own figures or
estimated from the photograph, and the finished job in the activity list
says which. An export uses
the method the photograph has.</p>
<h3 id="moving-between-photographs">Moving between photographs</h3>
<p>The roll along the foot of the canvas holds the photographs the grid was
showing; click one to open it. The right arrow, <code>D</code> or space opens the next,
and the left arrow or <code>A</code> the one before; held down, they go on past the
stretch the roll has loaded, through everything the grid would show. The
edit on screen is saved on the way, so stepping along a shoot loses nothing.</p>
<p>On a Nextcloud library a photograph may not be on this device yet. Its
thumbnail from the grid stands in at once; if the original has to come down,
the thumbnail dims under <em>Not on this device yet</em>, with how far the download
has got — <code>Downloading — 12.4 of 38.0 MB</code> — and a bar, and the photograph
opens when it lands. Step on before then and the one you step to is the one
that opens: a download that arrives late is kept for later and never takes
the place of the photograph whose name is showing. (Not pictured: a folder
library, which these recordings use, never has a photograph to wait for.)</p>
<h3 id="white-balance-from-the-photograph">White balance from the photograph</h3>
<p>Press <code>pick</code> 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.</p>
<figure><img loading="lazy" src="media/develop-wb.gif" alt="Cooling the frame with the slider, then picking a white air conditioner to set the white balance"><figcaption>Cooling the frame with the slider, then picking a white air conditioner to set the white balance</figcaption></figure>
<h3 id="composing">Composing</h3>
<p>Crop by dragging the frame's corners, straighten with the slider, lock a
ratio from the chips. <code>Done composing</code> returns to the photograph.</p>
<figure><img loading="lazy" src="media/compose.gif" alt="Cropping, straightening and choosing a ratio"><figcaption>Cropping, straightening and choosing a ratio</figcaption></figure>
<p><code>Vertical</code> and <code>Horizontal</code>, under <code>Straighten</code>, correct the lines that
converge when the camera is tilted up at a building; the crop refits to
what is left.</p>
<figure><img loading="lazy" src="media/compose-perspective.gif" alt="Standing towers shot from below upright with the Vertical slider"><figcaption>Standing towers shot from below upright with the Vertical slider</figcaption></figure>
<p>A crop that leaves a mask wholly outside the frame says so, and offers to
take the crop back or keep it.</p>
<figure><img loading="lazy" src="media/crop-orphan.gif" alt="A stroke in a corner, a crop that leaves it outside, and the notice with Undo crop and Keep crop"><figcaption>A stroke in a corner, a crop that leaves it outside, and the notice with Undo crop and Keep crop</figcaption></figure>
<h3 id="local-adjustments">Local adjustments</h3>
<p><code>Local</code> in the rail turns the column into a mask stack. <code>Find subjects</code> 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. A mask's slider adds to
the photograph's own rather than repeating it: contrast −20 in the mask over
−30 on the whole frame is −50 there, and +30 in the mask cancels the frame's
−30 inside it.</p>
<figure><img loading="lazy" src="media/local-categories.png" alt="What the model found in an urban scene: ground, architecture, sky, vegetation"><figcaption>What the model found in an urban scene: ground, architecture, sky, vegetation</figcaption></figure>
<figure><img loading="lazy" src="media/local-segment.png" alt="The sky chosen: tinted on the photograph, and the column now scoped to it"><figcaption>The sky chosen: tinted on the photograph, and the column now scoped to it</figcaption></figure>
<p>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. <code>Show masks as</code> draws the mask
tinted, as alpha, or as an outline; the eye on its row switches it off.</p>
<figure><img loading="lazy" src="media/local-paint.gif" alt="Looking at the mask three ways, painting into it, then growing its edge"><figcaption>Looking at the mask three ways, painting into it, then growing its edge</figcaption></figure>
<p>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. <code>∩ Intersect</code> keeps
only where the new part and the mask agree: below, a gradient over the
lower half, then two strokes that survive only where the gradient is.</p>
<figure><img loading="lazy" src="media/local-intersect.gif" alt="A linear gradient, then Intersect and two painted strokes"><figcaption>A linear gradient, then Intersect and two painted strokes</figcaption></figure>
<h3 id="repair">Repair</h3>
<p><code>Repair</code> 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.</p>
<figure><img loading="lazy" src="media/repair.gif" alt="Covering marks on a road"><figcaption>Covering marks on a road</figcaption></figure>
<h3 id="film">Film</h3>
<p>The <code>Film</code> 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. A stock takes the place of <code>Tone Mapping</code>: it is the last
thing that happens to the picture, so every other adjustment decides the
exposure the negative receives. The list opens over the column and scrolls on its own — by
wheel, drag or flick, or with <code>Up</code>, <code>Down</code> and <code>Enter</code> — down to the
black-and-white stocks at its end.</p>
<figure><img loading="lazy" src="media/film.gif" alt="Opening the film list, scrolling it, choosing Velvia, then holding Before"><figcaption>Opening the film list, scrolling it, choosing Velvia, then holding Before</figcaption></figure>
<p>The film's sliders work on a mask as they do on the whole photograph, the way
a printer dodges and burns: in a layer, <code>Print Exposure</code> darkens or lightens
that region of the print, <code>Push</code> develops it further, and the stock stays the
one the photograph was made on. Where layers overlap, the photograph takes the
average of what they ask for. Below, a negative stock on an alpine frame, then
a gradient over the sky whose <code>Print Exposure</code> burns it in.</p>
<figure><img loading="lazy" src="media/film-local.gif" alt="Kodak Ektar 100 on the whole frame, a gradient turned to cover the sky, its Print Exposure raised to burn the sky in, then holding Before"><figcaption>Kodak Ektar 100 on the whole frame, a gradient turned to cover the sky, its Print Exposure raised to burn the sky in, then holding Before</figcaption></figure>
<h3 id="history-snapshots-presets">History, snapshots, presets</h3>
<p>Every change is a step; <code>Undo</code> and the History panel walk them. <code>Snapshot</code>
keeps the current state under a name. <code>Presets</code>, at the foot of the tool
rail on the left, opens a menu of presets beside the rail, over the photograph, filed in
folders that start closed: your own under <code>Yours</code>, then the ones DarkRoom
ships — <code>Essentials</code>, <code>Skies</code>, and <code>Film</code>, which holds <code>Colour</code>, <code>Cinema</code>
and <code>Black and white</code>, one measured stock each. Choosing a folder opens it;
choosing a preset applies it. The menu's last row, <code>Save or manage…</code>, opens
the presets sheet, which lists the same folders and saves the settings to
apply elsewhere, renames and deletes them, and imports Lightroom presets —
<code>Folder…</code> for a folder of them, <code>.xmp file…</code> for one.</p>
<p>A <code>/</code> in a name files the preset: <code>Portraits/Warm skin</code> is <code>Warm skin</code> in a
<code>Portraits</code> folder under <code>Yours</code>, and renaming it is how it moves. An
imported Lightroom folder keeps its groups the same way.</p>
<p>A shipped preset is a look: it changes what it names and leaves the
photograph's own corrections alone, as an imported Lightroom preset does.
Saving under a shipped preset's name makes your version the one that name
applies, marked <em>changed</em>; <code>Revert</code> brings the shipped one back, and renaming
yours makes it one of your own. A film preset carries its stock: choosing one
sets the <code>Film</code> chooser and leaves the rest of the edit where it was.</p>
<figure><img loading="lazy" src="media/presets-menu.png" alt="The presets menu beside the tool rail, with Film and its colour stocks open"><figcaption>The presets menu beside the tool rail, with Film and its colour stocks open</figcaption></figure>
<figure><img loading="lazy" src="media/presets.png" alt="The presets sheet: a name for the current edit, the shipped Essentials, importing, and what an apply carries"><figcaption>The presets sheet: a name for the current edit, the shipped Essentials, importing, and what an apply carries</figcaption></figure>
<figure><img loading="lazy" src="media/presets-film.gif" alt="Opening Film, then Black and white, in the presets menu and applying Ilford HP5 Plus, then holding Before"><figcaption>Opening Film, then Black and white, in the presets menu and applying Ilford HP5 Plus, then holding Before</figcaption></figure>
<h3 id="copying-settings">Copying settings</h3>
<p><code>Copy</code> in the top bar, or Ctrl+C, takes this photograph's settings; <code>Paste</code>,
or Ctrl+V, puts them on another, and says what it would paste — how many
adjustments, and whether the crop comes too. In the grid, <code>Paste to N</code> on the
selection bar pastes onto every photograph selected. Which kinds of edit a
copy carries is chosen in the presets sheet, or with Ctrl+Shift+C: a look carried
across a shoot usually leaves each frame's own crop alone.</p>
<h2 id="merging-a-panorama">Merging a panorama</h2>
<p>Select the frames, then <code>Merge to panorama</code> 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 <code>Merge</code>. The composite is
written beside its sources as a DNG and is in the grid the moment it is
written — in a wide cell beside its frames, placed by when they were taken —
with the merge as the first step in its history. Its thumbnail is made during
the merge, from the finished picture, as develop will show it when you open
it; on a server library it is in the grid while the file is still uploading.
A second merge of the same frames is named <code>-pano-2</code>, never written over the
first.</p>
<p>Each frame has a box in the <code>Frames</code> list. Untick one to leave it out, and
the rest are aligned again at once, without reading the frames again; tick
it to bring it back. A frame that cannot be placed is named there with why,
and <code>Merge</code> stays off until it is unticked. Blown sky stays white in the
preview and in the composite.</p>
<p>A panorama is usually far wider than a graphics card can draw in one piece.
It opens in develop all the same, on a reduced copy that is drawn from the
full resolution wherever you zoom in, and it exports at full size. The same
goes for a panorama Lightroom stitched and saved as a DNG.</p>
<figure><img loading="lazy" src="media/giant-pano.gif" alt="A 22 927 × 8966 panorama of a glacier at dusk: zoomed from the whole frame into the peaks, panned along the ridge and back out, then 1:1 on the peaks with a double-click"><figcaption>A 22 927 × 8966 panorama of a glacier at dusk: zoomed from the whole frame into the peaks, panned along the ridge and back out, then 1:1 on the peaks with a double-click</figcaption></figure>
<figure><img loading="lazy" src="media/panorama.gif" alt="Twelve frames aligned, the first left out and brought back, the projections tried, and the border filled"><figcaption>Twelve frames aligned, the first left out and brought back, the projections tried, and the border filled</figcaption></figure>
<figure><img loading="lazy" src="media/panorama-aligned.png" alt="The alignment on a cylinder, each frame outlined where it landed"><figcaption>The alignment on a cylinder, each frame outlined where it landed</figcaption></figure>
<figure><img loading="lazy" src="media/panorama-filled.png" alt="The same, with the ragged border filled by the model rather than cropped away"><figcaption>The same, with the ragged border filled by the model rather than cropped away</figcaption></figure>
<figure><img loading="lazy" src="media/panorama-in-grid.png" alt="The composite in the grid straight after the merge, spanning four columns beside the twelve frames it was made from"><figcaption>The composite in the grid straight after the merge, spanning four columns beside the twelve frames it was made from</figcaption></figure>
<h2 id="export">Export</h2>
<p><code>Export</code> in the develop header, or <code>Export N</code> from a selection. Format,
size, colour space, sharpening and naming are in Settings, and apply to every
export until changed. Where the file goes is an album.</p>
<p>An album is a folder exports go to, listed under <strong>Albums</strong> in the sidebar,
below the collections. Press <code>+</code> there, or <code>New album…</code> in the export sheet
(<code>Ctrl+E</code>), name it, and choose its folder: on this device, in the system's
folder dialogue (on the tablet, Android's folder picker), or on the server,
in a browser that can make a folder as well as open one. Not inside the
library — a JPEG exported there would come back from the next scan as a
photograph of its own, and the browser says so rather than letting you.</p>
<figure><img loading="lazy" src="media/album-sheet.png" alt="A new album named, before its folder is chosen"><figcaption>A new album named, before its folder is chosen</figcaption></figure>
<p>The folder holds only the exported files. The album remembers which
photograph each came from, so selecting it in the sidebar shows the
originals behind its JPEGs — edit one and export it again. Albums reach your
other devices as collections do; a folder on this device does not, so an
album made on the desktop asks the tablet for a folder of its own.
Right-click an album, double-click it or press the arrow on its row to
rename it, give it another folder or delete it; deleting an album leaves
its files where they are.</p>
<figure><img loading="lazy" src="media/albums.gif" alt="Four New York frames exported to an album, then the album chosen in the sidebar"><figcaption>Four New York frames exported to an album, then the album chosen in the sidebar</figcaption></figure>
<figure><img loading="lazy" src="media/albums.png" alt="The album chosen: the four photographs behind its files"><figcaption>The album chosen: the four photographs behind its files</figcaption></figure>
<p>An export with no album chosen is refused, and the header says so. With one
chosen, the buttons name it: <code>Export to Exports</code> in develop, <code>Export 4 to Exports</code> on the selection bar.</p>
<figure><img loading="lazy" src="media/settings-export.png" alt="Export defaults in Settings, ending with the album exports go to"><figcaption>Export defaults in Settings, ending with the album exports go to</figcaption></figure>
<h2 id="settings">Settings</h2>
<figure><img loading="lazy" src="media/settings.png" alt="The settings page: background activity, indexing, storage, display"><figcaption>The settings page: background activity, indexing, storage, display</figcaption></figure>
<p>Background activity with progress, thumbnail and face indexing, how many
duplicate originals the library holds and the way to their review, storage
on this device, display and colour, export defaults, what is written to XMP
sidecars, the manual, and a diagnostics bundle for a bug report.</p>
<h2 id="people">People</h2>
<p>Face detection and identity run over the library and group faces by person;
the <code>Identity</code> page is where suggestions are confirmed, rejected and split,
and <code>People</code> on the filter bar narrows the grid to someone. Not pictured
here, for the obvious reason — <a href="https://gitea.tourolle.paris/dtourolle/DarkRoom/src/branch/master/docs/dev/faces.md">faces.md</a> has the design.</p>
<h2 id="where-things-are-written-down">Where things are written down</h2>
<table><thead><tr><th>Feature</th><th>Design</th></tr></thead><tbody>
<tr><td>Local masks and segmentation</td><td><a href="https://gitea.tourolle.paris/dtourolle/DarkRoom/src/branch/master/docs/dev/segmentation.md">segmentation.md</a>, <a href="https://gitea.tourolle.paris/dtourolle/DarkRoom/src/branch/master/docs/dev/mask-editing.md">mask-editing.md</a></td></tr>
<tr><td>Repair</td><td><a href="https://gitea.tourolle.paris/dtourolle/DarkRoom/src/branch/master/docs/dev/spot-removal.md">spot-removal.md</a></td></tr>
<tr><td>Panorama</td><td><a href="https://gitea.tourolle.paris/dtourolle/DarkRoom/src/branch/master/docs/dev/panorama.md">panorama.md</a></td></tr>
<tr><td>Faces and identity</td><td><a href="https://gitea.tourolle.paris/dtourolle/DarkRoom/src/branch/master/docs/dev/faces.md">faces.md</a></td></tr>
<tr><td>Gestures, generated from the code</td><td><a href="https://gitea.tourolle.paris/dtourolle/DarkRoom/src/branch/master/docs/gestures.md">gestures.md</a></td></tr>
<tr><td>Navigation and layout</td><td><a href="https://gitea.tourolle.paris/dtourolle/DarkRoom/src/branch/master/docs/dev/ui-navigation.md">ui-navigation.md</a></td></tr>
<tr><td>Sync and storage</td><td><a href="https://gitea.tourolle.paris/dtourolle/DarkRoom/src/branch/master/docs/dev/storage.md">storage.md</a></td></tr>
</tbody></table>
<h2 id="how-this-page-is-made">How this page is made</h2>
<p><a href="https://gitea.tourolle.paris/dtourolle/DarkRoom/src/branch/master/tools/manual/README.md"><code>tools/manual/</code></a> drives the desktop build on
a private X server and records each scene; <code>record.sh &lt;library&gt;</code> re-makes
every picture here. Run it after a change to the interface and commit what
changed. The pictures are in LFS.</p>
<p>The application carries this page. <code>cargo run -p traceability -- manual</code>
renders it to <code>index.html</code> beside it, which the packages install with the
pictures and the app opens from Help, from Settings, and from the "See it"
link beside a gesture on the help sheet. CI fails when the two differ.</p>
<p>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.</p>
</main>
</div>
</body>
</html>