Bring a Lightroom library across, and start with something in the list

Two halves of the same complaint: a preset sheet that opens on "No
presets yet" is homework, and a photographer with ten years of presets
in Lightroom has no way to bring them.

`dr-preset-xmp` reads Camera Raw `.xmp`. The mapping turned out to be
mostly a rename rather than a conversion, because Adobe and this
pipeline already agree: exposure is in stops in both, and contrast, the
four recovery controls, clarity, texture, vibrance and saturation are
all ±100 in both. That is not imitation, it is the convention raw
developers converged on — `highlights_shadows.yaml` cites it in as many
words. Only sharpening needed arithmetic, Adobe's 0…150 against our
0…100.

The white balance does not come across, and says so rather than
guessing. Adobe writes absolute Kelvin for a raw file where ours is a
relative nudge from what the camera recorded, so converting needs the
*target image's* as-shot white balance — exactly what a preset cannot
carry, since the same preset lands on a frame shot at 3200K and one shot
at 7000K. A guess would be wrong on most images and invisibly so.

A folder is read as readily as a file, nested, because that is the shape
an exported preset folder is in and importing ninety files one at a time
is asking someone not to bother.

`dr_pipeline::starter` is six presets a first run begins with, written
against this pipeline in its units and deliberately mild — a starting
point, not a caricature. They are seeded when the library *file* does
not exist rather than when the library is empty, so deleting all six
does not hand them back on the next launch.

Both of these name operations, and `ui_names_no_operation` was right to
stop them living in `ui/`. That test exists because the failure is
silent and cumulative, and it caught exactly what it was written for: a
preset called "Punch" is a statement about contrast, clarity and
vibrance, and a table mapping Adobe's vocabulary to ours is a statement
about the pipeline. Neither is a fact about an interface. So the starter
set went into `dr-pipeline`, and the importer into its own crate —
between two walls, since `dr-pipeline` depends on nothing on purpose and
XMP is real XML not worth hand-rolling.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-29 22:00:53 +02:00
co-authored by Claude Opus 5
parent bb35665bd2
commit 754ab91347
11 changed files with 1209 additions and 19 deletions
+29
View File
@@ -110,6 +110,14 @@ export component PresetSheet inherits Rectangle {
in property <bool> scope-empty: false;
callback scope-toggled(string);
/// TRACES: FR-DEV-6
/// Read Lightroom presets from a typed path, and what came of the last
/// attempt. A typed path rather than a file dialogue because that is the
/// idiom this application already has — the launch screen takes a library
/// the same way, and there is no native picker anywhere in it.
in property <string> import-report;
callback import-presets(string);
background: #000000CC;
// Swallows the taps that miss the card, and closes. First, so the card's
@@ -265,6 +273,27 @@ export component PresetSheet inherits Rectangle {
Rectangle { height: 1px; background: Theme.rule; }
// TRACES: FR-DEV-6
// Bringing a Lightroom library across. A folder rather than a
// file is the expected case — an exported preset folder, nested
// one level per group — so the field says so.
VerticalLayout {
spacing: Theme.gap-sm;
PanelHeading { text: "IMPORT"; }
Field {
placeholder: "Path to a .xmp file or folder";
accepted(path) => { root.import-presets(path); }
}
if root.import-report != "": Caption {
text: root.import-report;
}
}
Rectangle { height: 1px; background: Theme.rule; }
// TRACES: FR-DEV-6
// What an apply carries. At the bottom, because it qualifies every
// action above it rather than being one of them — and because the