web: open the stage on the neutral stock, not the CLASSIC NEGIPES preset

The boot recipe was DEFAULT_RECIPES[0], so every file that landed — NEF
or JPEG — came in with exposure +2 (+0.5 EV), contrast +1, saturation -1,
6300K / tint +2, highlight -2, clarity +2, grain +4 and the classic-neg
filter already on. On APACHAI-20160215-357.NEF that read as pink skin and
blown highlights, and it made a correct decode look like a decode bug.
Develop itself was fine: 179.0/168.2/171.2 against the embedded preview's
178.2/167.1/170.7.

Boot is now BASE_RECIPE — no filter, all knobs default, the same look
COMPARE splits against. A session left by the old boot holds that preset
verbatim, which was never the visitor's pick, so it is dropped; anything
the visitor actually touched moves the stored object off the exact
fingerprint and is kept.

Render bytes, same 1600x1068 view of the JPEG (R/G/B means):
  source file          170.7 / 159.1 / 163.1
  before               194.7 / 178.0 / 177.2
  after                169.5 / 158.5 / 162.0
NEF render stage: 202.4 / 186.3 / 185.4 -> 177.9 / 167.3 / 169.9
Output is byte-identical to the old neutral render (md5 a3932746...),
while a clicked chip (classic-neg-default) and a tweaked session both
still restore their own bytes.
This commit is contained in:
2026-09-28 16:29:24 +07:00
parent d1e9425b9c
commit e24ea9e71d
+17 -6
View File
@@ -292,12 +292,23 @@ export function Workspace() {
const [comparing, setComparing] = useState(false);
const [compareUrl, setCompareUrl] = useState<string | null>(null);
const [recipe, setRecipe] = useState<Recipe>(() => ({
...DEFAULT_RECIPES[0],
id: 'web-current',
name: DEFAULT_RECIPES[0]?.name ?? 'PROVIA',
...session.recipe,
}));
const [recipe, setRecipe] = useState<Recipe>(() => {
// The stage opens on the photo itself — the neutral stock, every knob at its
// default and no film filter, the same recipe COMPARE splits against — so a
// file that is dropped in is shown as the file. The bundled CLASSIC NEGIPES
// preset used to sit here as the boot look, and it baked exposure +2 (+0.5
// EV) plus a 6300K / tint +2 white balance onto every photo the moment it
// landed: that is what blew the highlights and turned skin pink on a fresh
// NEF. A look is now there only because a chip was clicked.
const boot = DEFAULT_RECIPES[0];
// A session written by that old boot still holds the preset verbatim, which
// was never the visitor's choice; it is dropped instead of restored. Any
// edit to a knob moved the stored object off this exact fingerprint.
const stale = !!boot && session.recipe?.id === 'web-current' &&
session.recipe.baseFilter === boot.baseFilter &&
JSON.stringify(session.recipe.adjustments) === JSON.stringify(boot.adjustments);
return { ...BASE_RECIPE, id: 'web-current', ...(stale ? null : session.recipe) };
});
const [simId, setSimId] = useState<string | null>(() => session.simId ?? null);
// HOVER PREVIEW: the look of the sim or recipe the pointer is over, laid on the
// photo for as long as it stays there. It never becomes `recipe`, so SAVE,