feat(keys_highway_3d): anti-plastic materials, studio env, themes, gradient sky, cinematic + glow (K3) (#711)

- Note gems -> MeshPhysicalMaterial: clearcoat 1.0/0.18, roughness 0.32,
  envMapIntensity 0.9 — lacquered glass, not plastic (the explicit ask)
- _makeStudioEnv (PORTED drum_highway_3d): PMREM studio -> scene.environment;
  black keys 0.22 roughness / 1.3 envInt (glossy piano black), whites
  0.42/0.55 ivory, floor 0.55/0.15/0.4 stage sheen
- Vertical-gradient background (light horizon -> theme clear -> dark deck),
  sRGB-tagged for the composer path
- BG_THEMES port (guitar ids/values; keys 'default' = original palette;
  themes drive gradient/fog/floor/rails, never the pitch-class colors);
  keys3dSetTheme + keys3d_bg_theme, live _applyTheme
- Cinematic lighting toggle (0.55/1.3 on; stock 0.75/1.1 off); Glow slider
  across NOTE_EMISSIVE_BASE / consume-flash / key approach-glow
- Env RT + gradient texture disposed in teardown
- Tests: theme table parity + default preservation (28 total)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Byron Gamatos
2026-07-02 08:51:48 +02:00
committed by GitHub
co-authored by Claude Fable 5
parent 95b0786725
commit 80fc371f11
5 changed files with 324 additions and 23 deletions
+52 -1
View File
@@ -11,7 +11,51 @@
<!-- Graphics -->
<div class="mt-3">
<h4 class="text-xs font-medium text-gray-300 mb-2">Graphics</h4>
<label for="keysh3d-fx-bloom" class="flex items-center gap-2 text-xs text-gray-300 cursor-pointer">
<label for="keysh3d-fx-theme" class="text-xs font-medium text-gray-400 mb-1 block">Scene theme</label>
<select id="keysh3d-fx-theme"
onchange="window.keys3dSetTheme && window.keys3dSetTheme(this.value)"
class="w-full bg-dark-700 border border-gray-800 rounded-lg px-3 py-2 text-xs text-gray-300 outline-none">
<option value="default">Default (original)</option>
<option value="midnight">Midnight</option>
<option value="charcoal">Charcoal</option>
<option value="deeppurple">Deep Purple</option>
<option value="forest">Forest</option>
<option value="warmslate">Warm Slate</option>
<option value="deepfocus">Deep Focus</option>
<option value="deepsea">Deep Sea</option>
<option value="cathode">Cathode</option>
<option value="cathodegreen">Cathode Green</option>
<option value="hearth">Hearth</option>
</select>
<p class="text-xs text-gray-500 mt-1 mb-3">
Background gradient, floor and lane rails — the same theme names
as the guitar highway. Pitch-class note colours never change.
</p>
<label for="keysh3d-fx-cinematic" class="flex items-center gap-2 text-xs text-gray-300 cursor-pointer">
<input type="checkbox" id="keysh3d-fx-cinematic" checked
onchange="window.keys3dSetFx && window.keys3dSetFx('cinematic', this.checked)">
Cinematic lighting
</label>
<p class="text-xs text-gray-500 mt-1">
Dimmer ambience, stronger key light — deeper shading on the keys
and gems.
</p>
<label for="keysh3d-fx-glow" class="text-xs font-medium text-gray-400 mb-1 mt-3 block">
Glow strength <span id="keysh3d-fx-glow-val" class="text-gray-500 font-mono">0.50</span>
</label>
<input type="range" id="keysh3d-fx-glow"
min="0" max="1" step="0.05" value="0.5"
oninput="window.keys3dSetFx && window.keys3dSetFx('glow', this.value); document.getElementById('keysh3d-fx-glow-val').textContent = parseFloat(this.value).toFixed(2)"
class="w-full">
<p class="text-xs text-gray-500 mt-1">
How hard the notes, key glow and sustain consume-flash
self-illuminate (0.5 = stock). Pairs with bloom.
</p>
<label for="keysh3d-fx-bloom" class="flex items-center gap-2 text-xs text-gray-300 cursor-pointer mt-3">
<input type="checkbox" id="keysh3d-fx-bloom" checked
onchange="window.keys3dSetFx && window.keys3dSetFx('bloom', this.checked)">
Glow (bloom)
@@ -95,6 +139,7 @@
hydrateFxBool('sparks', 'keysh3d-fx-sparks');
hydrateFxBool('timingFx', 'keysh3d-fx-timing');
hydrateFxBool('streakFx', 'keysh3d-fx-streak');
hydrateFxBool('cinematic', 'keysh3d-fx-cinematic');
const hydrateFxRange = (key, elId, valId) => {
const n = parseFloat(localStorage.getItem('keys3d_bg_' + key));
if (!Number.isFinite(n)) return;
@@ -104,6 +149,12 @@
};
hydrateFxRange('hitFx', 'keysh3d-fx-hitfx', 'keysh3d-fx-hitfx-val');
hydrateFxRange('vibrancy', 'keysh3d-fx-vibrancy', 'keysh3d-fx-vibrancy-val');
hydrateFxRange('glow', 'keysh3d-fx-glow', 'keysh3d-fx-glow-val');
const storedTheme = localStorage.getItem('keys3d_bg_theme');
const themeSel = document.getElementById('keysh3d-fx-theme');
if (storedTheme && Array.from(themeSel.options).some(o => o.value === storedTheme)) {
themeSel.value = storedTheme;
}
} catch (e) {
console.warn('[Keys-Hwy3D settings] hydration failed:', e);
}