Installation

SDS Motion Forge ships as one CSS file and two optional JS engines. The CSS is always required. The JS files are only needed for specific features — include only what you use.

CDN — no build step

Add the <link> to your <head>. Add the <script> tags before </body> only if you use those features.

HTML — <head>
<!-- ① ALWAYS REQUIRED — core CSS (600+ animations, ~39 KB gzip) -->
<link rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/@salkomdesignstudio/sds-motion-forge/dist/motion.min.css" />
HTML — before </body>
<!-- ② OPTIONAL — scroll engine (~0.6 KB gzip) -->
<!--   Add this ONLY if you use data-sds scroll-triggered animations -->
<script src="https://cdn.jsdelivr.net/npm/@salkomdesignstudio/sds-motion-forge/dist/sds-scroll.min.js"></script>

<!-- ③ OPTIONAL — interactive engine (~2.4 KB gzip) -->
<!--   Add this ONLY if you use cursor-reactive classes: -->
<!--   sds-word-morph · sds-magnetic-pull · sds-shockwave -->
<!--   sds-scatter-return · sds-spring-kerning · sds-repulsion-field -->
<script src="https://cdn.jsdelivr.net/npm/@salkomdesignstudio/sds-motion-forge/dist/motion-interactive.min.js"></script>

npm

$ npm install @salkomdesignstudio/sds-motion-forge
JS / TS — app entry file
// ① ALWAYS REQUIRED — import the core CSS
import '@salkomdesignstudio/sds-motion-forge/dist/motion.min.css';

// ② OPTIONAL — scroll engine (only for data-sds scroll animations)
import '@salkomdesignstudio/sds-motion-forge/dist/sds-scroll.min.js';

// ③ OPTIONAL — interactive engine (only for cursor-reactive classes)
import '@salkomdesignstudio/sds-motion-forge/dist/motion-interactive.min.js';

What gets installed

FileSize (gzip)When you need it
dist/motion.min.css~39 KB gzipAlways — core library, 600+ animations
dist/sds-scroll.min.js~0.6 KBWhen using data-sds scroll-gated animations
dist/motion-interactive.min.js~2.4 KBWhen using cursor-reactive animations (word-morph, magnetic-pull, shockwave…)
src/motion.css~366 KB rawCustom PostCSS builds only

Choose your setup

Pick the row that matches what you need — each one builds on the previous.

You want…Files to include
CSS-only animations (text, buttons, inputs, cards, loaders) motion.min.css only
Scroll-triggered animations (data-sds attribute) motion.min.css + sds-scroll.min.js
Cursor / hover interactive animations (word-morph, magnetic-pull, shockwave…) motion.min.css + motion-interactive.min.js
Everything motion.min.css + sds-scroll.min.js + motion-interactive.min.js

Full CDN setup (all features)

Copy this complete snippet into your <head> (and closing <body> tag) to enable every feature.
HTML — <head>
<!-- Step 1 · Core CSS — required for ALL animations -->
<link rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@salkomdesignstudio/sds-motion-forge/dist/motion.min.css" />
HTML — before </body>
<!-- Step 2 · Scroll engine — only if you use data-sds scroll animations -->
<script src="https://cdn.jsdelivr.net/npm/@salkomdesignstudio/sds-motion-forge/dist/sds-scroll.min.js"></script>

<!-- Step 3 · Interactive engine — only if you use cursor-reactive animations -->
<!--         (sds-word-morph, sds-magnetic-pull, sds-shockwave, sds-scatter-return…) -->
<script src="https://cdn.jsdelivr.net/npm/@salkomdesignstudio/sds-motion-forge/dist/motion-interactive.min.js"></script>

Quick Start

Copy this complete template into any HTML file — it includes the CSS and both optional JS engines. Delete the script tags you don't need.

HTML — complete setup
<!DOCTYPE html>
<html lang="en">
<head>
  <!-- ① REQUIRED — core CSS (600+ animations, ~39 KB gzip) -->
  <link rel="stylesheet"
        href="https://cdn.jsdelivr.net/npm/@salkomdesignstudio/sds-motion-forge/dist/motion.min.css" />
</head>
<body>

  <!-- your HTML with animation classes -->
  <h1 class="sds-velvet-drop">Hello World</h1>
  <button class="sds-btn-magnetic">Click me</button>
  <input  class="sds-input-voltage" placeholder="Type here" />
  <span   class="sds-loader-orbital"></span>
  <div    class="sds-card-float">Card</div>

  <!-- ② OPTIONAL — scroll engine (~0.6 KB gzip) -->
  <!--   Needed only when using data-sds scroll-triggered animations -->
  <script src="https://cdn.jsdelivr.net/npm/@salkomdesignstudio/sds-motion-forge/dist/sds-scroll.min.js"></script>

  <!-- ③ OPTIONAL — interactive engine (~2.4 KB gzip) -->
  <!--   Needed for: sds-word-morph  sds-magnetic-pull  sds-shockwave -->
  <!--               sds-scatter-return  sds-spring-kerning  sds-repulsion-field -->
  <script src="https://cdn.jsdelivr.net/npm/@salkomdesignstudio/sds-motion-forge/dist/motion-interactive.min.js"></script>

</body>
</html>

npm import (JS / TS projects)

JS / TS — app entry file
// ① Required — import CSS once
import '@salkomdesignstudio/sds-motion-forge/dist/motion.min.css';

// ② Optional — scroll engine
import '@salkomdesignstudio/sds-motion-forge/dist/sds-scroll.min.js';

// ③ Optional — interactive engine (word-morph, magnetic-pull, shockwave…)
import '@salkomdesignstudio/sds-motion-forge/dist/motion-interactive.min.js';
Rule of thumb: start with the CSS only. Add sds-scroll.min.js when you use data-sds attributes. Add motion-interactive.min.js only when you use cursor-reactive classes (they show a Needs JS badge in the live gallery).

Framework Integration

Import the CSS once in your entry file. No component, no wrapper, no setup beyond that.

JSX — _app.js / layout.tsx
import '@salkomdesignstudio/sds-motion-forge/dist/motion.min.css';

// Then use className anywhere:
<h1 className="sds-grand-entrance">Hello React</h1>
JS — main.js / main.ts
import '@salkomdesignstudio/sds-motion-forge/dist/motion.min.css';

<!-- template -->
<h1 class="sds-zoom-punch">Hello Vue</h1>
SCSS — styles.scss
@import '@salkomdesignstudio/sds-motion-forge/dist/motion.min.css';

<!-- or add to angular.json → architect.build.options.styles -->
<!-- template -->
<h1 class="sds-door-open">Hello Angular</h1>
Svelte — +layout.svelte
<script>
  import '@salkomdesignstudio/sds-motion-forge/dist/motion.min.css';
</script>

<h1 class="sds-elastic-bounce">Hello Svelte</h1>
HTML — Tailwind + Motion Forge
<!-- Classes never conflict — all SDS classes are prefixed sds- -->
<button class="px-6 py-3 rounded-full bg-blue-600 text-white sds-btn-plasma">
  Tailwind + Motion
</button>

<div class="rounded-xl shadow-lg p-6 sds-card-levitate">
  Ambient float
</div>
CSS — PostCSS source import
/* Import the source into your PostCSS pipeline */
@import '@salkomdesignstudio/sds-motion-forge/src/motion.css';

Text Animations 104

Apply to any element containing text. Animations are CSS @keyframes — they fire once on load unless a loop modifier is added.

HTML
<h1 class="sds-velvet-drop">Soft drop-in with blur</h1>
<p  class="sds-liquid-rise">Fluid upward reveal</p>
<span class="sds-grand-entrance">Combined combo entrance</span>
<span class="sds-refract sds-loop">RGB split loop</span>

All 104 text animation classes

Physics per-character animations

These 9 classes animate each character individually using the --i CSS variable as a stagger index. Each character must be wrapped in a <span class="sds-char" style="--i:N">.

Auto-split: Load motion-interactive.min.js once and these classes will split text automatically — no manual span markup needed.
HTML — manual char split
<h1 class="sds-drop-settle">
  <span class="sds-char" style="--i:0">H</span>
  <span class="sds-char" style="--i:1">e</span>
  <span class="sds-char" style="--i:2">l</span>
  <span class="sds-char" style="--i:3">l</span>
  <span class="sds-char" style="--i:4">o</span>
</h1>

For sds-explode-formation, add per-character displacement variables:

HTML — explode-formation
<span class="sds-explode-formation">
  <span class="sds-char" style="--i:0;--dx:-60px;--dy:-40px;--dr:-30deg">S</span>
  <span class="sds-char" style="--i:1;--dx:20px;--dy:-60px;--dr:45deg">D</span>
  <span class="sds-char" style="--i:2;--dx:70px;--dy:-20px;--dr:-20deg">S</span>
</span>

Button Animations 100

Apply directly to <button> or <a> elements. Effects are ambient — no hover or click required.

HTML
<button class="sds-btn-magnetic">Magnetic pulse</button>
<button class="sds-btn-aurora">Aurora border</button>
<button class="sds-btn-hologram">Hologram flicker</button>

All 100 button classes

Input Animations 100

State-based effects for <input> and <textarea> elements. Some trigger on :focus, others run continuously as ambient loops.

HTML
<input class="sds-input-focus"        placeholder="Focus glow" />
<input class="sds-input-voltage"     placeholder="Voltage pulse" />
<input class="sds-input-shake"       placeholder="Shake on error" />
<input class="sds-input-glow-border" placeholder="Animated glow border" />

Floating label wrappersds-input-elevate-wrap requires a specific DOM structure:

HTML — floating label
<div class="sds-input-elevate-wrap">
  <label for="email">Email address</label>
  <input id="email" type="email" placeholder=" " />
</div>

All 100 input classes

Card Animations 100

Entry and ambient effects for card and container elements.

HTML
<div class="sds-card-float">Ambient float</div>
<div class="sds-card-holo">Holographic tilt</div>
<div class="sds-card-levitate">Levitate with depth shadow</div>

Eight classes animate direct child elements and require children to be visible:

HTML — stagger cards
<div class="sds-card-stagger">
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
</div>
<!-- also: sds-card-cascade, sds-card-slice, sds-card-accordion-in,
     sds-card-checker, sds-card-fan-spread, sds-card-layers, sds-card-reveal-stack -->

All 100 card classes

Loader Animations 100

Add a class to an empty <span>. The animation is built entirely with CSS pseudo-elements — no child elements needed for most loaders.

HTML — self-contained
<span class="sds-loader-orbital"></span>
<span class="sds-loader-fluid"></span>
<span class="sds-loader-arc"></span>
<span class="sds-loader-skeleton"></span>

Sixteen loaders animate direct child elements and require children:

HTML — loaders with children
<!-- Wave: 5 bars -->
<div class="sds-loader-wave">
  <span></span><span></span><span></span><span></span><span></span>
</div>

<!-- Dots: 3 dots -->
<div class="sds-loader-dots">
  <span></span><span></span><span></span>
</div>

<!-- Grid: 9 items (3×3) -->
<div class="sds-loader-grid">
  <span></span><!-- ×9 -->
</div>

<!-- sds-loader-cascade and sds-loader-signal: variable children -->

All 100 loader classes

Scroll Animations 100

Scroll animation classes fire immediately when applied. Gate them on viewport entry using one of three methods.

Method 1 — JS scroll engine (recommended, works everywhere)

Load sds-scroll.min.js once. Add data-sds to any animated element. The engine adds sds-play on viewport entry.

HTML
<script src="dist/sds-scroll.min.js" defer></script>

<!-- Plays once on first entry -->
<div data-sds class="sds-scroll-rise">Rises on scroll</div>

<!-- Replays every time element re-enters the viewport -->
<div data-sds data-sds-repeat class="sds-scroll-spring">Replays on re-entry</div>

<!-- Wait 300ms after viewport entry -->
<div data-sds data-sds-delay="300" class="sds-scroll-blur">Delayed</div>
AttributeRequiredEffect
data-sdsYesGates animation until viewport entry. Script adds sds-play when element enters.
data-sds-repeatNoRemoves sds-play on exit so the animation replays on every re-entry.
data-sds-delay="N"NoWait N milliseconds after entering the viewport before adding sds-play.

Method 2 — Inline IntersectionObserver (paste-once, zero dependencies)

HTML
<div data-sds-scroll class="sds-scroll-rise">Content</div>

<script>
// Paste once per page — activates all [data-sds-scroll] elements
(function(){
  var io = new IntersectionObserver(function(es){
    es.forEach(function(e){
      if(e.isIntersecting){
        e.target.classList.add('sds-in');
        io.unobserve(e.target);
      }
    });
  }, { threshold: 0.08, rootMargin: '0px 0px -40px 0px' });
  document.querySelectorAll('[data-sds-scroll]').forEach(function(el){ io.observe(el); });
})();
</script>

Method 3 — CSS scroll-driven (Chrome / Edge 115+, zero JS)

HTML
<div class="sds-scroll-auto sds-scroll-rise">Zero JS, animates via CSS scroll-driven API</div>
Browser support: Chrome / Edge 115+ only. Other browsers see the element in its final visible state — graceful degradation, no JS error.

Stagger scroll animations (need children)

HTML
<div data-sds class="sds-scroll-stagger-pop">
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
</div>
<!-- also: sds-scroll-stagger-grid, sds-scroll-cascade -->

All 100 scroll classes

Interactive Animations

Load motion-interactive.min.js once. Add a class. Zero JavaScript from you — the engine auto-wires all listeners, physics loops, and cleanup.

HTML — load engine
<script src="dist/motion-interactive.min.js" defer></script>
ClassTriggerEffectOptions
sds-word-morphAuto (interval)Cycles through data-words with blur/translatedata-words="A,B,C" required
sds-jelly-hovermouseenterSquash + stretch spring
sds-scatter-returnmouseenter / mouseleaveChars scatter, spring back on leave
sds-shockwaveclickRadial impulse force from click point
sds-spring-kerningmousemoveMouse X → letter-spacing −12px…+12px
sds-magnetic-pullmousemoveCursor attracts each character spandata-sds-radius="N" (default 110)
sds-repulsion-fieldmousemoveCursor pushes each character span awaydata-sds-radius="N" (default 110)
HTML — examples
<h2 class="sds-word-morph" data-words="Fast,Beautiful,Precise">Fast</h2>
<h2 class="sds-magnetic-pull" data-sds-radius="140">Magnetic</h2>
<h2 class="sds-shockwave">Click for shockwave</h2>
<span class="sds-scatter-return">Hover to scatter</span>

SPA / dynamic content API

After inserting new elements into the DOM, call these to initialize or clean up:

JS
// Scan a container for new interactive elements
window.SDSInteractive.scan(containerElement);

// Initialize a single element manually
window.SDSInteractive.initEl(element);

// Remove all listeners / intervals (call before removing element)
window.SDSInteractive.cleanup(element);

Modifiers

Stack any modifier on any animation class. All SDS classes are sds- prefixed — they never conflict with your existing CSS.

HTML — stacking examples
<span class="sds-velvet-drop sds-slow sds-delay-3">Slow, delayed</span>
<span class="sds-refract sds-loop sds-alt">Alternating loop</span>
<span class="sds-neon-flare sds-loop sds-xslow sds-pause-hover">Pauses on hover</span>
ClassEffect
sds-fast0.5× duration (half speed)
sds-normal1× duration (reset to default)
sds-slow1.6× duration
sds-xslow2.2× duration
sds-delay-10.1s start delay
sds-delay-20.2s start delay
sds-delay-30.3s start delay
sds-delay-40.4s start delay
sds-delay-50.5s start delay
sds-delay-60.6s start delay
sds-delay-80.8s start delay
sds-delay-101.0s start delay
sds-loopInfinite iteration
sds-altAlternating direction each loop
sds-oncePlay once, stop in final state
sds-fill-bothHold both first and last keyframe
sds-fill-forwardHold last keyframe after completion
sds-pause-hoverPause animation when element is hovered
Note: sds-delay-7 and sds-delay-9 do not exist — the sequence steps 6 → 8 → 10 to match 0.6s, 0.8s, 1.0s timing intervals.

Stagger & Children Animations

Some animation classes target direct child elements (> *) rather than the element itself. These produce no visible effect without children.

CategoryClasses requiring child elements
Textsds-kinetic-wave, sds-arc-orbit, sds-signal-wave, sds-stagger-chars
Text (physics)sds-gravity-bounce, sds-drop-settle, sds-wave-cascade, sds-center-burst, sds-explode-formation
Cardssds-card-cascade, sds-card-slice, sds-card-stagger
Loaderssds-loader-cascade, sds-loader-dots, sds-loader-grid, sds-loader-signal, sds-loader-wave
Scrollsds-scroll-stagger-pop, sds-scroll-stagger-grid, sds-scroll-cascade

For char-split text animations (physics + wave), wrap each character in a span with class="sds-char" and a --i custom property:

HTML
<h1 class="sds-kinetic-wave">
  <span class="sds-char" style="--i:0">M</span>
  <span class="sds-char" style="--i:1">o</span>
  <span class="sds-char" style="--i:2">t</span>
  <span class="sds-char" style="--i:3">i</span>
  <span class="sds-char" style="--i:4">o</span>
  <span class="sds-char" style="--i:5">n</span>
</h1>
Auto-split: Load motion-interactive.min.js — it automatically splits text into sds-char spans for all the above classes. Screen reader accessibility is preserved with aria-label on the parent.

Theming

Override CSS custom properties to match your brand. Changes propagate to every animation that uses that variable.

CSS — global override
:root {
  --sds-primary:      #0015d1;   /* Brand colour — glows, gradients, text effects */
  --sds-primary-dim:  rgba(0, 21, 209, 0.08);
  --sds-primary-glow: rgba(0, 21, 209, 0.30);
  --sds-accent:       #d10028;   /* Accent / error colour */
  --sds-success:      #00c48c;   /* Success colour */
  --sds-duration:     0.8s;      /* Base animation duration */
  --sds-easing:       cubic-bezier(0.22, 1, 0.36, 1);
}

Scope to a specific section — changes only affect animations inside that container:

CSS — scoped override
.hero {
  --sds-primary:      #7c3aed;
  --sds-primary-glow: rgba(124, 58, 237, 0.35);
  --sds-duration:     1.2s;
}

TypeScript & Autocomplete

The package ships a complete index.d.ts with typed unions for every class. Full autocomplete in VS Code, WebStorm, and any TypeScript-aware editor.

Exported typeClasses
SdsTextAnimation104 text animation classes
SdsButtonAnimation100 button animation classes
SdsInputAnimation100 input animation classes
SdsCardAnimation100 card animation classes
SdsLoaderAnimation100 loader animation classes
SdsScrollAnimation100 scroll animation classes
SdsInteractiveAnimation7 JS-engine animation classes
SdsModifier18 modifier classes
SdsScrollGatesds-play, sds-scroll-auto
SdsAnimationClassUnion of all the above
TypeScript — utility function
import type { SdsTextAnimation, SdsModifier } from '@salkomdesignstudio/sds-motion-forge';

function anim(base: SdsTextAnimation, ...mods: SdsModifier[]): string {
  return [base, ...mods].join(' ');
}

const cls = anim('sds-velvet-drop', 'sds-slow', 'sds-delay-2');
// → 'sds-velvet-drop sds-slow sds-delay-2'
TypeScript — React component
import type { SdsButtonAnimation } from '@salkomdesignstudio/sds-motion-forge';

interface ButtonProps {
  animation?: SdsButtonAnimation;
  children: React.ReactNode;
}

export function Button({ animation = 'sds-btn-magnetic', children }: ButtonProps) {
  return <button className={animation}>{children}</button>;
}

Accessibility

Motion Forge respects prefers-reduced-motion automatically across all three layers. No configuration required.

LayerBehavior under prefers-reduced-motion: reduce
CSS coreAll animations collapse to 0.01ms — elements immediately reach their final state
Scroll gatesds-play added immediately to all [data-sds] elements — no observer delay
Interactive engineTransitions and physics loops skipped; static final state shown
sds-word-morphStill cycles words but skips blur/translate — instant word swap

Screen reader support: The interactive engine's text splitter sets aria-label on the parent element to preserve the full readable text, then marks each <span class="sds-char"> with aria-hidden="true".

Browser Support

The core library targets all modern browsers. IE 11 is not supported.

FeatureSupport
Core CSS animations (@keyframes)Chrome 80+, Firefox 78+, Safari 14+, Edge 80+
clip-path animationsAll targets — -webkit- prefixed via autoprefixer
backdrop-filterChrome 76+, Firefox 103+, Safari 9+ (with -webkit-)
Scroll gate data-sdsIntersectionObserver — all modern browsers
CSS scroll-driven (sds-scroll-auto)Chrome / Edge 115+ only — graceful fallback (element visible, animation skipped)
Interactive engineWeakMap + MutationObserver — all modern browsers
IE 11Not supported

Contributing

SDS Motion Forge is MIT-licensed and open to contributions. Here is how to get involved.

Reporting a bug

Open an issue and include: the affected class name(s), what you expected, what actually happened, your browser and version, and a minimal reproduction (HTML snippet or CodePen).

Requesting an animation

Open an issue with the label animation-request and describe the motion effect with a reference (gif, video, or live demo link).

Local development setup

BASH
git clone https://github.com/salkomdesignstudio/SDS-Motion-Forge.git
cd SDS-Motion-Forge
npm install

Available scripts

CommandWhat it does
npm run buildBuild CSS + JS engines for production
npm run build:cssBuild CSS only (PostCSS → cleancss)
npm run build:jsBuild JS engines only (terser + source maps)
npm run build:devBuild CSS with source maps for development
npm run build:watchWatch CSS and rebuild on save
npm run build:verifyRun the 8-stage pre-publish verification gate
npm run release:checkFull check: build + verify + publint + pack

Adding a new animation

  • All CSS animations live in src/motion.css
  • Class naming: sds-[descriptive-name] — lowercase, hyphenated
  • Keyframe naming: sds-camelCaseName matching the class (e.g. .sds-velvet-drop@keyframes sds-velvetDrop)
  • Use --sds-duration and --sds-easing in the animation shorthand
  • Add will-change: transform, opacity for GPU-composited animations
  • The global prefers-reduced-motion block handles reduced motion automatically
  • Use animation-fill-mode: both so the element holds its pre-animation state

After adding a CSS animation: add the class to REQUIRED_CLASSES and the @keyframes name to REQUIRED_KEYFRAMES in verify-build.js, and add the TypeScript type to the appropriate union in index.d.ts.

Submitting a PR

  • Fork the repo and create a branch: git checkout -b feat/my-animation
  • Make changes in src/ — never edit files in dist/ directly
  • Run npm run build to regenerate dist artifacts
  • Run npm run build:verify — all 8 checks must pass
  • Open a PR against main with a description of what the animation does

Changelog

A detailed changelog is maintained in the repository.

View CHANGELOG.md on GitHub

Current: v5.0.0

  • 245 new animation effects — every category now ships exactly 100 effects (Text: 104, Buttons: 100, Inputs: 100, Cards: 100, Loaders: 100, Scroll: 100)
  • v5 motion token scale — --sds-duration-* and --sds-ease-* design tokens (W3C format)
  • Lossless category split — import only the categories you use
  • 600+ animation classes typed in index.d.ts
  • 100% prefers-reduced-motion coverage including child-driven animations
  • Interactive engine: cursor-reactive physics (magnetic, shockwave, scatter, repulsion)
  • New package exports for React, Web Components, and Tailwind

Previous: v4.0.3

  • Fixed critical rootMargin crash in sds-scroll.min.js
  • Completed TypeScript types — all 177 animation classes typed
  • Fixed gallery accessibility (keyboard navigation, aria labels)
  • JS engine sizes: sds-scroll −20%, motion-interactive −25%

See the full changelog →