KenBurnsImage¶
Cinematic pan and zoom effect for still images
KenBurnsImage applies the Ken Burns effect to images - a slow zoom and pan that creates cinematic movement on still photographs, commonly used in documentaries.
Table of Contents¶
Overview¶
Create cinematic image movement:
KenBurnsImage(
assetPath: 'assets/landscape.jpg',
width: 800,
height: 600,
startScale: 1.0,
endScale: 1.3,
startAlignment: Alignment.centerLeft,
endAlignment: Alignment.centerRight,
)
The image slowly zooms and pans over the scene duration.
Properties¶
| Property | Type | Default | Description |
|---|---|---|---|
assetPath |
String |
required | Path to image asset |
width |
double |
required | Container width |
height |
double |
required | Container height |
startScale |
double |
1.0 |
Initial zoom level |
endScale |
double |
1.2 |
Final zoom level |
startAlignment |
Alignment |
center |
Initial focus point |
endAlignment |
Alignment |
center |
Final focus point |
fit |
BoxFit |
cover |
Image fit mode |
borderRadius |
BorderRadius? |
null |
Corner rounding |
curve |
Curve |
linear |
Animation curve |
errorBuilder |
Function? |
null |
Error widget builder |
Constructors¶
Default Constructor¶
Full control over zoom and pan:
KenBurnsImage(
assetPath: 'assets/photo.jpg',
width: 800,
height: 600,
startScale: 1.0,
endScale: 1.3,
startAlignment: Alignment.topLeft,
endAlignment: Alignment.bottomRight,
curve: Curves.easeInOut,
)
KenBurnsImage.zoomIn¶
Simple zoom towards a focus point:
KenBurnsImage.zoomIn(
assetPath: 'assets/photo.jpg',
width: 800,
height: 600,
zoomAmount: 0.2, // Zoom 20%
focus: Alignment.center, // Zoom target
)
KenBurnsImage.pan¶
Pan across the image without zooming:
KenBurnsImage.pan(
assetPath: 'assets/panorama.jpg',
width: 800,
height: 400,
from: Alignment.centerLeft,
to: Alignment.centerRight,
scale: 1.2, // Slight zoom enables panning
)
KenBurnsImage.zoomAndPan¶
Combined zoom and pan:
KenBurnsImage.zoomAndPan(
assetPath: 'assets/landscape.jpg',
width: 800,
height: 600,
startScale: 1.0,
endScale: 1.3,
from: Alignment.topLeft,
to: Alignment.bottomRight,
)
Examples¶
Basic Zoom In¶
KenBurnsImage.zoomIn(
assetPath: 'assets/portrait.jpg',
width: 600,
height: 800,
zoomAmount: 0.15,
focus: Alignment.center,
)
Zoom to Face¶
// Zoom toward the upper portion (assuming face is there)
KenBurnsImage.zoomIn(
assetPath: 'assets/person.jpg',
width: 600,
height: 800,
zoomAmount: 0.25,
focus: Alignment(0, -0.3), // Slightly above center
)
Horizontal Pan¶
KenBurnsImage.pan(
assetPath: 'assets/cityscape.jpg',
width: 1000,
height: 400,
from: Alignment.centerLeft,
to: Alignment.centerRight,
scale: 1.3,
)
Vertical Pan¶
KenBurnsImage.pan(
assetPath: 'assets/skyscraper.jpg',
width: 600,
height: 400,
from: Alignment.bottomCenter,
to: Alignment.topCenter,
scale: 1.4,
)
Diagonal Movement¶
KenBurnsImage.zoomAndPan(
assetPath: 'assets/landscape.jpg',
width: 800,
height: 600,
startScale: 1.0,
endScale: 1.25,
from: Alignment.topLeft,
to: Alignment.bottomRight,
)
With Rounded Corners¶
KenBurnsImage(
assetPath: 'assets/photo.jpg',
width: 600,
height: 400,
startScale: 1.0,
endScale: 1.2,
borderRadius: BorderRadius.circular(20),
)
Photo Slideshow¶
Video(
fps: 30,
width: 1920,
height: 1080,
scenes: [
Scene(
durationInFrames: 150,
transitionOut: SceneTransition.crossFade(durationInFrames: 20),
children: [
VPositioned.fill(
child: KenBurnsImage.zoomIn(
assetPath: 'assets/photo1.jpg',
width: 1920,
height: 1080,
zoomAmount: 0.15,
),
),
],
),
Scene(
durationInFrames: 150,
transitionOut: SceneTransition.crossFade(durationInFrames: 20),
children: [
VPositioned.fill(
child: KenBurnsImage.pan(
assetPath: 'assets/photo2.jpg',
width: 1920,
height: 1080,
from: Alignment.centerLeft,
to: Alignment.centerRight,
scale: 1.2,
),
),
],
),
Scene(
durationInFrames: 150,
children: [
VPositioned.fill(
child: KenBurnsImage.zoomAndPan(
assetPath: 'assets/photo3.jpg',
width: 1920,
height: 1080,
startScale: 1.0,
endScale: 1.3,
from: Alignment.bottomLeft,
to: Alignment.topRight,
),
),
],
),
],
)
With Overlay Text¶
Scene(
durationInFrames: 180,
children: [
// Background with Ken Burns
VPositioned.fill(
child: KenBurnsImage.zoomIn(
assetPath: 'assets/background.jpg',
width: 1920,
height: 1080,
zoomAmount: 0.2,
),
),
// Darkening overlay
VPositioned.fill(
child: Container(color: Colors.black.withOpacity(0.4)),
),
// Text
VCenter(
startFrame: 30,
fadeInFrames: 20,
child: Text(
'Your Journey',
style: TextStyle(
fontSize: 72,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
)
Reverse Zoom (Zoom Out)¶
KenBurnsImage(
assetPath: 'assets/detail.jpg',
width: 800,
height: 600,
startScale: 1.3, // Start zoomed in
endScale: 1.0, // End at normal size
startAlignment: Alignment.center,
endAlignment: Alignment.center,
)
Slow Dramatic Zoom¶
Scene(
durationInFrames: 300, // 10 seconds at 30fps
children: [
VPositioned.fill(
child: KenBurnsImage(
assetPath: 'assets/dramatic.jpg',
width: 1920,
height: 1080,
startScale: 1.0,
endScale: 1.5, // Large zoom
startAlignment: Alignment.center,
endAlignment: Alignment.center,
curve: Curves.easeInOut,
),
),
],
)
How It Works¶
The Ken Burns effect works by: 1. Displaying the image larger than the container 2. Clipping to the container bounds 3. Animating both scale and alignment over time
Container: ┌──────────────────┐
│ │
│ Visible Area │ ← You see this
│ │
└──────────────────┘
Actual Image: ┌─────────────────────────┐
│ │
│ ┌──────────────┐ │
│ │ Visible │ │ ← Image is larger
│ │ │ │
│ └──────────────┘ │
│ │
└─────────────────────────┘
The alignment determines which part of the larger image is visible.
Tips¶
Zoom Amount Guidelines¶
| Effect | Zoom Amount |
|---|---|
| Subtle | 0.1 - 0.15 |
| Normal | 0.15 - 0.25 |
| Dramatic | 0.25 - 0.4 |
Pan Requirements¶
Panning requires the image to be zoomed beyond 1.0 so there's room to pan:
// Won't pan - image fills container exactly
KenBurnsImage.pan(scale: 1.0, ...) // No room to move
// Will pan - image is larger than container
KenBurnsImage.pan(scale: 1.2, ...) // 20% extra for panning
Related¶
- PhotoCard - Photo card with Ken Burns option
- EmbeddedVideo - Video clips
- TimeConsumer - Frame-based animation