✨ The Prompt Phrase
Design a dark-themed drum machine UI for a music production web app. Include an 8 by 4 pad grid where each pad triggers a different drum sound, a BPM slider ranging from 60 to 200, a 16-step pattern sequencer showing active steps highlighted in amber, and a sidebar listing drum kit presets. Use dark charcoal and amber accents with glowing active pads and smooth hover transitions.

💻 Code Preview

📦 All-in-One Code
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>BeatForge — Drum Machine</title>
  <style>
    /* ═══════════════════════════════════════════════════════════
       DESIGN TOKENS
    ═══════════════════════════════════════════════════════════ */
    :root {
      --bg-900:    #0e0e0e;
      --bg-800:    #141414;
      --bg-700:    #1a1a1a;
      --bg-600:    #212121;
      --bg-500:    #2a2a2a;
      --bg-400:    #333333;

      --amber-600: #d97706;
      --amber-500: #f59e0b;
      --amber-400: #fbbf24;
      --amber-300: #fcd34d;
      --amber-glow: rgba(251,191,36,.35);
      --amber-glow-sm: rgba(251,191,36,.18);

      --green-500:  #22c55e;
      --green-glow: rgba(34,197,94,.3);
      --red-500:    #ef4444;
      --blue-500:   #3b82f6;
      --purple-500: #a855f7;

      --text-primary:   #f0f0f0;
      --text-secondary: #909090;
      --text-muted:     #555555;

      --border:     rgba(255,255,255,.07);
      --border-mid: rgba(255,255,255,.12);

      --r-sm:  6px;
      --r-md:  10px;
      --r-lg:  14px;
      --r-xl:  20px;

      --t: .15s cubic-bezier(.4,0,.2,1);
      --t-slow: .3s cubic-bezier(.4,0,.2,1);

      --sidebar-w: 210px;
    }

    /* ═══════════════════════════════════════════════════════════
       RESET
    ═══════════════════════════════════════════════════════════ */
    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
    html { height: 100%; }
    body {
      font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
      background: var(--bg-900);
      color: var(--text-primary);
      min-height: 100vh;
      display: flex;
      flex-direction: column;
      -webkit-font-smoothing: antialiased;
      overflow-x: hidden;
    }
    button { font-family: inherit; cursor: pointer; border: none; }
    input  { font-family: inherit; }
    ::-webkit-scrollbar { width: 5px; }
    ::-webkit-scrollbar-track { background: transparent; }
    ::-webkit-scrollbar-thumb { background: var(--bg-500); border-radius: 99px; }

    /* ═══════════════════════════════════════════════════════════
       TOP BAR
    ═══════════════════════════════════════════════════════════ */
    .topbar {
      display: flex;
      align-items: center;
      gap: 1rem;
      padding: .75rem 1.25rem;
      background: var(--bg-800);
      border-bottom: 1px solid var(--border);
      flex-shrink: 0;
      z-index: 50;
    }

    .logo {
      display: flex; align-items: center; gap: .55rem;
      font-size: 1rem; font-weight: 900;
      letter-spacing: -.03em; color: var(--text-primary);
      white-space: nowrap;
    }
    .logo-icon {
      width: 28px; height: 28px;
      background: linear-gradient(135deg, var(--amber-600), var(--amber-400));
      border-radius: var(--r-sm);
      display: flex; align-items: center; justify-content: center;
      font-size: .85rem;
      box-shadow: 0 0 12px var(--amber-glow);
    }
    .logo span { color: var(--amber-400); }

    .topbar-sep {
      width: 1px; height: 22px;
      background: var(--border-mid); flex-shrink: 0;
    }
    .topbar-spacer { flex: 1; }

    /* Transport controls */
    .transport {
      display: flex; align-items: center; gap: .5rem;
    }
    .t-btn {
      display: flex; align-items: center; justify-content: center;
      width: 36px; height: 36px;
      border-radius: var(--r-md);
      background: var(--bg-600);
      border: 1px solid var(--border-mid);
      color: var(--text-secondary);
      font-size: .9rem;
      transition: background var(--t), color var(--t), box-shadow var(--t);
    }
    .t-btn:hover {
      background: var(--bg-500);
      color: var(--text-primary);
    }
    .t-btn.play {
      width: 42px; height: 42px;
      background: linear-gradient(135deg, var(--amber-600), var(--amber-500));
      color: #000;
      font-size: 1rem;
      border: none;
      box-shadow: 0 0 16px var(--amber-glow);
    }
    .t-btn.play:hover {
      background: linear-gradient(135deg, var(--amber-500), var(--amber-400));
      box-shadow: 0 0 24px var(--amber-glow);
      transform: scale(1.05);
    }
    .t-btn.play.active {
      background: linear-gradient(135deg, var(--green-500), #16a34a);
      box-shadow: 0 0 20px var(--green-glow);
      color: #fff;
    }
    .t-btn.stop:hover { color: var(--red-500); }
    .t-btn.rec:hover  { color: var(--red-500); }

    /* BPM control */
    .bpm-wrap {
      display: flex; align-items: center; gap: .6rem;
      background: var(--bg-700);
      border: 1px solid var(--border-mid);
      border-radius: var(--r-md);
      padding: .35rem .75rem;
    }
    .bpm-label {
      font-size: .65rem; font-weight: 800;
      text-transform: uppercase; letter-spacing: .1em;
      color: var(--text-muted);
    }
    .bpm-val {
      font-size: 1.05rem; font-weight: 900;
      color: var(--amber-400);
      min-width: 38px; text-align: center;
      font-variant-numeric: tabular-nums;
    }
    .bpm-slider {
      -webkit-appearance: none;
      width: 100px; height: 4px;
      background: var(--bg-500);
      border-radius: 99px; outline: none;
      cursor: pointer;
    }
    .bpm-slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 14px; height: 14px;
      border-radius: 50%;
      background: var(--amber-400);
      box-shadow: 0 0 8px var(--amber-glow);
      cursor: pointer;
      transition: transform var(--t), box-shadow var(--t);
    }
    .bpm-slider::-webkit-slider-thumb:hover {
      transform: scale(1.3);
      box-shadow: 0 0 14px var(--amber-glow);
    }
    .bpm-slider::-moz-range-thumb {
      width: 14px; height: 14px;
      border-radius: 50%; border: none;
      background: var(--amber-400);
      box-shadow: 0 0 8px var(--amber-glow);
      cursor: pointer;
    }

    /* Step counter badge */
    .step-badge {
      display: flex; align-items: center; gap: .4rem;
      font-size: .72rem; color: var(--text-muted);
      white-space: nowrap;
    }
    .step-dot {
      width: 7px; height: 7px; border-radius: 50%;
      background: var(--green-500);
      box-shadow: 0 0 6px var(--green-glow);
      animation: pulse 1s ease-in-out infinite;
    }
    .step-dot.stopped { background: var(--bg-400); box-shadow: none; animation: none; }
    @keyframes pulse {
      0%,100% { opacity: 1; }
      50%      { opacity: .4; }
    }

    /* ═══════════════════════════════════════════════════════════
       MAIN LAYOUT
    ═══════════════════════════════════════════════════════════ */
    .main {
      display: flex;
      flex: 1;
      overflow: hidden;
      min-height: 0;
    }

    /* ═══════════════════════════════════════════════════════════
       SIDEBAR — PRESETS
    ═══════════════════════════════════════════════════════════ */
    .sidebar {
      width: var(--sidebar-w);
      flex-shrink: 0;
      background: var(--bg-800);
      border-right: 1px solid var(--border);
      display: flex; flex-direction: column;
      overflow-y: auto;
    }

    .sidebar-head {
      padding: 1rem 1rem .5rem;
      flex-shrink: 0;
    }
    .sidebar-head h2 {
      font-size: .65rem; font-weight: 800;
      letter-spacing: .12em; text-transform: uppercase;
      color: var(--text-muted);
      margin-bottom: .75rem;
    }

    .search-box {
      display: flex; align-items: center; gap: .4rem;
      background: var(--bg-700);
      border: 1px solid var(--border-mid);
      border-radius: var(--r-sm);
      padding: .4rem .6rem;
    }
    .search-box input {
      background: none; border: none; outline: none;
      color: var(--text-primary); font-size: .78rem;
      width: 100%;
    }
    .search-box input::placeholder { color: var(--text-muted); }
    .search-icon { color: var(--text-muted); font-size: .8rem; flex-shrink: 0; }

    .preset-section { padding: .5rem .75rem; }
    .preset-section-label {
      font-size: .6rem; font-weight: 800;
      letter-spacing: .1em; text-transform: uppercase;
      color: var(--text-muted);
      padding: .5rem .25rem .3rem;
    }

    .preset-item {
      display: flex; align-items: center; gap: .6rem;
      padding: .55rem .6rem;
      border-radius: var(--r-sm);
      cursor: pointer;
      transition: background var(--t), color var(--t);
      border: 1px solid transparent;
    }
    .preset-item:hover {
      background: var(--bg-600);
      color: var(--text-primary);
    }
    .preset-item.active {
      background: rgba(251,191,36,.1);
      border-color: rgba(251,191,36,.2);
      color: var(--amber-400);
    }
    .preset-dot {
      width: 8px; height: 8px; border-radius: 50%;
      flex-shrink: 0;
    }
    .preset-name {
      font-size: .8rem; font-weight: 500;
      flex: 1; color: inherit;
    }
    .preset-item.active .preset-name { font-weight: 700; }
    .preset-tag {
      font-size: .6rem; font-weight: 700;
      padding: .1em .45em; border-radius: 4px;
      background: rgba(255,255,255,.07);
      color: var(--text-muted);
      text-transform: uppercase; letter-spacing: .05em;
    }

    /* ═══════════════════════════════════════════════════════════
       CONTENT AREA
    ═══════════════════════════════════════════════════════════ */
    .content {
      flex: 1; min-width: 0;
      display: flex; flex-direction: column;
      overflow-y: auto;
      padding: 1.25rem;
      gap: 1.25rem;
    }

    /* ── Section header ── */
    .section-header {
      display: flex; align-items: center;
      justify-content: space-between;
      margin-bottom: .75rem;
    }
    .section-title {
      font-size: .65rem; font-weight: 800;
      letter-spacing: .12em; text-transform: uppercase;
      color: var(--text-muted);
      display: flex; align-items: center; gap: .5rem;
    }
    .section-title::before {
      content: '';
      display: block; width: 3px; height: 12px;
      background: linear-gradient(180deg, var(--amber-500), var(--amber-600));
      border-radius: 99px;
      box-shadow: 0 0 6px var(--amber-glow);
    }

    .chip-btn {
      display: flex; align-items: center; gap: .3rem;
      background: var(--bg-600);
      border: 1px solid var(--border-mid);
      border-radius: var(--r-sm);
      padding: .3rem .65rem;
      font-size: .72rem; font-weight: 600;
      color: var(--text-secondary);
      transition: all var(--t);
    }
    .chip-btn:hover { background: var(--bg-500); color: var(--text-primary); }
    .chip-btn.active {
      background: rgba(251,191,36,.12);
      border-color: rgba(251,191,36,.3);
      color: var(--amber-400);
    }

    /* ═══════════════════════════════════════════════════════════
       PAD GRID  8 × 4
    ═══════════════════════════════════════════════════════════ */
    .pad-panel {
      background: var(--bg-800);
      border: 1px solid var(--border);
      border-radius: var(--r-xl);
      padding: 1.25rem;
    }

    .pad-grid {
      display: grid;
      grid-template-columns: repeat(8, 1fr);
      gap: .55rem;
    }

    .pad {
      aspect-ratio: 1;
      border-radius: var(--r-md);
      display: flex; flex-direction: column;
      align-items: center; justify-content: center;
      gap: .25rem;
      cursor: pointer;
      position: relative;
      overflow: hidden;
      border: 1px solid rgba(255,255,255,.07);
      transition:
        transform var(--t),
        box-shadow var(--t),
        border-color var(--t),
        filter var(--t);
      user-select: none;
      -webkit-tap-highlight-color: transparent;
    }

    /* Pad shimmer overlay */
    .pad::before {
      content: '';
      position: absolute; inset: 0;
      background: linear-gradient(135deg,
        rgba(255,255,255,.08) 0%,
        transparent 60%);
      pointer-events: none;
    }

    /* Pad label */
    .pad-label {
      font-size: .58rem; font-weight: 800;
      letter-spacing: .06em; text-transform: uppercase;
      opacity: .6; z-index: 1; text-align: center;
      line-height: 1.2;
    }
    .pad-icon {
      font-size: 1.1rem; z-index: 1;
      transition: transform var(--t);
    }

    .pad:hover {
      transform: scale(1.04) translateY(-1px);
      border-color: rgba(255,255,255,.18);
      filter: brightness(1.15);
    }
    .pad:active, .pad.hit {
      transform: scale(.94);
      filter: brightness(1.4);
    }

    /* Colour themes per row */
    .pad.row-0 { background: linear-gradient(145deg, #1f1a10, #2a2210); color: #fcd34d; }
    .pad.row-0:hover { box-shadow: 0 0 18px rgba(251,191,36,.3); }
    .pad.row-0.active-pad {
      background: linear-gradient(145deg, var(--amber-600), var(--amber-500));
      color: #000;
      border-color: var(--amber-400);
      box-shadow: 0 0 24px var(--amber-glow), inset 0 1px 0 rgba(255,255,255,.2);
    }

    .pad.row-1 { background: linear-gradient(145deg, #101a1f, #102230); color: #93c5fd; }
    .pad.row-1:hover { box-shadow: 0 0 18px rgba(59,130,246,.25); }
    .pad.row-1.active-pad {
      background: linear-gradient(145deg, #1d4ed8, #3b82f6);
      color: #fff;
      border-color: #60a5fa;
      box-shadow: 0 0 24px rgba(59,130,246,.45), inset 0 1px 0 rgba(255,255,255,.2);
    }

    .pad.row-2 { background: linear-gradient(145deg, #1a101a, #22102a); color: #d8b4fe; }
    .pad.row-2:hover { box-shadow: 0 0 18px rgba(168,85,247,.25); }
    .pad.row-2.active-pad {
      background: linear-gradient(145deg, #7e22ce, #a855f7);
      color: #fff;
      border-color: #c084fc;
      box-shadow: 0 0 24px rgba(168,85,247,.45), inset 0 1px 0 rgba(255,255,255,.2);
    }

    .pad.row-3 { background: linear-gradient(145deg, #101a10, #102210); color: #86efac; }
    .pad.row-3:hover { box-shadow: 0 0 18px rgba(34,197,94,.25); }
    .pad.row-3.active-pad {
      background: linear-gradient(145deg, #15803d, #22c55e);
      color: #fff;
      border-color: #4ade80;
      box-shadow: 0 0 24px rgba(34,197,94,.45), inset 0 1px 0 rgba(255,255,255,.2);
    }

    /* ═══════════════════════════════════════════════════════════
       SEQUENCER
    ═══════════════════════════════════════════════════════════ */
    .seq-panel {
      background: var(--bg-800);
      border: 1px solid var(--border);
      border-radius: var(--r-xl);
      padding: 1.25rem;
    }

    .seq-rows { display: flex; flex-direction: column; gap: .5rem; }

    .seq-row {
      display: grid;
      grid-template-columns: 72px 1fr;
      align-items: center;
      gap: .75rem;
    }

    .seq-row-label {
      font-size: .7rem; font-weight: 700;
      color: var(--text-secondary);
      text-align: right;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .seq-steps {
      display: grid;
      grid-template-columns: repeat(16, 1fr);
      gap: .3rem;
    }

    .seq-step {
      aspect-ratio: 1;
      border-radius: var(--r-sm);
      background: var(--bg-600);
      border: 1px solid var(--border);
      cursor: pointer;
      position: relative;
      transition: background var(--t), box-shadow var(--t), border-color var(--t), transform var(--t);
    }
    /* Beat grouping — subtle separator every 4 steps */
    .seq-step:nth-child(4n+1) { margin-left: .15rem; }

    .seq-step:hover {
      background: var(--bg-500);
      border-color: rgba(255,255,255,.18);
      transform: scale(1.08);
    }

    /* Active (toggled on) step */
    .seq-step.on {
      background: linear-gradient(135deg, var(--amber-600), var(--amber-400));
      border-color: var(--amber-400);
      box-shadow: 0 0 10px var(--amber-glow), 0 0 3px var(--amber-glow-sm);
    }
    .seq-step.on:hover {
      background: linear-gradient(135deg, var(--amber-500), var(--amber-300));
      box-shadow: 0 0 16px var(--amber-glow);
    }

    /* Playhead highlight */
    .seq-step.playing {
      outline: 2px solid rgba(255,255,255,.5);
      outline-offset: 1px;
    }
    .seq-step.on.playing {
      background: linear-gradient(135deg, #fff, var(--amber-300));
      box-shadow: 0 0 20px rgba(255,255,255,.4), 0 0 10px var(--amber-glow);
    }

    /* Beat number ticks */
    .seq-ticks {
      display: grid;
      grid-template-columns: repeat(16, 1fr);
      gap: .3rem;
      margin-bottom: .3rem;
      padding-left: calc(72px + .75rem);
    }
    .seq-tick {
      font-size: .55rem; font-weight: 800;
      color: var(--text-muted);
      text-align: center;
      letter-spacing: 0;
    }
    .seq-tick.beat { color: var(--amber-600); }

    /* ═══════════════════════════════════════════════════════════
       MIXER STRIP
    ═══════════════════════════════════════════════════════════ */
    .mixer-panel {
      background: var(--bg-800);
      border: 1px solid var(--border);
      border-radius: var(--r-xl);
      padding: 1.25rem;
    }

    .mixer-strips {
      display: grid;
      grid-template-columns: repeat(8, 1fr);
      gap: .6rem;
    }

    .mixer-strip {
      display: flex; flex-direction: column;
      align-items: center; gap: .5rem;
    }

    .mix-label {
      font-size: .58rem; font-weight: 700;
      color: var(--text-muted); text-align: center;
      text-transform: uppercase; letter-spacing: .05em;
      line-height: 1.2;
    }

    .mix-fader-wrap {
      display: flex; flex-direction: column;
      align-items: center; gap: .3rem;
      width: 100%;
    }

    .mix-fader {
      -webkit-appearance: none;
      writing-mode: vertical-lr;
      direction: rtl;
      width: 4px; height: 60px;
      background: var(--bg-500);
      border-radius: 99px; outline: none;
      cursor: pointer;
    }
    .mix-fader::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 16px; height: 10px;
      border-radius: 4px;
      background: linear-gradient(135deg, var(--bg-400), var(--bg-300, #444));
      border: 1px solid rgba(255,255,255,.15);
      cursor: pointer;
      box-shadow: 0 2px 4px rgba(0,0,0,.4);
      transition: background var(--t);
    }
    .mix-fader::-webkit-slider-thumb:hover {
      background: linear-gradient(135deg, var(--amber-600), var(--amber-500));
      box-shadow: 0 0 8px var(--amber-glow);
    }

    .mix-val {
      font-size: .6rem; font-weight: 700;
      color: var(--text-muted);
      font-variant-numeric: tabular-nums;
    }

    .mix-mute {
      width: 28px; height: 18px;
      border-radius: 4px;
      background: var(--bg-600);
      border: 1px solid var(--border-mid);
      font-size: .55rem; font-weight: 800;
      color: var(--text-muted);
      transition: all var(--t);
      text-transform: uppercase;
      letter-spacing: .05em;
    }
    .mix-mute:hover { background: var(--bg-500); color: var(--text-primary); }
    .mix-mute.muted {
      background: rgba(239,68,68,.15);
      border-color: rgba(239,68,68,.3);
      color: var(--red-500);
    }

    /* ═══════════════════════════════════════════════════════════
       VU METER
    ═══════════════════════════════════════════════════════════ */
    .vu-meter {
      display: flex; gap: 2px; align-items: flex-end;
      height: 32px;
    }
    .vu-bar {
      width: 4px; border-radius: 2px;
      background: var(--bg-500);
      transition: height .08s ease, background .08s ease;
    }

    /* ═══════════════════════════════════════════════════════════
       STATUS BAR
    ═══════════════════════════════════════════════════════════ */
    .statusbar {
      display: flex; align-items: center; gap: 1rem;
      padding: .45rem 1.25rem;
      background: var(--bg-800);
      border-top: 1px solid var(--border);
      font-size: .68rem; color: var(--text-muted);
      flex-shrink: 0;
    }
    .status-item { display: flex; align-items: center; gap: .35rem; }
    .status-dot {
      width: 6px; height: 6px; border-radius: 50%;
      background: var(--green-500);
      box-shadow: 0 0 5px var(--green-glow);
    }
    .status-dot.amber {
      background: var(--amber-500);
      box-shadow: 0 0 5px var(--amber-glow);
    }
    .status-spacer { flex: 1; }
    .status-val { color: var(--text-secondary); font-weight: 600; }

    /* ═══════════════════════════════════════════════════════════
       RESPONSIVE
    ═══════════════════════════════════════════════════════════ */
    @media (max-width: 900px) {
      .sidebar { display: none; }
      .pad-grid { grid-template-columns: repeat(4, 1fr); }
      .mixer-strips { grid-template-columns: repeat(4, 1fr); }
      .bpm-slider { width: 70px; }
    }
    @media (max-width: 600px) {
      .seq-row { grid-template-columns: 52px 1fr; }
      .seq-row-label { font-size: .6rem; }
      .topbar { flex-wrap: wrap; gap: .5rem; }
    }
  </style>
</head>
<body>

<!-- ══════════════════════════════════════════════════════════════
     TOP BAR
══════════════════════════════════════════════════════════════ -->
<header class="topbar">
  <div class="logo">
    <div class="logo-icon">🥁</div>
    Beat<span>Forge</span>
  </div>

  <div class="topbar-sep"></div>

  <!-- Transport -->
  <div class="transport">
    <button class="t-btn rec"  id="btn-rec"  title="Record">⏺</button>
    <button class="t-btn stop" id="btn-stop" title="Stop">⏹</button>
    <button class="t-btn play" id="btn-play" title="Play / Pause">▶</button>
  </div>

  <div class="topbar-sep"></div>

  <!-- BPM -->
  <div class="bpm-wrap">
    <span class="bpm-label">BPM</span>
    <input type="range" class="bpm-slider" id="bpm-slider"
           min="60" max="200" value="120"/>
    <span class="bpm-val" id="bpm-val">120</span>
  </div>

  <div class="topbar-sep"></div>

  <!-- Step indicator -->
  <div class="step-badge">
    <div class="step-dot stopped" id="play-dot"></div>
    <span id="step-label">Stopped</span>
  </div>

  <div class="topbar-spacer"></div>

  <!-- Swing / Quantise chips -->
  <button class="chip-btn" id="btn-swing">⟳ Swing 0%</button>
  <button class="chip-btn active" id="btn-quant">⊞ Quantise</button>
  <button class="chip-btn" id="btn-clear">✕ Clear</button>
</header>

<!-- ══════════════════════════════════════════════════════════════
     MAIN
══════════════════════════════════════════════════════════════ -->
<div class="main">

  <!-- SIDEBAR -->
  <aside class="sidebar">
    <div class="sidebar-head">
      <h2>🎛 Kit Presets</h2>
      <div class="search-box">
        <span class="search-icon">🔍</span>
        <input type="text" placeholder="Search kits…" id="preset-search"/>
      </div>
    </div>

    <div class="preset-section">
      <div class="preset-section-label">Factory</div>

      <div class="preset-item active" data-kit="0">
        <div class="preset-dot" style="background:#fbbf24"></div>
        <span class="preset-name">Classic 808</span>
        <span class="preset-tag">Hip-Hop</span>
      </div>
      <div class="preset-item" data-kit="1">
        <div class="preset-dot" style="background:#3b82f6"></div>
        <span class="preset-name">TR-909 House</span>
        <span class="preset-tag">House</span>
      </div>
      <div class="preset-item" data-kit="2">
        <div class="preset-dot" style="background:#a855f7"></div>
        <span class="preset-name">Jungle Breaks</span>
        <span class="preset-tag">DnB</span>
      </div>
      <div class="preset-item" data-kit="3">
        <div class="preset-dot" style="background:#22c55e"></div>
        <span class="preset-name">Lo-Fi Boom Bap</span>
        <span class="preset-tag">Lo-Fi</span>
      </div>
      <div class="preset-item" data-kit="4">
        <div class="preset-dot" style="background:#ef4444"></div>
        <span class="preset-name">Trap Kit</span>
        <span class="preset-tag">Trap</span>
      </div>
      <div class="preset-item" data-kit="5">
        <div class="preset-dot" style="background:#f97316"></div>
        <span class="preset-name">Afrobeats</span>
        <span class="preset-tag">Afro</span>
      </div>

      <div class="preset-section-label" style="margin-top:.5rem">User</div>

      <div class="preset-item" data-kit="6">
        <div class="preset-dot" style="background:#06b6d4"></div>
        <span class="preset-name">My Session 1</span>
        <span class="preset-tag">Custom</span>
      </div>
      <div class="preset-item" data-kit="7">
        <div class="preset-dot" style="background:#84cc16"></div>
        <span class="preset-name">Late Night WIP</span>
        <span class="preset-tag">Custom</span>
      </div>
    </div>
  </aside>

  <!-- CONTENT -->
  <div class="content">

    <!-- ── PAD GRID ──────────────────────────────────────────── -->
    <div class="pad-panel">
      <div class="section-header">
        <div class="section-title">Drum Pads — 8 × 4</div>
        <div style="display:flex;gap:.4rem">
          <button class="chip-btn" id="btn-vel">Velocity</button>
          <button class="chip-btn active">Chromatic</button>
        </div>
      </div>
      <div class="pad-grid" id="pad-grid"></div>
    </div>

    <!-- ── SEQUENCER ─────────────────────────────────────────── -->
    <div class="seq-panel">
      <div class="section-header">
        <div class="section-title">16-Step Pattern Sequencer</div>
        <div style="display:flex;gap:.4rem">
          <button class="chip-btn" id="btn-steps-8">8</button>
          <button class="chip-btn active" id="btn-steps-16">16</button>
          <button class="chip-btn" id="btn-steps-32">32</button>
        </div>
      </div>

      <!-- Beat ticks -->
      <div class="seq-ticks" id="seq-ticks"></div>

      <!-- Rows -->
      <div class="seq-rows" id="seq-rows"></div>
    </div>

    <!-- ── MIXER ─────────────────────────────────────────────── -->
    <div class="mixer-panel">
      <div class="section-header">
        <div class="section-title">Channel Mixer</div>
      </div>
      <div class="mixer-strips" id="mixer-strips"></div>
    </div>

  </div><!-- /.content -->
</div><!-- /.main -->

<!-- STATUS BAR -->
<footer class="statusbar">
  <div class="status-item">
    <div class="status-dot" id="audio-dot"></div>
    <span>Audio Engine Ready</span>
  </div>
  <div class="status-item">
    <div class="status-dot amber"></div>
    <span>Kit: <span class="status-val" id="status-kit">Classic 808</span></span>
  </div>
  <div class="status-item">
    Step: <span class="status-val" id="status-step">—</span>
  </div>
  <div class="status-item">
    Pattern: <span class="status-val">A1</span>
  </div>
  <div class="status-spacer"></div>
  <div class="status-item">
    CPU: <span class="status-val" id="cpu-val">2%</span>
  </div>
  <div class="status-item">
    Latency: <span class="status-val">8ms</span>
  </div>
  <div class="status-item">
    44.1 kHz · 24-bit
  </div>
</footer>

<!-- ══════════════════════════════════════════════════════════════
     JAVASCRIPT
══════════════════════════════════════════════════════════════ -->
<script>
(() => {
  'use strict';

  /* ── PAD DEFINITIONS ─────────────────────────────────────── */
  const PADS = [
    // Row 0 — Amber (kick / snare family)
    { label: 'Kick',    icon: '🥁', row: 0, freq: 60,  type: 'kick'   },
    { label: 'Snare',   icon: '🪘', row: 0, freq: 200, type: 'snare'  },
    { label: 'Rim',     icon: '🔔', row: 0, freq: 400, type: 'rim'    },
    { label: 'Clap',    icon: '👏', row: 0, freq: 800, type: 'clap'   },
    { label: 'Snap',    icon: '✨', row: 0, freq: 1200,type: 'snap'   },
    { label: 'Tom Hi',  icon: '🥁', row: 0, freq: 180, type: 'tom'    },
    { label: 'Tom Mid', icon: '🥁', row: 0, freq: 120, type: 'tom'    },
    { label: 'Tom Lo',  icon: '🥁', row: 0, freq: 80,  type: 'tom'    },
    // Row 1 — Blue (hi-hats / cymbals)
    { label: 'HH Cls',  icon: '🎵', row: 1, freq: 8000, type: 'hh'   },
    { label: 'HH Opn',  icon: '🎶', row: 1, freq: 6000, type: 'hh'   },
    { label: 'HH Pdl',  icon: '🎵', row: 1, freq: 7000, type: 'hh'   },
    { label: 'Crash',   icon: '💥', row: 1, freq: 5000, type: 'cym'  },
    { label: 'Ride',    icon: '🔔', row: 1, freq: 4500, type: 'cym'  },
    { label: 'Bell',    icon: '🛎', row: 1, freq: 3500, type: 'bell' },
    { label: 'Shaker',  icon: '🎼', row: 1, freq: 9000, type: 'perc' },
    { label: 'Tamb',    icon: '🎵', row: 1, freq: 7500, type: 'perc' },
    // Row 2 — Purple (synth / FX)
    { label: '808 Sub', icon: '〰', row: 2, freq: 40,  type: '808'   },
    { label: 'Zap',     icon: '⚡', row: 2, freq: 500, type: 'synth' },
    { label: 'Blip',    icon: '🔵', row: 2, freq: 900, type: 'synth' },
    { label: 'Sweep',   icon: '🌊', row: 2, freq: 300, type: 'synth' },
    { label: 'Noise',   icon: '📡', row: 2, freq: 0,   type: 'noise' },
    { label: 'Rev Cym', icon: '🔄', row: 2, freq: 4000,type: 'fx'   },
    { label: 'Vinyl',   icon: '💿', row: 2, freq: 100, type: 'fx'   },
    { label: 'FX Hit',  icon: '🎯', row: 2, freq: 600, type: 'fx'   },
    // Row 3 — Green (percussion)
    { label: 'Conga Hi',icon: '🪘', row: 3, freq: 350, type: 'conga' },
    { label: 'Conga Lo',icon: '🪘', row: 3, freq: 220, type: 'conga' },
    { label: 'Bongo',   icon: '🥁', row: 3, freq: 450, type: 'bongo' },
    { label: 'Cowbell', icon: '🔔', row: 3, freq: 550, type: 'cowbell'},
    { label: 'Woodblk', icon: '🪵', row: 3, freq: 700, type: 'wood'  },
    { label: 'Maracas', icon: '🎶', row: 3, freq: 8500,type: 'perc'  },
    { label: 'Cabasa',  icon: '🎵', row: 3, freq: 7200,type: 'perc'  },
    { label: 'Claves',  icon: '🥢', row: 3, freq: 1800,type: 'wood'  },
  ];

  /* Sequencer row labels (one per row, 8 rows for 8 pads per row) */
  const SEQ_ROWS = [
    { label: 'Kick',     color: '#fbbf24' },
    { label: 'Snare',    color: '#fbbf24' },
    { label: 'HH Cls',   color: '#60a5fa' },
    { label: 'HH Opn',   color: '#60a5fa' },
    { label: '808 Sub',  color: '#c084fc' },
    { label: 'Zap',      color: '#c084fc' },
    { label: 'Conga Hi', color: '#4ade80' },
    { label: 'Cowbell',  color: '#4ade80' },
  ];

  /* Default pattern (8 rows × 16 steps) */
  const DEFAULT_PATTERN = [
    [1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0], // Kick
    [0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,0], // Snare
    [1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0], // HH Cls
    [0,0,0,0, 0,0,0,1, 0,0,0,0, 0,0,1,0], // HH Opn
    [1,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0], // 808 Sub
    [0,0,0,0, 0,0,1,0, 0,0,0,0, 0,1,0,0], // Zap
    [0,0,1,0, 0,0,0,0, 0,1,0,0, 0,0,0,0], // Conga Hi
    [0,0,0,0, 0,0,0,0, 0,0,0,0, 1,0,0,0], // Cowbell
  ];

  /* ── STATE ───────────────────────────────────────────────── */
  let bpm        = 120;
  let playing    = false;
  let currentStep = -1;
  let stepTimer  = null;
  let pattern    = DEFAULT_PATTERN.map(r => [...r]);
  let audioCtx   = null;
  let swingPct   = 0;
  let volumes    = new Array(8).fill(80);
  let muted      = new Array(8).fill(false);

  /* ── AUDIO ───────────────────────────────────────────────── */
  function getAudio() {
    if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
    return audioCtx;
  }

  function playSound(pad) {
    try {
      const ctx  = getAudio();
      const gain = ctx.createGain();
      gain.connect(ctx.destination);

      if (pad.type === 'noise') {
        const buf    = ctx.createBuffer(1, ctx.sampleRate * 0.15, ctx.sampleRate);
        const data   = buf.getChannelData(0);
        for (let i = 0; i < data.length; i++) data[i] = Math.random() * 2 - 1;
        const src = ctx.createBufferSource();
        src.buffer = buf;
        const filt = ctx.createBiquadFilter();
        filt.type = 'bandpass'; filt.frequency.value = 2000;
        src.connect(filt); filt.connect(gain);
        gain.gain.setValueAtTime(.4, ctx.currentTime);
        gain.gain.exponentialRampToValueAtTime(.001, ctx.currentTime + .15);
        src.start(); src.stop(ctx.currentTime + .15);
        return;
      }

      const osc  = ctx.createOscillator();
      const now  = ctx.currentTime;

      if (pad.type === 'kick') {
        osc.frequency.setValueAtTime(160, now);
        osc.frequency.exponentialRampToValueAtTime(pad.freq, now + .12);
        gain.gain.setValueAtTime(.9, now);
        gain.gain.exponentialRampToValueAtTime(.001, now + .35);
        osc.type = 'sine';
      } else if (pad.type === 'snare' || pad.type === 'clap') {
        osc.type = 'triangle';
        osc.frequency.setValueAtTime(pad.freq, now);
        osc.frequency.exponentialRampToValueAtTime(pad.freq * .5, now + .08);
        gain.gain.setValueAtTime(.6, now);
        gain.gain.exponentialRampToValueAtTime(.001, now + .18);
        // Add noise layer
        const nbuf = ctx.createBuffer(1, ctx.sampleRate * .18, ctx.sampleRate);
        const nd   = nbuf.getChannelData(0);
        for (let i = 0; i < nd.length; i++) nd[i] = Math.random() * 2 - 1;
        const nsrc = ctx.createBufferSource();
        nsrc.buffer = nbuf;
        const ng = ctx.createGain();
        ng.gain.setValueAtTime(.35, now);
        ng.gain.exponentialRampToValueAtTime(.001, now + .18);
        nsrc.connect(ng); ng.connect(ctx.destination);
        nsrc.start();
      } else if (pad.type === 'hh') {
        osc.type = 'square';
        osc.frequency.value = pad.freq;
        gain.gain.setValueAtTime(.25, now);
        const dur = pad.label.includes('Opn') ? .25 : .04;
        gain.gain.exponentialRampToValueAtTime(.001, now + dur);
      } else if (pad.type === '808') {
        osc.type = 'sine';
        osc.frequency.setValueAtTime(pad.freq * 3, now);
        osc.frequency.exponentialRampToValueAtTime(pad.freq, now + .08);
        gain.gain.setValueAtTime(.8, now);
        gain.gain.exponentialRampToValueAtTime(.001, now + .6);
      } else {
        osc.type = ['sine','triangle','sawtooth','square'][pad.row] || 'sine';
        osc.frequency.value = pad.freq;
        gain.gain.setValueAtTime(.4, now);
        gain.gain.exponentialRampToValueAtTime(.001, now + .12);
      }

      osc.connect(gain);
      osc.start(now);
      osc.stop(now + .8);
    } catch(e) { /* silent */ }
  }

  /* ── BUILD PAD GRID ──────────────────────────────────────── */
  const padGrid = document.getElementById('pad-grid');

  PADS.forEach((pad, i) => {
    const el = document.createElement('div');
    el.className = `pad row-${pad.row}`;
    el.dataset.idx = i;
    el.innerHTML = `<span class="pad-icon">${pad.icon}</span><span class="pad-label">${pad.label}</span>`;

    el.addEventListener('pointerdown', () => {
      playSound(pad);
      el.classList.add('hit');
      setTimeout(() => el.classList.remove('hit'), 120);
    });

    padGrid.appendChild(el);
  });

  /* ── BUILD SEQUENCER ─────────────────────────────────────── */
  const seqTicks = document.getElementById('seq-ticks');
  const seqRows  = document.getElementById('seq-rows');

  // Ticks
  for (let i = 0; i < 16; i++) {
    const t = document.createElement('div');
    t.className = 'seq-tick' + (i % 4 === 0 ? ' beat' : '');
    t.textContent = i % 4 === 0 ? (i/4 + 1) : '·';
    seqTicks.appendChild(t);
  }

  // Rows
  SEQ_ROWS.forEach((row, ri) => {
    const rowEl = document.createElement('div');
    rowEl.className = 'seq-row';

    const lbl = document.createElement('div');
    lbl.className = 'seq-row-label';
    lbl.textContent = row.label;
    lbl.style.color = row.color;
    rowEl.appendChild(lbl);

    const steps = document.createElement('div');
    steps.className = 'seq-steps';
    steps.dataset.row = ri;

    for (let si = 0; si < 16; si++) {
      const step = document.createElement('div');
      step.className = 'seq-step' + (pattern[ri][si] ? ' on' : '');
      step.dataset.row  = ri;
      step.dataset.step = si;

      step.addEventListener('click', () => {
        pattern[ri][si] = pattern[ri][si] ? 0 : 1;
        step.classList.toggle('on', !!pattern[ri][si]);
      });

      steps.appendChild(step);
    }

    rowEl.appendChild(steps);
    seqRows.appendChild(rowEl);
  });

  /* ── BUILD MIXER ─────────────────────────────────────────── */
  const mixerStrips = document.getElementById('mixer-strips');

  SEQ_ROWS.forEach((row, ri) => {
    const strip = document.createElement('div');
    strip.className = 'mixer-strip';

    strip.innerHTML = `
      <div class="mix-label">${row.label}</div>
      <div class="vu-meter" id="vu-${ri}">
        ${[...Array(6)].map((_,i) => `<div class="vu-bar" style="height:${4+i*4}px"></div>`).join('')}
      </div>
      <div class="mix-fader-wrap">
        <input type="range" class="mix-fader" min="0" max="100"
               value="${volumes[ri]}" data-row="${ri}"
               orient="vertical"/>
        <span class="mix-val" id="vol-val-${ri}">${volumes[ri]}</span>
      </div>
      <button class="mix-mute" data-row="${ri}">M</button>
    `;

    mixerStrips.appendChild(strip);
  });

  // Fader events
  document.querySelectorAll('.mix-fader').forEach(f => {
    f.addEventListener('input', () => {
      const ri = parseInt(f.dataset.row);
      volumes[ri] = parseInt(f.value);
      document.getElementById(`vol-val-${ri}`).textContent = f.value;
    });
  });

  // Mute events
  document.querySelectorAll('.mix-mute').forEach(btn => {
    btn.addEventListener('click', () => {
      const ri = parseInt(btn.dataset.row);
      muted[ri] = !muted[ri];
      btn.classList.toggle('muted', muted[ri]);
    });
  });

  /* ── SEQUENCER ENGINE ────────────────────────────────────── */
  function getStepMs() {
    const beatMs  = (60 / bpm) * 1000;
    const stepMs  = beatMs / 4; // 16th notes
    return stepMs;
  }

  function advanceStep() {
    currentStep = (currentStep + 1) % 16;

    // Clear previous playhead
    document.querySelectorAll('.seq-step.playing')
      .forEach(s => s.classList.remove('playing'));

    // Highlight current step column
    document.querySelectorAll(`.seq-step[data-step="${currentStep}"]`)
      .forEach(s => s.classList.add('playing'));

    // Fire sounds
    SEQ_ROWS.forEach((_, ri) => {
      if (pattern[ri][currentStep] && !muted[ri]) {
        const padIdx = ri * 8; // first pad of each row
        playSound(PADS[padIdx]);
        animateVU(ri);
      }
    });

    // Update status
    document.getElementById('status-step').textContent =
      `${Math.floor(currentStep / 4) + 1}.${(currentStep % 4) + 1}`;

    // Swing: odd steps get a slight delay
    const swing = currentStep % 2 === 1 ? (swingPct / 100) * getStepMs() * .5 : 0;
    stepTimer = setTimeout(advanceStep, getStepMs() + swing);
  }

  function startSeq() {
    if (playing) return;
    playing = true;
    currentStep = -1;
    document.getElementById('btn-play').classList.add('active');
    document.getElementById('btn-play').textContent = '⏸';
    document.getElementById('play-dot').classList.remove('stopped');
    document.getElementById('step-label').textContent = 'Playing';
    advanceStep();
  }

  function stopSeq() {
    playing = false;
    clearTimeout(stepTimer);
    currentStep = -1;
    document.querySelectorAll('.seq-step.playing')
      .forEach(s => s.classList.remove('playing'));
    document.getElementById('btn-play').classList.remove('active');
    document.getElementById('btn-play').textContent = '▶';
    document.getElementById('play-dot').classList.add('stopped');
    document.getElementById('step-label').textContent = 'Stopped';
    document.getElementById('status-step').textContent = '—';
  }

  /* ── VU METER ANIMATION ──────────────────────────────────── */
  function animateVU(ri) {
    const vu = document.getElementById(`vu-${ri}`);
    if (!vu) return;
    const bars = vu.querySelectorAll('.vu-bar');
    const colors = ['#22c55e','#22c55e','#22c55e','#fbbf24','#f97316','#ef4444'];
    bars.forEach((b, i) => {
      const h = 4 + Math.random() * 24;
      b.style.height    = h + 'px';
      b.style.background = h > 20 ? colors[5] : h > 14 ? colors[3] : colors[0];
    });
    setTimeout(() => {
      bars.forEach((b, i) => {
        b.style.height     = (4 + i * 4) + 'px';
        b.style.background = 'var(--bg-500)';
      });
    }, 140);
  }

  /* ── CONTROLS ────────────────────────────────────────────── */
  document.getElementById('btn-play').addEventListener('click', () => {
    if (playing) stopSeq(); else startSeq();
  });
  document.getElementById('btn-stop').addEventListener('click', stopSeq);

  document.getElementById('bpm-slider').addEventListener('input', e => {
    bpm = parseInt(e.target.value);
    document.getElementById('bpm-val').textContent = bpm;
  });

  document.getElementById('btn-clear').addEventListener('click', () => {
    pattern = SEQ_ROWS.map(() => new Array(16).fill(0));
    document.querySelectorAll('.seq-step').forEach(s => s.classList.remove('on'));
  });

  // Swing
  let swingIdx = 0;
  const swingVals = [0, 15, 30, 50, 65];
  document.getElementById('btn-swing').addEventListener('click', () => {
    swingIdx = (swingIdx + 1) % swingVals.length;
    swingPct = swingVals[swingIdx];
    document.getElementById('btn-swing').textContent = `⟳ Swing ${swingPct}%`;
  });

  // Presets
  const kitNames = [
    'Classic 808','TR-909 House','Jungle Breaks',
    'Lo-Fi Boom Bap','Trap Kit','Afrobeats',
    'My Session 1','Late Night WIP'
  ];
  document.querySelectorAll('.preset-item').forEach(item => {
    item.addEventListener('click', () => {
      document.querySelectorAll('.preset-item').forEach(i => i.classList.remove('active'));
      item.classList.add('active');
      const name = item.querySelector('.preset-name').textContent;
      document.getElementById('status-kit').textContent = name;
      // Randomise pattern for demo
      pattern = SEQ_ROWS.map(() =>
        Array.from({length:16}, () => Math.random() > .72 ? 1 : 0)
      );
      document.querySelectorAll('.seq-step').forEach(s => {
        const ri = parseInt(s.dataset.row);
        const si = parseInt(s.dataset.step);
        s.classList.toggle('on', !!pattern[ri][si]);
      });
    });
  });

  // CPU fake counter
  setInterval(() => {
    if (playing) {
      document.getElementById('cpu-val').textContent =
        (2 + Math.random() * 4).toFixed(0) + '%';
    }
  }, 1500);

  // Keyboard shortcuts
  document.addEventListener('keydown', e => {
    if (e.target.tagName === 'INPUT') return;
    if (e.code === 'Space') { e.preventDefault(); playing ? stopSeq() : startSeq(); }
  });

})();
</script>
</body>
</html>
Live Preview