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
- CSS transforms are hardware-accelerated
- Use
transform: scale()instead of animating width/height - Set
transform-origin: center centerfor centered zoom - Use
will-change: transformfor optimization on complex scenes