From e01660c1d4a46057fbac1c259e9cbd8716f5c3ab Mon Sep 17 00:00:00 2001 From: w1n5t0n Date: Fri, 3 Apr 2026 18:20:52 +0100 Subject: [PATCH] =?UTF-8?q?feat(playground):=20Linked=20mode=20training=20?= =?UTF-8?q?target=20UI=20=E2=80=94=20separate=20FX=20RL=20buttons=20(meml-?= =?UTF-8?q?0r0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- playground/a-immersive.html | 10 +++++ playground/css/a-immersive.css | 75 ++++++++++++++++++++++++++++++++++ playground/js/a-app.js | 47 +++++++++++++++++++++ 3 files changed, 132 insertions(+) diff --git a/playground/a-immersive.html b/playground/a-immersive.html index 79ad01f..4ccddb1 100644 --- a/playground/a-immersive.html +++ b/playground/a-immersive.html @@ -110,6 +110,7 @@
+
+ + +
0 examples · untrained @@ -371,6 +379,8 @@ Keyboard 1Negative feedback (−) 2Positive feedback (+) + 3FX negative feedback (Linked mode) + 4FX positive feedback (Linked mode) ZUndo Gamepad (Steam Deck, Xbox, etc.) Left stickJoystick control diff --git a/playground/css/a-immersive.css b/playground/css/a-immersive.css index 98ee391..f3be6c1 100644 --- a/playground/css/a-immersive.css +++ b/playground/css/a-immersive.css @@ -634,6 +634,67 @@ html, body { animation: rl-flash 0.25s ease-out; } +/* ---- RL label (shown in Linked mode to distinguish Synth vs FX) ---- */ +.rl-label { + grid-column: 1 / -1; + font-size: 10px; + text-transform: uppercase; + letter-spacing: 0.05em; + opacity: 0.6; + text-align: center; + color: var(--text); +} +.rl-label.hidden { display: none; } + +/* ---- EOC RL buttons (FX feedback, Linked mode) ---- */ +.eoc-rl-buttons { + position: fixed; + bottom: 36px; + left: calc(50% + 100px); + display: flex; + flex-direction: column; + align-items: center; + gap: 6px; + z-index: 45; + transition: opacity 0.3s; +} +.eoc-rl-buttons.hidden { display: none; } + +.eoc-rl-label { + font-size: 10px; + text-transform: uppercase; + letter-spacing: 0.05em; + opacity: 0.6; + color: var(--text); +} + +.eoc-rl-btn { + width: 48px; + height: 48px; +} + +.eoc-rl-btn.rl-up { + border-color: rgba(78, 205, 196, 0.4); + color: #4ecdc4; + background: rgba(78, 205, 196, 0.08); +} + +.eoc-rl-btn.rl-up:active { + background: rgba(78, 205, 196, 0.2); + box-shadow: 0 0 20px rgba(78, 205, 196, 0.3); +} + +.eoc-rl-btn.rl-down { + border-color: rgba(78, 205, 196, 0.3); + color: #e07040; + background: rgba(224, 112, 64, 0.08); +} + +.eoc-rl-btn.rl-down:active { + background: rgba(224, 112, 64, 0.2); + box-shadow: 0 0 20px rgba(224, 112, 64, 0.3); +} + /* ---- Status line (floating, minimal) ---- */ .status-line { position: fixed; @@ -1956,6 +2017,11 @@ html, body { font-size: 32px; } + .eoc-rl-btn { + width: 54px; + height: 54px; + } + .drawer-stack { width: 280px; } @@ -1985,6 +2051,15 @@ html, body { .rl-icon { font-size: 24px; } + + .eoc-rl-btn { + width: 42px; + height: 42px; + } + + .eoc-rl-buttons { + left: calc(50% + 80px); + } } /* ---- MIDI CC mode ---- */ diff --git a/playground/js/a-app.js b/playground/js/a-app.js index 5453317..9230478 100644 --- a/playground/js/a-app.js +++ b/playground/js/a-app.js @@ -1112,6 +1112,13 @@ async function init() { await initEocIML(); } } + + // Show/hide EOC RL buttons and Synth label based on linked mode + const isLinked = eocChain.nispsMode === 'linked'; + const eocRlContainer = document.getElementById('eoc-rl-buttons'); + if (eocRlContainer) eocRlContainer.classList.toggle('hidden', !isLinked); + const rlLabel = document.getElementById('rl-label'); + if (rlLabel) rlLabel.classList.toggle('hidden', !isLinked); }); // Debug probe — exposed on window when ?debug=1 is in the URL. @@ -2003,6 +2010,28 @@ function wireControls() { $btnThumbsUp.addEventListener('click', onThumbsUp); $btnThumbsDown.addEventListener('click', onThumbsDown); + // EOC RL buttons (Linked mode — target EOC IML directly) + const eocRlPlus = document.getElementById('eoc-rl-plus'); + const eocRlMinus = document.getElementById('eoc-rl-minus'); + if (eocRlPlus && eocRlMinus) { + eocRlPlus.addEventListener('click', () => { + if (!imlEoc) return; + const prevTarget = eocTrainingTarget; + eocTrainingTarget = 'eoc'; + onThumbsUp(); + eocTrainingTarget = prevTarget; + flash('eoc-rl-plus'); + }); + eocRlMinus.addEventListener('click', () => { + if (!imlEoc) return; + const prevTarget = eocTrainingTarget; + eocTrainingTarget = 'eoc'; + onThumbsDown(); + eocTrainingTarget = prevTarget; + flash('eoc-rl-minus'); + }); + } + // Undo button document.getElementById('btn-undo').addEventListener('click', onUndo); @@ -3056,6 +3085,24 @@ function wireKeyboard() { } else if (e.key === '2' || e.code === 'Numpad2') { e.preventDefault(); onThumbsUp(); + } else if (e.key === '3' || e.code === 'Numpad3') { + e.preventDefault(); + if (imlEoc && eocChain?.nispsMode === 'linked') { + const prevTarget = eocTrainingTarget; + eocTrainingTarget = 'eoc'; + onThumbsDown(); + eocTrainingTarget = prevTarget; + flash('eoc-rl-minus'); + } + } else if (e.key === '4' || e.code === 'Numpad4') { + e.preventDefault(); + if (imlEoc && eocChain?.nispsMode === 'linked') { + const prevTarget = eocTrainingTarget; + eocTrainingTarget = 'eoc'; + onThumbsUp(); + eocTrainingTarget = prevTarget; + flash('eoc-rl-plus'); + } } else if (e.key === 'z' || e.key === 'Z') { e.preventDefault(); onUndo();