@ds-gn/motion
v0.11.2
Published
Token-driven motion engine for the DS-GN Design System: timelines, sequencing, and enter/exit on the Web Animations API
Maintainers
Readme
@ds-gn/motion
Token-driven motion for the DS-GN Design System: timelines with overlap, staggered sequences, awaitable enter/exit animations, and viewport triggers, on the Web Animations API.
The core is framework-free and safe to import during server rendering. A Lit
controller ships as @ds-gn/motion/lit.
Public Beta · Website · Documentation · Changelog · Public repository
npm's Repository link points to our private build repository, which is required for Trusted Publishing. For examples and issue reporting, visit our public design-system repository.
Install
npm install @ds-gn/motion
pnpm add @ds-gn/motion
bun add @ds-gn/motionAnimate a dialog's backdrop independently with
enter(dialog, 'fade', { pseudoElement: '::backdrop' }). The option works on
exits, timelines, sequences and controller calls too. cancel(dialog) clears
both the dialog and its pseudo-elements.
lit is an optional peer dependency, needed only for @ds-gn/motion/lit.
Quick start
import * as motion from '@ds-gn/motion';
// Ordered steps; each starts `overlap` ms before the previous one ends.
motion.timeline([
{ el: heading, preset: 'slideUp', duration: 'moderate' },
{ el: asset, preset: 'fade', overlap: 200 },
{ el: cta, preset: 'scaleIn', overlap: 160 },
]);
// One preset across many elements, offset by a stagger.
motion.sequence(cards, { preset: 'slideUp', stagger: 60, maxDuration: 480 });
// Awaitable entrances and exits.
await motion.exit(panel, 'scaleIn');
panel.hidden = true;
// Run once when an element scrolls into view.
motion.inView(section, () => motion.sequence(cards, { preset: 'fade' }));
// Letter by letter: split, stagger, then restore the original text.
const split = motion.splitText(eyebrow);
motion
.sequence(split.chars, { preset: 'fade', y: 4, stagger: 30 })
.finished.then(split.revert);Named imports work the same way and keep bundles to what you use:
import { timeline } from '@ds-gn/motion'.
Lit
import { LitElement } from 'lit';
import { MotionController } from '@ds-gn/motion/lit';
class FeatureGrid extends LitElement {
motion = new MotionController(this);
firstUpdated() {
this.motion.inViewSequence('.card', { preset: 'slideUp', stagger: 40 });
}
}The controller resolves selectors against the host's shadow root, runs in-view motion once the host enters the viewport, and cancels everything when the host disconnects.
Presets
| Preset | Enter | Exit |
| --------- | ----------------------------- | ----------------------------- |
| slideUp | y 12px → 0, opacity 0 → 1 | y 0 → 8px, opacity 1 → 0 |
| fade | opacity 0 → 1 | opacity 1 → 0 |
| scaleIn | scale 0.96 → 1, opacity 0 → 1 | scale 1 → 0.96, opacity 1 → 0 |
The slideInLeft, slideInRight, slideInTop, and slideInBottom presets
move a sheet from/to its full width or height (translateX/Y(±100%)) without
fading. Under reduced motion they substitute a fade, so no empty keyframes or
spatial movement remain. Preset names describe the entrance; each includes
its matching exit, so exit(panel, 'slideInLeft') slides back to the left edge,
just as exit(panel, 'scaleIn') uses the scale preset's exit.
Entrances default to duration.moderate and ease.emphasized; exits to
duration.quick and ease.standard. Only transform and opacity animate.
Tokens
Durations and easings are named after the DS-GN motion tokens and resolve at runtime from the custom properties on the animated element:
| Name | Custom property | Fallback |
| ---------------------- | --------------------- | ------------------------------- |
| duration: 'quick' | --duration-quick | 180ms |
| duration: 'moderate' | --duration-moderate | 240ms |
| easing: 'emphasized' | --ease-emphasized | cubic-bezier(0.16, 1, 0.3, 1) |
| easing: 'standard' | --ease-standard | cubic-bezier(0.2, 0, 0, 1) |
A theme override from @ds-gn/tokens therefore applies automatically, including
one scoped to part of the page. This package does not depend on
@ds-gn/tokens; without its stylesheets the fallbacks apply. Raw milliseconds
and any CSS easing are accepted too.
Reduced motion
When the user prefers reduced motion, movement is dropped, delays, staggers
and overlaps collapse to 0, and everything cross-fades at duration.quick.
Pass reducedMotion: 'jump' to skip straight to the end state instead. Promises
resolve either way.
Package exports
| Export | Purpose |
| ------------------- | ------------------------------------------------------------------------------- |
| @ds-gn/motion | timeline, sequence, enter, exit, inView, splitText, presets, tokens |
| @ds-gn/motion/lit | MotionController for Lit hosts |
This table is the complete supported surface. Anything else inside dist is an
internal build artifact with no compatibility promise.
Versioning
@ds-gn/motion is 0.x and in Public Beta, released in lockstep with
@ds-gn/tokens and @ds-gn/ui. While it remains 0.x:
- The documented API is supported for evaluation and production trials, but may
change before
1.0. - Patch releases do not intentionally break documented APIs. Planned breaking changes ship in a minor release with migration guidance.
- A deprecated API remains available for at least one complete minor release and at least 90 days, whichever is longer, before removal. Security, legal, or broken-platform emergencies may require faster changes.
- Changing a preset's keyframes or a default duration or easing is a minor.
Support
Search or report package issues in the public issue tracker. For questions, email [email protected].
License
This package is available under the MIT License included in LICENSE.
Third-party materials included in the distribution remain subject to the
licenses listed in THIRD_PARTY_NOTICES.
