Skip to main content
The Web Stories animation system brings elements to life with entrance effects, motion, and visual interest. Animations are defined in serializable format and render consistently in both the editor and published stories.

Animation System Architecture

Animations are managed in the packages/animation package with dual rendering:
  • WAAPI (Web Animations API) - For editor preview
  • AMP - For published story output
Both share common keyframes to ensure visual parity. Reference: docs/animations.md:54-58

Animation Provider

The animation system is integrated through the StoryAnimation.Provider:
import { StoryAnimation } from '@googleforcreators/animation';

<StoryAnimation.Provider animations={animations} elements={elements}>
  {/* Story pages */}
</StoryAnimation.Provider>
Reference: packages/story-editor/src/components/canvas/displayLayer.js

Animation Types

Animation Effects

Effects are opinionated, complex animations for common use cases:
export const ANIMATION_EFFECTS = {
  DROP: { value: AnimationType.EffectDrop, name: 'Drop' },
  FADE_IN: { value: AnimationType.EffectFadeIn, name: 'Fade In' },
  FLY_IN: { value: AnimationType.EffectFlyIn, name: 'Fly In' },
  PAN: { value: AnimationType.EffectPan, name: 'Pan' },
  PULSE: { value: AnimationType.EffectPulse, name: 'Pulse' },
  TWIRL_IN: { value: AnimationType.EffectTwirlIn, name: 'Twirl In' },
  WHOOSH_IN: { value: AnimationType.EffectWhooshIn, name: 'Whoosh In' },
  ZOOM: { value: AnimationType.EffectZoom, name: 'Scale' },
  ROTATE_IN: { value: AnimationType.EffectRotateIn, name: 'Rotate In' },
};
Reference: packages/animation/src/constants.ts:58-95

Background Animations

Special animations for background images:
export const BACKGROUND_ANIMATION_EFFECTS = {
  ZOOM: { value: AnimationType.EffectBackgroundZoom, name: 'Zoom' },
  PAN: { value: AnimationType.EffectBackgroundPan, name: 'Pan' },
  PAN_AND_ZOOM: { 
    value: AnimationType.EffectBackgroundPanAndZoom, 
    name: 'Pan and Zoom' 
  },
};
Reference: packages/animation/src/constants.ts:97-110

Animation Parts

Atomic, configurable animations for advanced use:
export const ANIMATION_PARTS = {
  BLINK_ON: { value: AnimationType.BlinkOn, name: 'Blink On' },
  BOUNCE: { value: AnimationType.Bounce, name: 'Bounce' },
  FADE: { value: AnimationType.Fade, name: 'Fade' },
  FLIP: { value: AnimationType.Flip, name: 'Flip' },
  FLOAT_ON: { value: AnimationType.FloatOn, name: 'Float On' },
  MOVE: { value: AnimationType.Move, name: 'Move' },
  PULSE: { value: AnimationType.Pulse, name: 'Pulse' },
  SPIN: { value: AnimationType.Spin, name: 'Spin' },
  ZOOM: { value: AnimationType.Zoom, name: 'Zoom' },
};
Reference: packages/animation/src/constants.ts:112-149
The editor primarily uses Animation Effects. Animation Parts are available for advanced customization.

Adding Animations

Animation Panel

Add animations through the Design panel:
1

Select element

Click an element on the canvas to select it.
2

Open Animation panel

The Animation panel appears in the right sidebar Design section.
3

Choose effect

Select an animation from the Effect Chooser dropdown.
4

Adjust settings

Configure direction, duration, and other effect-specific options.
Reference: packages/story-editor/src/components/panels/design/animation/

Effect Chooser Dropdown

<EffectChooserDropdown
  value={animation?.type}
  onChange={handleAnimationChange}
  isBackgroundEffects={isBackground}
/>
Reference: packages/story-editor/src/components/panels/design/animation/effectChooserDropdown/

Animation Configuration

Serializable Animation Object

Animations are stored as JSON objects:
const animationObject = {
  id: 'unique-id',           // Unique identifier
  type: 'effect-drop',       // Animation type
  targets: ['element-123'],  // Target element IDs
  duration: 1000,            // Duration in milliseconds
  delay: 0,                  // Delay before start
  // Effect-specific properties:
  ease: 'cubic-bezier(0.4, 0.4, 0.0, 1)',
  panDir: 'leftToRight',
};
Reference: docs/animations.md:9-23

Easing Functions

Supported easing curves:
export const BEZIER = {
  linear: 'linear',
  in: 'ease-in',
  out: 'ease-out',
  inOut: 'ease-in-out',
  // Quad
  inQuad: 'cubic-bezier(0.55, 0.085, 0.68, 0.53)',
  outQuad: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
  inOutQuad: 'cubic-bezier(0.455, 0.03, 0.515, 0.955)',
  // ... more bezier curves
  default: 'cubic-bezier(0.4, 0.4, 0.0, 1)',
};
Reference: packages/animation/src/constants.ts:27-54

Direction Controls

Many animations support directional input:
<DirectionRadioInput
  value={direction}
  onChange={setDirection}
  directions={availableDirections}
/>
Common directions:
  • Fly In: Left to Right, Right to Left, Top to Bottom, Bottom to Top
  • Pan: Same directional options
  • Rotate In: Clockwise, Counter-clockwise
Reference: packages/story-editor/src/components/panels/design/animation/directionRadioInput.js

Animation Details

Drop Effect

// packages/animation/src/parts/effects/drop.ts
interface DropAnimation {
  type: 'effect-drop';
  duration: number;     // Default: 1600ms
  delay: number;        // Default: 0
  easing: BezierType;   // Default: 'cubic-bezier(0.4, 0.4, 0.0, 1)'
}
Element drops in from above with bounce effect. Reference: packages/animation/src/parts/effects/drop.ts

Fade In Effect

// packages/animation/src/parts/effects/fadeIn.ts
interface FadeInAnimation {
  type: 'effect-fade-in';
  duration: number;     // Default: 1000ms
  delay: number;
  easing: BezierType;
}
Element gradually appears with opacity transition. Reference: packages/animation/src/parts/effects/fadeIn.ts

Fly In Effect

interface FlyInAnimation {
  type: 'effect-fly-in';
  duration: number;     // Default: 1000ms
  delay: number;
  flyInDir: 'leftToRight' | 'rightToLeft' | 'topToBottom' | 'bottomToTop';
  easing: BezierType;
}
Element enters from the specified direction. Reference: packages/animation/src/parts/effects/flyIn.tsx

Pan Effect

interface PanAnimation {
  type: 'effect-pan';
  duration: number;
  panDir: 'leftToRight' | 'rightToLeft' | 'topToBottom' | 'bottomToTop';
  easing: BezierType;
}
Element moves across the screen in the specified direction. Reference: packages/animation/src/parts/effects/pan.ts

Rotate In Effect

interface RotateInAnimation {
  type: 'effect-rotate-in';
  duration: number;
  rotateInDir: 'clockwise' | 'counterClockwise';
  easing: BezierType;
}
Element rotates as it appears. Reference: packages/animation/src/parts/effects/rotateIn.tsx

Zoom (Scale) Effect

interface ZoomAnimation {
  type: 'effect-zoom';
  duration: number;
  scaleDirection: 'scaleIn' | 'scaleOut';
  easing: BezierType;
}
Element scales in or out. Reference: packages/animation/src/parts/effects/zoom.tsx

Background Animations

Background images have special animation considerations:

Background Pan

// packages/animation/src/parts/effects/backgroundPan.ts
interface BackgroundPanAnimation {
  type: 'effect-background-pan';
  duration: number;
  panDir: Direction;
}
Pans background image, accounting for current offset and zoom to prevent panning past borders. Reference: packages/animation/src/parts/effects/backgroundPan.ts

Background Zoom

// Zoom constraints
export const BG_MIN_SCALE = 100;
export const BG_MAX_SCALE = 400;
Background zoom is constrained to prevent excessive scaling. Reference: packages/animation/src/constants.ts:156-157

Animation State Management

Animations are stored in the story state:
const { animations } = useStory(({ state }) => ({
  animations: state.currentPage.animations
}));
Reference: docs/animations.md:5

WAAPI Wrapper

Elements are wrapped for Web Animations API:
<StoryAnimation.WAAPIWrapper
  target={element}
  animation={animation}
>
  {children}
</StoryAnimation.WAAPIWrapper>
Reference: packages/story-editor/src/components/canvas/displayElement.js

AMP Output

For published stories, AMP animations are used:
<StoryAnimation.AMPWrapper
  target={element}
  animation={animation}
>
  {children}
</StoryAnimation.AMPWrapper>
Reference: packages/output/src/element.js

Animation Timeline

An internal animation timeline tool was removed in PR #7067. For complex multi-element animations, consider using templates with pre-configured animation sequences.
Reference: docs/animations.md:76-84

Single Target Constraint

Animations in the editor target only one element:
“We have changed this spec to only allow an animation to have a single target element. This new spec is manually enforced in the editor code.”
Reference: docs/animations.md:70-74

Preview Animations

Test animations in the editor:
Animations play automatically in the Display Layer as you navigate between pages.The preview uses WAAPI for real-time playback.

Animation Panel Components

Effect Panel

<EffectPanel
  selectedElement={element}
  animation={currentAnimation}
  onChange={updateAnimation}
/>
Reference: packages/story-editor/src/components/panels/design/animation/effectPanel.js

Effect Input

<EffectInput
  effectConfig={config}
  value={effectValue}
  onChange={handleChange}
/>
Reference: packages/story-editor/src/components/panels/design/animation/effectInput.js

Creating Custom Animations

Animation Part Structure

import { createAnimationPart } from '@googleforcreators/animation';

const customAnimation = createAnimationPart({
  type: 'my-custom-animation',
  defaultDuration: 1000,
  generateKeyframes: (args) => {
    return [
      { offset: 0, /* initial state */ },
      { offset: 1, /* final state */ },
    ];
  },
});
Reference: packages/animation/src/parts/createAnimationPart.ts

Best Practices

1

Use animations sparingly

Too many animations can overwhelm users. Choose 1-2 key elements per page.
2

Match animation to content

Use subtle animations for text, more dramatic for hero images.
3

Consider timing

Animations should complete before users tap to next page (typically under 2 seconds).
4

Test on devices

Preview animations on mobile devices to ensure smooth performance.
5

Maintain accessibility

Avoid animations that could trigger vestibular disorders (rapid spinning, flashing).
Excessive or complex animations can impact story performance, especially on lower-end devices.

Debugging Animations

Animation issues can be debugged through:
  • Browser DevTools - Inspect WAAPI animations in the Animations panel
  • Preview Mode - Test AMP animations in preview
  • Console Logging - Animation provider logs warnings for invalid configurations

Next Steps

Templates

Use templates with pre-configured animations

Text & Styling

Combine animations with text effects

Media Library

Animate images and videos

Build docs developers (and LLMs) love