API Documentation
Complete reference for the PinePaper programmatic interface. Build animated graphics with code or integrate with AI agents.
Quick Start
PinePaper exposes a global window.PinePaper object. Access it from the browser console or your scripts:
// Access the PinePaper instance
const app = window.PinePaper;
// Create text
const text = app.create('text', {
content: 'Hello World',
x: 400,
y: 300,
fontSize: 48,
color: '#3730a3'
});
// Add animation
app.animate(text, {
animationType: 'pulse',
animationSpeed: 1.0
});
// Export as SVG
app.exportAnimatedSVG();Core API Methods
create(type, params)
Create a new item on the canvas.
Parameters:
type(string) - Item type:'text','circle','star','rectangle','triangle','polygon','ellipse'params(object) - Properties:x, y- Position (default: canvas center)content- Text content (for text items)color- Fill color (default: fontColor config)fontSize- Font size (for text)fontFamily- Font familyradius,width,height- Shape dimensions
// Create text
const text = app.create('text', {
content: 'Hello!',
x: 400,
y: 300,
fontSize: 64,
color: '#3730a3'
});
// Create circle
const circle = app.create('circle', {
x: 200,
y: 200,
radius: 50,
color: '#ef4444'
});select(query, replace)
Select items on the canvas.
Parameters:
query- Item,'all', or filter objectreplace(boolean) - Clear existing selection (default: true)
// Select an item
app.select(item);
// Select all items
app.select('all');
// Select by type
app.select({ type: 'text' });modify(changes)
Modify selected items.
Parameters:
changes(object) - Properties to modify:fontSize,color,content,x,y,rotationanimationType,animationSpeed
app.modify({
fontSize: 72,
color: '#10b981',
rotation: 45
});animate(item, params)
Apply animation to an item.
Parameters:
item- Target itemparams(object):animationType-'pulse','rotate','bounce','fade','wobble','swing','shake','jelly','typewriter','path'animationSpeed- Speed multiplier (default: 1.0)animationDelay- Start delay in seconds
app.animate(item, {
animationType: 'pulse',
animationSpeed: 1.5,
animationDelay: 0.5
});removeSelectedItems()
Remove all currently selected items from the canvas.
app.select('all');
app.removeSelectedItems();nudgeSelection(dx, dy)
Move selected items by pixel offset.
// Move right 10px, down 5px
app.nudgeSelection(10, 5);Timeline System NEW
The Timeline system enables sequential, choreographed animations with precise timing control. Access it via the Timeline panel in the editor or programmatically via window.timelineUI.
Timeline UI Components
The timeline interface provides visual control over animation timing:
- ▸ Playhead - Red vertical line showing current time position
- ▸ Tracks - Horizontal rows for each animatable item
- ▸ Keyframes - Diamond markers indicating animation points
- ▸ Interpolation Curves - Visual representation of easing between keyframes
- ▸ Transport Controls - Play, pause, stop, and loop buttons
window.timelineUI
Global timeline controller object.
Methods:
play()- Start playbackpause()- Pause playbackstop()- Stop and reset to startseek(time)- Jump to specific time in secondssetDuration(seconds)- Set total timeline durationaddKeyframe(item, time, properties, easing)- Add keyframeapplyPreset(item, presetName)- Apply animation preset
// Access timeline
const timeline = window.timelineUI;
// Set 5 second duration
timeline.setDuration(5);
// Play the animation
timeline.play();
// Seek to 2.5 seconds
timeline.seek(2.5);
// Pause playback
timeline.pause();Keyframe Animations NEW
addKeyframe(item, time, properties, easing)
Add a keyframe to an item at a specific time.
Parameters:
item- Target Paper.js itemtime(number) - Time in secondsproperties(object) - Animatable properties:opacity- 0 to 1x, y- Position coordinatesscaleX, scaleY- Scale factorsrotation- Rotation in degrees
easing(string) - Easing function:'linear','easeIn','easeOut','easeInOut'
// Fade in animation
timelineUI.addKeyframe(text, 0, { opacity: 0 }, 'linear');
timelineUI.addKeyframe(text, 2, { opacity: 1 }, 'easeOut');
// Move and scale animation
timelineUI.addKeyframe(shape, 0, { x: 100, scaleX: 0.5, scaleY: 0.5 }, 'linear');
timelineUI.addKeyframe(shape, 1.5, { x: 400, scaleX: 1, scaleY: 1 }, 'easeInOut');applyPreset(item, presetName)
Apply a predefined animation preset to an item.
Available Presets:
'fadeIn'- Fade from 0% to 100% opacity'fadeOut'- Fade from 100% to 0% opacity'fadeInOut'- Fade in, hold, fade out'popIn'- Scale up with bounce effect'slideIn'- Slide in from left'pulse'- Scale up and down continuously
// Apply fade in preset
timelineUI.applyPreset(text, 'fadeIn');
// Apply pop in effect
timelineUI.applyPreset(title, 'popIn');
// Apply continuous pulse
timelineUI.applyPreset(logo, 'pulse');Easing Functions
Control how values interpolate between keyframes.
linear
Constant speed from start to end
easeIn
Starts slow, accelerates
easeOut
Starts fast, decelerates
easeInOut
Smooth acceleration and deceleration
Example: Sequential Text Reveal
Create a choreographed sequence where elements appear one after another:
// Create elements
const title = app.create('text', { content: 'Welcome', y: 200, fontSize: 64 });
const subtitle = app.create('text', { content: 'To PinePaper', y: 280, fontSize: 32 });
const cta = app.create('text', { content: 'Start Creating →', y: 400, fontSize: 24 });
// Set timeline duration
timelineUI.setDuration(4);
// Title: Fade in at 0-1s
timelineUI.addKeyframe(title, 0, { opacity: 0 }, 'linear');
timelineUI.addKeyframe(title, 1, { opacity: 1 }, 'easeOut');
// Subtitle: Fade in at 1-2s
timelineUI.addKeyframe(subtitle, 0, { opacity: 0 }, 'linear');
timelineUI.addKeyframe(subtitle, 1, { opacity: 0 }, 'linear');
timelineUI.addKeyframe(subtitle, 2, { opacity: 1 }, 'easeOut');
// CTA: Pop in at 2.5-3.5s
timelineUI.addKeyframe(cta, 0, { opacity: 0, scaleX: 0.5, scaleY: 0.5 }, 'linear');
timelineUI.addKeyframe(cta, 2.5, { opacity: 0, scaleX: 0.5, scaleY: 0.5 }, 'linear');
timelineUI.addKeyframe(cta, 3.5, { opacity: 1, scaleX: 1, scaleY: 1 }, 'easeOut');
// Play the sequence
timelineUI.play();Drawing & Brush Styles
The drawing system uses Paper.js Path objects. AI agents and developers can create custom brush styles programmatically using the full power of Paper.js path manipulation.
setBackgroundMode(mode)
Switch between background modes.
Modes:
'pattern'- Geometric pattern background'drawing'- Freehand drawing mode (activates drawing tool)'image'- Background image mode
// Activate drawing mode
app.setBackgroundMode('drawing');Basic Path Drawing
Create paths programmatically using Paper.js:
// Basic freehand-style path
const path = new Path();
path.strokeColor = '#FF0000';
path.strokeWidth = 5;
path.strokeCap = 'round';
path.strokeJoin = 'round';
// Add points to create the path
path.add(new Point(100, 100));
path.add(new Point(150, 120));
path.add(new Point(200, 100));
path.add(new Point(250, 130));
// Smooth the path for organic look
path.smooth();Brush Style Properties
Paper.js path properties for different brush effects:
strokeCap
'round', 'square', 'butt'
strokeJoin
'round', 'miter', 'bevel'
dashArray
[10, 5] for dashed lines
blendMode
'multiply', 'screen', 'overlay'
Brush Style Examples
// Dotted/Stipple brush
const dottedPath = new Path();
dottedPath.strokeColor = 'blue';
dottedPath.strokeWidth = 2;
dottedPath.dashArray = [2, 8]; // dot pattern
// Marker/Highlighter style (semi-transparent overlay)
const markerPath = new Path();
markerPath.strokeColor = new Color(1, 1, 0, 0.5); // Yellow with alpha
markerPath.strokeWidth = 20;
markerPath.strokeCap = 'round';
markerPath.blendMode = 'multiply';
// Neon glow effect
const neonPath = new Path();
neonPath.strokeColor = '#00ff00';
neonPath.strokeWidth = 3;
neonPath.shadowColor = '#00ff00';
neonPath.shadowBlur = 10;
// Spray/Airbrush effect (multiple small circles)
function sprayBrush(center, radius, density, color) {
for (let i = 0; i < density; i++) {
const offset = new Point({
angle: Math.random() * 360,
length: Math.random() * radius
});
const dot = new Path.Circle({
center: center.add(offset),
radius: Math.random() * 2 + 0.5,
fillColor: color
});
dot.opacity = Math.random() * 0.5 + 0.2;
}
}
// Usage: sprayBrush(new Point(200, 200), 30, 50, '#ff6b6b');Drawing Configuration
Get and set drawing settings:
Methods:
getDrawColor()- Get current stroke colorsetDrawColor(color)- Set stroke colorgetDrawWidth()- Get current stroke widthsetDrawWidth(width)- Set stroke widthgetBackgroundMode()- Get current mode
// Get current settings
const color = app.getDrawColor();
const width = app.getDrawWidth();
const mode = app.getBackgroundMode();
// Modify settings
app.setDrawColor('#3b82f6');
app.setDrawWidth(8);clearDrawings()
Clear all freehand drawings from the canvas.
app.clearDrawings();Background Generators Enhanced
PinePaper provides procedural background generators that create dynamic, customizable backgrounds using Paper.js. These functions use advanced distribution algorithms (Poisson disk sampling, Golden Ratio) for natural-looking results.
executeGenerator(name, params)
Execute a background generator function with custom parameters.
Available Generators:
'drawSunburst'Radiating rays from center with customizable colors
'drawSunsetScene'Animated sunset with gradient sky and clouds
'drawGrid' NewLines, dots, or squares grid pattern
'drawStackedCircles' NewOverlapping circles with Poisson/Golden distribution
'drawCircuit' NewTech circuit board pattern with animated bolt
'drawWaves' NewLayered wave pattern with gradient colors
'drawPattern'Geometric shapes in circular orbit
// Stacked circles with Poisson disk sampling
app.executeGenerator('drawStackedCircles', {
colors: ['#4f46e5', '#7c3aed', '#2563eb', '#0891b2'],
count: 50,
distribution: 'poisson', // 'poisson', 'golden', 'random'
minRadius: 20,
maxRadius: 100,
bgColor: '#1a1a2e'
});
// Circuit board pattern
app.executeGenerator('drawCircuit', {
lineColor: '#22c55e',
bgColor: '#0a0a0a',
nodeSize: 6,
gridSize: 60,
animated: true
});
// Grid pattern
app.executeGenerator('drawGrid', {
gridType: 'dots', // 'lines', 'dots', 'squares'
spacing: 40,
lineColor: '#374151',
bgColor: '#1f2937'
});Distribution Utilities New
Low-level utilities for procedural placement of elements.
Available Methods:
poissonDiskSampling(width, height, minDist)Generates natural-looking random distribution using Bridson's algorithm. Points are guaranteed to be at least minDist apart.
goldenRatioDistribution(count, width, height)Generates points in a golden ratio spiral pattern for elegant distribution.
simpleNoise(x, y, scale)Returns pseudo-random noise value (0-1) for position-based variation.
getColorFromPosition(colors, x, y, noiseScale)Selects color from palette based on position for coherent color regions.
// Generate Poisson disk points for natural placement
const points = app.poissonDiskSampling(800, 600, 50);
// Place shapes at each point with noise-based variation
points.forEach(p => {
const noise = app.simpleNoise(p.x, p.y, 100);
const radius = 10 + noise * 40;
const color = app.getColorFromPosition(['#ff0', '#0ff', '#f0f'], p.x, p.y);
new Path.Circle({
center: [p.x, p.y],
radius: radius,
fillColor: color,
parent: app.patternGroup
});
});getAvailableGenerators()
Get list of all available background generators with their parameter schemas.
const generators = app.getAvailableGenerators();
// Returns array of:
// {
// name: 'drawStackedCircles',
// displayName: 'Stacked Circles',
// description: 'Overlapping circles with glow',
// params: {
// colors: { type: 'colors', default: [...], description: '...' },
// count: { type: 'number', min: 10, max: 100, default: 30 },
// distribution: { type: 'select', options: ['poisson', 'golden', 'random'] }
// }
// }setBackgroundColor(color)
Set solid background color.
app.setBackgroundColor('#0B0F19');Arrow System
arrowSystem.createArrow(points, config)
Create an arrow programmatically with full configuration.
Configuration Options:
Path Options:
lineColor- Stroke color (default: '#60a5fa')lineWidth- Line thickness (default: 3)style- 'straight', 'orthogonal', 'smooth'smoothness- Curve factor 0-100 (for smooth)
Head Options:
headStyle- 'classic', 'stealth', 'open', 'none'headSize- Size multiplier (default: 1.0)
Bolt Effect:
boltEnabled- Enable animated boltboltColor- Bolt color (default: '#fbbf24')boltSpeed- Animation speed
// Create arrow with full config
app.arrowSystem.createArrow(
[new Point(100, 100), new Point(200, 150), new Point(300, 100)],
{
lineColor: '#60a5fa',
lineWidth: 3,
style: 'smooth',
smoothness: 60,
headStyle: 'stealth', // 'classic', 'stealth', 'open', 'none'
headSize: 1.2,
boltEnabled: true,
boltColor: '#fbbf24'
}
);Arrowhead Styles
'classic'
Filled triangle
'stealth'
Diamond with notch
'open'
V-shape stroke
'none'
No arrowhead
arrowSystem.updateArrowSettings(config)
Update settings for selected arrow or set defaults for new arrows.
// Update arrow settings
app.arrowSystem.updateArrowSettings({
headStyle: 'stealth',
lineWidth: 5,
lineColor: '#ef4444'
});Arrow Management
// Get all arrows
const arrows = app.arrowSystem.arrows;
// Clear all arrows
app.arrowSystem.clear();
// Remove specific arrow
app.arrowSystem.removeArrow(arrow);Effect System
applyEffect(item, effectType, config)
Apply particle effects to any item (text, shapes, arrows).
Available Effects:
'sparkle'- Animated bolt that follows item path/bounds with particle trail'blast'- One-shot explosion of particles from item center
Sparkle Config:
app.applyEffect(item, 'sparkle', {
color: '#fbbf24', // Particle/glow color
speed: 1.0, // Animation speed multiplier
size: 3 // Bolt size
});Blast Config:
app.applyEffect(item, 'blast', {
color: '#ef4444', // Particle color
radius: 100, // Blast radius/speed
count: 20 // Number of particles
});effectSystem.removeEffectsFrom(item)
Remove all effects from an item.
// Remove effects from specific item
app.effectSystem.removeEffectsFrom(item);
// Clear ALL effects
app.effectSystem.clear();Effect Lifecycle
Effects are automatically managed:
- • Sparkle effects persist and are saved with templates
- • Blast effects are transient (one-shot, not saved)
- • Effects are stored in
item.data.effectsarray - • Call
effectSystem.rebuildEffects()after loading scenes
Scene Management
getSceneState()
Get a semantic description of the current scene for AI agents.
const state = app.getSceneState();
// Returns: { canvas, items, arrows, background }exportTemplate()
Export current scene as a template (full state capture).
const template = app.exportTemplate();
// Save template JSON for later restorationloadScene(templateData)
Load a complete scene from template data.
app.loadScene(templateData);clearCanvas()
Clear all items and reset the canvas.
app.clearCanvas();View Controls
Zoom Methods
zoomIn()- Zoom in by 20%zoomOut()- Zoom out by 20%resetZoom()- Reset to 1:1 zoom
app.zoomIn();
app.zoomOut();
app.resetZoom();Paper.js Integration
PinePaper is built on Paper.js, a powerful vector graphics scripting framework. All Paper.js globals are available in the editor scope.
Key Paper.js Objects
Item Creation
// Create shapes directly
const circle = new Path.Circle({
center: [200, 200],
radius: 50,
fillColor: '#3b82f6'
});
// Create text
const text = new PointText({
point: [100, 100],
content: 'Hello',
fillColor: 'black',
fontSize: 24
});Common Item Properties
item.position- Get/set position as Pointitem.fillColor- Fill coloritem.strokeColor- Stroke coloritem.strokeWidth- Stroke widthitem.opacity- Opacity (0-1)item.visible- Visibility booleanitem.rotation- Rotation in degreesitem.scaling- Scale factoritem.bounds- Bounding rectangle
View & Project
// Access view
view.center; // Canvas center point
view.size; // Canvas size
view.zoom; // Current zoom level
// Access project
project.activeLayer; // Current active layer
project.exportSVG(); // Export as SVGCustom Events
// Listen to PinePaper events
window.addEventListener('selectionChanged', (e) => {
console.log('Selected:', e.detail.items);
});
window.addEventListener('modeChanged', (e) => {
console.log('Mode:', e.detail.mode);
});Item Registry NEW
Overview
The Item Registry tracks all canvas items with unique IDs, types, and declarative associations. Every item (text, shape, generator element) is automatically registered.
Querying Items
// Get all registered items
const allItems = app.itemRegistry.getAll();
// Get items by type
const textItems = app.itemRegistry.getByType('text');
const circles = app.itemRegistry.getByType('circle');
// Get items by source
const userItems = app.itemRegistry.getBySource('user');
const generatorItems = app.itemRegistry.getBySource('generator');
// Get item by ID
const item = app.itemRegistry.getItem('item_5');
// Check if item exists
if (app.itemRegistry.has('item_5')) { /* ... */ }
// Get item count
const count = app.itemRegistry.count();
// Custom query with predicate
const largeItems = app.itemRegistry.query(entry =>
entry.item.bounds.width > 100
);Item Associations
Create relationships between items for complex scene logic:
// Create relationships
app.itemRegistry.addAssociation('item_1', 'item_2', 'orbits');
app.itemRegistry.addAssociation('item_1', 'item_3', 'contains');
// Query associations
const orbiting = app.itemRegistry.getAssociations('item_1', 'orbits');
const allRelated = app.itemRegistry.getAssociations('item_1');
// Remove association
app.itemRegistry.removeAssociation('item_1', 'item_2', 'orbits');Item Properties & Names
// Update item properties
app.itemRegistry.updateProperties('item_1', {
customProp: 'value',
animationType: 'pulse'
});
// Set item name for identification
app.itemRegistry.setName('item_1', 'MainTitle');
// Find by name
const headers = app.itemRegistry.getByName('MainTitle');Relation System NEW
The Relation System enables behavior-driven associations between items. Define relationships like "orbits", "follows", or "attached_to" and items will automatically animate based on their relations.
Built-in Relations
'orbits'Circular motion around target (radius, speed, direction)
'follows'Move toward target with smoothing (offset, delay)
'attached_to'Move with target like parent-child (offset)
'maintains_distance'Stay fixed distance from target (distance, strength)
'points_at'Rotate to face target (offset_angle)
'mirrors'Mirror position across axis (vertical, horizontal)
addRelation(fromId, toId, relation, params)
Create a behavior-driven relationship between two items.
// Make moon orbit earth
app.addRelation(moonId, earthId, 'orbits', {
radius: 100,
speed: 0.5,
direction: 'counterclockwise'
});
// Make label follow player
app.addRelation(labelId, playerId, 'follows', {
offset: [0, -50], // 50px above
smoothing: 0.1
});
// Attach name tag to character
app.addRelation(nameTagId, characterId, 'attached_to', {
offset: [0, -30]
});Querying Relations
// Get all relations for an item
const relations = app.getRelations(itemId);
// Get specific relation type
const orbits = app.getRelations(itemId, 'orbits');
// Find items that orbit a specific target
const orbiters = app.queryByRelationTarget(earthId, 'orbits');
// Check if relation exists
if (app.hasRelation(moonId, earthId, 'orbits')) {
console.log('Moon orbits Earth');
}
// Remove a relation
app.removeRelation(moonId, earthId, 'orbits');Advanced Queries
Powerful query methods for complex scene analysis:
// Compound query with multiple conditions
const results = app.queryCompound([
{ relation: 'orbits' }, // Must orbit something
{ relation: 'follows', not: true } // Must NOT follow anything
]);
// Chain query - follow relation chains
const chains = app.queryRelationChain(['follows', 'orbits']);
// Find items with no relations
const isolated = app.queryIsolatedItems();
// Get relation statistics
const stats = app.getRelationStats();
// { activeItems: 5, ruleCount: 8, associationsByType: {...} }Example: Solar System
// Create celestial bodies
const sun = app.create('circle', { x: 400, y: 300, radius: 50, color: '#fbbf24' });
const earth = app.create('circle', { x: 550, y: 300, radius: 20, color: '#3b82f6' });
const moon = app.create('circle', { x: 580, y: 300, radius: 8, color: '#9ca3af' });
// Get registry IDs
const sunId = sun.data.registryId;
const earthId = earth.data.registryId;
const moonId = moon.data.registryId;
// Earth orbits sun
app.addRelation(earthId, sunId, 'orbits', { radius: 150, speed: 0.1 });
// Moon orbits earth
app.addRelation(moonId, earthId, 'orbits', { radius: 30, speed: 0.3 });
// Label attached to earth
const label = app.create('text', { content: 'Earth', x: 550, y: 330, fontSize: 12 });
app.addRelation(label.data.registryId, earthId, 'attached_to', { offset: [0, 25] });Worker Pool NEW
Overview
Web Worker pool for offloading heavy computations. Keeps the UI responsive during complex operations. Includes automatic fallback to main thread if Workers are unavailable.
Available Operations
// Poisson disk sampling (non-blocking)
const points = await app.workerPool.poissonDiskSampling(800, 600, 50);
// Golden ratio distribution
const spiralPoints = await app.workerPool.goldenRatioDistribution(100, 800, 600);
// Path simplification (Douglas-Peucker algorithm)
const simplified = await app.workerPool.simplifyPath(points, 5);
// Color calculations for large datasets
const colors = await app.workerPool.calculateColors(positions, palette, 0.01);
// Scene serialization (for large scenes)
const json = await app.workerPool.serializeScene(sceneData);
const scene = await app.workerPool.deserializeScene(jsonString);Worker Status & Statistics
// Check if workers are available
if (app.workerPool.isAvailable()) {
// Use async methods
}
// Get performance statistics
const stats = app.workerPool.getStats();
// { tasksCompleted, tasksFailed, averageTaskTime, workersActive, ... }
// Warm up workers (pre-initialize)
await app.workerPool.warmUp();Async Generators NEW
Using Async Generators
Async generators leverage Web Workers for computation-heavy operations, keeping the UI responsive.
// Execute async generator (non-blocking)
await app.generatorRegistry.executeAsync('drawPoissonShapesAsync', {
shape: 'circle',
minDistance: 40,
colors: ['#8B5CF6', '#A78BFA']
});Creating Custom Async Generators
app.generatorRegistry.register('myAsyncGenerator', {
displayName: 'My Async Pattern',
description: 'Pattern using Web Workers',
category: 'custom',
async: true, // Mark as async
params: {
count: { type: 'number', default: 100 }
},
fn: async function(ctx) {
const { params, register, patternGroup, view } = ctx;
// Use async helpers from WorkerPool
let points;
if (ctx.async && ctx.async.poissonDiskSampling) {
// Non-blocking computation via Web Worker
points = await ctx.async.poissonDiskSampling(
view.size.width, view.size.height, 30, 30
);
}
// Create visuals on main thread
const group = new Group({ parent: patternGroup });
points.forEach(pt => {
new Path.Circle({
center: [pt.x, pt.y],
radius: 5,
fillColor: '#8B5CF6',
parent: group
});
});
register(group, 'myPattern', { count: points.length });
}
});Async Context Helpers:
ctx.async.poissonDiskSampling(w, h, dist, attempts)- Poisson samplingctx.async.goldenRatioDistribution(count, w, h, padding)- Golden spiralctx.async.simplifyPath(points, tolerance)- Path simplificationctx.async.calculateGeneratorPositions(config)- Generic position calc
OnFrame Callbacks NEW
Overview
Register custom animation callbacks with built-in performance guardrails. Callbacks are automatically monitored and can be disabled if they impact performance.
// Add a callback (called every frame)
app.addOnFrameCallback('myAnimation', (event) => {
// event.delta - time since last frame
// event.time - total elapsed time
// event.count - frame count
myItem.rotate(event.delta * 30); // 30 degrees per second
}, {
throttleMs: 16, // Optional: minimum ms between calls
priority: 0 // Optional: execution order
});
// Remove callback
app.removeOnFrameCallback('myAnimation');
// Remove all callbacks
app.clearOnFrameCallbacks();Features:
- Built-in performance monitoring
- Automatic throttling for slow callbacks
- Priority-based execution order
Animation Optimization
// Get count of animated items
const count = app.getAnimatedItemCount();
// Stop all animations on an item
app.stopAnimation(item);
// Rebuild animation tracking (after scene load)
app.rebuildAnimatedItemsSet();Complete Example
Create an animated greeting card with timeline sequencing:
// Set background
app.setBackgroundGenerator('drawSunsetScene');
// Create title
const title = app.create('text', {
content: 'Happy Birthday!',
y: 200,
fontSize: 72,
color: '#ffffff'
});
// Create subtitle
const subtitle = app.create('text', {
content: 'Hope your day is amazing!',
y: 400,
fontSize: 32,
color: '#fbbf24'
});
// Set up timeline (4 seconds)
timelineUI.setDuration(4);
// Animate title: fade in 0-1s
timelineUI.addKeyframe(title, 0, { opacity: 0 }, 'linear');
timelineUI.addKeyframe(title, 1, { opacity: 1 }, 'easeOut');
// Animate subtitle: fade in 1.5-2.5s
timelineUI.addKeyframe(subtitle, 0, { opacity: 0 }, 'linear');
timelineUI.addKeyframe(subtitle, 1.5, { opacity: 0 }, 'linear');
timelineUI.addKeyframe(subtitle, 2.5, { opacity: 1 }, 'easeOut');
// Add sparkles
app.applyEffect(title, 'sparkle', {
count: 30,
color: '#fbbf24'
});
// Play and export
timelineUI.play();
// app.exportAnimatedSVG();