Straight ahead vs pose to pose

스트레이트 어헤드 vs 포즈 투 포즈

Two opposite ways to build an animation. Straight ahead draws sequentially from the first frame with no fixed endpoint; pose to pose plans the key poses first, then fills in the frames between them.

Also known as: Straight ahead actionPose to pose animation
···
html
<div class="lane-label l1">Straight ahead</div>
<div class="lane-label l2">Pose to pose</div>
<canvas id="sc"></canvas>
css
.lane-label{position:absolute;left:6%;font:700 clamp(10px,2.8vmin,13px)/1 ui-monospace,monospace;color:var(--muted);z-index:2}
.l1{top:12%}
.l2{top:56%}
#sc{position:absolute;inset:0;width:100%;height:100%;display:block}
js
const canvas = document.getElementById('sc');
const ctx = canvas.getContext('2d');
const cs = getComputedStyle(document.documentElement);
function col(name, fb) { const v = cs.getPropertyValue(name).trim(); return v || fb; }
const MUTED = col('--muted', '#6b6b76');
const ACCENT = col('--accent', '#5b5bf7');
const ACCENT2 = col('--accent-2', '#f25c8a');
let w = 0, h = 0;
function resize() {
  const dpr = Math.min(devicePixelRatio || 1, 2);
  w = innerWidth; h = innerHeight;
  canvas.width = w * dpr; canvas.height = h * dpr;
  ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
}
addEventListener('resize', resize);
resize();

function ball(x, y, r, color, alpha) {
  ctx.globalAlpha = alpha === undefined ? 1 : alpha;
  ctx.beginPath(); ctx.arc(x, y, Math.max(r, 1), 0, Math.PI * 2);
  ctx.fillStyle = color; ctx.fill(); ctx.globalAlpha = 1;
}

const DUR = 3200;
const startT = performance.now();
function loop(now) {
  const t = ((now - startT) % DUR) / DUR;
  ctx.clearRect(0, 0, w, h);
  const y1 = h * 0.38, y2 = h * 0.78;
  const r = h * 0.05;

  for (let k = 6; k >= 1; k--) {
    const tt = ((t - k * 0.025) + 1) % 1;
    const ex = w * 0.1 + tt * w * 0.75;
    const ey = y1 + Math.sin(tt * 16) * h * 0.09;
    ball(ex, ey, r * 0.8, ACCENT, 0.08 * (7 - k));
  }
  const x1 = w * 0.1 + t * w * 0.75;
  ball(x1, y1 + Math.sin(t * 16) * h * 0.09, r, ACCENT);

  const poses = [0.14, 0.4, 0.62, 0.86];
  for (let i = 0; i < poses.length; i++) {
    ctx.fillStyle = MUTED; ctx.globalAlpha = 0.4;
    ctx.fillRect(w * poses[i] - 3, y2 - 3, 6, 6);
    ctx.globalAlpha = 1;
  }
  const idx = Math.min(Math.floor(t * poses.length), poses.length - 1);
  ball(w * poses[idx], y2, r * 1.05, ACCENT2);

  requestAnimationFrame(loop);
}
requestAnimationFrame(loop);

Straight ahead action means drawing one frame after another in sequence, without deciding the endpoint in advance. The result feels spontaneous and alive, but proportions and timing can drift over a long sequence. It suits unpredictable motion — fire, water, smoke.

Pose to pose works the opposite way: lock in the key poses (start, middle, end) first, then go back and fill the in-between frames. It gives tight control over composition and timing, which is why it's favored for precise acting and dialogue scenes. Most professional animation actually blends both.

In UI terms, hand-tweaking a value in DevTools until it "feels right" is closer to straight ahead; defining exact stops in CSS @keyframes at 0%, 50% and 100% is pose to pose.

The top lane below is straight ahead — the ball wanders forward with continuous, improvised motion, leaving a faint onion-skin trail of where it's been. The bottom lane is pose to pose — it jumps between four pre-marked key poses, holding briefly at each.

When to use

Reach for pose to pose (fixed keyframes) when timing and composition must be exact. Reach for straight ahead (a physics sim, per-frame rAF) when you want a freer, more organic feel.