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

Straight ahead vs pose to pose

애니메이션을 만드는 두 가지 상반된 작업 방식. 스트레이트 어헤드는 첫 장면부터 순서대로 그려나가고, 포즈 투 포즈는 핵심 포즈부터 정해놓고 사이를 채웁니다.

다른 이름: 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);

스트레이트 어헤드 액션은 한 장 한 장 이어서 그려나가는 방식입니다. 다음에 뭐가 나올지 미리 정해두지 않아서 결과가 즉흥적이고 생동감 있지만, 비율이나 타이밍이 도중에 틀어지기 쉽습니다. 불·물·연기처럼 예측 불가능한 움직임에 잘 맞습니다.

포즈 투 포즈는 반대로 시작·중간·끝 같은 핵심 포즈(키 포즈)를 먼저 확정하고, 그 사이를 채우는 인비트윈은 나중에 작업합니다. 구도와 타이밍을 미리 통제할 수 있어서 정확한 연기나 대사 장면에 적합합니다. 실무에서는 대부분 두 방식을 섞어 씁니다.

UI로 옮기면, 개발자 도구에서 값을 하나씩 조정하며 "느낌"을 찾아가는 작업이 스트레이트 어헤드에 가깝고, CSS keyframes에 0%·50%·100% 같은 정확한 정지 지점을 먼저 정의하는 게 포즈 투 포즈입니다.

데모 위쪽 레인은 스트레이트 어헤드 — 공이 매 순간 즉흥적으로 흔들리며 나아가고, 지나온 자리에 옅은 잔상(어니언 스킨)이 남습니다. 아래쪽 레인은 포즈 투 포즈 — 미리 표시된 4개의 키 포즈 사이를 건너뛰며 각 포즈에서 잠시 멈춥니다.

언제 쓰나

정확한 타이밍·구도가 중요하면 포즈 투 포즈(고정 키프레임)로, 자유롭고 유기적인 느낌이 필요하면 스트레이트 어헤드(물리 시뮬레이션·rAF)로 접근하세요.