← Back to Home

How to Apply Ken Burns Zoom Effects with CSS Transforms

Updated January 14, 2026
cssken burnszoom effectstransformanimation

Applying Ken Burns Zoom Effects with CSS Transforms

Ken Burns zoom effects create slow, cinematic zoom on images using CSS transforms.

Zoom In Effect

Gradual zoom from 1.0 to 1.2 scale:

@keyframes zoomIn {
  from { transform: scale(1.0); }
  to { transform: scale(1.2); }
}

.zoom-in {
  animation: zoomIn 10s ease-in-out forwards;
}

Zoom Out Effect

Gradual zoom from 1.2 to 1.0 scale:

@keyframes zoomOut {
  from { transform: scale(1.2); }
  to { transform: scale(1.0); }
}

.zoom-out {
  animation: zoomOut 10s ease-in-out forwards;
}

Frame-Based Calculation (Remotion)

Calculate scale based on current frame:

function calculateZoomScale(
  frame: number,
  duration: number,
  direction: 'in' | 'out',
  intensity: number = 0.5
): number {
  const progress = frame / duration;
  const maxScale = 1 + intensity;  // 1.5 at intensity 0.5

  if (direction === 'in') {
    return 1 + (progress * intensity);
  } else {
    return maxScale - (progress * intensity);
  }
}

React Component

interface ZoomAnimationProps {
  frame: number;
  duration: number;
  direction: 'in' | 'out';
  intensity?: number;  // 0-1, default 0.5
}

export const ZoomAnimation: React.FC<ZoomAnimationProps> = ({
  frame,
  duration,
  direction,
  intensity = 0.5,
  children
}) => {
  const scale = calculateZoomScale(frame, duration, direction, intensity);

  return (
    <div
      style={{
        transform: `scale(${scale})`,
        transformOrigin: 'center center',
      }}
    >
      {children}
    </div>
  );
};

With Easing Functions

type EasingFunction = (t: number) => number;

const Easing = {
  linear: (t: number) => t,
  easeIn: (t: number) => t * t,
  easeOut: (t: number) => t * (2 - t),
  easeInOut: (t: number) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
};

function calculateZoomScale(
  frame: number,
  duration: number,
  direction: 'in' | 'out',
  intensity: number = 0.5,
  easing: EasingFunction = Easing.linear
): number {
  const progress = easing(frame / duration);
  const maxScale = 1 + intensity;

  if (direction === 'in') {
    return 1 + (progress * intensity);
  } else {
    return maxScale - (progress * intensity);
  }
}

Usage in Remotion

import { useCurrentFrame, useVideoConfig } from 'remotion';

export const BackgroundAnimation: React.FC = () => {
  const frame = useCurrentFrame();
  const { durationInFrames } = useVideoConfig();

  const scale = calculateZoomScale(
    frame,
    durationInFrames,
    'in',  // or 'out'
    0.5,   // intensity
    Easing.easeInOut
  );

  return (
    <div
      style={{
        transform: `scale(${scale})`,
        transformOrigin: 'center center',
        width: '100%',
        height: '100%',
      }}
    >
      <img src="background.jpg" alt="" />
    </div>
  );
};

Intensity Guidelines

Intensity Effect Use Case
0.3 Subtle zoom Calm scenes, establishing shots
0.5 Medium zoom Standard narration
0.7 Strong zoom Dramatic moments, emphasis
0.8+ Heavy zoom Extreme emphasis (rare)

Performance Notes