Patterns Hard
Backlog - MIDI Audio Reactive Lab
MIDI plus microphone-reactive visual bars experiment.
Open in Lab
MCP
midi audio reactive
Targets: JS HTML
Code
body {
margin: 0;
font-family: "Trebuchet MS", "Segoe UI", sans-serif;
background: #080712;
color: #f2f6ff;
}
.topbar {
padding: 0.75rem 1rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.topbar a {
color: #8ee7ff;
text-decoration: none;
}
button {
border: 1px solid rgba(255, 255, 255, 0.25);
background: rgba(255, 255, 255, 0.08);
color: #f2f6ff;
border-radius: 999px;
padding: 0.35rem 0.7rem;
}
main {
width: min(980px, 92%);
margin: 0 auto;
}
.kicker {
color: #8ee7ff;
text-transform: uppercase;
letter-spacing: 0.1em;
}
.bars {
margin-top: 1rem;
border: 1px solid #2f2e4e;
border-radius: 12px;
min-height: 220px;
display: grid;
grid-template-columns: repeat(24, minmax(0, 1fr));
gap: 0.35rem;
align-items: end;
padding: 0.8rem;
}
.bar {
border-radius: 6px;
background: linear-gradient(180deg, #ffa36d, #8070ff);
}if (!window.MotionPreference) {
const __mql = window.matchMedia("(prefers-reduced-motion: reduce)");
const __listeners = new Set();
const MotionPreference = {
prefersReducedMotion() {
return __mql.matches;
},
setOverride(value) {
const reduced = Boolean(value);
document.documentElement.classList.toggle("reduced-motion", reduced);
window.dispatchEvent(new CustomEvent("motion-preference", { detail: { reduced } }));
for (const listener of __listeners) {
try {
listener({ reduced, override: reduced, systemReduced: __mql.matches });
} catch {}
}
},
onChange(listener) {
__listeners.add(listener);
try {
listener({
reduced: __mql.matches,
override: null,
systemReduced: __mql.matches,
});
} catch {}
return () => __listeners.delete(listener);
},
getState() {
return { reduced: __mql.matches, override: null, systemReduced: __mql.matches };
},
};
window.MotionPreference = MotionPreference;
}
async function initSoundReactiveHooks() {
return {
supported: false,
reason: "shared module unavailable in imported version",
getLevel() {
return 0;
},
destroy() {},
};
}
const audioBtn = document.getElementById("audioBtn");
const statusEl = document.getElementById("status");
const bars = document.getElementById("bars");
let sound;
let raf = 0;
const nodes = Array.from({ length: 24 }, () => {
const el = document.createElement("span");
el.className = "bar";
el.style.height = "20%";
bars.appendChild(el);
return el;
});
async function enableMidi() {
if (!navigator.requestMIDIAccess) {
return "MIDI unavailable in this browser.";
}
try {
const access = await navigator.requestMIDIAccess();
let hit = false;
access.inputs.forEach((input) => {
input.onmidimessage = (event) => {
hit = true;
const velocity = event.data[2] || 0;
const normalized = velocity / 127;
nodes.forEach((el, i) => {
const wave = Math.sin(performance.now() * 0.002 + i) * 0.3 + 0.7;
el.style.height = `${Math.max(10, normalized * wave * 100)}%`;
});
};
});
return hit ? "MIDI input attached." : "MIDI ready. Send notes from a controller.";
} catch (_error) {
return "MIDI permission rejected.";
}
}
function animateAudio() {
if (sound && sound.supported) {
const level = sound.getLevel();
nodes.forEach((el, i) => {
const wave = Math.sin(performance.now() * 0.003 + i * 0.4) * 0.25 + 0.75;
el.style.height = `${Math.max(10, level * wave * 100)}%`;
});
}
raf = requestAnimationFrame(animateAudio);
}
audioBtn.addEventListener("click", async () => {
sound = await initSoundReactiveHooks();
const midiMessage = await enableMidi();
if (sound.supported) {
statusEl.textContent = `Audio reactive active. ${midiMessage}`;
cancelAnimationFrame(raf);
raf = requestAnimationFrame(animateAudio);
} else {
statusEl.textContent = `Audio unavailable (${sound.reason}). ${midiMessage}`;
}
});
window.addEventListener("beforeunload", () => {
cancelAnimationFrame(raf);
if (sound && sound.destroy) sound.destroy();
});<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MIDI / Audio Reactive Lab</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<header class="topbar">
<a href="../">Back to demos</a>
<button id="audioBtn">Enable Audio Reactive</button>
</header>
<main>
<p class="kicker">Backlog 28</p>
<h1>MIDI / Audio Reactive Layers</h1>
<p id="status">MIDI + audio listeners are idle.</p>
<div class="bars" id="bars"></div>
</main>
<script src="script.js"></script>
</body>
</html>Backlog - MIDI Audio Reactive Lab
MIDI plus microphone-reactive visual bars experiment.
Source
- Repository:
libs-gen - Original demo id:
28-midi-audio-reactive-lab
Notes
MIDI plus microphone-reactive visual bars experiment.