feat(sim+engine): lock alteration calibration + fix psychedelic dark grade
Tuning the look by eye in the simulator (design §8) surfaced that the dark mood pole rendered a full-frame hue-rotate(-200deg) — rock orange, trees purple: the disorienting look rejected in session 0008, not the peaceful POC dark_frame. Replace it with darken + slight desaturate on the video filter plus a multiply-blended deep-blue wash (#tint, below the SVG HUD so the overlay stays legible). Dark now reads cool/somber with natural greens, like the approved POC look; light/left/right unchanged and confirmed peaceful. With full tilt now tasteful on every axis, LOCK DEFAULT_CALIBRATION to unity gains + linear variant map as a deliberate by-eye choice (not placeholders), closing the open session-0006 knob->strength decision: knobs run 0=off..4=max, equal Dark/Light = identity, the 5 notches map 1:1 to the 5 discrete Right bakes. Guard the locked constants with test_default_calibration_is_locked. Resolves design §8 open questions (calibration curve shape; grade-vs-overlay ordering) and records the dark-grade fix. Full suite 193 passed / 2 skipped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// Thin renderer: post controls+calibration -> RenderPlan; render grade, Right
|
||||
// variant crossfade, and the live Left overlay. All math stays in Python.
|
||||
const $ = (id) => document.getElementById(id);
|
||||
const vid = $("vid"), overlay = $("overlay"), black = $("black"), readout = $("readout");
|
||||
const vid = $("vid"), tint = $("tint"), overlay = $("overlay"), black = $("black"), readout = $("readout");
|
||||
|
||||
let clip = null; // active clip manifest entry
|
||||
let currentVariant = -1; // last loaded Right strength
|
||||
@@ -19,12 +19,16 @@ function variantFile(strength) {
|
||||
}
|
||||
|
||||
function applyGrade(tone) {
|
||||
// Light: warm + brighten; Dark: cool + darken; 0: raw.
|
||||
// Light: warm + brighten (sepia). Dark: cool + darken via a multiply-blended
|
||||
// blue wash (#tint) that lifts shadows toward blue while keeping natural
|
||||
// greens — the peaceful POC dark look, NOT a full-frame hue spin.
|
||||
const warm = tone > 0 ? tone : 0, cool = tone < 0 ? -tone : 0;
|
||||
const bright = 1 + 0.25 * tone, sat = 1 + 0.15 * Math.abs(tone);
|
||||
const bright = 1 + 0.25 * warm - 0.35 * cool;
|
||||
const sat = 1 + 0.15 * warm - 0.30 * cool;
|
||||
vid.style.filter =
|
||||
`brightness(${bright}) saturate(${sat}) ` +
|
||||
`sepia(${(warm * 0.5).toFixed(3)}) hue-rotate(${(-cool * 200).toFixed(0)}deg)`;
|
||||
`brightness(${bright.toFixed(3)}) saturate(${sat.toFixed(3)}) ` +
|
||||
`sepia(${(warm * 0.5).toFixed(3)})`;
|
||||
tint.style.opacity = (cool * 0.6).toFixed(3);
|
||||
}
|
||||
|
||||
function loadVariant(strength) {
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<section class="stage">
|
||||
<div class="screen">
|
||||
<video id="vid" loop muted playsinline></video>
|
||||
<div id="tint"></div>
|
||||
<svg id="overlay" viewBox="0 0 100 100" preserveAspectRatio="none"></svg>
|
||||
<div id="black" class="black hidden"></div>
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,9 @@ main { display: flex; gap: 1rem; padding: 1rem; flex-wrap: wrap; }
|
||||
.screen { position: relative; width: 100%; aspect-ratio: 16 / 9; background: #000;
|
||||
border-radius: 6px; overflow: hidden; }
|
||||
#vid { width: 100%; height: 100%; object-fit: cover; transition: opacity 0.15s ease; }
|
||||
#tint { position: absolute; inset: 0; pointer-events: none; opacity: 0;
|
||||
background: #28425f; mix-blend-mode: multiply;
|
||||
transition: opacity 0.2s ease; }
|
||||
#overlay { position: absolute; inset: 0; width: 100%; height: 100%;
|
||||
pointer-events: none; transition: opacity 0.2s ease; }
|
||||
.anno-box { fill: none; stroke: #6cf; stroke-width: 0.4; vector-effect: non-scaling-stroke; }
|
||||
|
||||
Reference in New Issue
Block a user