motionify
v1.0.0
Published
A tiny animation library for tweening any object, with React components and CSS animation presets
Maintainers
Readme
Overview
motionify is a tiny animation library for tweening any JavaScript object — plain objects,
DOM styles, three.js vectors, anything with numeric values. The core has zero dependencies
and does not require React. An optional React layer (motionify/react) adds hooks, a component,
and 98 ready-made CSS animation presets.
- Zero dependencies — the core is React-free and framework-agnostic
- Chainable API — every method returns the motion, so calls read as one sentence
- Nested & unit-aware —
{ position: { x: 5 } },'100px','50%'all work - Sequencing —
chain(),parallel(),repeat(),yoyo(), delays and callbacks - React —
useMotion()hook,<DivMotion>component, andcssMotion()presets
Runs in the browser — the core uses
window.requestAnimationFrame.
Installation
npm install motionifyReact features live in a subpath so the core stays dependency-free:
import { Motion, Easing } from 'motionify'
import { useMotion, DivMotion, cssMotion, cssPresets } from 'motionify/react'react is an optional peer dependency (>=19.1). You only need it for motionify/react.
Basic Usage
1) Tween any object
import { Motion, Easing } from 'motionify'
new Motion( mesh.position )
.action({ to: { x: 5, y: 2 }, duration: 1000, easing: Easing.Quadratic.Out })
.start()2) Sequence, repeat, yoyo
new Motion()
.action({ to: { x: 5 } }, mesh.position )
.action({ to: { y: Math.PI } }, mesh.rotation )
.repeat( 3 )
.yoyo( true )
.start()Actions run one after another by default. parallel(true) runs them at the same time.
3) Arrays as keyframes
// x: 5 → -5 → 0, while y goes 5 → 5 → 0 (in step)
new Motion( mesh.position )
.action({ to: { x: [ 5, -5, 0 ], y: [ 5, 5, 0 ] } })
.start()4) Waiting for completion
Every method returns the motion itself, start() included — so you can keep a reference
and control it later. To wait for the end, await the finished promise:
const motion = new Motion( mesh.position )
.action({ to: { x: [ 5, 0 ] } })
.repeat( 3 )
.start()
motion.stop() // ...later, from anywhere
await motion.finished // or: await motion.start().finishedAPI
new Motion( target?, action? )
| Method | Description |
|---|---|
| .target( obj ) | Sets the default target object |
| .action( action, obj? ) | Adds an action. obj overrides the default target |
| .parallel( bool ) | Run actions simultaneously instead of sequentially |
| .repeat( count ) | Repeat the whole sequence count more times |
| .yoyo( bool ) | Play forward, then reverse back to the start |
| .chain( ...motions ) | Queue other motions to run after this one |
| .start() | Start playing. Returns the motion; finished holds the promise |
| .stop() | Stop playing |
| .startDelay( ms ) | Wait before the first action |
| .repeatDelay( ms ) | Wait between repetitions |
| .completeDelay( ms ) | Wait before onComplete fires |
| .onStart( fn ) · .onUpdate( fn ) · .onRepeat( fn ) · .onComplete( fn ) | Callbacks |
Action options
| Option | Default | Description |
|---|---|---|
| to | the target itself | End values. Numbers, arrays (keyframes), nested objects, or non-numeric values (set at the end) |
| duration | 1000 | Milliseconds |
| easing | Easing.Linear.None | An easing function — built-in or your own t => number |
| relative | false | Treat to as an offset from the current value |
Easing
11 families, each with In, Out, and InOut (Linear also has None):
Linear · Quadratic · Cubic · Quartic · Quintic · Sinusoidal ·
Exponential · Circular · Elastic · Back · Bounce
easing: Easing.Bounce.Out
easing: t => Math.floor( t * 5 ) / 5 // custom easing works tooEasing.generatePow( power ) builds a family for any exponent (default 4):
const pow7 = Easing.generatePow( 7 )
easing: pow7.InOutReact
useMotion()
Returns a ref to attach to an element, and a motion() factory. Called with no argument,
motion() targets ref.current.
import { useMotion } from 'motionify/react'
function Box() {
const { ref, motion } = useMotion()
useEffect(() => {
motion( ref.current.style )
.action({ to: { width: [ '75vw', '100vw' ] } })
.start()
}, [])
return <div ref={ref}>Hello</div>
}<DivMotion>
A div that animates its own CSS on mount. Starting values are read from the computed style,
so you do not have to declare them. Any other prop (className, id, …) passes through.
<DivMotion
to={{ marginLeft: '50%', opacity: 0.5 }}
duration={2000}
easing={Easing.Quadratic.InOut}
>
<h2>Hello</h2>
</DivMotion>| Prop | Default | Description |
|---|---|---|
| to | — | CSS properties to animate (camelCase). Required; renders nothing without it |
| duration | 1000 | Milliseconds |
| easing | Easing.Linear.None | Easing function |
cssMotion()
Injects a preset's keyframes into the document and returns its class name.
<div className={ cssMotion({ name: 'bounceIn', duration: '2s' }) } />| Option | Default | Maps to |
|---|---|---|
| name | 'none' | animation-name — one of the 98 presets |
| duration | '0s' | animation-duration |
| timingFunction | 'ease' | animation-timing-function |
| delay | '0s' | animation-delay |
| iterationCount | '1' | animation-iteration-count |
| direction | 'normal' | animation-direction |
| fillMode | 'none' | animation-fill-mode |
| playState | 'running' | animation-play-state |
| timeline | 'auto' | animation-timeline |
CSS presets
98 presets ported from animate.css, in 16 groups:
| Group | Presets |
|---|---|
| Attention seekers | bounce flash headShake heartBeat jello pulse rubberBand shake shakeX shakeY swing tada wobble |
| Back entrances / exits | backIn* backOut* — Down Left Right Up |
| Bouncing entrances / exits | bounceIn bounceOut (+ Down Left Right Up) |
| Fading entrances / exits | fadeIn fadeOut (+ Down Left Right Up, *Big, and corners) |
| Flippers | flip flipInX flipInY flipOutX flipOutY |
| Lightspeed | lightSpeedInLeft lightSpeedInRight lightSpeedOutLeft lightSpeedOutRight |
| Rotating entrances / exits | rotateIn rotateOut (+ DownLeft DownRight UpLeft UpRight) |
| Sliding entrances / exits | slideIn* slideOut* — Down Left Right Up |
| Specials | hinge jackInTheBox rollIn rollOut |
| Zooming entrances / exits | zoomIn zoomOut (+ Down Left Right Up) |
Every name is available on cssPresets:
import { cssPresets } from 'motionify/react'
Object.keys( cssPresets ) // 'bounce', 'fadeInUp', 'zoomOutLeft', ...Contact
Questions, bug reports, and suggestions are welcome — open an issue or contact us at [email protected].
- Website: https://www.nova-graphix.com
- LinkedIn: https://www.linkedin.com/company/novagraphix/
- Facebook: https://www.facebook.com/NovaGraphixCo
- YouTube: https://www.youtube.com/@3D-novagraphix
