- Glass-style modal explains NISPS, how learning works, and what to expect - Documents all controls: touch, keyboard, and gamepad bindings - Shows automatically on first visit (localStorage flag) - Dismissible via close button, "Got it", overlay click, or Escape - Reopenable via ? button at bottom right
232 lines
11 KiB
HTML
232 lines
11 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="mobile-web-app-capable" content="yes">
|
|
<title>NISPS Immersive</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="css/a-immersive.css">
|
|
</head>
|
|
<body>
|
|
<!-- Back button -->
|
|
<a href="designs.html" class="back-btn" title="Back to designs">
|
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M10 2L4 8l6 6"/>
|
|
</svg>
|
|
</a>
|
|
|
|
<!-- Synth quick controls (play button + drawer, next to back button) -->
|
|
<div class="synth-quick-controls hidden" id="synth-quick-controls">
|
|
<button class="play-btn" id="quick-play" title="Start audio + arpeggiator">
|
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" id="quick-play-icon"><path d="M4 2l10 6-10 6z"/></svg>
|
|
</button>
|
|
<div class="play-drawer" id="play-drawer">
|
|
<label>Vol <input type="range" id="quick-vol" min="0" max="1" step="0.01" value="0.5"></label>
|
|
<label>BPM <input type="range" id="quick-bpm" min="40" max="240" step="1" value="120"><span id="quick-bpm-val">120</span></label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Fullscreen flow field canvas -->
|
|
<canvas id="vis-canvas"></canvas>
|
|
|
|
<!-- Synth visualization canvas -->
|
|
<canvas id="synth-vis-canvas"></canvas>
|
|
|
|
<!-- Heatmap strip (top) -->
|
|
<div class="heatmap-strip" id="heatmap-strip">
|
|
<div class="heatmap-cells" id="heatmap-cells"></div>
|
|
<div class="heatmap-tooltip" id="heatmap-tooltip"></div>
|
|
</div>
|
|
|
|
<!-- Floating joystick with integrated map -->
|
|
<div class="joystick-container" id="joystick-container">
|
|
<div class="joystick-glow" id="joystick-glow"></div>
|
|
<canvas id="joy-map" width="160" height="160"></canvas>
|
|
<div class="noise-ring" id="noise-ring"></div>
|
|
<div class="follow-badge hidden" id="follow-badge">FOLLOW</div>
|
|
<div id="gamepad-status" style="color: #ff6a00; font-size: 0.6rem; text-align: center; position: absolute; bottom: -16px; left: 0; right: 0; pointer-events: none;"></div>
|
|
</div>
|
|
|
|
<!-- RL floating buttons -->
|
|
<div class="rl-buttons" id="rl-buttons">
|
|
<button class="rl-btn rl-down" id="btn-thumbsdown" title="Explore more"><span class="rl-icon">−</span><span class="key-num">1</span></button>
|
|
<button class="rl-btn rl-up" id="btn-thumbsup" title="Keep this"><span class="rl-icon">+</span><span class="key-num">2</span></button>
|
|
</div>
|
|
|
|
<!-- Bottom sheet -->
|
|
<div class="bottom-sheet collapsed" id="bottom-sheet">
|
|
<!-- Floating mode bar (sticky inside sheet) -->
|
|
<div class="floating-bar" id="floating-bar">
|
|
<div class="pill-toggle pill-toggle-sm" id="output-toggle-float">
|
|
<button class="pill-opt active" data-mode="visual">Visual</button>
|
|
<button class="pill-opt" data-mode="synth">Synth</button>
|
|
</div>
|
|
<button class="float-btn accent" id="btn-train-bar" title="Train on examples">Train</button>
|
|
<button class="float-btn" id="btn-randomize-bar" title="Randomize weights">Randomize</button>
|
|
<button class="float-btn" id="btn-clear-examples-bar" title="Clear examples">Clear Ex</button>
|
|
<button class="follow-pill" id="follow-pill" title="Toggle follow mode">Follow</button>
|
|
<button class="chevron-btn" id="chevron-btn" title="Expand panel">▲</button>
|
|
</div>
|
|
|
|
<!-- Status line -->
|
|
<div class="sheet-status" id="sheet-status">
|
|
<span id="status-text">0 examples · untrained</span>
|
|
</div>
|
|
|
|
<!-- Sheet content -->
|
|
<div class="sheet-content" id="sheet-content">
|
|
<!-- Examples mode actions -->
|
|
<div class="action-row" id="examples-actions">
|
|
<button class="action-btn" id="btn-add-example">Add Example</button>
|
|
<button class="action-btn accent" id="btn-train">Train</button>
|
|
<button class="action-btn dim" id="btn-clear-examples">Clear Examples</button>
|
|
<button class="action-btn dim" id="btn-clear">Clear All</button>
|
|
<button class="action-btn dim" id="btn-randomize">Randomize</button>
|
|
</div>
|
|
|
|
<!-- Preset palette -->
|
|
<div class="preset-row" id="preset-row">
|
|
<span class="preset-label">Presets</span>
|
|
<button class="preset-chip" data-preset="calm-to-chaotic">Calm/Chaos</button>
|
|
<button class="preset-chip" data-preset="rainbow-sweep">Rainbow</button>
|
|
<button class="preset-chip" data-preset="vortex">Vortex</button>
|
|
<button class="preset-chip" data-preset="spiral">Spiral</button>
|
|
<button class="preset-chip" data-preset="embers">Embers</button>
|
|
</div>
|
|
|
|
<!-- Synth controls -->
|
|
<div class="synth-panel hidden" id="synth-panel">
|
|
<div class="synth-row">
|
|
<button class="action-btn accent" id="synth-start">Start Audio</button>
|
|
<span class="synth-status" id="synth-status">Stopped</span>
|
|
</div>
|
|
<div class="synth-row">
|
|
<label>Volume</label>
|
|
<input type="range" id="synth-volume" min="0" max="1" step="0.01" value="0.5">
|
|
</div>
|
|
<div class="synth-row">
|
|
<label>Arpeggiator</label>
|
|
<button class="action-btn" id="arp-toggle">Play</button>
|
|
</div>
|
|
<div class="synth-row">
|
|
<label>Progression</label>
|
|
<select id="arp-progression">
|
|
<option value="I-vi-IV-V">I-vi-IV-V</option>
|
|
<option value="I-IV-vi-V">I-IV-vi-V</option>
|
|
<option value="i-VI-III-VII">i-VI-III-VII</option>
|
|
<option value="I-V-vi-IV">I-V-vi-IV</option>
|
|
</select>
|
|
</div>
|
|
<div class="synth-row">
|
|
<label>Tempo <span id="tempo-val">120</span></label>
|
|
<input type="range" id="arp-tempo" min="40" max="240" step="1" value="120">
|
|
</div>
|
|
<div class="synth-row">
|
|
<label>Octaves <span id="octaves-val">2</span></label>
|
|
<input type="range" id="arp-octaves" min="1" max="5" step="1" value="2">
|
|
</div>
|
|
<div class="synth-row">
|
|
<label>Oct Offset <span id="offset-val">0</span></label>
|
|
<input type="range" id="arp-offset" min="-2" max="3" step="1" value="0">
|
|
</div>
|
|
<div class="synth-row" id="midi-row" style="display:none">
|
|
<label>MIDI Input</label>
|
|
<button class="action-btn" id="midi-toggle">Enable</button>
|
|
<select id="midi-select" style="flex:1;min-width:0"></select>
|
|
</div>
|
|
<div class="synth-row" id="midi-status-row" style="display:none">
|
|
<span class="synth-status" id="midi-status"></span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Loss plot -->
|
|
<div class="loss-section">
|
|
<label>Loss History</label>
|
|
<canvas id="loss-canvas" width="280" height="80"></canvas>
|
|
</div>
|
|
|
|
<!-- Advanced: raw param sliders -->
|
|
<details class="advanced-section">
|
|
<summary>Advanced: Raw Parameters</summary>
|
|
<div class="raw-params" id="raw-params"></div>
|
|
</details>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Help button -->
|
|
<button class="help-btn" id="help-btn" title="Help">?</button>
|
|
|
|
<!-- Help modal -->
|
|
<div class="help-overlay hidden" id="help-overlay">
|
|
<div class="help-modal" id="help-modal">
|
|
<button class="help-close" id="help-close">×</button>
|
|
<h2>Welcome to NISPS</h2>
|
|
<p class="help-subtitle">Neural Interactive Shaping of Parameter Spaces</p>
|
|
|
|
<div class="help-section">
|
|
<h3>What is this?</h3>
|
|
<p>NISPS lets you <strong>teach a neural network</strong> how to map a 2D joystick position to a rich set of visual or audio parameters. Move the joystick, shape the outputs you want, and the network learns your preferences in real time.</p>
|
|
</div>
|
|
|
|
<div class="help-section">
|
|
<h3>How it works</h3>
|
|
<p>A small neural network takes your joystick X/Y position as input and produces dozens of output parameters. You teach it by either:</p>
|
|
<ul>
|
|
<li><strong>Examples</strong> — set the parameter sliders to what you want at a given joystick position, add the example, then hit Train. Do this a few times from different positions and the network interpolates between them.</li>
|
|
<li><strong>Feedback (RL)</strong> — move the joystick around. If you like what you see/hear, press <strong>+</strong> (keep this). If you don't, press <strong>−</strong> (explore more). The network gradually learns what you prefer.</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="help-section">
|
|
<h3>What to expect</h3>
|
|
<ul>
|
|
<li><strong>Moving the joystick</strong> changes all outputs in real time through the network</li>
|
|
<li><strong>Randomize</strong> shuffles the network weights — instant new mapping</li>
|
|
<li><strong>Train</strong> fits the network to your saved examples</li>
|
|
<li><strong>+ / − feedback</strong> nudges the network: + reinforces the current mapping, − adds exploration noise</li>
|
|
<li>Switch between <strong>Visual</strong> (particle flow field) and <strong>Synth</strong> (C15 synthesizer) output modes</li>
|
|
<li>The <strong>heatmap bar</strong> at the top shows all output parameters at a glance</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="help-section">
|
|
<h3>Controls</h3>
|
|
<table class="help-keys">
|
|
<tr><th colspan="2">Touch / Mouse</th></tr>
|
|
<tr><td>Drag joystick</td><td>Move through parameter space</td></tr>
|
|
<tr><td>+ / − buttons</td><td>Positive / negative feedback</td></tr>
|
|
<tr><td>Bottom bar</td><td>Train, Randomize, Clear, Follow mode</td></tr>
|
|
<tr><th colspan="2">Keyboard</th></tr>
|
|
<tr><td><kbd>1</kbd></td><td>Negative feedback (−)</td></tr>
|
|
<tr><td><kbd>2</kbd></td><td>Positive feedback (+)</td></tr>
|
|
<tr><th colspan="2">Gamepad (Steam Deck, Xbox, etc.)</th></tr>
|
|
<tr><td>Left stick</td><td>Joystick control</td></tr>
|
|
<tr><td>LB (left bumper)</td><td>Negative feedback</td></tr>
|
|
<tr><td>RB (right bumper)</td><td>Positive feedback</td></tr>
|
|
<tr><td>A</td><td>Train</td></tr>
|
|
<tr><td>X</td><td>Randomize</td></tr>
|
|
<tr><td>B</td><td>Clear examples</td></tr>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="help-section">
|
|
<h3>Tips</h3>
|
|
<ul>
|
|
<li>Start with <strong>Randomize</strong> a few times to hear/see different mappings, then use feedback to refine</li>
|
|
<li>Use <strong>Follow</strong> mode to let the joystick wander automatically while you give feedback</li>
|
|
<li>In Synth mode, press the <strong>play button</strong> (top left) to start audio, then explore</li>
|
|
<li>Tap a heatmap cell to see which parameter it controls</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<button class="help-got-it" id="help-got-it">Got it</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="module" src="js/a-app.js"></script>
|
|
</body>
|
|
</html>
|