# Particles

> Sparks, glints, fireworks, confetti, smoke, fountains and snow with Particles. Fire bursts from code, run streams while a prop is set, start from ready-made presets or your own, and shape how particles fly and change colour and size over their life.

`<Particles>` sends out particles in two ways:

- **Bursts**, fired from code: a sparkle when a coin is earned, confetti for a milestone, a firework.
- **Streams**, running while you want them: smoke from a chimney, a fountain, snow, a sparkler.

Between bursts they cost the CPU nothing, and the scene goes back to sleep once the last particle fades.

## A burst

```tsx title="Reward.tsx"
import { Box, Particles, type ParticlesHandle, Scene } from "@apricot/react";
import { useRef } from "react";

export function Reward() {
  const sparks = useRef<ParticlesHandle>(null);
  return (
    <Scene style={{ flex: 1 }} look="soft">
      <Box
        size={0.8}
        material="gold"
        onPress={() => sparks.current?.burst("sparkle", { at: [0, 0.6, 0] })}
      />
      <Particles ref={sparks} />
    </Scene>
  );
}
```

`burst(name, changes)` fires a ready-made burst, with your changes on top. `burst(options)` fires one of your own:

```ts
sparks.current?.burst("confetti", { at: [0, 1, 0], colors: ["#ff5a7a", "#ffd166"] });
sparks.current?.burst({ at: [0, 1, 0], count: 30, speed: [1, 2], spread: 45, life: 0.8, size: 0.05, gravity: 3 });
```

| Burst | Looks like |
| --- | --- |
| `"sparkle"` | Gold glints rising a little and fading: a coin, a reward |
| `"firework"` | A firework's shell bursting: sparks every way, slowing and falling |
| `"pop"` | A small pop: something placed, a button's reward |
| `"confetti"` | Paper confetti thrown up, fluttering down: a celebration |

## A stream

Set `emit` to run a stream; set it to `false` (or remove it) to stop. Changes to it follow as it runs.

```tsx title="Chimney.tsx"
import { EMITTERS, Particles } from "@apricot/react";

export const Chimney = ({ lit }: { lit: boolean }) => (
  <Particles emit={lit && { ...EMITTERS.smoke, at: [1.7, 1.6, -0.8] }} />
);
```

`emit` takes a name (`emit="snow"`) or options. Spread a ready-made stream from `EMITTERS` to change it, as above.

| Stream | Looks like |
| --- | --- |
| `"smoke"` | Soft grey smoke rising, spreading and drifting: a chimney, a campfire |
| `"fountain"` | Water thrown up and falling back |
| `"snow"` | Snow falling slowly over an area (give it `area`, and `at` above the ground) |
| `"sparkler"` | A sparkler's glints, thrown out and falling: hold it at the tip |

Streams can also be started from code: `ref.current.emit(name or options, changes)` returns an `Emitter`, with `set(options)` to change it as it goes (move it with `at`), `stop()` to end it (those already out finish their lives) and `running`.

```tsx title="Sparkler.tsx"
import { Particles, type ParticlesHandle, type Emitter } from "@apricot/react";
import { useEffect, useRef } from "react";

export function Sparkler({ tip }: { tip: [number, number, number] }) {
  const particles = useRef<ParticlesHandle>(null);
  const stream = useRef<Emitter | null>(null);
  useEffect(() => {
    stream.current = particles.current?.emit("sparkler", { at: tip }) ?? null;
    return () => stream.current?.stop();
  }, []);
  useEffect(() => {
    stream.current?.set({ at: tip });
  }, [tip]);
  return <Particles ref={particles} glow />;
}
```

## Shaping particles

Bursts and streams take the same options (streams have `rate` instead of `count`). A value written as a range `[min, max]` gives each particle a random value in it.

| Option | Default | Meaning |
| --- | --- | --- |
| `at` | `[0, 0, 0]` | Where they start, in the particles' own space |
| `area` | none | `[x, y, z]` size of a box round `at` they start anywhere in: snow over a garden, smoke off a fire |
| `count` | `40` | How many in a burst |
| `rate` | `20` | How many a second, for a stream |
| `colors` | `["#ffffff"]` | Each particle takes one |
| `fadeTo` | none | A colour they turn to over their life: embers cooling, smoke greying |
| `speed` | `[1, 2]` | How fast they fly out, metres per second |
| `direction` | `[0, 1, 0]` (up) | The way they fly |
| `spread` | `180` | Degrees round `direction` they spread: `180` is every way, `10` a narrow jet |
| `life` | `[0.6, 1.2]` | Seconds each lives |
| `size` | `0.05` | Metres |
| `grow` | `1` | Size at the end of its life against its start: `3` smoke spreading, `0` shrinking away |
| `spin` | `0` | Degrees per second. A range like `[-90, 90]` turns some one way, some the other |
| `shape` | `"dot"` | `"dot"`, a soft round dot, or `"square"`, a square that flutters as it turns, like paper |
| `gravity` | `0` | Pull down, metres per second². `9.8` is a dropped stone; below `0` they rise, like smoke |
| `wind` | `[0, 0, 0]` | A steady push, metres per second²: `[1, 0, 0]` is a breeze along x |
| `drag` | `0` | How quickly they slow in the air: `2`–`4` for a firework's sparks |

## How they look

| Prop | Default | Meaning |
| --- | --- | --- |
| `glow` | `false` | `true` adds them to what is behind, so they glow: fireworks at night. `false` draws them over it, which also shows on a light scene |
| `texture` | a soft dot | A picture each particle shows (a leaf, a star), tinted by its colour. Load it with `useTexture` |
| `max` | `1000` | The most alive at once. More reuse the oldest |

Plus `position`, `rotation` and `scale`, which move all of them (and `at` is in that space).

Leaves blown off a tree, with a picture of a leaf:

```tsx title="FallingLeaves.tsx"
import { Particles } from "@apricot/react";
import { useTexture } from "@apricot/react/model";

export function FallingLeaves() {
  const leaf = useTexture(require("./assets/leaf.png"));
  return (
    <Particles
      texture={leaf}
      emit={{
        rate: 6,
        at: [0, 3, 0],
        area: [2, 0.5, 2],
        colors: ["#d9822b", "#b5502a"],
        fadeTo: "#7a4a2a",
        speed: 0.2,
        direction: [0, -1, 0],
        life: [4, 6],
        size: 0.12,
        spin: [-90, 90],
        gravity: 0.6,
        wind: [0.4, 0, 0.1],
        drag: 1.5,
      }}
    />
  );
}
```

## Tips

- One `<Particles>` can fire many bursts and run several streams; use more than one when they need different `glow` or `texture`.
- Keep `<Particles>` **outside** a `<Bundle>`: their particles move every frame.
- Changing `max`, `glow` or `texture` makes a new set of particles (streams started from code start again). Keep them steady.

## Related

- [Particles reference](https://matthiasbrandolin.dev/apricot/reference/particles).
- [Falling objects](https://matthiasbrandolin.dev/apricot/guides/falling-objects): solid objects that bounce and pile up.
