ng-motion is an Angular 21 animation library built on motion-dom. It is designed to feel familiar if you already know Framer Motion: the same core ideas (initial, animate, exit, variants, layout, motion values, imperative animate()), but expressed with Angular directives, DI providers, and injection-context hooks.
The project is still pre-1.0. The core API is already usable, but some advanced areas may still change.
- Getting Started
- Core Motion
- Motion Values
- Gestures
- Presence
- Layout
- Scroll
- Reorder
- Imperative Animation
- Advanced APIs
- API Reference
- Contributors
import { Component, signal, type WritableSignal } from '@angular/core';
import { NgmMotionDirective, type TargetAndTransition, type Transition } from '@scripttype/ng-motion';
@Component({
selector: 'app-demo',
standalone: true,
imports: [NgmMotionDirective],
template: `
<button
ngmMotion
[initial]="{ opacity: 0, y: 16 }"
[animate]="open() ? openState : closedState"
[whileHover]="hoverState"
[whileTap]="tapState"
[transition]="transition"
(click)="open.set(!open())"
>
Toggle me
</button>
`,
})
export class DemoComponent {
readonly open: WritableSignal<boolean> = signal(true);
readonly openState: TargetAndTransition = { opacity: 1, y: 0 };
readonly closedState: TargetAndTransition = { opacity: 0.6, y: 8 };
readonly hoverState: TargetAndTransition = { scale: 1.04 };
readonly tapState: TargetAndTransition = { scale: 0.96 };
readonly transition: Transition = { type: 'spring', stiffness: 320, damping: 24 };
}If you know Framer Motion, the mapping is straightforward:
motion.div-> a normal Angular element withngmMotionAnimatePresence->*ngmPresenceLayoutGroup->ngmLayoutGroupuseMotionValue,useSpring,useTransform,animate()-> same names, same jobLazyMotion-style feature loading ->provideMotionFeatures(...)
- Keep the Angular layer thin. Physics, layout projection, and animation state live in
motion-dom. - Use Angular
signal()andcomputed()for application state and declarative animation choices. - Keep high-frequency animation data in
MotionValues. - Use Angular signals for application state, not for every animation frame.
- Drive directive inputs from
signal()andcomputed()bindings when state is reactive. - Prefer declarative APIs first; use imperative APIs when orchestration is the real requirement.