-
DarkRoom 0.19.0
StableBenchmarks / CPU and I/O (per commit) (push) Successful in 5m27sBenchmarks / Frame budget (on demand) (push) SkippedTraceability / Requirement traces (push) Successful in 1m2sBuild and test / Android (aarch64) (push) Successful in 29m53sBuild and test / android-image (push) Successful in 2s🐳 Android image / Build and push (push) Successful in 2sBuild and test / Desktop (Linux) (push) Successful in 50m11sBuild and test / windows-image (push) Successful in 2s🐳 Windows image / Build and push (push) Successful in 1sBuild and test / Layer separation (push) Successful in 38sBuild and test / Windows (x86_64, cross) (push) Successful in 35m28sBuild and test / Publish the release (push) Successful in 1m10sreleased this
2026-09-27 23:50:48 +00:00 | 113 commits to master since this releaseEdits now work on the scene as the camera recorded it, with a new Tone Mapping control to fit it to the screen — every photograph renders differently from 0.18, so update the tablet and the desktop together. Also: panoramas too large for the GPU open in develop, presets live in folders and a menu on the tool rail, and a panorama can leave a frame out.
Scene-referred editing (D19). The camera's colour is converted before the edits instead of after, so exposure, white balance and the rest work on the scene as recorded, highlights beyond white included. A new Tone Mapping control — Contrast and White Point — fits the result to the screen at the end, replacing the per-camera base curves. A film stock is now the last step: every other adjustment decides the exposure the negative receives. Sharpening, noise reduction and the tone curve no longer clip recovered highlights. Tone Mapping does nothing on a JPEG.
- Every photograph renders differently. Raw frames come out a little darker, with more contrast and fewer clipped highlights. Update the tablet and the desktop together: two devices on different builds render the same edit differently. Previews rendered before the update keep the old look until they are rendered again.
Panoramas too large for one texture. Linear DNGs bigger than the GPU can hold — a 22927×8966 Lightroom panorama, or DarkRoom's own merged composites — now open in develop instead of as a read-only preview, pan and zoom smoothly, and export at full size in tiles. Clarity, texture and dehaze preview at the same strength zoomed in as they export. (A patched rawler 0.7.2 is vendored to decode DNGs wider than 16,700 pixels.)
Presets in folders, on the tool rail. Presets open from a Presets entry at the foot of the develop tool rail: a menu beside it applies one in a click, and "Save or manage…" opens the sheet. They are filed in folders that open and close — Film holds Colour, Cinema and Black and white — and naming one "Folder/Name" files your own. Lightroom imports keep their subfolders.
Panorama. Blown highlights stay white instead of turning pink, in the preview and in the merged DNG. On the panorama page, untick a frame to leave it out; the rest re-align in a fraction of a second. A frame that cannot be placed no longer ends the job — its row names it, and Merge waits until it is unticked.
Known issues. Now that merged panoramas open at full size, the experimental border fill shows a repeating pattern along the top edge and a smear in a corner (#79). The wheel stops at 16× fit, short of 1:1 on a very wide image — double-click reaches 1:1 (#80). Tone Mapping's sliders stay live while a film stock replaces them (#81).
No catalog schema change. The sidecar gains two view-transform settings, written only when moved.
The manual is re-recorded under the new pipeline, with new pictures of Tone Mapping and of navigating a giant panorama.
The APK, the desktop binary, the Windows installer and SHA256SUMS are built by CI from this tag's commit.
Downloads
-
DarkRoom 0.18.2
StableBenchmarks / CPU and I/O (per commit) (push) Successful in 5m34sBenchmarks / Frame budget (on demand) (push) SkippedTraceability / Requirement traces (push) Successful in 1m0sBuild and test / Android (aarch64) (push) Successful in 30m28sBuild and test / android-image (push) Successful in 1s🐳 Android image / Build and push (push) Successful in 1sBuild and test / Desktop (Linux) (push) Successful in 47m53sBuild and test / windows-image (push) Successful in 1s🐳 Windows image / Build and push (push) Successful in 1sBuild and test / Layer separation (push) Successful in 34sBuild and test / Windows (x86_64, cross) (push) Successful in 36m29sBuild and test / Publish the release (push) Successful in 1m10sreleased this
2026-09-27 12:23:06 +00:00 | 143 commits to master since this releaseFilm now works inside local adjustments, hot pixels are repaired before the demosaic, and mask layers finally add to the global edit instead of replacing it. This release also carries 0.18.1's two fixes, whose downloads were never published.
Film inside local adjustments. In a mask layer, Print exposure burns or dodges that region and Push develops it further; the film stock stays the photograph's own, and where layers overlap the photograph takes the average of their settings. Film push, print exposure and format now respond without re-baking the stock, and print exposure is exact at any setting. Whole-frame film edits render as before (within one 8-bit step). A mask layer that already carried film settings now applies them — they were stored but ignored until now — so such photographs change inside the mask.
Hot pixels are gone. A hot or dead photosite is repaired on the sensor data before demosaicing, so a long or high-ISO exposure no longer shows coloured crosses where a leaky photosite was. A photosite is replaced only when it stands far above or below every photosite of its own colour around it and every neighbour beside it, so stars and small glints are left alone. Bayer and X-Trans, applied to export too, no setting, and no measurable cost (a Canon 6D frame demosaics in 94–98 ms, against 91–99 ms before). (FR-RAW-3)
Mask layers add to the global edit (from 0.18.1). A mask layer's settings are applied as offsets to the global ones, at each operation's place in the chain, rather than as a separate edit — so a layer that lifts exposure by a stop lifts it from wherever the global exposure left it.
Contrast flattens toward grey (from 0.18.1). Lowering contrast pulls tones toward middle grey instead of scaling shadows by a ratio.
A scroll cue on the tablet. Android's lists and panels show a thin line at the edge while they move, fading when they stop, so a long list says it is long. It takes no touch; the desktop keeps its scrollbars. (#69)
Under the hood.
- Every worker thread starts through one module that names its executor and role (
net:sync,decode:thumbs…), and a blocking wait on the interface thread now fails loudly in debug builds. (#58, NFR-ARCH-1) - CI fails if anything but a person's action — or a verdict carried from another device, a sidecar, or duplicate consolidation — writes a rating, flag, label or trash entry: evidence such as faces, focus or clipping can never become a verdict. (#55, first half)
- The desktop CI job frees its test binaries before the release build; the runner's disk ran out on 0.18.1's tag, which is why that release has no downloads. A flaky catalog test is fixed.
No schema change. 0.18.x devices sync with each other and with 0.17.0.
The APK, the desktop binary, the Windows installer and SHA256SUMS are built by CI from this tag's commit.
Downloads
- Every worker thread starts through one module that names its executor and role (
-
DarkRoom 0.18.0
StableBenchmarks / CPU and I/O (per commit) (push) Successful in 5m56sBenchmarks / Frame budget (on demand) (push) SkippedTraceability / Requirement traces (push) Successful in 45sBuild and test / Android (aarch64) (push) Successful in 17m8sBuild and test / android-image (push) Successful in 2s🐳 Android image / Build and push (push) Successful in 2sBuild and test / Desktop (Linux) (push) Successful in 48m1sBuild and test / windows-image (push) Successful in 2s🐳 Windows image / Build and push (push) Successful in 2sBuild and test / Layer separation (push) Successful in 36sBuild and test / Windows (x86_64, cross) (push) Successful in 21m35sBuild and test / Publish the release (push) Successful in 1m12sreleased this
2026-09-26 23:13:07 +00:00 | 170 commits to master since this releaseFaces and people now come together across devices: a face the two devices boxed differently is matched by what it looks like, and a person typed twice under one name becomes one person. Also four Skies presets, and the sidebar counts the whole library again.
Faces sync even when the boxes disagree. The catalog merge matched another device's faces to this one's by box alone, so a face the tablet and the desktop drew in different places never carried its name across. Where a box leaves a face unmatched, the merge now compares the faces themselves — a pair is accepted only when each is the other's closest match by a clear margin (cosine ≥ 0.7, a lead of 0.2 over the runner-up). On the reference pair of catalogs that recovers 20 faces, 2 of them confirmed, with no false match. The merge also keeps one person to one face per photograph: a confirmation arriving from the other device moves a local suggestion instead of doubling it. (#77)
One person per name. Two devices that each typed "Jessie" before they synced held two people called Jessie, each showing half the photographs. After every sync, people of the same name are now merged when their confirmed faces agree, and a face held twice in one photograph is folded into one; namesakes whose faces disagree stay apart and are logged. On the reference library this merges five empty duplicates — Claudine, Jessie twice, Mathias, Noemi, and Ian on the tablet — and keeps Pascal and PJ apart. A merge now also carries the merged-away person's rejections to the person kept. The merge travels as the redirect a 0.17.0 device already honours, so an older tablet never brings the duplicate back. (#78)
After upgrading, the tablet's duplicate "Ian" merges, and four of his old low-confidence suggestions (similarity 0.38) arrive on Ian as suggestions; reject them in People.
Skies. Four presets that deepen a blue sky the way a polarising filter does — Blue sky, Deep blue sky, Polariser, and Blue sky with golden land — and leave an overcast frame alone.
The sidebar counts the whole library. "All photographs" showed the size of the open album or collection instead of the library's. (#76)
No schema change. 0.17.0 and 0.18.0 devices sync with each other.
The APK, the desktop binary, the Windows installer and SHA256SUMS are built by CI from this tag's commit.
Downloads
-
DarkRoom 0.17.0
StableBenchmarks / CPU and I/O (per commit) (push) Successful in 5m22sBenchmarks / Frame budget (on demand) (push) SkippedTraceability / Requirement traces (push) Successful in 1m1sBuild and test / Android (aarch64) (push) Successful in 32m18sBuild and test / android-image (push) Successful in 1s🐳 Android image / Build and push (push) Successful in 1sBuild and test / Desktop (Linux) (push) Successful in 50m25sBuild and test / windows-image (push) Successful in 1s🐳 Windows image / Build and push (push) Successful in 1sBuild and test / Layer separation (push) Successful in 31sBuild and test / Windows (x86_64, cross) (push) Successful in 38m0sBuild and test / Publish the release (push) Successful in 50sreleased this
2026-09-26 20:18:20 +00:00 | 182 commits to master since this releaseFolders are chosen in your own desktop's dialog and exports go to albums outside the library, DarkRoom ships its own presets and film looks, a photograph still on the server says so instead of failing, and the catalog, sync and dehaze are faster again.
Albums, and folders chosen in a real dialog. Folders are picked in your desktop's own folder dialog (the XDG portal on Linux, the system dialog on Windows), which can create folders, instead of typed paths: the library folder, the import source and its second copy, and preset import. Exports go to albums — named export folders in the sidebar, on this device or on your Nextcloud but never inside the library — and an album shows the originals behind its JPEGs. Albums sync between devices, and the server browser can now create a folder. On Android, export goes to a folder on the tablet chosen in the system folder picker. (FR-EXP-10, FR-EXP-6)
Presets and film looks ship with the application. Essentials plus colour, cinema and black-and-white film looks, one measured stock each, updated with the app. Saving under a shipped preset's name makes your own version, and Revert gets the original back. Presets and Copy/Paste now carry the film stock, and shipped or imported Lightroom presets change only what they set, so your exposure and white-balance corrections survive applying a look. (FR-DEV-6)
A photograph that is not on this device says so. Opening one shows "Not on this device yet" and a download progress bar over its thumbnail, instead of "Could not load image". Stepping quickly through photographs that are still downloading no longer shows the wrong one, or saves one photograph's edit into another's.
Faster.
- Opening the catalog no longer repeats its repair pass on every open, and a photograph landing in develop costs about 2 ms of catalog work instead of about 80 ms. (#72)
- The library's counts: rating and label chips about 5× faster, the local-originals count 1.3 ms → 0.05 ms, keyword lists about 2×, the unfiltered grid count about 4×; a sync merge 230 → 135 ms. (#75)
- The upload snapshot is built directly instead of copying the whole 158 MB catalog and stripping it, about 1.2 s → 0.4 s per pass, with the same content uploaded. (#71)
- Dehaze runs in two passes instead of five, bit-identical: 22.9 → 9.1 ms at 2560×1600 on the desktop GPU; not yet measured on the tablet. (#74)
Fixed: thumbnail jobs nobody ran. Every scan queued a thumbnail job per photograph that nothing consumed — 23,582 on the reference library. Scans no longer queue them, the leftovers are cleared on open, and a test now refuses any job kind enqueued without a consumer. (#73)
No schema change. Two indexes are created on first use; the first sync after upgrading builds one of them inside the merge, about a second, once. A 0.16.0 tablet keeps syncing with a 0.17.0 desktop and the other way round.
The APK, the desktop binary, the Windows installer and SHA256SUMS are built by CI from this tag's commit.
Downloads
-
DarkRoom 0.16.0
StableBenchmarks / CPU and I/O (per commit) (push) Successful in 5m57sBenchmarks / Frame budget (on demand) (push) SkippedTraceability / Requirement traces (push) Successful in 47sBuild and test / Android (aarch64) (push) Successful in 31m41sBuild and test / android-image (push) Successful in 4s🐳 Android image / Build and push (push) Successful in 4sBuild and test / Desktop (Linux) (push) Successful in 47m44sBuild and test / windows-image (push) Successful in 4s🐳 Windows image / Build and push (push) Successful in 3sBuild and test / Layer separation (push) Successful in 45sBuild and test / Windows (x86_64, cross) (push) Successful in 36m16sBuild and test / Publish the release (push) Successful in 1m35sreleased this
2026-09-26 13:46:34 +00:00 | 231 commits to master since this releaseDuplicate RAWs can be folded into one, every film stock can be reached again, the desktop shows where it scrolls, and the catalog and the fit view are several times faster.
Consolidate duplicate originals. A library that has been copied, backed up and renamed holds the same RAW several times over — on the reference library, 1,836 groups and 3,379 surplus files. "Duplicate originals" in the sidebar and in Settings lists each group, proves its copies identical before anything moves (a hash of the first and last megabyte of each, read by range, so a Nextcloud library is not downloaded whole; results are kept so a second check is free), and keeps the copy not in a backup folder and still under the camera's own name — changeable per group. Collections, keywords, the highest rating, faces and a single edit are merged onto the copy that stays, in one transaction per group, and the rest go to DarkRoom's trash, from which they can be restored. Groups whose copies carry different edits are listed and left alone until virtual copies exist (#11). (#67)
Every film stock can be reached again. The film list opened ten rows tall and could not be scrolled — the develop column took every drag and most wheel turns meant for it — so eighteen stocks, all seven black-and-white among them, looked as though they had gone. It is now a popup over the column: the wheel, a drag, a flick and the scrollbar all reach the last stock, and Up, Down, Enter and Escape work while it is open. A test fails if the last stock ever becomes unreachable again.
Scrollbars on the desktop. The develop column, the library grid, the collections sidebar, the settings page, the help sheet and the film list show a scrollbar that tracks position, can be dragged, and pages on a click in its track. The tablet stays flick-only.
Help from develop. F1 opens Help from develop as well as from the grid, and a "?" sits beside Settings in develop's top bar; the bar is tightened so Settings fits at 1600 px. (#63)
Stepping along the roll on large libraries. A/D and the arrows in develop stopped at the edge of the grid's loaded window, and after a reload the roll could mark or judge the wrong photograph. Stepping now goes by library position. (#64) Develop's rating and flag keys are held to the open photograph, with tests. (#62)
Labels on text fields. "Filename template", "Destination", the storage budgets, export width and height and the import location had been drawn behind their fields, invisible, since 0.9.0. (#61)
Faster. The fit view reads its source gather once per framing rather than every frame — about 2.7× faster at 2560×1600 and 3× at 4K, bit-identical output — and a sharpen pass that changes nothing between two neighbourhood operations is skipped (sharpen plus clarity about 25% faster). On the catalog side, a full library scan went from about 2 s to 0.19 s, pulling another device's sidecars from about 650 ms to 9 ms for 342 files, opening the catalog takes about half as long, a sync pass merges faces about 1.7× faster and moves face shards 3–4× faster. No schema change.
Documentation brought up to the tree. The README no longer calls Android's CPU readback the one deliberate compromise (that ended in 0.15.0), and its feature list and "Where it stands" match what is built. The outstanding-work register, requirement status notes, architecture, catalog, storage and distribution notes and CONTRIBUTING were swept against the code, and the manual was re-recorded on this build — the film popup, the scrollbars, Help from develop, and a new picture of the duplicates review.
The APK, the desktop binary, the Windows installer and SHA256SUMS are built by CI from this tag's commit.
Downloads
-
DarkRoom 0.15.0
StableBenchmarks / CPU and I/O (per commit) (push) Successful in 5m19sBenchmarks / Frame budget (on demand) (push) SkippedTraceability / Requirement traces (push) Successful in 49sBuild and test / Android (aarch64) (push) Successful in 31m25sBuild and test / android-image (push) Successful in 1s🐳 Android image / Build and push (push) Successful in 1sBuild and test / Desktop (Linux) (push) Successful in 48m26sBuild and test / windows-image (push) Successful in 5s🐳 Windows image / Build and push (push) Successful in 4sBuild and test / Layer separation (push) Successful in 34sBuild and test / Windows (x86_64, cross) (push) Successful in 19m57sBuild and test / Publish the release (push) Successful in 1m6sreleased this
2026-09-25 11:51:43 +00:00 | 277 commits to master since this releaseThe keyboard reaches every part of the application, a help page CI keeps honest links each gesture to a bundled manual showing it, and develop gains perspective correction, mask intersection, colour labels and a true 1:1.
Perspective correction. Vertical and Horizontal sliders under Straighten in Compose correct converging lines: positive Vertical stands up a building photographed from below. The keystone maps the frame onto a trapezoid inside the photograph, so it never leaves black corners, and releasing a slider refits the crop as Straighten does. Masks, gradients and repair spots follow it. (#13, FR-DEV-20)
Intersection as a third way to join a mask part. Beside Add and Subtract, "∩ Intersect" keeps only where both selections agree: paint across a gradient and only the painted part of the gradient remains. The chip on each part cycles + / − / ∩, and J does the same from the keyboard. Older sidecars load unchanged. (#9)
Colour labels. Keys 6–9 set red, yellow, green and blue on the photograph under the pointer or on the selection, the same key again takes the label off, and a Label button offers all five. Each label is marked with its initial as well as its colour, the filter bar has a chip per label with a count, and labels travel in DarkRoom's sidecar and in XMP. A test now fails if stars, flags, peaking or labels ever become distinguishable by colour alone. (#37)
The photograph's own pixels at 1:1 and beyond. From 1:1 up, the develop view renders the visible region at the file's resolution and enlarges it nearest-neighbour, so each pixel is a hard-edged square and sharpening and noise reduction are judged on real pixels rather than on an enlargement the pipeline invented. It is also less GPU work when zoomed in.
A warning when a crop leaves a mask behind. When a crop takes a mask layer out of the frame, a notice names it and offers Undo crop or Keep crop. It never blocks, stays quiet during the drag, and one undo takes back both. (#10, FR-DEV-17)
No sharp renders in the middle of a drag. A long slider drag used to render a full-quality frame every 128 ms, which is what made it stutter. The sharp frame now comes 120 ms after the last movement, the draft fades into it, and the histogram dims while it describes a draft. (#24, FR-DSP-4)
The keyboard, everywhere. Ctrl+0 and Ctrl+1 for fit and 1:1, Ctrl+= and Ctrl+- to zoom, Shift+arrows to pan, = and - to nudge the control last moved, 0–5, P, X and U to judge the open photograph, G back to the grid; in the grid, Ctrl+D to select none, = and - for thumbnail size, Ctrl+K for keywords; arrows, F2 and Escape on the People screen; Escape closes the help sheet. Everything the keys do has a pointer and touch route too: a star strip and Pick/Reject in the develop top bar, a Flag button on the selection bar, and flags and stars on the develop roll.
A help page that cannot drift. Every key the application handles goes through one function, and CI fails if a bound key is missing from the help page or the page names a key nothing binds.
The manual, bundled and linked. The manual ships as an HTML page with the Arch package, the Windows installer and the APK, and opens offline from Help and Settings (Android shows it in-app). Fifty gestures on the help sheet have a "See it" link that opens the manual at the section showing it, and CI fails if a link points at a section that does not exist. The Flatpak cannot open it yet (#66).
A manual that re-records itself. The scripts that record the manual's pictures now find controls by their accessible names instead of screen coordinates, so a layout change no longer breaks them. Every picture was re-recorded for this release, with new ones for perspective, intersection, the crop warning and colour labels; CI fails if the manual shows a picture no scene makes, and
record.sh --changedre-records only what moved.Android draws develop on the GPU again (TD-1). Android's develop view read every frame back through the CPU, because wgpu's Vulkan swapchain would not rotate for a landscape-mounted panel and tore in portrait. Patched copies of wgpu-hal and Slint's Skia renderer now pre-rotate the swapchain, and the frame goes to the compositor as a texture as it does on desktop. Checked by eye on the tablet; no composition measurements yet.
Nextcloud over https only. The Nextcloud client refuses plain http below every URL it sends, browser sign-in keeps the server you typed and opens only https, and accounts saved as http:// are upgraded on launch.
Smaller things. The RAW decoder sits behind a trait, with a test that a stub decoder reaches the scan, previews and export (#57). The People tray's ticks move in place instead of rebuilding the tray per press.
The APK, the desktop binary, the Windows installer and SHA256SUMS are built by CI from this tag's commit.
Downloads
-
DarkRoom 0.14.1
StableBenchmarks / CPU and I/O (per commit) (push) Successful in 2m8sBenchmarks / Frame budget (on demand) (push) SkippedTraceability / Requirement traces (push) Successful in 33sBuild and test / Android (aarch64) (push) Successful in 14m21sBuild and test / android-image (push) Successful in 1s🐳 Android image / Build and push (push) Successful in 1sBuild and test / Desktop (Linux) (push) Successful in 47m57sBuild and test / windows-image (push) Successful in 1s🐳 Windows image / Build and push (push) Successful in 1sBuild and test / Layer separation (push) Successful in 51sBuild and test / Windows (x86_64, cross) (push) Successful in 34m3sBuild and test / Publish the release (push) Successful in 1m3sreleased this
2026-09-25 00:11:33 +00:00 | 327 commits to master since this releaseThe actions that apply to a whole edit or a whole selection are where they can be seen and where the keyboard expects them: copy, paste and presets in the develop top bar, batch export always on screen in the library, and Lightroom's and darktable's shortcuts for rating, exporting and stepping through a roll.
Batch export you can find. "Export N" was the last of a dozen buttons in a selection bar that scrolls sideways at desktop width, so it sat past the right edge and batch export looked like a feature the library did not have. It is pinned to the right of the bar now, always visible, and is still the cancel for a running batch.
Copy, paste and presets in the develop top bar. They sat in the develop column under a "SETTINGS" heading, which read as application settings, and vanished with the panel toggle and in the mask and spot modes. They now sit beside undo, since like undo they act on the whole edit. The paste button still names what it would apply.
"Paste to N" on every selection. It appeared only once settings had been copied in the session, so with nothing copied the selection bar gave no hint that pasting onto a selection was possible. It now shows whenever there is a selection, disabled until something is copied, next to Presets.
The keyboard steps through a library's roll. The arrow keys and space in develop walked only the files given on the command line, so a photograph opened from a library could be left only by clicking the roll. They now open the neighbouring frame exactly as a click would, saving the outgoing edit. A and D do the same.
Lightroom's export and copy shortcuts in develop. Ctrl+E opens an export sheet over the photograph and Ctrl+Shift+E exports straight away on the saved defaults; the export options are one set of controls shared with the settings page. Ctrl+Shift+C opens a copy sheet with the edit-kind chips, so a paste can leave each photograph's crop alone. While a sheet is up the develop keys stand down and Escape closes it.
Rate under the pointer, filter a star range. In the grid, 0-5, P, X and U judge the photograph under the pointer when it is outside the selection, and the whole selection otherwise. Holding F and tapping digits filters by stars: one digit for exactly that many, two for a range, F alone to clear. The grid also takes Ctrl+E, Ctrl+Shift+E, Ctrl+V and Ctrl+A, and "Gestures" is now "Help" ("Controls and shortcuts"), opened with F1.
A flaky test made reliable. The in-flight thumbnail claim test turned 0.14.0's Linux CI red: the waiter signalled before it reached the lock, so the first claim could be released before it waited. The test now waits for the waiter to park; 500 runs in a row pass.
Releases made by CI. A v* tag now builds and publishes its own Gitea Release, titled and described from the tag, with the downloads and their checksums attached.
The APK, the desktop binary, the Windows installer and SHA256SUMS are built by CI from this tag's commit.
Downloads
-
DarkRoom 0.13.2 — The People screen answers at once
StableBenchmarks / CPU and I/O (per commit) (push) Failing after 6m36sBenchmarks / Frame budget (on demand) (push) SkippedBuild and test / Desktop (Linux) (push) Failing after 46sBuild and test / Layer separation (push) Successful in 34sTraceability / Requirement traces (push) Failing after 40s🐳 Android image / Build and push (push) Successful in 2sBuild and test / android-image (push) Successful in 2s🐳 Windows image / Build and push (push) Successful in 2sBuild and test / windows-image (push) Successful in 2sBuild and test / Android (aarch64) (push) Failing after 2m26sBuild and test / Windows (x86_64, cross) (push) Failing after 3m7sreleased this
2026-09-20 09:07:45 +00:00 | 409 commits to master since this releasefile, a folder can be a library from its top level, and there is a manual.
- Confirming a face costs a frame, not half a second. Every click on
the face grid redrew the screen, and the redraw recomputed the coverage
line — several scans of the whole catalog to answer a question a
confirm cannot change — then re-read and re-decoded every crop of the
selected person. On a 24,000-image library with 19,000 faces a click was
~530 ms of catalog work; it is ~15 ms. "Confirm all" and a split write
their group in one transaction instead of one per face, and the rail is
filtered in the query rather than after reading 17,000 empty groups.
The coverage figure, when it is recomputed (opening the screen, ending a
sweep), is served from new partial indexes — schema V19, applied on
first open. CLAUDE.md records the patterns. - Deleting an image is one round trip. Each move to the trash asked
the server to create the trash folder's whole ancestor chain first;
the connection now remembers what it has confirmed exists. - A folder is a library from its top level. Confirming "/" in the
picker used to leave "Open library" disabled; a folder is now shown as
a LIBRARY, the subfolder question is optional, and the header names the
folder. - Thumbnail shards sync from a snapshot, never the live file. A shard
written moments earlier could upload as an empty file with its schema
still in the WAL, and every other device failed with "no such table"
on every pass. - A merged panorama is dated and sorted with its frames. The linear
DNG the merge writes puts its IFDs after the pixels; the scan reads the
tail as well as the head, and the composite takes the mean of its
frames' capture times rather than the first. - The border filler is fine-tuned on projection-shaped voids. ~2 dB
better in edges and corners than the stock model because it stops
inventing objects; still experimental (docs/panorama.md has the
measurements and what is left). - Smaller: the month headings in the grid are named on the row a month
opens; a mask's tint shows only while masking; a category mask no
longer widens the develop column past the window; a merge worker that
dies out of GPU memory is reported instead of leaving the page on
"Stop"; the keyword sheet takes focus; the empty trash says it is
empty; the export settings no longer promise to ask for a folder. - A manual. docs/manual/README.md pictures every feature from the
application itself; tools/manual/ regenerates the pictures.
darkroom-0.13.2-arm64-v8a.apkis the release-signed Android build (API
28+, arm64).darkroom-desktop-0.13.2-x86_64-linuxis the desktop binary.
SHA256SUMScovers both.Downloads
- Confirming a face costs a frame, not half a second. Every click on
-
DarkRoom 0.12.0 — Faces with a quality
StableBenchmarks / CPU and I/O (per commit) (push) Successful in 2m52sBenchmarks / Frame budget (on demand) (push) SkippedBuild and test / Desktop (Linux) (push) Successful in 44m13sBuild and test / Layer separation (push) Successful in 56s🐳 Android image / Build and push (push) Successful in 17m16sBuild and test / android-image (push) Successful in 17m17sTraceability / Requirement traces (push) Successful in 1m6sBuild and test / Android (aarch64) (push) Successful in 23m37sreleased this
2026-09-12 02:01:24 +00:00 | 536 commits to master since this releaseFaces that know how good they are, and masks you can see.
Faces
- Every face carries a quality. The embedder's raw output has a length,
and the length is the model's own reading of how recognisable the crop
was — a blur, an occlusion or a hard profile comes out short. It is kept
now, stored as the raw vector, and shown on the People screen as
"Quality 17.3". - A poor face is never a reference. Faces below the floor are still
placed with the person they match, but nothing is ever compared against
them, two of them are never paired, and they count as nobody's evidence.
One bad crop can no longer bridge two people into one group. - Faces already indexed are measured, not re-detected. The next "Index
faces" pass fetches each original once, embeds the faces it already found
from their stored landmarks, and writes the quality over them — ids,
boxes, confirmations and suggestions untouched. A synced device adopts the
measured vectors rather than redoing the work. - Choose the detector. Fast / Balanced / Thorough on the settings page,
per device: the measured trade is 14% more (small, real) faces for 12%
more time at Balanced, and a further 12% for 3.1× the time at Thorough.
Switching is a new model id and a re-index, never a silent change under
existing faces, and an image holds the faces of whichever pipeline looked
at it last.
Masks
- An eye and a colour on every mask. Each layer in the stack shows its
mask in its own colour, several at once, so where the sky's edge meets the
building's is something you can look at rather than guess. - A mask shows itself as soon as it is made, from the resting position,
so choosing a category answers what it selected. - A mask that is nothing but a brush. Paint sits beside Linear and
Radial; pressing it arms the brush and shows the mask. - The brush works again — and so do selecting a subject by clicking it,
placing a repair and sampling a neutral, all of which sat behind the
pan/zoom area and were never offered a press.
Build
- The Android build is signed with a real key from this release on. Any
device holding an earlier, debug-signed build has to uninstall once; every
build after this one installs over it with data intact. - CI is green on every job for the tagged commit.
Assets
darkroom-0.12.0-arm64-v8a.apkis the release-signed Android build (API 28+,
arm64).darkroom-desktop-0.12.0-x86_64-linuxis the desktop binary.
SHA256SUMScovers both.Downloads
- Every face carries a quality. The embedder's raw output has a length,
-
DarkRoom 0.7.0 — Film simulation
Stable🐳 Android image / Build and push (push) Successful in 1sBuild and test / android-image (push) Successful in 1sBuild and test / Desktop (Linux) (push) Successful in 1h20m35sBuild and test / Layer separation (push) Successful in 31sTraceability / Requirement traces (push) Failing after 1m0sBuild and test / Android (aarch64) (push) Failing after 33m5sreleased this
2026-08-26 16:14:23 +00:00 | 929 commits to master since this releaseFilm simulation, and the library that can keep up with it.
Film simulation
DarkRoom now renders a film stock from that stock's own measured
characteristic curves rather than from someone's approximation of the look.
The stock is chosen per photograph and remembered with it.- Five Ilford stocks — Delta 100, Delta 400, FP4 Plus, HP5 Plus and
Pan F Plus — alongside the colour stocks. The profiles state plainly
that they are constructed rather than measured, so nothing here claims
an authority it does not have. - Grain counts silver instead of adding noise on top: density drives
the grain, so it behaves the way the stock does rather than the way a
noise generator does. - Black-and-white negatives are printed rather than shown as a scan,
and development runs from the measurements rather than a contrast slider. - The whole stock renders on the GPU and takes over the render path, so
choosing a film is not a reason to wait.
Library
The grid stopped re-answering the same questions every time the window
moved. It pages along an index rather than re-sorting the library, loads
the window around the whole view instead of its first cell, and fetches
what is on screen before what is not. Shift-click now takes the whole run
it names rather than the part that happened to be loaded, and shows which
cell it is measuring from.Build and CI
Most of this is invisible unless it was broken, and it was.
- The segmentation model reaches CI again. Git LFS was being sent two
Authorizationheaders and Gitea answered 400; the Android image had no
git-lfsclient at all, and then nofile(1)for the API-level check. - The Android build produces an installable APK, assembled by the same
scriptpackage.shuses locally, and signs it with a real key when one
is configured — seedocs/android-signing.md. - The test build stopped filling the runner's disk: no debug info, no
incremental state, 24 GB down to 3.3 GB.
Files
file what darkroom-0.7.0-arm64-v8a.apkAndroid, arm64-v8a, minSdk 28. Debug-signed — this is a build you can install, not a distribution signature. darkroom-desktop-0.7.0-x86_64-linuxLinux desktop binary, x86-64. Needs libfontconfig1andlibxkbcommonpresent.SHA256SUMSchecksums for both. Downloads
- Five Ilford stocks — Delta 100, Delta 400, FP4 Plus, HP5 Plus and