Effects, particles and the cleared-piece pop

Fire ready-made effects in one call, or shape your own particles with world.burst.

Ready-made effects

Import effects and call one function per event; each layers a few bursts (big slow pieces, small fast ones, a glow, lingering puffs) that move, fade and clean up in Rust. Particles advance with the world, so they pause with the game.

Every particle takes a world slot, so size the World's capacity for the busiest moment. Effects throw on a disposed world: check world.isDisposed in callbacks that can run late.

Ready-made effects reference
CallUse it for
effects.confetti(world, options)Wins and level-ups: tumbling paper, glints, a pop of light.
effects.sparkle(world, options)Pickups and perfect moves: bright beads and glints.
effects.shatter(world, options)Bricks, crates, glass: chunks, crumbs, a glow and dust.
effects.splash(world, options)Water, juice, paint: droplets and mist.
effects.sparks(world, options)Scrapes, strikes, electricity: hot streaks and beads.
effects.explosion(world, options)Flash, fireball cooling to smoke, embers and optional debris.
effects.dust(world, DustOptions)Soft swelling puffs: landing dust, sand, steam. Returns the count.
effects.flash(world, FlashOptions)One swelling glow: hits, strikes, muzzle flashes. Returns the count.
effects.pop(world, entity, PopOptions)A cleared piece swells, flashes white and shrinks away. Returns a Promise.
effects.hot(color, peak = 2.2, alpha?)The same hue made self-lit, for glows.
effects.pale(color, t, alpha?)The color moved part way (t, 0..1) toward white.
effects.POP_TIMEDefault pop duration: 0.5 seconds.

Celebrate a win and reward a pickup

React and React Native · shared engine API

Celebrate a win and reward a pickup
import { effects, type Vec3, type World } from "@nayan-ui/engine";
export function celebrate(world: World, position: Vec3) {
effects.confetti(world, {
position, colors: ["#FF4D4D", "#FFD933", "#3399FF"],
size: 0.12, speed: 6, count: 40, lifetime: 1.2, gravity: -6,
});
}
export function collect(world: World, position: Vec3) {
effects.sparkle(world, { position, colors: "#FFD933", size: 0.08, speed: 3, count: 14, lifetime: 0.6 });
}

EffectOptions

confetti, sparkle, shatter, splash, sparks and explosion share EffectOptions; position, colors, size, speed, count and lifetime are required, except colors for explosion. Sizes are world units, speeds units per second and times seconds.

EffectOptions reference
OptionMeaning
positionWhere the effect starts.
colorsOne CSS color or tuple, or several picked at random.
size / speedTypical particle size; top speed.
countAbout how many particles; a few extra go to the glow and puffs.
lifetimeSeconds.
gravityVertical acceleration; negative falls. Default 0.
direction / spreadMain direction (default up); cone half-angle (default π, all directions).
flashA brief glow at the source. Default true.
shatter: mesh / dustChunk shape (default "cube"); dust: false skips the puff.
explosion: debris / smokeColors of flying chunks; smoke color. size is the fireball's puff size.

Break, splash, scrape and blow up

React and React Native · shared engine API

Break, splash, scrape and blow up
import { effects, type EffectOptions, type Vec3, type World } from "@nayan-ui/engine";
const water: Omit<EffectOptions, "position"> = {
colors: "rgba(77, 153, 255, 0.9)", size: 0.1, speed: 4, count: 24, lifetime: 0.8, gravity: -9.8,
};
export const splashAt = (world: World, position: Vec3) => effects.splash(world, { ...water, position });
export function breakCrate(world: World, position: Vec3) {
effects.shatter(world, { position, colors: ["#8B5A2B", "#6B4220"], size: 0.2, speed: 5, count: 16,
lifetime: 0.7, gravity: -9.8, mesh: "cube" });
}
export function scrape(world: World, position: Vec3, away: Vec3) {
effects.sparks(world, { position, colors: "orange", size: 0.05, speed: 8, count: 20, lifetime: 0.4,
direction: away, spread: 0.5, gravity: -6 });
}
export function blowUp(world: World, position: Vec3) {
effects.explosion(world, { position, size: 0.6, speed: 6, count: 40, lifetime: 1,
debris: ["#4D4D52"], smoke: "rgba(50, 50, 50, 0.6)" });
}

Dust puffs and flashes

effects.dust makes soft puffs that swell and fade; gravity defaults to 0 so dust hangs, and positive values rise like smoke. effects.flash draws one glow at a point; channels above 1 glow, most easily via effects.hot(color).

Dust puffs and flashes reference
OptionMeaning
positionRequired by both.
dust: colorStart color (alpha is thickness), or several. Required.
dust: size / speed / count / lifetimeRequired: puff size, top speed, puffs, seconds.
dust: direction / spread / gravityDefault up, π and 0 (positive rises).
dust: endSize / endColorGrowth by the end (default 2); end color (default: faded).
dust: meshDefault "puff" (blended); "flame" adds light.
flash: color / sizeRequired. Channels above 1 glow.
flash: lifetime / endSizeDefaults 0.22 seconds and 2.2.
flash: endColorDefault: color faded to transparent.
flash: meshDefault "flame" (additive); "sphere" or "puff" for solid or soft.
flash: count / speedGlows drawn (default 1), scattered when speed > 0 (default 0).

Landing dust, a hit flash and steam

React and React Native · shared engine API

Landing dust, a hit flash and steam
import { effects, type Vec3, type World } from "@nayan-ui/engine";
export function landed(world: World, feet: Vec3) {
effects.dust(world, { position: feet, color: "rgba(204, 191, 166, 0.6)", size: 0.3, speed: 1.5, count: 6, lifetime: 0.5 });
}
export function hit(world: World, at: Vec3) {
effects.flash(world, { position: at, color: effects.hot("#FF8000"), size: 0.8 });
}
export function steam(world: World, vent: Vec3) {
effects.dust(world, { position: vent, color: effects.pale("#99B3CC", 0.6, 0.4), size: 0.4, speed: 1,
count: 8, lifetime: 1.5, gravity: 1, endSize: 3 });
}

Pop a cleared piece

effects.pop(world, entity, options) swells a cleared, matched or collected piece, flashes it white, settles it and shrinks it to nothing, stopping any animation it had. It resolves when the piece is gone; despawn it then, with no guard needed since despawn is safe after dispose.

Pop a cleared piece reference
PopOptionsMeaning
scaleIts rest scale, a number or Vec3. Required.
colorRest color to return to after the white flash; omit to skip it.
flashChild entities (white at rest) to flash as well.
delaySeconds before it starts. Default 0.
durationSeconds. Default effects.POP_TIME (0.5).

Clear matched pieces in a wave

React and React Native · shared engine API

Clear matched pieces in a wave
import { effects, type ColorInput, type Entity, type World } from "@nayan-ui/engine";
export async function clearPieces(world: World, pieces: readonly Entity[], color: ColorInput) {
await Promise.all(pieces.map((piece, i) =>
effects.pop(world, piece, { scale: 1, color, delay: i * 0.05 }).then(() => world.despawn(piece))));
}

Custom particles with world.burst

Use world.burst(options) only when you need one plain layer under exact control; it spawns up to count particles in one native call and returns how many fit. Particles advance and expire with world.update.

The "puff" mesh is a soft camera-facing sprite that alpha-blends, and "flame" is the same sprite added to the scene, so overlaps build a bright core. Neither is solid or a light source, and shapeGeometry can't build them.

Custom particles with world.burst reference
BurstOptionsMeaning
positionOrigin. Required.
countParticles. Default 16.
direction / spreadMain direction, default up; cone half-angle, default π.
meshBuilt-in shape or Model. Default "cube".
size / speed / lifetimeDefaults 0.15 units, 5 units per second, 0.8 seconds.
gravityVertical acceleration. Default -9.81; 0 floats.
colorOne color, or up to four picked per particle. Default white.
endSizeEnd size as a multiple of the start; above 1 grows. Default 1.
endColorColor reached by the end; alpha below 1 fades out.

Smoke and sparks

React and React Native · shared engine API

Smoke and sparks
import type { Vec3, World } from "@nayan-ui/engine";
export function smokeAndSparks(world: World, position: Vec3) {
world.burst({ position, mesh: "puff", count: 18, color: "rgba(128, 128, 128, 0.5)", size: 0.3,
speed: 2, gravity: 0, lifetime: 1.5, endSize: 4, endColor: "rgba(50, 50, 50, 0)" });
// Glowing colors need channels above 1, so these are 0..1+ tuples.
return world.burst({ position, mesh: "flame", count: 28, direction: [0, 1, 0], spread: Math.PI / 2,
color: [[2, 1.2, 0.2], [2, 0.4, 0.1]], speed: 7, lifetime: 0.6, endSize: 0.1 });
}