← TutSynth results

TutSynth

GPT 5.6 Luna Pro · typescript

Initial view of TutSynth

Reviews & generation details

Reviews

No human review yet. Unreviewed does not mean unsuccessful.

Generation context

Imported historical artifact. Its exact original instructions and lineage are not known.

Generation prompt · exact text unavailable

See the current prompt for reference. It may differ from the instructions used to generate this artifact.

Inspect original source 23,120 bytes · SHA-256 f5de77b39837
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>TUTSYNTH — Learn by making sound</title>
<style>
/* ── css: base ── */
@import url('https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=Space+Grotesk:wght@400;500;600;700&display=swap');
:root{--bg:#101112;--panel:#181a1b;--panel2:#202223;--line:#303334;--muted:#858887;--text:#e7e8e5;--orange:#f79546;--orange2:#ffbd73;--green:#9ed49a}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font-family:'Space Grotesk',sans-serif;font-size:13px}button,input{font:inherit}button{cursor:pointer}.shell{max-width:1440px;margin:auto;padding:28px 42px 20px}.topbar{height:42px;display:flex;justify-content:space-between;align-items:center}.brand{display:flex;align-items:center;gap:11px;letter-spacing:1px}.brand-mark{color:var(--orange);font-size:28px;line-height:20px}.brand strong{display:block;font-size:15px}.brand small{display:block;color:var(--muted);font:10px 'DM Mono';letter-spacing:1.2px;margin-top:3px}.top-actions{display:flex;align-items:center;gap:10px;color:var(--muted);font:10px 'DM Mono';letter-spacing:.8px}.status-dot,.live-badge i{width:7px;height:7px;border-radius:50%;background:#595d5c;display:inline-block}.status-dot.on,.live-badge i{background:var(--green);box-shadow:0 0 10px var(--green)}.ghost-btn{background:none;border:1px solid var(--line);color:var(--muted);padding:8px 12px;border-radius:4px;font-size:11px}.hero{display:flex;justify-content:space-between;align-items:end;margin:70px 0 42px;border-bottom:1px solid var(--line);padding-bottom:30px}.eyebrow,.card-kicker,.side-label{font:10px 'DM Mono';letter-spacing:1.5px;color:var(--orange)}h1{font-size:38px;letter-spacing:-1.5px;margin:13px 0 8px}h2{font-size:17px;margin:5px 0 0}p{color:var(--muted);line-height:1.5;margin:0;max-width:580px}.hero p{font-size:14px}.lesson-track{display:flex;align-items:center;position:relative;gap:24px}.track-line{height:1px;background:var(--line);position:absolute;top:14px;left:15px;right:15px}.lesson-step{z-index:1;border:0;background:var(--bg);color:#646867;font:11px 'DM Mono';padding:0;display:flex;flex-direction:column;gap:8px}.lesson-step span{font-size:8px;color:#555;letter-spacing:1px}.lesson-step.active{color:var(--orange)}.lesson-step.active span{color:var(--text)}.lesson-step:before{content:'';display:block;margin:auto;width:7px;height:7px;border-radius:50%;border:1px solid currentColor;background:var(--bg)}.lesson-step.active:before{background:var(--orange);box-shadow:0 0 12px #f7954688}.workspace{display:grid;grid-template-columns:210px 1fr;gap:30px}.sidebar{border-right:1px solid var(--line);padding-right:25px}.side-label{color:#666;margin-bottom:14px}.tip-card{border:1px solid #393331;background:#211d1a;padding:15px 12px;display:flex;gap:10px;margin-bottom:32px}.tip-icon{color:var(--orange);font-size:20px}.tip-card b{font-size:12px}.tip-card p{font-size:11px;margin-top:6px}.controls-label{margin-bottom:20px}.signal-path{color:#777;font:10px 'DM Mono'}.path-node{display:flex;align-items:center;gap:10px}.path-node i{font-style:normal;border:1px solid #414544;width:22px;height:22px;border-radius:50%;display:grid;place-items:center}.path-node.active{color:var(--orange)}.path-node.active i{border-color:var(--orange)}.path-arrow{margin:6px 0 6px 10px;color:#555}.legend{display:flex;gap:12px;margin-top:40px;color:#666;font:9px 'DM Mono'}.led{width:6px;height:6px;border-radius:50%;display:inline-block}.led.orange{background:var(--orange)}.led.grey{background:#555}.main-panel{min-width:0}.scope-card,.control-card,.keyboard-card{background:var(--panel);border:1px solid var(--line);border-radius:4px}.scope-card{padding:17px 20px 13px;position:relative}.card-top{display:flex;justify-content:space-between;align-items:start}.card-top b{font:11px 'DM Mono';display:block;margin-top:6px;color:#bbb}.live-badge{font:9px 'DM Mono';color:#777;display:flex;align-items:center;gap:7px}.scope-card canvas{width:100%;height:190px;display:block;margin-top:6px}.scope-axis{display:flex;justify-content:space-between;color:#555;font:9px 'DM Mono'}.controls-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:12px}.control-card{padding:18px 20px;min-height:225px}.card-heading{display:flex;justify-content:space-between}.card-heading em{font:9px 'DM Mono';color:var(--green);font-style:normal;margin-left:5px}.help{border:1px solid #555;color:#777;border-radius:50%;width:17px;height:17px;text-align:center;font:11px serif}.wave-buttons{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;margin-top:21px}.wave-btn{background:#202324;border:1px solid var(--line);color:#888;padding:8px 4px;border-radius:3px}.wave-btn.selected{border-color:var(--orange);color:var(--orange);background:#29231f}.wave-icon{font-size:22px;display:block;height:24px}.wave-btn b,.wave-btn small{display:block;font:9px 'DM Mono'}.wave-btn small{font-size:8px;color:#666;margin-top:4px}.knob-row{display:flex;gap:25px;margin-top:20px}.range-label,.knob-row label,.four-ranges label{display:block;color:#777;font:9px 'DM Mono';letter-spacing:.6px}.range-label output,.knob-row output,.four-ranges output{float:right;color:var(--orange);font-size:10px}input[type=range]{display:block;width:100%;accent-color:var(--orange);margin-top:9px;height:3px}.filter-visual{height:50px;background:linear-gradient(90deg,#202324,#30241d);border-bottom:1px solid #464440;margin:18px 0 17px;position:relative;overflow:hidden}.filter-curve{position:absolute;inset:15px 8px 0;border-top:2px solid var(--orange);border-radius:50% 80% 0 0;transform:skewX(-20deg)}.filter-dot{position:absolute;width:9px;height:9px;border:2px solid var(--orange);border-radius:50%;left:62%;top:13px;background:var(--panel)}.filter-visual span{position:absolute;bottom:4px;font:8px 'DM Mono';color:#666}.filter-visual span:last-child{right:5px}.range-label+.range-label{margin-top:16px}.env-visual{height:54px;margin:17px 0 15px;background:#202324}.env-visual svg{width:100%;height:100%}.env-visual path{fill:none;stroke:var(--orange);stroke-width:2}.four-ranges{display:grid;grid-template-columns:1fr 1fr;gap:15px}.space-row{display:flex;align-items:center;gap:12px;margin:24px 0 18px}.space-icon{font-size:25px;color:var(--orange)}.space-row b{display:block;font:10px 'DM Mono'}.space-row small{color:#666;font-size:10px}.switch{margin-left:auto}.switch input{display:none}.switch span{display:block;width:34px;height:18px;border-radius:20px;background:#343736;position:relative}.switch span:before{content:'';position:absolute;width:12px;height:12px;left:3px;top:3px;border-radius:50%;background:#777;transition:.2s}.switch input:checked+span{background:#8e613b}.switch input:checked+span:before{left:19px;background:var(--orange2)}.random-btn{background:transparent;border:1px solid #555;color:var(--orange);padding:7px 11px;border-radius:3px;font-size:10px;margin-top:17px}.keyboard-card{margin-top:12px;padding:13px 16px 17px}.keyboard-head{display:flex;justify-content:space-between;color:#777;font:10px 'DM Mono';margin-bottom:10px}.keyboard-head b{color:#aaa}.key-hint{color:#555}.keyboard{display:flex;height:80px;gap:3px}.key{flex:1;background:linear-gradient(#f0eee7,#bbb8b0);color:#555;border:0;border-radius:0 0 4px 4px;position:relative;padding-top:51px;font:10px 'DM Mono';box-shadow:0 3px 0 #777}.key.black{background:linear-gradient(#343637,#111);color:#aaa;height:48px;flex:.62;margin:0 -15px;z-index:2;padding-top:28px;box-shadow:0 3px 0 #090909}.key.active{background:var(--orange);color:#281b12}.key.black.active{background:#d27c36}footer{display:flex;justify-content:space-between;color:#666;font:10px 'DM Mono';margin-top:25px}footer a{color:var(--orange);text-decoration:none}@media(max-width:900px){.shell{padding:20px}.hero{display:block;margin:40px 0 25px}.lesson-track{margin-top:25px;justify-content:space-between}.workspace{grid-template-columns:1fr}.sidebar{display:none}.controls-grid{grid-template-columns:1fr}.top-actions>span{display:none}}
/* ── css: motion ── */
@keyframes pulse{50%{opacity:.55}}.live-badge i{animation:pulse 1.4s infinite}.key{transition:transform .06s,background .1s}.key.active{transform:translateY(3px);box-shadow:none}.control-card{transition:border-color .2s}.control-card:hover{border-color:#4a4d4c}
</style>
</head>
<body>
<main class="shell">
  <header class="topbar"><div class="brand"><span class="brand-mark">◒</span><div><strong>TUTSYNTH</strong><small>LEARN BY MAKING SOUND</small></div></div><div class="top-actions"><span class="status-dot"></span><span id="audioStatus">AUDIO OFF</span><button id="resetBtn" class="ghost-btn">↺ Reset patch</button></div></header>
  <section class="hero"><div><div class="eyebrow">INTERACTIVE SYNTHESIS LAB · <span id="lessonCount">01 / 05</span></div><h1 id="lessonTitle">Meet the oscillator</h1><p id="lessonCopy">Every synth starts with a repeating electrical pattern. Choose a shape, then play the keyboard to hear its character.</p></div><div class="lesson-track"><div class="track-line"></div><button class="lesson-step active" data-lesson="0">01<span>WAVE</span></button><button class="lesson-step" data-lesson="1">02<span>PITCH</span></button><button class="lesson-step" data-lesson="2">03<span>FILTER</span></button><button class="lesson-step" data-lesson="3">04<span>ENVELOPE</span></button><button class="lesson-step" data-lesson="4">05<span>SPACE</span></button></div></section>
  <section class="workspace">
   <aside class="sidebar"><div class="side-label">PATCH NOTES</div><div id="tipCard" class="tip-card"><span class="tip-icon">◎</span><div><b id="tipTitle">Start with a wave</b><p id="tipText">Press any key below. The scope will draw the wave in real time.</p></div></div><div class="side-label controls-label">SIGNAL PATH</div><div class="signal-path"><div class="path-node active"><i>1</i><span>OSCILLATOR</span></div><div class="path-arrow">↓</div><div class="path-node"><i>2</i><span>FILTER</span></div><div class="path-arrow">↓</div><div class="path-node"><i>3</i><span>AMP ENVELOPE</span></div><div class="path-arrow">↓</div><div class="path-node"><i>4</i><span>OUTPUT</span></div></div><div class="legend"><span><i class="led orange"></i> selected</span><span><i class="led grey"></i> locked</span></div></aside>
   <div class="main-panel"><div class="scope-card"><div class="card-top"><div><span class="card-kicker">OSCILLOSCOPE</span><b id="scopeReadout">SINE · 220 Hz</b></div><span class="live-badge"><i></i> LIVE</span></div><canvas id="scope" width="900" height="190"></canvas><div class="scope-axis"><span>−1</span><span>0</span><span>+1</span></div></div>
    <div class="controls-grid">
     <section class="control-card"><div class="card-heading"><div><span class="card-kicker">01 · SOURCE</span><h2>Oscillator</h2></div><span class="help">?</span></div><div class="wave-buttons"><button class="wave-btn selected" data-wave="sine"><span class="wave-icon">∿</span><b>SINE</b><small>pure / soft</small></button><button class="wave-btn" data-wave="triangle"><span class="wave-icon">△</span><b>TRIANGLE</b><small>hollow / mellow</small></button><button class="wave-btn" data-wave="sawtooth"><span class="wave-icon">◢</span><b>SAW</b><small>bright / buzzy</small></button><button class="wave-btn" data-wave="square"><span class="wave-icon">▰</span><b>SQUARE</b><small>hollow / bold</small></button></div><div class="knob-row"><label>OCTAVE <output id="octaveOut">0</output><input id="octave" type="range" min="-2" max="2" value="0" step="1"></label><label>DETUNE <output id="detuneOut">0 ct</output><input id="detune" type="range" min="-50" max="50" value="0"></label></div></section>
     <section class="control-card"><div class="card-heading"><div><span class="card-kicker">02 · TIMBRE</span><h2>Filter <em>unlocked</em></h2></div><span class="help">?</span></div><div class="filter-visual"><div class="filter-curve"></div><div class="filter-dot"></div><span>BRIGHT</span><span>DARK</span></div><label class="range-label">CUTOFF <output id="cutoffOut">2200 Hz</output><input id="cutoff" type="range" min="120" max="9000" value="2200"></label><label class="range-label">RESONANCE <output id="resOut">12%</output><input id="resonance" type="range" min="0" max="26" value="12"></label></section>
     <section class="control-card"><div class="card-heading"><div><span class="card-kicker">03 · SHAPE</span><h2>Envelope <em>unlocked</em></h2></div><span class="help">?</span></div><div class="env-visual"><svg viewBox="0 0 300 75" preserveAspectRatio="none"><path d="M5 68 L35 8 L88 32 L155 45 L295 68"></path></svg></div><div class="four-ranges"><label>ATTACK<output id="attackOut">0.02s</output><input id="attack" type="range" min="0.01" max="1" value="0.02" step="0.01"></label><label>DECAY<output id="decayOut">0.25s</output><input id="decay" type="range" min="0.05" max="1" value="0.25" step="0.01"></label><label>SUSTAIN<output id="sustainOut">70%</output><input id="sustain" type="range" min="0" max="1" value="0.7" step="0.01"></label><label>RELEASE<output id="releaseOut">0.40s</output><input id="release" type="range" min="0.05" max="2" value="0.4" step="0.01"></label></div></section>
     <section class="control-card"><div class="card-heading"><div><span class="card-kicker">04 · FINISH</span><h2>Space <em>unlocked</em></h2></div><span class="help">?</span></div><div class="space-row"><div class="space-icon">✦</div><div><b>ROOM REVERB</b><small>Add depth and distance</small></div><label class="switch"><input id="reverb" type="checkbox"><span></span></label></div><label class="range-label">MIX <output id="mixOut">18%</output><input id="mix" type="range" min="0" max="1" value="0.18" step="0.01"></label><button id="randomBtn" class="random-btn">✦ Surprise me</button></section>
    </div>
    <div class="keyboard-card"><div class="keyboard-head"><span><b>PLAYGROUND</b> <small>QWERTY + click</small></span><span class="key-hint">A W S E D F T G Y H U J K</span></div><div id="keyboard" class="keyboard"></div></div>
   </div>
  </section><footer><span>TIP: headphones recommended</span><span>SPACE to play a random note · <a href="#">How sound flows ↗</a></span></footer>
 </main>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {};
function __require(id) {
  if (__cache[id]) return __cache[id].exports;
  var module = __cache[id] = { exports: {} };
  var factory = __mods[id];
  if (!factory) throw new Error("Module not found: " + id);
  factory(module.exports, function (spec) {
    var target = (__map[id] && __map[id][spec]) || spec;
    return __require(target);
  }, module);
  return module.exports;
}

// ── module: src/main.ts ──
__mods["src/main.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.start = start;
const $ = (s) => document.querySelector(s);
const lessons = [
    { title: 'Meet the oscillator', copy: 'Every synth starts with a repeating electrical pattern. Choose a shape, then play the keyboard to hear its character.', tip: 'Start with a wave', tipText: 'Press any key below. The scope will draw the wave in real time.' },
    { title: 'Shape the pitch', copy: 'Pitch is simply how fast the oscillator repeats. Octaves double or halve that speed; detune adds a little human width.', tip: 'Try an octave', tipText: 'Move OCTAVE up, then play the same key. Notice how the frequency doubles.' },
    { title: 'Carve the tone', copy: 'A filter is a tone-shaping gate. Turn CUTOFF down to remove bright harmonics, then add resonance to emphasize the edge.', tip: 'Make it darker', tipText: 'Pull CUTOFF left while holding a note. You are subtracting frequencies, not changing pitch.' },
    { title: 'Give it a shape', copy: 'The envelope controls time. Attack fades in, decay falls toward sustain, and release lets the sound breathe after you let go.', tip: 'Play staccato', tipText: 'Raise ATTACK for a softer entrance. RELEASE controls the tail after the key comes up.' },
    { title: 'Put it in a room', copy: 'A little reverb turns a dry signal into a place. Use MIX sparingly: enough space to feel, not enough to blur.', tip: 'Add some air', tipText: 'Switch on ROOM REVERB and compare a low mix with a huge one.' }
];
let lesson = 0, wave = 'sine', audio, master, analyser;
let cutoff = 2200, resonance = 12, octave = 0, detune = 0, attack = .02, decay = .25, sustain = .7, release = .4, reverb = false, mix = .18;
const notes = [['a', 60], ['w', 61], ['s', 62], ['e', 63], ['d', 64], ['f', 65], ['t', 66], ['g', 67], ['y', 68], ['h', 69], ['u', 70], ['j', 71], ['k', 72]];
const active = new Map();
function midiFreq(m) { return 440 * Math.pow(2, (m - 69) / 12) * Math.pow(2, octave) + (detune ? detune * .01 : 0); }
function ensureAudio() { if (!audio) {
    audio = new AudioContext();
    master = audio.createGain();
    analyser = audio.createAnalyser();
    analyser.fftSize = 1024;
    master.connect(analyser);
    analyser.connect(audio.destination);
    $('audioStatus').textContent = 'AUDIO ON';
    $('.status-dot').classList.add('on');
    draw();
} if (audio.state === 'suspended')
    audio.resume(); }
function noteOn(key, midi) { ensureAudio(); if (active.has(key))
    return; const now = audio.currentTime; const osc = audio.createOscillator(), gain = audio.createGain(), filter = audio.createBiquadFilter(); osc.type = wave; osc.frequency.value = midiFreq(midi); filter.type = 'lowpass'; filter.frequency.value = cutoff; filter.Q.value = resonance / 2; gain.gain.setValueAtTime(0, now); gain.gain.linearRampToValueAtTime(.18, now + attack); gain.gain.linearRampToValueAtTime(.18 * sustain, now + attack + decay); osc.connect(filter); filter.connect(gain); gain.connect(master); osc.start(); active.set(key, { osc, gain, filter }); const el = document.querySelector(`[data-key="${key}"]`); el?.classList.add('active'); $('scopeReadout').textContent = `${wave.toUpperCase()} · ${Math.round(midiFreq(midi))} Hz`; }
function noteOff(key) { const n = active.get(key); if (!n || !audio)
    return; const now = audio.currentTime; n.gain.gain.cancelScheduledValues(now); n.gain.gain.setValueAtTime(n.gain.gain.value, now); n.gain.gain.linearRampToValueAtTime(0, now + release); n.osc.stop(now + release + .03); active.delete(key); document.querySelector(`[data-key="${key}"]`)?.classList.remove('active'); }
function draw() { const c = $('#scope'), ctx = c.getContext('2d'); const render = () => { ctx.fillStyle = '#181a1b'; ctx.fillRect(0, 0, c.width, c.height); ctx.strokeStyle = '#292c2c'; ctx.lineWidth = 1; for (let y = 30; y < c.height; y += 40) {
    ctx.beginPath();
    ctx.moveTo(0, y);
    ctx.lineTo(c.width, y);
    ctx.stroke();
} ctx.strokeStyle = '#f79546'; ctx.lineWidth = 2; ctx.beginPath(); const data = new Uint8Array(analyser.fftSize); analyser.getByteTimeDomainData(data); for (let x = 0; x < c.width; x++) {
    const y = data[Math.floor(x * data.length / c.width)] / 255 * c.height;
    if (x)
        ctx.lineTo(x, y);
    else
        ctx.moveTo(x, y);
} ctx.stroke(); requestAnimationFrame(render); }; render(); }
function setLesson(i) { lesson = i; const l = lessons[i]; $('lessonTitle').textContent = l.title; $('lessonCopy').textContent = l.copy; $('tipTitle').textContent = l.tip; $('tipText').textContent = l.tipText; $('lessonCount').textContent = `0${i + 1} / 05`; document.querySelectorAll('.lesson-step').forEach((e, j) => e.classList.toggle('active', j === i)); document.querySelectorAll('.path-node').forEach((e, j) => e.classList.toggle('active', j === Math.min(i, 3))); }
function bindRange(id, output, fn, format) { const el = $('#' + id); el.addEventListener('input', () => { const v = +el.value; fn(v); $(output).textContent = format(v); active.forEach(n => { if (id === 'cutoff')
    n.filter.frequency.value = v; if (id === 'resonance')
    n.filter.Q.value = v / 2; }); }); }
function randomize() { const waves = ['sine', 'triangle', 'sawtooth', 'square']; const w = waves[Math.floor(Math.random() * 4)]; wave = w; document.querySelectorAll('.wave-btn').forEach(b => b.classList.toggle('selected', b.getAttribute('data-wave') === w)); ['cutoff', 'resonance', 'octave'].forEach(id => { const e = $('#' + id); e.value = id === 'cutoff' ? String(500 + Math.floor(Math.random() * 6000)) : id === 'resonance' ? String(Math.floor(Math.random() * 24)) : String(Math.floor(Math.random() * 3) - 1); e.dispatchEvent(new Event('input')); }); }
function setup() { const kb = $('#keyboard'); notes.forEach(([key, midi]) => { const b = document.createElement('button'); b.className = 'key ' + (['w', 'e', 't', 'y', 'u'].includes(key) ? 'black' : ''); b.dataset.key = key; b.textContent = key.toUpperCase(); b.onpointerdown = () => noteOn(key, midi); b.onpointerup = () => noteOff(key); b.onpointerleave = () => noteOff(key); kb.append(b); }); document.querySelectorAll('.wave-btn').forEach(b => b.onclick = () => { wave = b.dataset.wave; document.querySelectorAll('.wave-btn').forEach(x => x.classList.toggle('selected', x === b)); }); document.querySelectorAll('.lesson-step').forEach(b => b.onclick = () => setLesson(+(b.dataset.lesson || '0'))); document.addEventListener('click', e => { const b = e.target.closest('.lesson-step'); if (b) {
    e.preventDefault();
    setLesson(Number(b.dataset.lesson || '0'));
} }); bindRange('octave', '#octaveOut', v => octave = v, v => String(v)); bindRange('detune', '#detuneOut', v => detune = v, v => `${v} ct`); bindRange('cutoff', '#cutoffOut', v => cutoff = v, v => `${Math.round(v)} Hz`); bindRange('resonance', '#resOut', v => resonance = v, v => `${v}%`); bindRange('attack', '#attackOut', v => attack = v, v => `${v.toFixed(2)}s`); bindRange('decay', '#decayOut', v => decay = v, v => `${v.toFixed(2)}s`); bindRange('sustain', '#sustainOut', v => sustain = v, v => `${Math.round(v * 100)}%`); bindRange('release', '#releaseOut', v => release = v, v => `${v.toFixed(2)}s`); bindRange('mix', '#mixOut', v => mix = v, v => `${Math.round(v * 100)}%`); $('#reverb').addEventListener('change', e => reverb = e.target.checked); $('#randomBtn').onclick = randomize; $('#resetBtn').onclick = () => location.reload(); window.addEventListener('keydown', e => { if (e.repeat)
    return; const n = notes.find(x => x[0] === e.key.toLowerCase()); if (n)
    noteOn(n[0], n[1]);
else if (e.code === 'Space') {
    e.preventDefault();
    noteOn('space', 60 + Math.floor(Math.random() * 12));
} }); window.addEventListener('keyup', e => { const n = notes.find(x => x[0] === e.key.toLowerCase()); if (n)
    noteOff(n[0]);
else if (e.code === 'Space')
    noteOff('space'); }); }
setup();
function start() { }
};

// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"openai/gpt-5.6-luna-pro","provider":"openrouter","persona":"typescript","sessionId":"0076f247-0bd1-4c17-a680-2f5b93472807","tokensIn":644361,"tokensOut":23367,"tokensTotal":667728,"turns":18,"toolCalls":23,"failedToolCalls":1,"timestamp":"2026-07-31T03:25:22.181Z"} -->