web: fold the create form's groups and add the white/black point rows
The CREATE RECIPES form had grown into one long scroll. The six categorical groups (SIMULATION, DYNAMIC RANGE, GRAIN EFFECT, COLOR CHROME EFFECT, COLOR CHROME EFFECT BLUE, WHITE BALANCE) are now native <details> folds — the browser keeps the open flag, so no state and no library. The two tone-curve ENDS join the numeric grid: EXPOSURE (the matrix gain the IQ tab already drives), EV (the old EXPOSURE COMP. row, renamed to the phone's word), WHITE and BLACK. WHITE/BLACK are new ColorAdjustments fields, applied in TONE_SKSL as cubic end-weights rather than another smoothstep knee — the HL/SH knees already spend the slope budget, and the cubic keeps the curve monotonic for every combination (derivative >= 0.46), so a brighter input can still never come out darker. Both are optional, so stored recipes keep working.
This commit is contained in:
@@ -25,6 +25,9 @@ import { BaseFilter, ColorAdjustments } from '../types';
|
||||
// (Fuji extended DR); 0/auto/DR100 = no extra curve.
|
||||
// hl - highlight -1..1: + lifts toward white, - rolls the bright side down.
|
||||
// sh - shadow -1..1: + lifts the dark side, - deepens it.
|
||||
// wh - white point -1..1: + pushes the top of the ramp toward white, - rolls
|
||||
// it down. Cubic end-weight, so it never fights the HL knee.
|
||||
// bl - black point -1..1: + lifts the toe (faded black), - crushes it.
|
||||
// vib - vibrance -1..1: chroma-masked saturation. It rides along in this shader
|
||||
// (rather than the colour matrix) because it needs per-pixel chroma:
|
||||
// already-vivid pixels move least, so skins/skies deepen without the neon
|
||||
@@ -41,6 +44,8 @@ uniform shader src;
|
||||
uniform float dr;
|
||||
uniform float hl;
|
||||
uniform float sh;
|
||||
uniform float wh;
|
||||
uniform float bl;
|
||||
uniform float vib;
|
||||
uniform float shTr;
|
||||
uniform float shTg;
|
||||
@@ -61,6 +66,14 @@ vec4 main(vec2 xy) {
|
||||
// Dynamic range: gentle shadow lift + highlight roll (protect brights).
|
||||
o += dr * 0.12 * shMask * (1.0 - t);
|
||||
o -= dr * 0.18 * hlMask * t;
|
||||
// White/black point. The HL/SH knees above already spend the slope budget
|
||||
// (each just under 1.0), so these two use cubic end-weights instead of
|
||||
// another smoothstep: only the last/first stretch of the ramp moves, and the
|
||||
// derivative stays >= 1 - 3*0.18 = 0.46 for every combination, so the curve
|
||||
// can never invert. + lifts that end (faded blacks / brighter whites),
|
||||
// - digs it in (true black / rolled white).
|
||||
o += bl * 0.18 * (1.0 - t) * (1.0 - t) * (1.0 - t);
|
||||
o += wh * 0.18 * t * t * t;
|
||||
o = clamp(o, 0.0, 1.0);
|
||||
// Lightness takes the curve, hue stays: the colour difference is gained
|
||||
// only part-way so darkening cannot collapse a colour to black and lifting
|
||||
@@ -176,6 +189,8 @@ export interface ToneUniforms {
|
||||
dr: number; // 0..1
|
||||
hl: number; // -1..1 (adjustments.highlight / 10)
|
||||
sh: number; // -1..1 (adjustments.shadow / 10)
|
||||
wh: number; // -1..1 (adjustments.whites / 10 — white point)
|
||||
bl: number; // -1..1 (adjustments.blacks / 10 — black point)
|
||||
vib: number; // -1..1 (adjustments.vibrance / 10)
|
||||
shT: [number, number, number]; // shadow split-tone RGB bias, -1..1
|
||||
hlT: [number, number, number]; // highlight split-tone RGB bias, -1..1
|
||||
@@ -208,6 +223,8 @@ export function getToneUniforms(adj: ColorAdjustments, baseFilter?: BaseFilter):
|
||||
const dr = drRaw === 'auto' || drRaw === 100 ? 0 : (drRaw - 100) / 300;
|
||||
const hl = Math.max(-1, Math.min(1, (adj.highlight ?? 0) / 10));
|
||||
const sh = Math.max(-1, Math.min(1, (adj.shadow ?? 0) / 10));
|
||||
const wh = Math.max(-1, Math.min(1, (adj.whites ?? 0) / 10));
|
||||
const bl = Math.max(-1, Math.min(1, (adj.blacks ?? 0) / 10));
|
||||
const vib = Math.max(-1, Math.min(1, (adj.vibrance ?? 0) / 10));
|
||||
const film = (baseFilter && FILM_TONE[baseFilter]) || {};
|
||||
const shT: [number, number, number] = film.shT ?? [0, 0, 0];
|
||||
@@ -224,6 +241,8 @@ export function getToneUniforms(adj: ColorAdjustments, baseFilter?: BaseFilter):
|
||||
dr,
|
||||
hl: hl + (film.hl ?? 0),
|
||||
sh: sh + (film.sh ?? 0),
|
||||
wh,
|
||||
bl,
|
||||
vib,
|
||||
shT,
|
||||
hlT,
|
||||
@@ -235,7 +254,7 @@ export function getToneUniforms(adj: ColorAdjustments, baseFilter?: BaseFilter):
|
||||
// Flat uniform buffer for `makeShaderWithChildren` / `<Shader uniforms>` — the
|
||||
// order must match TONE_SKSL's declarations.
|
||||
export function toneUniformArray(u: ToneUniforms): number[] {
|
||||
return [u.dr, u.hl, u.sh, u.vib, u.shT[0], u.shT[1], u.shT[2], u.hlT[0], u.hlT[1], u.hlT[2], u.cc, u.ccb];
|
||||
return [u.dr, u.hl, u.sh, u.wh, u.bl, u.vib, u.shT[0], u.shT[1], u.shT[2], u.hlT[0], u.hlT[1], u.hlT[2], u.cc, u.ccb];
|
||||
}
|
||||
|
||||
export function toneIsActive(u: ToneUniforms): boolean {
|
||||
@@ -243,6 +262,8 @@ export function toneIsActive(u: ToneUniforms): boolean {
|
||||
u.dr !== 0 ||
|
||||
u.hl !== 0 ||
|
||||
u.sh !== 0 ||
|
||||
u.wh !== 0 ||
|
||||
u.bl !== 0 ||
|
||||
u.vib !== 0 ||
|
||||
u.shT[0] !== 0 ||
|
||||
u.shT[1] !== 0 ||
|
||||
|
||||
Reference in New Issue
Block a user