Reveal animations
without the bloat.
Your Lighthouse score stays perfect. Your bundle stays under 2 KB. Works with React, Vue, Svelte, Astro, or plain HTML — in 3 lines of
code.
How it works
One observer. Pure CSS. Done.
Viewmotion watches elements entering the viewport with a single global
IntersectionObserver and triggers CSS animations. No scroll events. No polling. No runtime cost.
IntersectionObserver
A single global observer monitors all animated elements. When they enter the viewport, a CSS class is applied that triggers the animation. One observer — any number of elements.
CSS @keyframes
Animations are pure CSS keyframes — hardware-accelerated by the browser. No JavaScript animation loop. No requestAnimationFrame. Just the platform doing what it does best.
Zero dependencies
No GSAP. No Framer Motion. No scroll libraries. viewmotion ships under 2 KB gzipped and uses only native browser APIs. Smooth scroll is opt-in via Lenis.
Quick start
Three lines to animate
Install, initialize, and add data attributes. That’s it.
Install
npm install viewmotion Initialize
import "viewmotion/styles.css";
import { initMotion } from "viewmotion";
await initMotion(); Animate
<h1 data-motion="fade-up">
Hello world
</h1> 8 built-in animations
Every preset is a composable CSS keyframe. Scroll to see each one in
action. Need a custom animation? Use registerPreset() to add your own.
Pure opacity transition from 0 to 1.
Opacity + translate up 24px.
Opacity + translate down 24px.
Enters from right 32px.
Enters from left 32px.
Scales up from 92% with fade.
Shrinks from 108% with fade.
Fades in with 6px blur dissolve.
Framework adapters
Works with your stack
The core library is framework-agnostic. Official adapters bring idiomatic APIs to React, Vue, Svelte, and Astro.
Vanilla / Core
Framework-agnostic. Works with any HTML.
React
useMotion hook for refs.
Vue
v-motion directive + composable.
Svelte
use:motion action.
Code examples
Idiomatic in every framework
Each adapter exposes the API pattern native to its framework. Same animations, zero learning curve.
Vanilla HTML
<script type="module">
import "viewmotion/styles.css";
import { initMotion } from "viewmotion";
await initMotion();
</script>
<h1 data-motion="fade-up">
Hello world
</h1> React
import { useMotion } from "viewmotion-react";
function Hero() {
const ref = useMotion({ preset: "fade-up" });
return (
<h1 ref={ref}>Hello</h1>
);
} Vue
<script setup>
import { vMotion } from "viewmotion-vue";
</script>
<template>
<h1 v-motion="{ preset: 'fade-up' }">
Hello
</h1>
</template> Svelte
<script>
import { motion } from "viewmotion-svelte";
</script>
<h1
use:motion={{ preset: "fade-up" }}
>
Hello
</h1> Stagger
Cascading reveals, zero effort
Wrap a container with stagger() and each
child animates with an automatic incremental delay. Perfect for grids, lists, and cards.
Single observer
One IntersectionObserver manages all elements on the page. No per-element setup needed.
8 built-in presets
From subtle fades to directional slides. Extend with registerPreset() for custom animations.
Reduced motion
Automatically respects prefers-reduced-motion. Elements reveal instantly without animation.
Zero runtime deps
No external libraries at runtime. Pure IntersectionObserver + CSS keyframes.
SSR-ready
Works with server-rendered HTML, static pages, and any framework's SSR output.
Smooth scroll
Optional Lenis integration for buttery smooth scrolling as a peer dependency.
Philosophy
Not a scroll engine.
A reveal system.
viewmotion doesn't try to be GSAP or Framer Motion. It deliberately solves one problem: revealing elements as they enter the viewport with performant, composable CSS animations.
There's no scroll-driven timeline. No spring physics. No animation orchestration. Just battle-tested browser APIs assembled into a clean, minimal package.
The result is a library that ships under 2 KB gzipped, installs in seconds, and delivers the 90% of scroll animations that landing pages actually need.
Animations use CSS transforms & opacity — GPU-composited, never blocking the main thread.
Respects prefers-reduced-motion automatically.
No user opt-out required.
Standard CSS classes & data attributes. Inspect in DevTools like any other element.
Import only what you use. Add custom presets with registerPreset().
Comparison
Smaller. Simpler.
No compromises.
viewmotion is built for the 90% of scroll animations landing pages actually need. Not a swiss-army knife — a precision tool.
| Feature | viewmotion | AOS.js | Animate.css | GSAP ST |
|---|---|---|---|---|
| Bundle size | < 2 KB | ~ 14 KB | ~ 80 KB | ~ 67 KB |
| Zero dependencies | ✓ | ✓ | ✓ | ✗ |
| SSR safe | ✓ | ⚠ Partial | ✓ | ⚠ Partial |
| Framework adapters | ✓ | ✗ | ✗ | Partial |
| prefers-reduced-motion | Automatic | Manual | Manual | Manual |
| Custom presets API | ✓ | ✗ | ✗ | ✓ |
| Stagger support | ✓ | ✗ | ✗ | ✓ |
| TypeScript support | ✓ | Partial | ✗ | ✓ |
Bundle sizes from Bundlephobia. GSAP ST = ScrollTrigger plugin.
Start animating today.
Three lines of code. Zero config. Instant scroll-reveal animations that work with any framework or plain HTML.