← Back to Home

How to Apply Ken Burns Pan Effects with CSS Transforms

Updated January 14, 2026
cssken burnspan effectstransformanimationtranslate

Applying Ken Burns Pan Effects with CSS Transforms

Ken Burns pan effects create slow, cinematic horizontal movement using CSS transforms.

Pan Left Effect

Pan from right to left (landscape moves left, camera pans right):

@keyframes panLeft {
  from { transform: translateX(0%); }
  to { transform: translateX(-10%); }
}

.pan-left {
  animation: panLeft 10s ease-in-out forwards;
}

Pan Right Effect

Pan from left to right (landscape moves right, camera pans left):

@keyframes panRight {
  from { transform: translateX(-10%); }
  to { transform: translateX(0%); }
}

.pan-right {
  animation: panRight 10s ease-in-out forwards;
}

Frame-Based Calculation (Remotion)

Calculate translation based on current frame:

function calculatePanTranslation(
  frame: number,
  duration: number,
  direction: 'left' | 'right',
  intensity: number = 0.5
): number {
  const progress = frame / duration;
  const maxOffset = intensity * 10;  // 10% at intensity 1.0

  if (direction === 'left') {
    return -progress * maxOffset;  // Negative = pan left
  } else {
    return -maxOffset + (progress * maxOffset);  // Start negative, move to 0
  }
}

React Component

interface PanAnimationProps {
  frame: number;
  duration: number;
  direction: 'left' | 'right';
  intensity?: number;  // 0-1, default 0.5
}

export const PanAnimation: React.FC<PanAnimationProps> = ({
  frame,
  duration,
  direction,
  intensity = 0.5,
  children
}) => {
  const translateX = calculatePanTranslation(frame, duration, direction, intensity);

  return (
    <div
      style={{
        transform: `translateX(${translateX}%)`,
        width: '110%',  // Oversized to prevent edge visibility
        height: '100%',
      }}
    >
      {children}
    </div>
  );
};

Combined Zoom + Pan

For more dynamic effects, combine zoom and pan:

function calculateKenBurnsTransform(
  frame: number,
  duration: number,
  options: {
    zoom?: { direction: 'in' | 'out'; intensity: number };
    pan?: { direction: 'left' | 'right'; intensity: number };
  }
): { scale: number; translateX: number } {
  const scale = options.zoom
    ? calculateZoomScale(frame, duration, options.zoom.direction, options.zoom.intensity)
    : 1;

  const translateX = options.pan
    ? calculatePanTranslation(frame, duration, options.pan.direction, options.pan.intensity)
    : 0;

  return { scale, translateX };
}

Usage Example

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

  const { scale, translateX } = calculateKenBurnsTransform(frame, durationInFrames, {
    zoom: { direction: 'in', intensity: 0.5 },
    pan: { direction: 'left', intensity: 0.3 },
  });

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

Direction Guidelines

Direction Effect Use Case
Pan Left Camera moves right, scene moves left Reading right to left content
Pan Right Camera moves left, scene moves right Natural reading direction
Zoom In Scale 1.0 → 1.2 Emphasize details, focus
Zoom Out Scale 1.2 → 1.0 Reveal context, conclusions

Intensity Guidelines

Intensity Translation Use Case
0.2 2% Subtle movement
0.5 5% Standard pan
0.8 8% Noticeable movement
1.0 10% Maximum pan (may show edges)

Important Notes