web: a film sim is colour and tone only

The ten PHOTO STYLE sims now carry nothing but their stock's own grade, and
each is named for the stock it stands for: PROVIA, VELVIA, CLASSIC CHROME,
CLASSIC VIVID (Velvia spliced with Classic Chrome at the blue row), CLASSIC
NEGATIVE, ASTIA, ETERNA, ACROS, LC STREETLIFE CLASSIC, LC STREETLIFE VIVID.
Grain, clarity, saturation and light moves were dropped from their
`adjustments`, so a sim is a clean starting point and the general knobs read
their defaults while the look still lands on the pixels.

LC STREETLIFE VIVID keeps the one brightness step its stock needs, but as
SIM_EXPOSURE_BIAS in colorUtils rather than as an adjustment: it is folded in
where the Exposure slider applies, so the picture gets the lift and the
parameter stays at 0.

Also in this checkpoint: the watermark/GPS boxes and their colour pickers, the
WATERMARK chip column, the real admin stats, and the fix that stopped presets
from doubling and a frame from refusing to come off when a photo was reopened
(/file is the finished render, /base the editable pixels).
This commit is contained in:
2026-09-22 08:32:28 +07:00
parent 52b672deec
commit 428e7fa682
18 changed files with 1831 additions and 148 deletions
+13 -1
View File
@@ -105,7 +105,10 @@
.col .chip { justify-content: space-between; text-align: left; }
/* UNDO/REDO are one glyph each, so the pair reads as a single control. */
.header .btn.icon { padding: 4px 9px; font-size: 15px; line-height: 1.2; }
.wm-extra { border-right-color: var(--accent-line); }
/* WATERMARK's own column: its chips carry the longest labels in the app
("GPS WATERMARK OFF", "CUSTOM WATERMARK OFF" + PRO), which wrap in the
default column width. */
.wm-extra { border-right-color: var(--accent-line); width: 200px; }
.chip {
border: 1px solid var(--border);
background: var(--bg-elev);
@@ -312,6 +315,15 @@ input[type="range"] { width: 100%; accent-color: var(--accent); }
.crop-handle.tr { right: 0; top: 0; transform: translate(50%, -50%); cursor: nesw-resize; }
.crop-handle.bl { left: 0; bottom: 0; transform: translate(-50%, 50%); cursor: nesw-resize; }
.crop-handle.br { right: 0; bottom: 0; transform: translate(50%, 50%); cursor: nwse-resize; }
/* FRAME's custom watermark box: drag the body to move, the corner to scale. */
.wm-layer { position: absolute; border-radius: var(--radius-sm); pointer-events: none; }
.wm-rect { position: absolute; border: 1px dashed var(--accent); cursor: move; pointer-events: auto; touch-action: none; }
.wm-handle { position: absolute; width: 14px; height: 14px; background: var(--accent); border: 2px solid #fff; border-radius: 3px; touch-action: none; }
.wm-handle.br { right: 0; bottom: 0; transform: translate(50%, 50%); cursor: nwse-resize; }
/* A watermark's colour: the preset chips are a shortcut, the well picks any. */
.color-well { display: flex; align-items: center; gap: 8px; padding: 6px 8px; cursor: pointer; }
.color-well input[type="color"] { width: 34px; height: 22px; padding: 0; border: 1px solid var(--accent-line); border-radius: 3px; background: none; cursor: pointer; }
.color-well .val { font-size: 11px; letter-spacing: 0.08em; color: var(--muted); }
/* Eyedropper: the photo's own box, left transparent, with a crosshair cursor. */
.pick-layer {
position: absolute;