Stereo panning

스테레오 패닝

Positioning a sound anywhere between the left and right speakers — the thing that creates spatial and directional cues.

Also known as: PanL/R balance
···
html
<div class="wrap">
  <div class="meter l" id="ml"><i></i></div>
  <div class="field" id="field">
    <div class="mid"></div>
    <div class="dot" id="dot"></div>
    <button class="play" id="play" type="button" aria-label="play sound"><span class="tri"></span></button>
  </div>
  <div class="meter r" id="mr"><i></i></div>
</div>
css
.wrap{position:relative;width:94%;height:86%;display:flex;align-items:center;gap:4%}
.field{position:relative;flex:1;height:60%;border:1px solid var(--line);border-radius:12px;background:var(--surface);overflow:hidden}
.mid{position:absolute;left:50%;top:0;bottom:0;width:1px;background:var(--line)}
.dot{position:absolute;top:50%;width:14px;height:14px;border-radius:50%;background:var(--accent);transform:translate(-50%,-50%);left:50%}
.meter{width:10%;height:70%;border:1px solid var(--line);border-radius:6px;background:var(--surface);display:flex;align-items:flex-end;overflow:hidden}
.meter i{width:100%;height:10%;background:linear-gradient(0deg,var(--accent-3),var(--accent))}
.play{position:absolute;top:6px;right:6px;width:20px;height:20px;border-radius:50%;border:1px solid var(--line);background:var(--surface);display:grid;place-items:center;cursor:pointer;box-shadow:0 2px 6px rgba(0,0,0,.12);z-index:3}
.play .tri{width:0;height:0;border-style:solid;border-width:5px 0 5px 7px;border-color:transparent transparent transparent var(--fg);margin-left:1px}
.play:active{transform:scale(.92)}
@media (min-width:460px){
  .dot{width:26px;height:26px}
  .play{width:38px;height:38px;top:12px;right:12px}
  .play .tri{border-width:8px 0 8px 11px;margin-left:2px}
}
js
const dot = document.getElementById('dot');
const barL = document.querySelector('#ml i');
const barR = document.querySelector('#mr i');
let shotStart = null;
const IDLE_PERIOD = 3200;
function pos(t) {
  if (shotStart !== null) {
    const p = Math.min(1, (t - shotStart) / 1000);
    if (p >= 1) shotStart = null;
    return p * 2 - 1;
  }
  return Math.sin(((t % IDLE_PERIOD) / IDLE_PERIOD) * Math.PI * 2) * 0.85;
}
function frame(t) {
  const pan = pos(t);
  dot.style.left = (50 + pan * 42) + '%';
  const rNorm = (pan + 1) / 2;
  barL.style.height = (14 + (1 - rNorm) * 70) + '%';
  barR.style.height = (14 + rNorm * 70) + '%';
  requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
document.getElementById('play').addEventListener('click', () => {
  shotStart = performance.now();
  const ctx = new (window.AudioContext || window.webkitAudioContext)();
  const now = ctx.currentTime;
  const osc = ctx.createOscillator();
  const gain = ctx.createGain();
  const panner = ctx.createStereoPanner();
  osc.type = 'sine';
  osc.frequency.value = 523.25;
  gain.gain.setValueAtTime(0.13, now);
  gain.gain.setValueAtTime(0.13, now + 0.9);
  gain.gain.exponentialRampToValueAtTime(0.0001, now + 1);
  panner.pan.setValueAtTime(-1, now);
  panner.pan.linearRampToValueAtTime(1, now + 1);
  osc.connect(gain).connect(panner).connect(ctx.destination);
  osc.start(now);
  osc.stop(now + 1);
  osc.onended = () => ctx.close();
});

Send a mono sound to the left and right channels at different ratios, and the brain perceives it as coming from a particular direction. The Web Audio API's StereoPannerNode.pan controls this from -1 (full left) to 1 (full right), with 0 dead center. Equal-power panning keeps perceived loudness constant as a sound sweeps across, instead of dipping in the middle.

Notification and UI sounds mostly stay locked at center (0) so they're never missed regardless of which ear is closer. Active panning is reserved for cases where spatial information itself carries meaning — a footstep sound from the left in a game, or distinguishing two panels in an app. Perception differs between headphones and speakers, and panning disappears entirely on a phone's single mono speaker, so panning alone should never be the only signal carrying information.

Used for directional game sound effects, multitrack music mixing, and left/right-positioned notifications (e.g. a collaborator's cursor side in a collab tool).

When to use

Reserve it for when spatial/directional information itself matters. Keep notification sounds centered (pan=0) by default.