viewmotion

Performance

viewmotion is designed for performance from the ground up. Here are the architectural decisions that make it fast, and best practices to keep your pages smooth.

Why viewmotion is fast

IntersectionObserver, not scroll listeners

viewmotion uses the IntersectionObserver API — a browser-native mechanism that runs off the main thread. Unlike scroll event listeners, it does not cause layout thrashing or jank.

CSS keyframe animations

All animations run via CSS @keyframes, which are composited by the browser’s GPU when possible. This means animations run at 60fps+ without JavaScript frame-by-frame updates.

Tiny bundle size

The core package is ~2 KB gzipped. No dependencies, no heavy runtime — just attribute parsing + one observer instance.

Single observer pattern

viewmotion creates one IntersectionObserver for all animated elements, rather than one per element. This reduces memory usage and callback overhead.

Best practices

1. Animate transforms and opacity

All built-in presets use only transform and opacity. When creating custom presets, stick to these GPU-composited properties:

RecommendedAvoid
opacitywidth / height
transform: translate()top / left
transform: scale()margin / padding
transform: rotate()box-shadow (expensive)

2. Limit animated elements per page

While viewmotion handles many elements efficiently, as a guideline:

  • < 50 elements — no concerns, runs smoothly
  • 50–100 elements — fine on modern devices
  • 100+ elements — consider lazy loading or paginating

3. Use reasonable stagger delays

Keep stagger increments between 50–120ms. Very short values (< 30ms) make animations indistinguishable; very long values (> 200ms) slow down perceived page load.

// Good: 80ms between each element
stagger({ step: 80 });

// Avoid: too fast, elements appear at once
stagger({ step: 10 });

4. Avoid animating above the fold unnecessarily

Elements visible on first paint don’t benefit much from scroll-reveal. Consider using a simple CSS fade-in for hero content instead of scroll-triggered animations.

Measuring performance

Use Chrome DevTools’ Performance panel to check for:

  • Layout shifts — should be zero if using transform/opacity only
  • Paint events — should be minimal during animations
  • Long tasksinitMotion() should complete in < 1ms
  • FPS — should stay at 60fps during animation playback

Found a performance issue? If you’re seeing unexpected jank or overhead, open an issue on GitHub with a minimal reproduction. Performance regressions are treated as bugs.