Animation and springs

Tween, keyframe and spring entities in Rust, awaiting their completion.

Animate and await

world.animate(targets, to, options?) runs in Rust and returns a promise that resolves when every part finishes, is replaced or stopped, or its entity or world goes. Resolution means it ended, not that it reached the target.

Each property runs on its own channel, so a piece can move while it pulses; animating a property again replaces only that one.

Animate and await reference
AnimateTargetBehavior
position / rotationMove to a Vec3; turn to a quat.
scale / colorNumber or Vec3; CSS color or tuple.
moveByOffset from where the animation starts.
turnRadians around x, y, z from the start; 2π spins once.
shakeShakes the drawn position by up to this distance, fading.

Sequence two steps

React and React Native · shared engine API

Sequence two steps
import type { Entity, World } from "@nayan-ui/engine";
export async function reveal(world: World, tile: Entity) {
await world.animate(tile, { scale: 1.15, color: "#FFCC4D" }, { duration: 0.2, easing: "back" });
await world.animate(tile, { scale: 1 }, { duration: 0.15 });
}
export function flip(world: World, card: Entity) {
return world.animate(card, { turn: [0, Math.PI, 0] });
}

AnimateOptions reference

A repeat: "forever" promise resolves only when stopped, replaced or despawned, so never await it.

AnimateOptions reference reference
OptionBehavior
durationSeconds; default 0.3; ignored by springs.
delaySeconds before it starts; default 0.
easinglinear, easeIn, easeOut (default), easeInOut, back, bounce, elastic.
repeatExtra runs after the first, or "forever"; default 0.
yoyoEvery other run plays backwards.
staggerExtra delay per entity when animating several.
pathlinear (default) or "smooth" curve through keyframes.
springtrue, "bouncy" or SpringOptions instead of a duration.

Pulse and shake

React and React Native · shared engine API

Pulse and shake
import type { Entity, World } from "@nayan-ui/engine";
export function pulse(world: World, coin: Entity) {
void world.animate(coin, { scale: 1.2 }, { duration: 0.5, repeat: "forever", yoyo: true, easing: "easeInOut" });
}
export function wrong(world: World, tile: Entity) {
return world.animate(tile, { shake: 0.15 }, { duration: 0.4, delay: 0.05 });
}

Keyframes and paths

Pass an array of up to 64 Keyframes to pass through values in order. Each may set at (0..1 of the duration; default evenly spaced), and path: "smooth" curves through them.

Hop

React and React Native · shared engine API

Hop
import type { Entity, World } from "@nayan-ui/engine";
export function hop(world: World, piece: Entity) {
return world.animate(piece, [
{ moveBy: [1, 1.5, 0], at: 0.5 },
{ moveBy: [2, 0, 0], at: 1 },
], { duration: 0.6, path: "smooth" });
}

Groups and stagger

Pass an array of entities to animate them together with one promise. stagger adds a delay per entity for waves and board reveals.

Reveal a board

React and React Native · shared engine API

Reveal a board
import type { Entity, World } from "@nayan-ui/engine";
export function revealBoard(world: World, tiles: readonly Entity[]) {
for (const tile of tiles) world.set(tile, { scale: 0 });
return world.animate(tiles, { scale: 1 }, { stagger: 0.03, easing: "back" });
}

Springs

spring replaces the duration with simulated motion: true (smooth, no overshoot), "bouncy" or { stiffness, damping, mass } (defaults 170, 26, 1). Interrupting a spring keeps its speed, so following a finger never jerks.

Follow the finger

React and React Native · shared engine API

Call on every drag move; each call retargets the running spring.

Follow the finger
import type { Entity, World } from "@nayan-ui/engine";
export function moveCursor(world: World, cursor: Entity, x: number, z: number) {
void world.animate(cursor, { position: [x, 0, z] }, { spring: { stiffness: 220, damping: 20 } });
}
export function landPiece(world: World, piece: Entity) {
return world.animate(piece, { scale: 1 }, { spring: "bouncy" });
}

Stop animations

stopAnimation(entity) stops every channel where it is and resolves their promises. Despawning or disposing does the same, so no guard is needed afterwards.

Stop a pulse on pickup

React and React Native · shared engine API

Stop a pulse on pickup
import type { Entity, World } from "@nayan-ui/engine";
export async function pickUp(world: World, coin: Entity) {
world.stopAnimation(coin);
await world.animate(coin, { scale: 0, moveBy: [0, 1, 0] }, { duration: 0.25 });
world.despawn(coin);
}