Animations
CSS keyframes, timing functions, and multi-scene output to WebP / GIF / APNG.
Moved from /docs/keyframe-animation.
For animated image output, you have two APIs:
render()withtimeMsfor a single frame at a specific moment.renderAnimation()for a complete WebP / GIF / APNG.
For video output (MP4, high frame rate, ffmpeg pipelines), see Video Frames.
CSS @keyframes
Define a @keyframes rule inline or in a stylesheet; attach it with the animation shorthand.
import { } from "takumi-js/node";
import { } from "takumi-js/helpers/jsx";
const = new ();
const { , } = await (
< ="w-full h-full items-center justify-center">
<>{`
@keyframes slide {
from { transform: translateX(0); }
50% { transform: translateX(120px); }
to { transform: translateX(0); }
}
`}</>
< ="w-16 h-16 bg-blue-500 animate-[slide_2s_ease-in-out_infinite]" />
</>,
);
await .({
: 400,
: 200,
: 30,
: "webp",
,
: [{ : 2000, }],
});The structured form is equivalent and lives in the JS layer:
import { } from "takumi-js";
await (< ="animate-[slide_2s_ease-in-out_infinite]" />, {
: 400,
: 200,
: "png",
: 1000,
: {
: {
: { : "translateX(0)" },
"50%": { : "translateX(120px)" },
: { : "translateX(0)" },
},
},
});Stylesheet keyframes travel with the JSX tree; structured keyframes stay in user space. Pick whichever matches how your project is organized.
Timing functions
Standard CSS timing functions all work, including custom cubic-beziers and steps().
<div style={{ animation: "slide 2s ease-in-out infinite" }} />
<div style={{ animation: "slide 2s linear infinite" }} />
<div style={{ animation: "slide 2s cubic-bezier(0.32, 0, 0.67, 0) infinite" }} />
<div style={{ animation: "tick 1s steps(4, end) infinite" }} />steps() is the right pick for sprite-like animations where you want discrete frames; the cubic-bezier form covers anything the four named easings can't express.
Multi-scene animations
renderAnimation takes an array of scenes. Each scene is a node + a duration. Scenes play back to back; there is no transition between them — if you want a crossfade, render it as an animation inside one scene.
import { } from "takumi-js/node";
import { } from "takumi-js/helpers/jsx";
const = new ();
const = await (<Intro />);
const = await (<Main />);
const = await (<Outro />);
await .({
: 1200,
: 630,
: 30,
: "webp",
: [...., ...., ....],
: [
{ : 1000, : . },
{ : 3000, : . },
{ : 1000, : . },
],
});In most cases you'll keep a single scene and let CSS handle the motion. Reach for multiple scenes when the layout itself changes — different nodes, not just different transforms.
Tailwind animation utilities
These forms compile straight through to animation shorthand:
- Presets:
animate-none,animate-spin,animate-ping,animate-pulse,animate-bounce. - Arbitrary values:
animate-[slide_2s_ease-in-out_infinite_alternate]— underscores become spaces.
<div tw="w-12 h-12 bg-blue-500 animate-spin rounded" />
<div tw="w-12 h-12 bg-red-500 animate-[slide_2s_ease-in-out_infinite_alternate]" />animate-(--custom-property) is not supported — CSS custom property resolution for animation
shorthand is not implemented.
Format choice
| Format | Transparency | Compression | Animation length | Use for |
|---|---|---|---|---|
| Animated WebP | Yes | Best | Short / medium | Default. Modern browsers. |
| APNG | Yes | Good | Short / medium | Compatibility with older clients. |
| GIF | 1-bit only | Worst | Short | Email, embeds that reject WebP. |
Default to animated WebP unless you have a known consumer that doesn't accept it. For anything more than a few seconds at 30 fps, switch to video — see Video Frames.
Last updated on