← TutSynth results

TutSynth

GPT 5.6 Luna Pro · full

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 18,255 bytes · SHA-256 5b316dd75fb8
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>Signal Garden — Synth Playground</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=Outfit:wght@400;500;600;700&display=swap');
:root{--bg:#101216;--panel:#171a20;--panel2:#1d2129;--line:#2b303a;--text:#f1f0eb;--muted:#8e96a3;--cyan:#6de0d1;--orange:#ff9a62;--yellow:#f8d568;--pink:#eb7aa6;--green:#9fe18a}*{box-sizing:border-box}body{margin:0;background:radial-gradient(circle at 75% 0%,#27313a 0,#101216 42%),var(--bg);color:var(--text);font-family:Outfit,system-ui,sans-serif;min-height:100vh}button,input{font:inherit}button{cursor:pointer}.app{max-width:1380px;margin:auto;padding:28px 32px 36px}.top{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:26px}.brand{display:flex;gap:13px;align-items:center}.mark{width:38px;height:38px;border:1px solid var(--cyan);border-radius:11px;display:grid;place-items:center;color:var(--cyan);font-size:19px;box-shadow:0 0 24px #6de0d130}.eyebrow,.mono{font:500 10px 'DM Mono',monospace;letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}h1{font-size:24px;margin:0;letter-spacing:-.04em}p{color:var(--muted);line-height:1.5}.top p{margin:4px 0 0;font-size:13px}.status{display:flex;gap:10px;align-items:center}.pill{border:1px solid var(--line);border-radius:20px;padding:8px 12px;color:var(--muted);font:11px 'DM Mono',monospace}.dot{display:inline-block;width:7px;height:7px;background:var(--orange);border-radius:50%;margin-right:7px;box-shadow:0 0 10px var(--orange)}.layout{display:grid;grid-template-columns:minmax(0,1fr) 330px;gap:18px}.main,.side{background:#14171cdb;border:1px solid var(--line);border-radius:18px;box-shadow:0 18px 45px #0002}.main{padding:20px}.side{padding:22px}.scope{height:190px;background:#0e1115;border:1px solid #262d35;border-radius:12px;position:relative;overflow:hidden}.scope canvas{width:100%;height:100%}.scope-label{position:absolute;top:12px;left:14px;color:#65717a}.scope-caption{position:absolute;right:14px;top:12px}.toolbar{display:flex;justify-content:space-between;align-items:center;margin:17px 0 14px}.transport{display:flex;gap:8px}.transport button,.learn-btn{border:1px solid var(--line);background:var(--panel2);color:var(--text);border-radius:9px;padding:9px 12px}.transport button.active{background:var(--cyan);color:#14201f;border-color:var(--cyan)}.tempo{display:flex;gap:10px;align-items:center}.tempo input{width:82px}.section{border-top:1px solid var(--line);padding:17px 2px 3px;margin-top:14px}.section-head{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:14px}.section h2{font-size:14px;margin:0;letter-spacing:-.02em}.tag{color:var(--cyan);font:10px 'DM Mono',monospace;text-transform:uppercase;letter-spacing:.1em}.controls{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}.control{background:#191d24;border:1px solid #272e38;border-radius:11px;padding:12px}.control label{display:flex;justify-content:space-between;color:#c8cbd0;font-size:12px;margin-bottom:12px}.val{font:11px 'DM Mono',monospace;color:var(--cyan)}input[type=range]{width:100%;accent-color:var(--cyan);height:4px}.waves{display:flex;gap:5px;flex-wrap:wrap}.wave{background:#222731;border:1px solid #343b46;color:#bfc5cd;border-radius:7px;padding:6px 8px;font:11px 'DM Mono',monospace}.wave.active{background:#25514f;color:var(--cyan);border-color:var(--cyan)}.knobs{grid-template-columns:repeat(4,1fr)}.note-row{display:flex;gap:6px;margin-top:18px;flex-wrap:wrap}.key{height:54px;flex:1;min-width:48px;background:linear-gradient(#faf9f3 0 72%,#c9c7c0 72%);color:#252a2f;border:0;border-radius:5px 5px 9px 9px;box-shadow:0 4px 0 #777;position:relative;font:12px 'DM Mono',monospace}.key.black{background:linear-gradient(#30333a,#15171b);color:#f1f0eb;height:35px;margin:0 -16px;z-index:2;box-shadow:0 3px 0 #000}.key:active,.key.down{transform:translateY(3px);box-shadow:0 1px 0 #777}.hint{font-size:11px;color:var(--muted);margin-top:12px}.lesson-num{color:var(--orange);font:500 11px 'DM Mono',monospace}.side h2{font-size:22px;margin:7px 0 10px;letter-spacing:-.04em}.side p{font-size:13px;margin:0 0 18px}.lesson-card{background:linear-gradient(135deg,#202b2f,#1c2027);border:1px solid #31424a;border-radius:13px;padding:16px;margin-bottom:18px}.lesson-card strong{display:block;font-size:14px;margin-bottom:6px}.lesson-card span{font-size:12px;color:#bcc6c8;line-height:1.45;display:block}.progress{height:5px;background:#2b303a;border-radius:4px;margin:18px 0}.progress i{display:block;height:100%;background:var(--cyan);border-radius:4px;width:25%;transition:.3s}.lesson-actions{display:flex;gap:8px}.learn-btn{flex:1;background:var(--cyan);color:#11201e;border:0;font-weight:600}.reset{background:transparent;color:var(--muted)!important;border:1px solid var(--line)!important}.tip{border-top:1px solid var(--line);padding-top:17px;margin-top:20px}.tip h3{font-size:12px;margin:0 0 8px;color:var(--yellow)}.tip p{font-size:12px;margin:0}.event{margin-top:18px;color:var(--muted);font-size:11px}.toast{position:fixed;left:50%;bottom:24px;transform:translate(-50%,20px);background:#e9f6ef;color:#14201d;padding:11px 17px;border-radius:30px;font-size:13px;opacity:0;pointer-events:none;transition:.25s}.toast.show{opacity:1;transform:translate(-50%,0)}@media(max-width:900px){.layout{grid-template-columns:1fr}.side{order:-1}.controls,.knobs{grid-template-columns:repeat(2,1fr)}}@media(max-width:560px){.app{padding:20px 14px}.top{display:block}.status{margin-top:16px}.controls{grid-template-columns:1fr 1fr}.scope{height:145px}.main{padding:13px}.side{padding:17px}}
</style>
</head>
<body>
<div class="app"><header class="top"><div class="brand"><div class="mark">∿</div><div><div class="eyebrow">Interactive sound lab</div><h1>Signal Garden</h1><p>Grow a sound from a single oscillator.</p></div></div><div class="status"><div class="pill"><span class="dot" id="statusDot"></span><span id="statusText">audio sleeping</span></div><div class="pill">keyboard ready</div></div></header>
<div class="layout"><main class="main"><div class="scope"><canvas id="scope"></canvas><span class="scope-label mono">waveform / live</span><span class="scope-caption mono" id="scopeMode">sine · 440 hz</span></div>
<div class="toolbar"><div class="transport"><button id="start">▶ start tone</button><button id="stop">■ stop</button></div><div class="tempo"><span class="mono">master</span><input id="master" type="range" min="0" max="1" step=".01" value=".72"><span class="val" id="masterVal">72%</span></div></div>
<div class="section"><div class="section-head"><h2>01 / oscillator</h2><span class="tag">the voice</span></div><div class="controls"><div class="control"><label>waveform <span class="val" id="waveVal">sine</span></label><div class="waves"><button class="wave active" data-wave="sine">SIN</button><button class="wave" data-wave="triangle">TRI</button><button class="wave" data-wave="sawtooth">SAW</button><button class="wave" data-wave="square">SQR</button></div></div><div class="control"><label>pitch <span class="val" id="pitchVal">440 hz</span></label><input id="pitch" type="range" min="110" max="880" value="440"></div><div class="control"><label>detune <span class="val" id="detuneVal">0 ct</span></label><input id="detune" type="range" min="-100" max="100" value="0"></div><div class="control"><label>sub oscillator <span class="val" id="subVal">0%</span></label><input id="sub" type="range" min="0" max="1" step=".01" value="0"></div></div></div>
<div class="section"><div class="section-head"><h2>02 / envelope</h2><span class="tag">shape time</span></div><div class="controls knobs"><div class="control"><label>attack <span class="val" id="attackVal">0.02 s</span></label><input id="attack" type="range" min=".005" max="2" step=".005" value=".02"></div><div class="control"><label>decay <span class="val" id="decayVal">0.25 s</span></label><input id="decay" type="range" min=".01" max="2" step=".01" value=".25"></div><div class="control"><label>sustain <span class="val" id="sustainVal">70%</span></label><input id="sustain" type="range" min="0" max="1" step=".01" value=".7"></div><div class="control"><label>release <span class="val" id="releaseVal">0.35 s</span></label><input id="release" type="range" min=".01" max="3" step=".01" value=".35"></div></div></div>
<div class="section"><div class="section-head"><h2>03 / filter</h2><span class="tag">color it</span></div><div class="controls"><div class="control"><label>cutoff <span class="val" id="cutVal">4200 hz</span></label><input id="cutoff" type="range" min="120" max="10000" value="4200"></div><div class="control"><label>resonance <span class="val" id="resVal">12%</span></label><input id="resonance" type="range" min="0" max="25" value="12"></div><div class="control"><label>filter type <span class="val" id="filterVal">lowpass</span></label><div class="waves"><button class="wave active" data-filter="lowpass">LOW</button><button class="wave" data-filter="highpass">HIGH</button></div></div><div class="control"><label>filter sweep <span class="val" id="sweepVal">0%</span></label><input id="sweep" type="range" min="0" max="1" step=".01" value="0"></div></div></div>
<div class="section"><div class="section-head"><h2>04 / play it</h2><span class="tag">A S D F G H J</span></div><div class="note-row" id="keys"><button class="key" data-note="261.63">C<span> A</span></button><button class="key" data-note="293.66">D<span> S</span></button><button class="key" data-note="329.63">E<span> D</span></button><button class="key" data-note="349.23">F<span> F</span></button><button class="key" data-note="392">G<span> G</span></button><button class="key" data-note="440">A<span> H</span></button><button class="key" data-note="493.88">B<span> J</span></button></div><div class="hint">Click a key or use your computer keyboard. Hold for expressive attack + release.</div></div></main>
<aside class="side"><div class="lesson-num" id="lessonNum">LESSON 01 / 04</div><h2 id="lessonTitle">Meet the oscillator</h2><p id="lessonText">Every synth starts with a repeating electrical pattern. Choose a waveform, then play a note. Sine is pure and soft; saw is bright and buzzy.</p><div class="lesson-card"><strong id="lessonCardTitle">Try it: compare the waves</strong><span id="lessonCardText">Press the four waveform buttons, then listen to how the same pitch changes character.</span></div><div class="progress"><i id="progress"></i></div><div class="lesson-actions"><button class="learn-btn" id="next">I got it — next</button><button class="learn-btn reset" id="reset">reset</button></div><div class="tip"><h3>FIELD NOTE</h3><p id="tipText">A waveform is timbre, not pitch. Pitch comes from how fast it repeats.</p></div><div class="event mono" id="event">ready for input</div></aside></div></div><div class="toast" id="toast">Lesson unlocked</div>
<script>
const $=s=>document.querySelector(s), $$=s=>[...document.querySelectorAll(s)];let ctx,master,filter,osc,subOsc,gain,subGain,analyser,active=false,currentWave='sine',filterType='lowpass',notes={};
const state={wave:'sine',pitch:440,detune:0,sub:0,attack:.02,decay:.25,sustain:.7,release:.35,cutoff:4200,resonance:12,sweep:0,master:.72};
function init(){if(ctx)return;ctx=new (window.AudioContext||window.webkitAudioContext)();master=ctx.createGain();filter=ctx.createBiquadFilter();analyser=ctx.createAnalyser();analyser.fftSize=1024;master.gain.value=state.master;filter.type=filterType;filter.connect(master).connect(analyser).connect(ctx.destination);ctx.resume();$('#statusText').textContent='audio awake';$('#statusDot').style.background='var(--cyan)';draw()}
function voice(freq){init();let now=ctx.currentTime;let o=ctx.createOscillator(),g=ctx.createGain();o.type=state.wave;o.frequency.value=freq;o.detune.value=state.detune;g.gain.setValueAtTime(0,now);g.gain.linearRampToValueAtTime(.55,now+state.attack);g.gain.linearRampToValueAtTime(.55*state.sustain,now+state.attack+state.decay);o.connect(g).connect(filter);o.start();if(state.sub>0){subOsc=ctx.createOscillator();subGain=ctx.createGain();subOsc.type='sine';subOsc.frequency.value=freq/2;subGain.gain.value=.22*state.sub;subOsc.connect(subGain).connect(filter);subOsc.start()}return{o,g,subOsc,subGain}}
function down(freq,key){if(notes[key])return;let v=voice(freq),now=ctx.currentTime;filter.frequency.cancelScheduledValues(now);filter.frequency.setValueAtTime(state.cutoff,now);if(state.sweep)filter.frequency.linearRampToValueAtTime(Math.min(12000,state.cutoff+state.sweep*6000),now+state.attack+state.decay);notes[key]=v;key?.classList.add('down');active=true}
function up(key){let v=notes[key];if(!v)return;let now=ctx.currentTime;v.g.gain.cancelScheduledValues(now);v.g.gain.setValueAtTime(v.g.gain.value,now);v.g.gain.linearRampToValueAtTime(0,now+state.release);v.o.stop(now+state.release+.03);if(v.subOsc)v.subOsc.stop(now+state.release+.03);delete notes[key];if(!Object.keys(notes).length)active=false}
const keyMap={'a':261.63,'s':293.66,'d':329.63,'f':349.23,'g':392,'h':440,'j':493.88};
$$('.key').forEach(k=>{k.onmousedown=()=>down(+k.dataset.note,k);k.onmouseup=k.onmouseleave=()=>up(k);k.ontouchstart=e=>{e.preventDefault();down(+k.dataset.note,k)};k.ontouchend=()=>up(k)});window.onkeydown=e=>{let k=e.key.toLowerCase();if(keyMap[k]&&!e.repeat){let el=$$('.key').find(x=>+x.dataset.note===keyMap[k]);down(keyMap[k],el)}};window.onkeyup=e=>{let k=e.key.toLowerCase();if(keyMap[k]){let el=$$('.key').find(x=>+x.dataset.note===keyMap[k]);up(el)}};
$('#start').onclick=()=>down(state.pitch,null);$('#stop').onclick=()=>Object.keys(notes).forEach(k=>up(k));$('#master').oninput=e=>{state.master=+e.target.value;$('#masterVal').textContent=Math.round(state.master*100)+'%';if(master)master.gain.value=state.master};
function bind(id,fmt,outId=id+'Val'){let el=$('#'+id),out=$('#'+outId);el.oninput=()=>{state[id]=+el.value;out.textContent=fmt(state[id]);if(id==='cutoff'&&filter)filter.frequency.value=state.cutoff;if(id==='resonance'&&filter)filter.Q.value=state.resonance};out.textContent=fmt(+el.value)}bind('pitch',v=>Math.round(v)+' hz');bind('detune',v=>(v>0?'+':'')+v+' ct');bind('sub',v=>Math.round(v*100)+'%');bind('attack',v=>v.toFixed(2)+' s');bind('decay',v=>v.toFixed(2)+' s');bind('sustain',v=>Math.round(v*100)+'%');bind('release',v=>v.toFixed(2)+' s');bind('cutoff',v=>Math.round(v)+' hz','cutVal');bind('resonance',v=>v+'%','resVal');bind('sweep',v=>Math.round(v*100)+'%');
$$('[data-wave]').forEach(b=>b.onclick=()=>{$$('[data-wave]').forEach(x=>x.classList.remove('active'));b.classList.add('active');state.wave=b.dataset.wave;$('#waveVal').textContent=state.wave;$('#scopeMode').textContent=state.wave+' · '+Math.round(state.pitch)+' hz'});$$('[data-filter]').forEach(b=>b.onclick=()=>{$$('[data-filter]').forEach(x=>x.classList.remove('active'));b.classList.add('active');filterType=b.dataset.filter;$('#filterVal').textContent=filterType;if(filter)filter.type=filterType});
const lessons=[['Meet the oscillator','Every synth starts with a repeating electrical pattern. Choose a waveform, then play a note. Sine is pure and soft; saw is bright and buzzy.','Try it: compare the waves','Press the four waveform buttons, then listen to how the same pitch changes character.','A waveform is timbre, not pitch. Pitch comes from how fast it repeats.'],['Shape a note','A note is not just on/off. The envelope is a four-part choreography: attack rises, decay falls, sustain holds, release fades.','Try it: make a pluck','Set attack near 0, sustain low, and release around 0.4s. Tap a key.','Short attack + low sustain makes drums, plucks, and piano-like shapes.'],['Sculpt the tone','The filter is a frequency gate. Lowpass keeps lows and removes brightness; resonance emphasizes the edge of that gate.','Try it: open the filter','Choose SAW, lower cutoff, then turn resonance up. Sweep cutoff while holding a note.','Resonance gives the cutoff a peak. Automating cutoff is the classic “synth sweep.”'],['Make it yours','You now have the core subtractive synth: source, time, and color. Add a sub for weight and detune for movement.','Try it: design a patch','Build a bass: SAW, pitch low, sub 40%, cutoff 600Hz, release 0.2s.','There are no wrong settings—listen, notice, and iterate.']];let lesson=0;function renderLesson(){let l=lessons[lesson];$('#lessonNum').textContent='LESSON 0'+(lesson+1)+' / 04';$('#lessonTitle').textContent=l[0];$('#lessonText').textContent=l[1];$('#lessonCardTitle').textContent=l[2];$('#lessonCardText').textContent=l[3];$('#tipText').textContent=l[4];$('#progress').style.width=((lesson+1)*25)+'%';$('#next').textContent=lesson===3?'restart lessons':'I got it — next'}$('#next').onclick=()=>{lesson=(lesson+1)%4;renderLesson();$('#toast').textContent=lesson===0?'Back to the garden':'Lesson unlocked';$('#toast').classList.add('show');setTimeout(()=>$('#toast').classList.remove('show'),1600)};$('#reset').onclick=()=>{location.reload()};renderLesson();
const canvas=$('#scope'),c=canvas.getContext('2d');function draw(){requestAnimationFrame(draw);let w=canvas.width=canvas.clientWidth*devicePixelRatio,h=canvas.height=canvas.clientHeight*devicePixelRatio;c.clearRect(0,0,w,h);c.strokeStyle='#202932';c.lineWidth=1*devicePixelRatio;for(let x=0;x<w;x+=w/8){c.beginPath();c.moveTo(x,0);c.lineTo(x,h);c.stroke()}for(let y=0;y<h;y+=h/4){c.beginPath();c.moveTo(0,y);c.lineTo(w,y);c.stroke()}c.strokeStyle='#6de0d1';c.lineWidth=2*devicePixelRatio;c.beginPath();if(analyser){let data=new Uint8Array(analyser.fftSize);analyser.getByteTimeDomainData(data);for(let i=0;i<data.length;i++){let x=i/data.length*w,y=data[i]/255*h;if(i===0)c.moveTo(x,y);else c.lineTo(x,y)}}else{for(let x=0;x<w;x++){let y=h/2+Math.sin(x/w*18)*h*.18;c.lineTo(x,y)}}c.stroke();$('#event').textContent=active?'playing · signal flowing':'ready for input'}
</script></body></html>
<!-- agent-meta {"model":"openai/gpt-5.6-luna-pro","provider":"openrouter","persona":"full","sessionId":"d2784093-1580-4bb5-b6cb-79b90638f701","tokensIn":221871,"tokensOut":17388,"tokensTotal":239259,"turns":7,"toolCalls":10,"failedToolCalls":0,"timestamp":"2026-07-31T00:49:28.958Z"} -->