Tween, keyframe and spring entities in Rust, awaiting their completion.
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.
| AnimateTarget | Behavior |
|---|---|
| position / rotation | Move to a Vec3; turn to a quat. |
| scale / color | Number or Vec3; CSS color or tuple. |
| moveBy | Offset from where the animation starts. |
| turn | Radians around x, y, z from the start; 2π spins once. |
| shake | Shakes the drawn position by up to this distance, fading. |
Sequence two steps
React and React Native · shared engine API
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] });}
A repeat: "forever" promise resolves only when stopped, replaced or despawned, so never await it.
| Option | Behavior |
|---|---|
| duration | Seconds; default 0.3; ignored by springs. |
| delay | Seconds before it starts; default 0. |
| easing | linear, easeIn, easeOut (default), easeInOut, back, bounce, elastic. |
| repeat | Extra runs after the first, or "forever"; default 0. |
| yoyo | Every other run plays backwards. |
| stagger | Extra delay per entity when animating several. |
| path | linear (default) or "smooth" curve through keyframes. |
| spring | true, "bouncy" or SpringOptions instead of a duration. |
Pulse and shake
React and React Native · shared engine API
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 });}
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
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" });}
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
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" });}
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.
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" });}
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
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);}