navius

Micro

Attention and ambient keyframe animations that play on an element directly, rather than riding the discrete presence-state attributes: a validation shake, a live-status pulse, a shimmer sweep, a focus-glow ring. One preset table (MicroPresets) feeds both the generated CSS classes and the runtime handle, so the two tiers animate identically.

Live status
Focus glow

The four presets

Shake is one-shot: trigger it on an event and it plays once. The other three loop until stopped. Values are inky and restrained by design: distances in a few pixels, colours driven by neutral CSS variables (one-ink, no hue).

Preset Feel Shot Duration / easing CSS vars
ShakeA quick decaying left/right nudge that ends exactly at identity.One-shot450ms, cubic-bezier(0.36, 0.07, 0.19, 0.97)-
PulseA gentle breathing of opacity and scale, for a live-status dot or similar.Loop1600ms, ease-in-out-
ShimmerA translucent one-ink highlight sweeping across the element via background-position.Loop1600ms, linear--navius-motion-shimmer-tint
FocusGlowA hairline ring that pulses outward and fades.Loop1800ms, ease-out--navius-motion-glow-color, --navius-motion-glow-color-fade, --navius-motion-glow-ring

Shimmer and FocusGlow also carry a static base style (the gradient surface, the resting hairline ring) that is present whether or not the animation is playing, which is what their reduced-motion fallback rests on.

CSS tier

Add the class and it animates on its own. Shake replays only when the class is re-added (remount it, or use the runtime tier to trigger it on demand); the loops start immediately and run until removed.

Class Keyframes Runs
.motion-shakenavius-shakeOnce, on class add.
.motion-pulsenavius-pulseInfinite.
.motion-shimmernavius-shimmerInfinite.
.motion-focus-glownavius-focus-glowInfinite.

Motion has a matching splat for each, for zero-wrapper usage with @attributes.

Prop Type Default
Motion.Shake() IReadOnlyDictionary<string, object> motion-shake
Motion.Pulse() IReadOnlyDictionary<string, object> motion-pulse
Motion.Shimmer() IReadOnlyDictionary<string, object> motion-shimmer
Motion.FocusGlow() IReadOnlyDictionary<string, object> motion-focus-glow

Runtime tier

Bind CreateMicroAsync to get a MotionMicro handle: nothing runs until you call PlayAsync, and a looped preset keeps going until StopAsync. MotionPrograms.Micro converts a preset's keyframes to the WAAPI frames the executor plays, so the runtime animates with the exact same curve as the generated class.

Bind a micro preset to an element, built with MotionPrograms.Micro. Dispose the handle to stop it and release the JS reference.

Prop Type Default
CreateMicroAsync(ElementReference element, MicroOptions options) Task<MotionMicro> -
MotionPrograms.Micro(MicroPreset preset) MicroOptions -

The live binding. PlayAsync starts (or restarts) the animation; StopAsync cancels a running loop and returns the element to its natural style.

Prop Type Default
PlayAsync() Task Plays once (one-shot) or starts the loop (looping).
StopAsync() Task Cancels a running loop; the element returns to its natural style.
DisposeAsync() ValueTask Stops the animation and releases the JS handle.

Serialized to the executor (camelCase). Build it from a preset with MotionPrograms.Micro rather than by hand.

Prop Type Default
Keyframes IReadOnlyList<IReadOnlyDictionary<string, object>> -
DurationMs double -
Easing string "ease-in-out"
Loop bool false
ReduceMotion string "user"

Reduced motion

Every micro preset declares its own MicroReduce behaviour, honoured by both tiers under prefers-reduced-motion: reduce (CSS tier) or ReduceMotion (runtime tier, default "user").

Preset MicroReduce What is left
ShakeCollapseNothing plays, it never moves at all (transform-only, no base style).
PulseOpacityOnlyThe opacity beat continues (scale dropped); the live status still reads, non-vestibular.
ShimmerCollapseThe sweep stops, but the gradient base style remains: a static placeholder, not a blank box.
FocusGlowCollapseThe pulse stops, but the base hairline ring remains: the emphasis is kept, just not animated.

MicroReduce.Collapse means animation: none in the generated CSS: the element rests at its base style, which is empty for Shake and the gradient/ring for Shimmer and FocusGlow. MicroReduce.OpacityOnly swaps to a second, opacity-only @keyframes block generated alongside the main one, so the runtime tier strips every non-opacity property instead of switching keyframe sets, and reaches the same result.