Animations
Apply rich motion using built-in aliases like fade-in, scale-in, or spin, then customize timing and keyframe variables directly in markup.
Setup
Maple generates the necessary CSS animation properties automatically. However, built-in animations like fade-in, slide-in-up, spin, or shake require matching CSS @keyframes rules to execute. To use them, include the companion keyframes.css stylesheet in your document head before loading maple.js.
<head>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@f12io/maple/dist/keyframes.css"
/>
<script src="https://cdn.jsdelivr.net/npm/@f12io/maple/dist/maple.js"></script>
</head> The Fast Path
fade-in-up. Use individual utilities like animdur-900 when you need to override a property. Use anim-* when you need a custom animation shorthand: anim-scale-in_500_ease-out_300_both. Define variables like --animdur-fade-in-up=900ms on a parent to customize timing across an entire scope. Mental Model
Animation classes answer two questions: which keyframes should run, and how should the browser run them? Aliases answer both at once using Maple defaults, while shorthand utilities let you define custom recipes explicitly. To tune motion, use property overrides for individual elements, scoped overrides for entire sections, or keyframe variables to control spatial distance and scale. Finally, combine these with state and media selectors to activate motion only in response to user actions or responsive preferences.
fade-in-upReach for this first. It is readable and uses Maple defaults.
anim-fade-in-up_500_ease_bothUse when name, duration, easing, delay, or fill mode differ.
fade-in-up animdur-900Use when a preset is right but one property needs tuning.
--animdur-fade-in-up=900msUse fallback chain variables on a parent or element to tune animations across a scope.
--fade-distance=96pxUse keyframe variables to customize spatial properties like distance, scale, or angle.
&:hover:fade-in-upUse selectors to run motion only for hover, focus, or parent state.
@motion-safe:fade-in-upUse media queries to run motion based on screen sizes, dark mode, or motion preferences.
Animation Aliases
Aliases are named shortcuts that expand to complete anim-* shorthands. They keep common UI motion readable while still letting you override any part with variables or individual utilities.
For example, the fade-in alias expands to the shorthand anim-fade-in_600_ease-out_forwards. One-shot animations (such as entrances and exits) use the forwards fill mode so the element retains its final animated state. By default, entrance aliases resolve to 600ms ease-out and exit aliases to 200ms ease-in. Looping aliases run infinitely, while attention presets execute once so they can be cleanly triggered on state selectors (e.g., hover or active states).
fade-infade-outfade-in-upfade-in-downfade-in-leftfade-in-rightfade-out-upfade-out-downfade-out-leftfade-out-rightMessages, panels, menus, and soft entrance motion.
scale-inscale-outPopovers, badges, dialogs, and pressed feedback.
slide-in-upslide-in-downslide-in-leftslide-in-rightslide-out-upslide-out-downslide-out-leftslide-out-rightDrawers, sheets, toasts, and off-canvas elements.
spinpingpulsebouncefloatborder-beamLoading indicators, status lights, and ambient feedback.
shakeshake-xshake-ybeatbellwiggleValidation errors, hints, and temporary emphasis.
Use the interactive playground below to select any built-in animation alias, trigger its motion, and copy the ready-to-use HTML class name.
Fade Entrance fade-in <!-- Opacity-only entrance for content that is already in place. -->
<div class="fade-in">Motion preview</div> Looping presets such as ping, pulse, and spin repeat infinitely by default, making them ideal for activity indicators, loading spinners, or ambient UI states:
<!-- Ping -->
<div class="square-24 fxrow-cc rel">
<span class="abs square-14 rad-% bgc-coral-400/25 wc-tf,o ping"></span>
<span class="square-8 rad-% bgc-coral-500"></span>
</div>
<!-- Pulse -->
<div class="square-24 fxcol-cc g-2">
<span class="w-9/12 h-3 rad-2 bgc-azure-500 wc-o pulse"></span>
<span class="w-6/12 h-3 rad-2 bgc-azure-300 wc-o pulse"></span>
</div>
<!-- Bounce -->
<div class="square-24 fxrow-cc rel">
<span class="square-10 rad-% bgc-teal-500 wc-tf bounce"></span>
<span class="abs w-12 h-1 b-5 rad-% bgc-teal-500/20"></span>
</div>
<!-- Spin -->
<div class="square-24 fxrow-cc">
<div class="square-10 rad-% br-2px_solid_crimson-500 brtc=transparent wc-tf spin"></div>
</div>
<!-- Border Beam -->
<div class="square-24 fxrow-cc">
<div class="square-10 rad-2 bgc-blue-500/20 c-blue-600border-beam"></div>
</div>
Shorthand Syntax
The anim-* utility maps to CSS animation property. Separate shorthand parts with underscores. Maple classifies each token by meaning, so the class can stay compact while still producing a complete animation declaration.
animation-namefade-in-upanimation-duration600, 500ms, 1sanimation-delay150, 0.2sanimation-timing-functionlinear, ease-outanimation-iteration-countinfinite, 3fill / direction / play-stateboth, alternate, paused
<!-- name + duration + easing + fill mode -->
<div class="anim-fade-in-up_500_ease-out_both">Panel</div>
<!-- name + duration + easing + delay + fill mode -->
<div class="anim-scale-in_300_ease-out_150_both">Popover</div>
<!-- multiple animations separated with a comma -->
<span class="anim-fade-in_300_ease-out_forwards,spin_1000_linear_infinite">
Loading
</span>
Custom Keyframes
Maple writes animation declarations, not keyframes. For product-specific motion, define normal CSS @keyframes, reference the name with anim-*, and optionally create a custom alias on html. Put variables with fallbacks inside your keyframes when the same motion should be tunable per element.
<style>
@keyframes slide-intro {
from {
opacity: 0;
transform: translateY(var(--slide-y, 10px));
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
<!-- Use the keyframe name directly -->
<div class="anim-slide-intro_500_ease-out">Hello</div>
<!-- Or define an alias on html for cleaner markup -->
<html class="--alias-intro=anim-slide-intro_500_ease-out">
<div class="@intro">Hello</div>
</html>
Custom Timing
Built-in aliases use a simple timing model: entrances run at 600ms ease-out, while exits run at 200ms ease-in. Override a single element with animdur-* or animdel-*. Override a scope with shared variables like --animdur, --animdel or the named ones such as --animdur-fade-in-up and --animdel-fade-in-up.
<!-- A: Default preset timing -->
<div class="fade-in-up">Default</div>
<!-- B: Override with property utilities -->
<div class="fade-in-up animdur-900 animdel-300">Property override</div>
<!-- C: Override scope with shared variables -->
<div class="--animdur=1200ms --animdel=400ms">
<div class="fade-in-up">Scoped timing for all animations</div>
</div>
<!-- D: Override scope with named variables -->
<div class="--animdur-fade-in-up=1500ms --animdel-fade-in-up=500ms">
<div class="fade-in-up">Scoped timing specific to fade-in-up</div>
</div>
Keyframe Variables
Several animations expose variables inside the keyframes themselves. This lets you keep the same animation name while changing the distance, scale, opacity, or angle for a specific component. These variables change what the keyframes do, while animdur-* and friends change how the keyframes run.
--fade-from-opacity--fade-to-opacity0 / 1 Starting and ending opacity values. Used by fade-in, fade-out, fade-in-*, fade-out-*
--fade-distance48px Distance the element travels during the fade. Used by fade-in-*, fade-out-*
--fade-scale-from--fade-scale-to0.98 Starting and ending scale factor during the fade. Used by fade-in-*, fade-out-*
--slide-distance100% Distance the element travels during the slide. Used by slide-in-*, slide-out-*
--scale-from-opacity--scale-to-opacity0 / 1 Starting and ending opacity values. Used by scale-in, scale-out
--scale-from0.96 Starting scale factor. Used by scale-in
--scale-to0.96 Ending scale factor. Used by scale-out
--ping-scale2 Maximum scale factor. Used by ping
--pulse-opacity0.5 Minimum opacity value. Used by pulse
--bounce-distance25% Maximum vertical displacement. Used by bounce
--float-distance8px Maximum vertical displacement. Used by float
--beam-core-color--beam-glow-colorcurrentColor Core stroke and surrounding glow colors. Used by border-beam
--beam-tail-start75% Gradient start position for the fading tail. Used by border-beam
--beam-glow-start88% Gradient start position for the surrounding glow. Used by border-beam
--beam-core-start92% Gradient start position for the bright core stroke. Used by border-beam
--beam-glow-end96% Gradient end position for the surrounding glow. Used by border-beam
--beam-width1px Stroke width of the border outline. Used by border-beam
--beam-offset0px Displacement offset relative to the border box. Used by border-beam
--beam-radiusinherit Border radius of the border outline. Used by border-beam
--beam-opacity1 Overall opacity of the border outline. Used by border-beam
--shake-distance10px Displacement distance of the shake oscillation. Used by shake, shake-x, shake-y
--beat-scale1.12 Maximum scale factor of the expansion. Used by beat
--bell-angle10deg Maximum rotation angle of the swing. Used by bell
--bell-origintop center Transform origin point for the rotation. Used by bell
--wiggle-angle6deg Maximum rotation angle of the tilt. Used by wiggle
<!-- Move farther before fading in -->
<div class="--fade-distance=96px fade-in-up"></div>
<!-- Start from a smaller scale -->
<div class="--scale-from=0.3 scale-in"></div>
<!-- Increase the ping radius -->
<span class="--ping-scale=3.5 ping"></span>
<!-- Bounce higher -->
<div class="--bounce-distance=45% bounce"></div>
Triggered Animations
Animation utilities work with Maple selectors, so motion can be attached to hover, focus, active, parent state, media query, and child selectors.
<!-- Runs "shake" when hovered -->
<button class="&:hover:shake">Shake</button>
<!-- Runs "wiggle" when parent is hovered over button -->
<button class="parent">
<span class="^.parent:hover:wiggle">Wiggle</span>
</button>
<!-- Runs "beat" when focused to parent -->
<button class="parent">
<span class="^.parent:focus:beat">Beat</span>
</button>
Individual Utilities
Individual animation utilities map directly to CSS animation properties. Use them when an alias is almost right but one part of the animation needs to change, or when you are composing your own animation from a custom keyframe name.
anim-*animationanim-fade-inFull CSS animation shorthand.
animname-*animation-nameanimname-spinReferences an existing keyframe name.
animdur-*animation-durationanimdur-500Numbers resolve as milliseconds.
animdel-*animation-delayanimdel-200Use for staggered entrance motion.
animtf-*animation-timing-functionanimtf-ease-in-outAccepts named CSS timing functions.
animic-*animation-iteration-countanimic-infiniteUse finite counts for attention effects.
animdir-*animation-directionanimdir-alternateUseful for oscillating loops.
animfm-*animation-fill-modeanimfm-bothUse both when delayed entrances should apply their first keyframe before they start.
animps-*animation-play-stateanimps-pausedPause or resume loops from selectors.
<!-- Compose a spinner from individual properties -->
<span class="animname-spin animdur-1200 animtf-linear animic-infinite">
Loading
</span>
<!-- Override parts of a preset -->
<div class="fade-in-up animdur-900 animdel-200 animfm-both">
Delayed entrance
</div>
<!-- Pause and resume animation play state -->
<div class="pulse animps-paused &:hover:animps-running">
Hover to resume
</div>
Accessibility and Performance
Good UI motion is brief, purposeful, and cheap for the browser to render. Prefer opacity and transform animations, respect reduced-motion preferences, and reserve infinite motion for real progress or live status.
Gate non-essential motion with @motion-safe: or remove it with @motion-reduce:anim-none.
Use one motion idea per interaction. Avoid chaining attention effects, long loops, and competing animated regions.
Prefer transform and opacity. Avoid animating layout properties like width, height, margin, top, and left for frequent motion.
Use wc-tf,o only on elements that are about to animate. Remove broad or permanent hints from large surfaces.
<!-- Respect people who prefer less motion -->
<div class="@motion-safe:fade-in-up">
Motion only when safe
</div>
<!-- Prefer transform and opacity, and scope will-change narrowly -->
<div class="fade-in-up wc-tf,o">
Fast for the browser to composite
</div>
<!-- Use transition and transform for simple UI feedback -->
<button class="ts-tf_150 &:hover:scale-1.05">
Transition instead of animation
</button>
Practical Examples
The smoothest animation work happens when motion supports a specific UI job. These examples combine aliases, timing utilities, state selectors, and keyframe variables into product patterns you can copy directly.
Modal Confirmation
Use a quiet scale-in for surfaces that appear above the page.
Animated Notifications
Use fade-in-down animation for messages that appear on top of the content.
Live Sync Card
Use looped motion for ongoing work, then stagger small status rows as new sync steps complete.
Related Properties
Refer to the underlying CSS properties for granular animation control. Maple also supports newer animation properties such as animation composition and animation range utilities where the browser supports the underlying CSS.