Overview

Mates motion splits into two layers: WAAPI presets (animationPresets) for enter/exit show-hide via animatedIf, animatedX, and animatedRouter; and CSS keyframes (keyframes()) that inject a named @keyframes rule and return a string for style.animation.

Presets are plain { keyframes, options } objects — swap them at runtime. Defaults on animatedIf are fade in 250ms / fade out 200ms when omitted.

Presets vs keyframes

API
Returns
Use with
animationPresets.* AnimationPreset animatedIf / animatedRouter config.
keyframes(name, stops) string (CSS name) style.animation / stylesheets.
animatedIf Directive See /docs/directives for the full conditional API.

Preset enter / exit

slideIn + fadeOut via animationPresets on animatedIf.

import { html, atom, animatedIf, animationPresets, nothing, renderApp } from 'mates';

const App = () => {
const show = atom(true);
return () => html`
<div class="m-col m-gap m-items-center center">
<button @click=${() => show.set(v => !v)}>
${show() ? 'Hide' : 'Show'}
</button>
${animatedIf(
show(),
html`<div class="card card-body p-20 center"><span>✨</span></div>`,
nothing,
{
enter: animationPresets.slideIn('up', '16px', 300),
exit: animationPresets.fadeOut(200),
},
)}
</div>
`;
};
renderApp(App, document.getElementById('app'));

CSS keyframes name

keyframes() returns a scoped animation name for inline style.animation.

import { html, atom, keyframes, renderApp } from 'mates';

const wobble = keyframes('wobble', {
'0%, 100%': { transform: 'rotate(0deg)' },
'25%': { transform: 'rotate(-6deg)' },
'75%': { transform: 'rotate(6deg)' },
});

const App = () => {
const on = atom(true);
return () => html`
<div class="m-col m-gap m-items-center center">
<button @click=${() => on.set(v => !v)}>Toggle</button>
${on()
? html`<div class="card card-body" style="animation:${wobble} 0.5s ease infinite">👋</div>`
: html`<p class="label">Off</p>`}
</div>
`;
};
renderApp(App, document.getElementById('app'));