Keyframe Animations
Keyframe animations provide precise property control over time.
Supported Properties
| Property | Description | Format |
|---|---|---|
position |
Item position | [x, y] |
x, y |
Position components | number |
scale |
Uniform scale | number |
scaleX, scaleY |
Axis scale | number |
rotation |
Rotation in degrees | number |
opacity |
Transparency (0-1) | number |
fillColor |
Fill color | color string |
strokeColor |
Stroke color | color string |
fontSize |
Text size | number |
Creating Keyframes
const item = app.create({
type: 'circle',
position: [400, 100],
radius: 50,
fillColor: '#fbbf24'
});
app.modify(item, {
animationType: 'keyframe',
keyframes: [
{ time: 0, properties: { position: [400, 100], fillColor: '#fbbf24' }, easing: 'linear' },
{ time: 3, properties: { position: [400, 300], fillColor: '#f97316' }, easing: 'easeInOut' },
{ time: 6, properties: { position: [400, 500], fillColor: '#dc2626' }, easing: 'easeOut' }
]
});
Easing Functions
| Easing | Description |
|---|---|
linear |
Constant speed |
easeIn |
Slow start, fast end |
easeOut |
Fast start, slow end |
easeInOut |
Slow start and end |
bounce |
Bounce effect at end |
elastic |
Elastic overshoot |
Color Interpolation
Colors smoothly interpolate in RGB space:
app.modify(sky, {
animationType: 'keyframe',
keyframes: [
{ time: 0, properties: { fillColor: '#1e3a5f' } }, // Night
{ time: 2, properties: { fillColor: '#ff7e5f' } }, // Sunrise
{ time: 4, properties: { fillColor: '#87ceeb' } }, // Day
{ time: 6, properties: { fillColor: '#ff6b6b' } }, // Sunset
{ time: 8, properties: { fillColor: '#1e3a5f' } } // Night
]
});
Color Formats
All valid formats for keyframe colors:
{ fillColor: '#ff0000' } // Hex
{ fillColor: '#ff000080' } // Hex with alpha
{ fillColor: 'rgb(255, 0, 0)' } // RGB
{ fillColor: 'rgba(255, 0, 0, 0.5)' } // RGBA
{ fillColor: 'red' } // Named colors
Keyframe Manipulation API
addKeyframe(item, time, properties)
Add a keyframe at a specific time.
Parameters:
item(paper.Item): Target itemtime(number): Time in secondsproperties(object): Properties to animate
app.addKeyframe(circle, 2.5, { x: 500, opacity: 0.5 });
getKeyframe(item, index)
Get a keyframe by its index.
Parameters:
item(paper.Item): Target itemindex(number): Keyframe index (0-based)
Returns: object - Keyframe object { time, properties, easing }
const kf = app.getKeyframe(circle, 0);
console.log(kf.time, kf.properties);
getKeyframeAtTime(item, time)
Get the keyframe at a specific time.
Parameters:
item(paper.Item): Target itemtime(number): Time in seconds
Returns: object|null - Keyframe object or null
const kf = app.getKeyframeAtTime(circle, 2.5);
getKeyframes(item)
Get all keyframes for an item.
Parameters:
item(paper.Item): Target item
Returns: Array<object> - Array of keyframe objects
const keyframes = app.getKeyframes(circle);
keyframes.forEach(kf => {
console.log(`t=${kf.time}:`, kf.properties);
});
removeKeyframe(item, index)
Remove a keyframe by index.
Parameters:
item(paper.Item): Target itemindex(number): Keyframe index to remove
app.removeKeyframe(circle, 2); // Remove 3rd keyframe
clearKeyframes(item)
Remove all keyframes from an item.
Parameters:
item(paper.Item): Target item
app.clearKeyframes(circle);
updateKeyframe(item, index, properties)
Update an existing keyframe’s properties.
Parameters:
item(paper.Item): Target itemindex(number): Keyframe indexproperties(object): New properties to merge
app.updateKeyframe(circle, 1, { x: 600, easing: 'bounce' });
moveKeyframe(item, fromIndex, toIndex)
Reorder a keyframe within the keyframe array.
Parameters:
item(paper.Item): Target itemfromIndex(number): Current indextoIndex(number): New index
app.moveKeyframe(circle, 0, 2); // Move first keyframe to third position
Playback Control
// Play with duration and loop
app.playKeyframeTimeline(8, true);
// Stop
app.stopKeyframeTimeline();
// Scrub to specific time
app.setPlaybackTime(2.5);
Example: Day/Night Cycle
// Create scene elements
const sky = app.create({ type: 'rectangle', position: [400, 300], size: [800, 600] });
const sun = app.create({ type: 'circle', position: [100, 500], radius: 60, fillColor: '#fbbf24' });
// Animate sky
app.modify(sky, {
animationType: 'keyframe',
keyframes: [
{ time: 0, properties: { fillColor: '#0f172a' } },
{ time: 2, properties: { fillColor: '#fb923c' } },
{ time: 4, properties: { fillColor: '#38bdf8' } },
{ time: 6, properties: { fillColor: '#f97316' } },
{ time: 8, properties: { fillColor: '#0f172a' } }
]
});
// Animate sun arc
app.modify(sun, {
animationType: 'keyframe',
keyframes: [
{ time: 0, properties: { position: [100, 600], opacity: 0 } },
{ time: 2, properties: { position: [200, 100], opacity: 1 } },
{ time: 4, properties: { position: [400, 50], opacity: 1 } },
{ time: 6, properties: { position: [600, 100], opacity: 1 } },
{ time: 8, properties: { position: [700, 600], opacity: 0 } }
]
});
// Play
app.playKeyframeTimeline(8, true);