CSS
/* ─── 06 Modular Synth Controls — audio control panel ──────── */
@import url('https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Rajdhani:wght@400;500;600;700&display=swap');
.cd-syn {
--cd-syn-panel: #1a1c22;
--cd-syn-inset: #14161b;
--cd-syn-text-dim: rgba(120,140,180,0.4);
--cd-syn-cyan: #00e8cc;
--cd-syn-amber: #ffaa00;
--cd-syn-red: #ff3840;
--cd-syn-green: #00e060;
--cd-syn-purple: #c060ff;
--cd-syn-bg: #11131a;
position: relative;
width: 100%;
min-height: 580px;
background: var(--cd-syn-bg);
font-family: 'Share Tech Mono', ui-monospace, monospace;
overflow: hidden;
box-sizing: border-box;
}
.cd-syn *,
.cd-syn *::before,
.cd-syn *::after { box-sizing: border-box; margin: 0; padding: 0; }
.cd-syn .card {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 32px 16px;
}
.cd-syn .panel {
width: 100%;
max-width: 640px;
background: var(--cd-syn-panel);
border-radius: 16px;
padding: 28px;
box-shadow:
0 0 0 1px rgba(255,255,255,0.05),
0 2px 0 rgba(255,255,255,0.04),
0 4px 24px rgba(0,0,0,0.6),
0 1px 0 rgba(255,255,255,0.06) inset,
0 -1px 0 rgba(0,0,0,0.4) inset;
position: relative;
}
.cd-syn .panel::before {
content: '';
position: absolute;
inset: 0;
border-radius: 16px;
background-image: repeating-linear-gradient(90deg, transparent 0px, transparent 2px, rgba(255,255,255,0.007) 2px, rgba(255,255,255,0.007) 3px);
pointer-events: none;
}
.cd-syn .readout {
background: var(--cd-syn-inset);
border-radius: 8px;
padding: 11px 16px;
box-shadow: inset 0 2px 6px rgba(0,0,0,0.5);
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 18px;
gap: 8px;
}
.cd-syn .readout-item { text-align: center; }
.cd-syn .readout-key {
font-size: 7px;
letter-spacing: 3px;
color: var(--cd-syn-text-dim);
text-transform: uppercase;
margin-bottom: 3px;
}
.cd-syn .readout-val {
font-family: 'Share Tech Mono', monospace;
font-size: 13px;
letter-spacing: 2px;
color: var(--cd-syn-cyan);
text-shadow: 0 0 10px rgba(0,232,204,0.5);
}
.cd-syn .readout-val.live {
color: var(--cd-syn-green);
text-shadow: 0 0 10px rgba(0,224,96,0.5);
}
.cd-syn .section { margin-bottom: 22px; }
.cd-syn .section:last-child { margin-bottom: 0; }
.cd-syn .section-label {
font-family: 'Share Tech Mono', monospace;
font-size: 9px;
letter-spacing: 3px;
color: var(--cd-syn-text-dim);
text-transform: uppercase;
margin-bottom: 14px;
display: flex;
align-items: center;
gap: 8px;
}
.cd-syn .section-label::after {
content: '';
flex: 1;
height: 1px;
background: rgba(255,255,255,0.06);
}
.cd-syn .section-label.rl { margin-bottom: 10px; }
.cd-syn .main-layout {
display: flex;
gap: 22px;
align-items: flex-start;
}
.cd-syn .left-controls { flex: 1; }
.cd-syn .right-controls { display: flex; flex-direction: column; gap: 4px; }
/* Push buttons */
.cd-syn .btn-row { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.cd-syn .push-btn {
position: relative;
cursor: pointer;
border: none;
background: none;
padding: 0;
outline: none;
}
.cd-syn .push-btn-body {
width: 72px;
height: 50px;
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 4px;
position: relative;
transition: transform 0.08s ease, box-shadow 0.08s ease;
background: var(--cd-syn-btn-color);
box-shadow:
0 6px 0 var(--cd-syn-btn-shadow),
0 7px 12px rgba(0,0,0,0.5),
inset 0 1px 0 rgba(255,255,255,0.18),
inset 0 -1px 0 rgba(0,0,0,0.3);
}
.cd-syn .push-btn:active .push-btn-body,
.cd-syn .push-btn.pressed .push-btn-body {
transform: translateY(4px);
box-shadow:
0 2px 0 var(--cd-syn-btn-shadow),
0 3px 6px rgba(0,0,0,0.5),
inset 0 2px 4px rgba(0,0,0,0.3),
inset 0 1px 0 rgba(255,255,255,0.08);
}
.cd-syn .push-btn-label {
font-family: 'Share Tech Mono', monospace;
font-size: 8px;
letter-spacing: 1.5px;
color: rgba(255,255,255,0.85);
text-transform: uppercase;
}
.cd-syn .btn-led {
width: 6px;
height: 6px;
border-radius: 50%;
background: rgba(0,0,0,0.4);
transition: background 0.2s, box-shadow 0.2s;
}
.cd-syn .push-btn.active .btn-led {
background: var(--cd-syn-led-color);
box-shadow: 0 0 6px var(--cd-syn-led-color), 0 0 14px var(--cd-syn-led-color);
}
.cd-syn .push-btn:nth-child(1) { --cd-syn-btn-color: #1a2838; --cd-syn-btn-shadow: #0e1820; --cd-syn-led-color: #00e8cc; }
.cd-syn .push-btn:nth-child(2) { --cd-syn-btn-color: #281a10; --cd-syn-btn-shadow: #180e08; --cd-syn-led-color: #ffaa00; }
.cd-syn .push-btn:nth-child(3) { --cd-syn-btn-color: #281818; --cd-syn-btn-shadow: #180808; --cd-syn-led-color: #ff3840; }
.cd-syn .push-btn:nth-child(4) { --cd-syn-btn-color: #182818; --cd-syn-btn-shadow: #081808; --cd-syn-led-color: #00e060; }
.cd-syn .push-btn:nth-child(5) { --cd-syn-btn-color: #1e1a30; --cd-syn-btn-shadow: #100e20; --cd-syn-led-color: #c060ff; }
/* Toggles */
.cd-syn .toggle-row { display: flex; gap: 22px; align-items: center; flex-wrap: wrap; }
.cd-syn .toggle-unit { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.cd-syn .toggle-label {
font-size: 8px;
letter-spacing: 2px;
color: var(--cd-syn-text-dim);
text-transform: uppercase;
}
.cd-syn .toggle-sw {
position: relative;
width: 60px;
height: 28px;
cursor: pointer;
border-radius: 6px;
background: var(--cd-syn-inset);
border: none;
padding: 3px;
box-shadow:
inset 0 2px 6px rgba(0,0,0,0.6),
inset 0 1px 2px rgba(0,0,0,0.8),
0 1px 0 rgba(255,255,255,0.06);
}
.cd-syn .toggle-thumb {
display: block;
width: 26px;
height: 22px;
border-radius: 4px;
background: linear-gradient(180deg, #2e3248 0%, #22263a 100%);
box-shadow:
0 3px 0 #12141e,
0 4px 8px rgba(0,0,0,0.5),
inset 0 1px 0 rgba(255,255,255,0.12);
transition: transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.cd-syn .toggle-sw.on .toggle-thumb { transform: translateX(28px); }
.cd-syn .toggle-sw-led {
position: absolute;
width: 4px;
height: 4px;
border-radius: 50%;
top: 50%;
right: 7px;
transform: translateY(-50%);
background: rgba(0,0,0,0.5);
transition: background 0.2s, box-shadow 0.2s;
}
.cd-syn .toggle-sw.on .toggle-sw-led {
background: var(--led-col);
box-shadow: 0 0 6px var(--led-col);
}
/* Faders */
.cd-syn .fader-row { display: flex; gap: 18px; align-items: flex-end; flex-wrap: wrap; }
.cd-syn .fader-unit { display: flex; flex-direction: column; align-items: center; gap: 7px; }
.cd-syn .fader-track-wrap {
width: 28px;
height: 120px;
background: var(--cd-syn-inset);
border-radius: 6px;
box-shadow:
inset 0 2px 6px rgba(0,0,0,0.6),
inset 0 1px 3px rgba(0,0,0,0.8),
0 1px 0 rgba(255,255,255,0.05);
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.cd-syn .fader-track-wrap::before {
content: '';
position: absolute;
left: 4px;
right: 4px;
top: 10px;
bottom: 10px;
background: repeating-linear-gradient(to bottom, rgba(255,255,255,0.06) 0px, rgba(255,255,255,0.06) 1px, transparent 1px, transparent 10px);
pointer-events: none;
}
.cd-syn .fader-thumb {
width: 24px;
height: 20px;
border-radius: 4px;
background: linear-gradient(180deg, #3a3f58 0%, #2a2e44 100%);
box-shadow:
0 3px 0 #141620,
0 4px 8px rgba(0,0,0,0.5),
inset 0 1px 0 rgba(255,255,255,0.15);
position: absolute;
cursor: ns-resize;
user-select: none;
touch-action: none;
z-index: 2;
}
.cd-syn .fader-fill {
position: absolute;
bottom: 10px;
left: 10px;
right: 10px;
border-radius: 2px;
background: linear-gradient(to top, var(--cd-syn-fader-color), transparent);
opacity: 0.5;
pointer-events: none;
}
.cd-syn .fader-label {
font-size: 8px;
letter-spacing: 2px;
color: var(--cd-syn-text-dim);
text-transform: uppercase;
}
.cd-syn .fader-value {
font-size: 10px;
font-family: 'Share Tech Mono', monospace;
letter-spacing: 1px;
min-height: 16px;
color: var(--cd-syn-fader-color);
}
/* VU */
.cd-syn .vu-row { display: flex; gap: 9px; align-items: flex-end; margin-left: 8px; }
.cd-syn .vu-bar-wrap { display: flex; flex-direction: column; align-items: center; gap: 5px; }
.cd-syn .vu-track {
width: 13px;
height: 120px;
background: var(--cd-syn-inset);
border-radius: 4px;
box-shadow: inset 0 2px 5px rgba(0,0,0,0.6);
display: flex;
flex-direction: column-reverse;
overflow: hidden;
gap: 1px;
padding: 3px;
}
.cd-syn .vu-seg {
width: 100%;
height: 7px;
border-radius: 2px;
background: var(--cd-syn-seg-color);
opacity: 0.15;
transition: opacity 0.08s;
flex-shrink: 0;
}
.cd-syn .vu-seg.lit { opacity: 1; box-shadow: 0 0 6px var(--cd-syn-seg-color); }
.cd-syn .vu-label {
font-size: 8px;
letter-spacing: 2px;
color: var(--cd-syn-text-dim);
text-transform: uppercase;
}
@media (max-width: 720px) {
.cd-syn .main-layout { flex-direction: column; }
.cd-syn .right-controls { width: 100%; }
.cd-syn .vu-row { justify-content: flex-start; margin-left: 0; }
}
@media (prefers-reduced-motion: reduce) {
.cd-syn .toggle-thumb { transition: none !important; }
.cd-syn .vu-seg { transition: none !important; }
} JS
(() => {
const root = document.querySelector('.cd-syn');
if (!root) return;
// Push buttons
const modeReadout = root.querySelector('[data-cd-syn-mode]');
root.querySelectorAll('.push-btn').forEach(btn => {
btn.addEventListener('click', () => {
btn.classList.toggle('active');
const action = btn.dataset.action;
const modes = { play: 'PLAY', rec: 'RECORD', stop: 'STOPPED', loop: 'LOOP', fx: 'FX ON' };
if (modes[action] && modeReadout) modeReadout.textContent = modes[action];
});
});
// Toggles
root.querySelectorAll('.toggle-sw').forEach(sw => {
sw.addEventListener('click', () => sw.classList.toggle('on'));
});
// Faders
const faderRow = root.querySelector('[data-cd-syn-faderrow]');
const masterReadout = root.querySelector('[data-cd-syn-master]');
const faderData = [
{ label: 'CH.1', color: 'var(--cd-syn-cyan)', val: 87 },
{ label: 'CH.2', color: 'var(--cd-syn-cyan)', val: 62 },
{ label: 'CH.3', color: 'var(--cd-syn-amber)', val: 74 },
{ label: 'CH.4', color: 'var(--cd-syn-amber)', val: 90 },
{ label: 'SUB', color: 'var(--cd-syn-purple)', val: 55 },
{ label: 'MST', color: 'var(--cd-syn-green)', val: 87 },
];
const TRACK_H = 120, PADDING = 10, THUMB_H = 20;
const TRAVEL = TRACK_H - PADDING * 2 - THUMB_H;
faderData.forEach((fd, fi) => {
const unit = document.createElement('div');
unit.className = 'fader-unit';
unit.innerHTML = `
<div class="fader-value" style="--cd-syn-fader-color:${fd.color}">${fd.val}</div>
<div class="fader-track-wrap">
<div class="fader-fill" style="--cd-syn-fader-color:${fd.color}"></div>
<div class="fader-thumb"></div>
</div>
<div class="fader-label">${fd.label}</div>
`;
faderRow.appendChild(unit);
const thumb = unit.querySelector('.fader-thumb');
const fill = unit.querySelector('.fader-fill');
const valEl = unit.querySelector('.fader-value');
function setVal(v) {
v = Math.max(0, Math.min(100, v));
fd.val = Math.round(v);
const pct = v / 100;
thumb.style.top = (PADDING + TRAVEL * (1 - pct)) + 'px';
fill.style.height = (TRAVEL * pct + THUMB_H / 2) + 'px';
valEl.textContent = fd.val;
if (fi === 5 && masterReadout) masterReadout.textContent = fd.val;
}
setVal(fd.val);
let dragging = false, startY = 0, startVal = 0;
thumb.addEventListener('mousedown', e => {
dragging = true; startY = e.clientY; startVal = fd.val; e.preventDefault();
});
root.addEventListener('mousemove', e => {
if (!dragging) return;
setVal(startVal + ((startY - e.clientY) / TRAVEL) * 100);
});
root.addEventListener('mouseup', () => { dragging = false; });
root.addEventListener('mouseleave', () => { dragging = false; });
thumb.addEventListener('touchstart', e => {
dragging = true; startY = e.touches[0].clientY; startVal = fd.val;
}, { passive: true });
root.addEventListener('touchmove', e => {
if (!dragging) return;
setVal(startVal + ((startY - e.touches[0].clientY) / TRAVEL) * 100);
}, { passive: true });
root.addEventListener('touchend', () => { dragging = false; });
});
// VU meters
const vuRow = root.querySelector('[data-cd-syn-vurow]');
const vuData = [
{ label: 'L', color: '#00e8cc' },
{ label: 'R', color: '#00e8cc' },
];
const N_SEGS = 12;
const vuIntervals = [];
vuData.forEach((vu, vi) => {
const wrap = document.createElement('div');
wrap.className = 'vu-bar-wrap';
const track = document.createElement('div');
track.className = 'vu-track';
for (let s = 0; s < N_SEGS; s++) {
const seg = document.createElement('div');
seg.className = 'vu-seg';
const segColor = s >= N_SEGS - 2 ? '#ff3840' : s >= N_SEGS - 4 ? '#ffaa00' : vu.color;
seg.style.setProperty('--cd-syn-seg-color', segColor);
track.appendChild(seg);
}
const lbl = document.createElement('div');
lbl.className = 'vu-label';
lbl.textContent = vu.label;
wrap.appendChild(track);
wrap.appendChild(lbl);
vuRow.appendChild(wrap);
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (prefersReduced) return;
function animateVU() {
const segs = track.querySelectorAll('.vu-seg');
const base = 6;
const variation = Math.random() > 0.9 ? Math.floor(Math.random() * 3) : 0;
const level = base + variation;
segs.forEach((seg, si) => {
seg.classList.toggle('lit', si < level);
});
vuIntervals[vi] = setTimeout(animateVU, 80 + Math.random() * 60);
}
setTimeout(animateVU, vi * 40);
});
// BPM blink
const bpmReadout = root.querySelector('[data-cd-syn-bpm]');
if (bpmReadout) {
setInterval(() => {
bpmReadout.textContent = 124 + (Math.random() > 0.96 ? 1 : 0);
}, 500);
}
})();