sdsqni (html, doesn't expire)
<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>KORG Kaoscillator - Digital Hardcore (Low-Latency)</title>
    <style>
        :root {
            --bg-color: #0d0d0d;
            --panel-bg: #18181f;
            --accent-yellow: #ffcc00;
            --accent-red: #ff3333;
        }

        body {
            background-color: var(--bg-color);
            color: #fff;
            font-family: 'Courier New', Courier, monospace;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            user-select: none;
        }

        .kaoss-container {
            background: var(--panel-bg);
            border: 4px solid #333;
            border-radius: 16px;
            padding: 20px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.9), inset 0 0 15px rgba(255,255,255,0.05);
            width: 380px;
            display: flex;
            flex-direction: column;
            gap: 12px;
        }

        .header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 2px solid #333;
            padding-bottom: 6px;
        }

        .title {
            font-weight: bold;
            font-size: 1.1rem;
            color: var(--accent-yellow);
            letter-spacing: 2px;
        }

        .subtitle {
            font-size: 0.65rem;
            color: var(--accent-red);
            font-weight: bold;
        }

        .display {
            background: #000;
            border: 2px solid #444;
            border-radius: 6px;
            padding: 8px 12px;
            display: flex;
            flex-direction: column;
            gap: 4px;
            font-family: monospace;
            color: var(--accent-yellow);
            text-shadow: 0 0 5px var(--accent-yellow);
            font-size: 0.85rem;
        }

        .display-row {
            display: flex;
            justify-content: space-between;
        }

        .pad-container {
            position: relative;
            width: 100%;
            height: 260px;
            background: #050505;
            border: 3px solid #444;
            border-radius: 12px;
            overflow: hidden;
            cursor: crosshair;
            touch-action: none;
        }

        canvas {
            width: 100%;
            height: 100%;
        }

        .controls {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 8px;
        }

        .control-group {
            display: flex;
            flex-direction: column;
            gap: 3px;
        }

        label {
            font-size: 0.65rem;
            color: #aaa;
            text-transform: uppercase;
            font-weight: bold;
        }

        select, button, input {
            background: #252530;
            color: #fff;
            border: 1px solid #444;
            padding: 6px;
            border-radius: 4px;
            font-family: inherit;
            font-size: 0.78rem;
            font-weight: bold;
            cursor: pointer;
        }

        select:focus, button:focus, input:focus {
            outline: none;
            border-color: var(--accent-yellow);
        }

        button.active {
            background: var(--accent-red);
            color: #fff;
            box-shadow: 0 0 10px var(--accent-red);
        }
    </style>
</head>
<body>

<div class="kaoss-container">
    <div class="header">
        <div class="title">KAOSS-DHC</div>
        <div class="subtitle">ZERO-LATENCY EDITION</div>
    </div>

    <div class="display">
        <div class="display-row">
            <span id="disp-preset">SYNTH: DHC SAW</span>
            <span id="disp-bpm">180 BPM</span>
        </div>
        <div class="display-row">
            <span id="disp-scale">SKALA: PHRYGIAN DOM</span>
            <span id="disp-pattern">BEAT: DHC BREAK</span>
        </div>
    </div>

    <div class="pad-container" id="pad">
        <canvas id="visualizer"></canvas>
    </div>

    <div class="controls">
        <div class="control-group">
            <label for="preset">Preset</label>
            <select id="preset">
                <option value="saw">Aggro Saw Lead</option>
                <option value="acid">Screaming 303</option>
                <option value="sub">Distorted Sub</option>
                <option value="noise">Cyber Chaos</option>
            </select>
        </div>

        <div class="control-group">
            <label for="scale">Skala (Exotisch)</label>
            <select id="scale">
                <option value="phrygianDom">Phrygisch-Dominant</option>
                <option value="hirajoshi">Hirajoshi (Japan)</option>
                <option value="hungarianMin">Ungarisch Moll</option>
                <option value="arabic">Arabisch (Bayati)</option>
                <option value="pelog">Pelog (Bali)</option>
                <option value="minor">Min-Pentatonisch</option>
                <option value="blues">Blues</option>
                <option value="chromatic">Chromatisch</option>
                <option value="raw">Unquantisiert</option>
            </select>
        </div>

        <div class="control-group">
            <label for="beat-pattern">Drum Pattern</label>
            <select id="beat-pattern">
                <option value="dhc">DHC Breakbeat</option>
                <option value="amen">Amen Cyber Cut</option>
                <option value="gabber">Gabber 4-to-Floor</option>
                <option value="industrial">Industrial Sync</option>
                <option value="speedcore">Speedcore Terror</option>
            </select>
        </div>

        <div class="control-group">
            <label for="bpm">Tempo / Beat</label>
            <div style="display: flex; gap: 4px;">
                <input type="number" id="bpm" value="180" min="120" max="240" style="width: 45%;">
                <button id="beat-btn" style="width: 55%;">BEAT RUN</button>
            </div>
        </div>
    </div>
</div>

<script>
    let audioCtx = null;
    let masterGain, driveNode, filterNode, mainOsc, subOsc;
    let noiseBuffer = null;
    let isTouching = false;
    let beatPlaying = false;

    // Scheduler Variables (Low Latency Web Audio Clock)
    let lookahead = 25.0; // ms
    let scheduleAheadTime = 0.1; // seconds
    let nextNoteTime = 0.0;
    let current16thNote = 0;
    let timerID = null;

    const baseFreq = 110; // A2

    // Exotic & Standard Scales
    const scales = {
        phrygianDom:  [0, 1, 4, 5, 7, 8, 10, 12, 13, 16, 17, 19, 20, 22, 24],
        hirajoshi:    [0, 2, 3, 7, 8, 12, 14, 15, 19, 20, 24],
        hungarianMin: [0, 2, 3, 6, 7, 8, 11, 12, 14, 15, 18, 19, 20, 23, 24],
        arabic:       [0, 1, 4, 5, 7, 8, 11, 12, 13, 16, 17, 19, 20, 23, 24],
        pelog:        [0, 1, 3, 7, 8, 12, 13, 15, 19, 20, 24],
        minor:        [0, 3, 5, 7, 10, 12, 15, 17, 19, 22, 24],
        blues:        [0, 3, 5, 6, 7, 10, 12, 15, 17, 18, 19, 22, 24],
        chromatic:    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
    };

    // 16-step Drum Patterns
    const drumPatterns = {
        dhc: {
            kick:  [1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0],
            snare: [0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0],
            hat:   [1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0]
        },
        amen: {
            kick:  [1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0],
            snare: [0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1],
            hat:   [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
        },
        gabber: {
            kick:  [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
            snare: [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
            hat:   [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0]
        },
        industrial: {
            kick:  [1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0],
            snare: [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0],
            hat:   [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
        },
        speedcore: {
            kick:  [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            snare: [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0],
            hat:   [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
        }
    };

    function initAudio() {
        if (audioCtx) return;
        audioCtx = new (window.AudioContext || window.webkitAudioContext)({ latencyHint: 'interactive' });

        masterGain = audioCtx.createGain();
        masterGain.gain.value = 0.3;

        // Hardcore Overdrive Distortion Node
        driveNode = audioCtx.createWaveShaper();
        driveNode.curve = makeDistortionCurve(95);
        driveNode.oversample = '4x';

        // Filter Node
        filterNode = audioCtx.createBiquadFilter();
        filterNode.type = 'lowpass';
        filterNode.frequency.value = 2000;
        filterNode.Q.value = 6;

        filterNode.connect(driveNode);
        driveNode.connect(masterGain);
        masterGain.connect(audioCtx.destination);

        // Pre-generate noise buffer to avoid audio thread stalls
        createNoiseBuffer();
    }

    function createNoiseBuffer() {
        const bufferSize = audioCtx.sampleRate * 1.0;
        noiseBuffer = audioCtx.createBuffer(1, bufferSize, audioCtx.sampleRate);
        const output = noiseBuffer.getChannelData(0);
        for (let i = 0; i < bufferSize; i++) {
            output[i] = Math.random() * 2 - 1;
        }
    }

    function makeDistortionCurve(amount) {
        let k = amount, n = 44100, curve = new Float32Array(n), deg = Math.PI / 180;
        for (let i = 0; i < n; ++i) {
            let x = i * 2 / n - 1;
            curve[i] = (3 + k) * x * 20 * deg / (Math.PI + k * Math.abs(x));
        }
        return curve;
    }

    function mtof(note) {
        return baseFreq * Math.pow(2, note / 12);
    }

    function startSynth() {
        initAudio();
        if (audioCtx.state === 'suspended') audioCtx.resume();
        if (mainOsc) return;

        const preset = document.getElementById('preset').value;

        mainOsc = audioCtx.createOscillator();
        subOsc = audioCtx.createOscillator();

        if (preset === 'saw') {
            mainOsc.type = 'sawtooth'; subOsc.type = 'square';
        } else if (preset === 'acid') {
            mainOsc.type = 'sawtooth'; subOsc.type = 'sawtooth';
        } else if (preset === 'sub') {
            mainOsc.type = 'triangle'; subOsc.type = 'sine';
        } else if (preset === 'noise') {
            mainOsc.type = 'square'; subOsc.type = 'sawtooth';
        }

        mainOsc.connect(filterNode);
        subOsc.connect(filterNode);

        mainOsc.start();
        subOsc.start();
    }

    function stopSynth() {
        if (mainOsc) { mainOsc.stop(); mainOsc.disconnect(); mainOsc = null; }
        if (subOsc) { subOsc.stop(); subOsc.disconnect(); subOsc = null; }
    }

    function updateSynth(x, y) {
        if (!mainOsc) return;

        const scaleType = document.getElementById('scale').value;
        let freq;

        if (scaleType === 'raw') {
            freq = 80 * Math.pow(2, x * 4);
        } else {
            const currentScale = scales[scaleType];
            const noteIndex = Math.floor(x * currentScale.length);
            const note = currentScale[Math.min(noteIndex, currentScale.length - 1)];
            freq = mtof(note);
        }

        const minVal = 100, maxVal = 10000;
        const cutoff = minVal * Math.pow(maxVal / minVal, y);

        // Immediate value scheduling for zero latency
        const now = audioCtx.currentTime;
        mainOsc.frequency.setValueAtTime(freq, now);
        subOsc.frequency.setValueAtTime(freq / 2, now);
        filterNode.frequency.setValueAtTime(cutoff, now);

        if (document.getElementById('preset').value === 'acid') {
            filterNode.Q.setValueAtTime(4 + (y * 18), now);
        } else {
            filterNode.Q.setValueAtTime(4, now);
        }
    }

    // High-Precision Drum Synthesizer
    function triggerDrum(type, time) {
        if (type === 'kick') {
            let osc = audioCtx.createOscillator();
            let gain = audioCtx.createGain();
            osc.frequency.setValueAtTime(180, time);
            osc.frequency.exponentialRampToValueAtTime(30, time + 0.1);
            gain.gain.setValueAtTime(1.4, time);
            gain.gain.exponentialRampToValueAtTime(0.001, time + 0.14);
            osc.connect(driveNode);
            osc.start(time); osc.stop(time + 0.14);
        } else if (type === 'snare') {
            let noiseSrc = audioCtx.createBufferSource();
            noiseSrc.buffer = noiseBuffer;
            let filter = audioCtx.createBiquadFilter();
            filter.type = 'highpass';
            filter.frequency.value = 800;
            let gain = audioCtx.createGain();
            gain.gain.setValueAtTime(0.9, time);
            gain.gain.exponentialRampToValueAtTime(0.01, time + 0.09);
            noiseSrc.connect(filter);
            filter.connect(driveNode);
            noiseSrc.start(time); noiseSrc.stop(time + 0.09);
        } else if (type === 'hat') {
            let noiseSrc = audioCtx.createBufferSource();
            noiseSrc.buffer = noiseBuffer;
            let filter = audioCtx.createBiquadFilter();
            filter.type = 'highpass';
            filter.frequency.value = 6000;
            let gain = audioCtx.createGain();
            gain.gain.setValueAtTime(0.4, time);
            gain.gain.exponentialRampToValueAtTime(0.001, time + 0.04);
            noiseSrc.connect(filter);
            filter.connect(driveNode);
            noiseSrc.start(time); noiseSrc.stop(time + 0.04);
        }
    }

    // Web Audio Lookahead Scheduler
    function nextNote() {
        const bpm = parseInt(document.getElementById('bpm').value);
        const secondsPerBeat = 60.0 / bpm;
        nextNoteTime += 0.25 * secondsPerBeat; // 16th note step
        current16thNote = (current16thNote + 1) % 16;
    }

    function scheduleNote(step, time) {
        const patKey = document.getElementById('beat-pattern').value;
        const pat = drumPatterns[patKey];

        if (pat.kick[step]) triggerDrum('kick', time);
        if (pat.snare[step]) triggerDrum('snare', time);
        if (pat.hat[step]) triggerDrum('hat', time);
    }

    function scheduler() {
        while (nextNoteTime < audioCtx.currentTime + scheduleAheadTime) {
            scheduleNote(current16thNote, nextNoteTime);
            nextNote();
        }
        if (beatPlaying) {
            timerID = window.setTimeout(scheduler, lookahead);
        }
    }

    document.getElementById('beat-btn').addEventListener('click', (e) => {
        initAudio();
        if (audioCtx.state === 'suspended') audioCtx.resume();

        beatPlaying = !beatPlaying;
        e.target.classList.toggle('active', beatPlaying);

        if (beatPlaying) {
            current16thNote = 0;
            nextNoteTime = audioCtx.currentTime;
            scheduler();
        } else {
            clearTimeout(timerID);
        }
    });

    // Touch / Mouse Interaction with RAF Decoupling for smooth performance
    const pad = document.getElementById('pad');
    const canvas = document.getElementById('visualizer');
    const ctx = canvas.getContext('2d');
    let touchX = 0, touchY = 0;

    function resizeCanvas() {
        canvas.width = pad.clientWidth; canvas.height = pad.clientHeight;
    }
    window.addEventListener('resize', resizeCanvas);
    resizeCanvas();

    function handleInputStart(e) {
        isTouching = true;
        startSynth();
        handleInputMove(e);
    }

    function handleInputEnd() {
        isTouching = false;
        stopSynth();
    }

    function handleInputMove(e) {
        if (!isTouching) return;
        const rect = pad.getBoundingClientRect();
        const clientX = e.touches ? e.touches[0].clientX : e.clientX;
        const clientY = e.touches ? e.touches[0].clientY : e.clientY;

        touchX = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
        touchY = Math.max(0, Math.min(1, 1 - (clientY - rect.top) / rect.height));

        updateSynth(touchX, touchY);
    }

    pad.addEventListener('mousedown', handleInputStart);
    window.addEventListener('mouseup', handleInputEnd);
    pad.addEventListener('mousemove', handleInputMove);

    pad.addEventListener('touchstart', handleInputStart, { passive: true });
    window.addEventListener('touchend', handleInputEnd);
    pad.addEventListener('touchmove', handleInputMove, { passive: true });

    // Canvas Visualization Loop
    function renderVisualizer() {
        requestAnimationFrame(renderVisualizer);

        ctx.fillStyle = 'rgba(5, 5, 5, 0.25)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        // Grid
        ctx.strokeStyle = '#1a1a1a';
        ctx.lineWidth = 1;
        for (let i = 0; i < canvas.width; i += 30) {
            ctx.beginPath(); ctx.moveTo(i, 0); ctx.lineTo(i, canvas.height); ctx.stroke();
        }
        for (let j = 0; j < canvas.height; j += 30) {
            ctx.beginPath(); ctx.moveTo(0, j); ctx.lineTo(canvas.width, j); ctx.stroke();
        }

        // Touch Cursor
        if (isTouching) {
            const cx = touchX * canvas.width;
            const cy = (1 - touchY) * canvas.height;

            ctx.strokeStyle = 'rgba(255, 204, 0, 0.6)';
            ctx.beginPath(); ctx.moveTo(cx, 0); ctx.lineTo(cx, canvas.height); ctx.stroke();
            ctx.beginPath(); ctx.moveTo(0, cy); ctx.lineTo(canvas.width, cy); ctx.stroke();

            ctx.fillStyle = '#ff3333';
            ctx.shadowColor = '#ff3333';
            ctx.shadowBlur = 15;
            ctx.beginPath();
            ctx.arc(cx, cy, 10, 0, Math.PI * 2);
            ctx.fill();
            ctx.shadowBlur = 0;
        }
    }
    renderVisualizer();

    // UI Display Listeners
    document.getElementById('scale').addEventListener('change', (e) => {
        document.getElementById('disp-scale').innerText = `SKALA: ${e.target.options[e.target.selectedIndex].text.toUpperCase()}`;
    });

    document.getElementById('preset').addEventListener('change', (e) => {
        document.getElementById('disp-preset').innerText = `SYNTH: ${e.target.options[e.target.selectedIndex].text.toUpperCase()}`;
        if (mainOsc) { stopSynth(); startSynth(); }
    });

    document.getElementById('beat-pattern').addEventListener('change', (e) => {
        document.getElementById('disp-pattern').innerText = `BEAT: ${e.target.options[e.target.selectedIndex].text.toUpperCase()}`;
    });

    document.getElementById('bpm').addEventListener('change', (e) => {
        document.getElementById('disp-bpm').innerText = `${e.target.value} BPM`;
    });
</script>

</body>
</html>