# ParticlesHandle

> Talos 0.7 · Since 0.6; changed in 0.7

Reached in a behaviour as `ctx.particles`.

## Signature

```ts
export interface ParticlesHandle {
  /**
   * One-shot emit of a preset at a point, with parameter overrides in `@argus/gameplay`'s `ParticleParams`
   * names: `rate`, `burst`, `lifetime` `[min, max]` s, `speed` `[min, max]` m/s, `size` `[start, end]` m,
   * `color` / `colorEnd` hex, `opacity` `[start, end]`, `gravity` (m/s² along -Y: positive falls), `drag`,
   * `spreadDeg`, `direction`, `blend` (`"alpha"` | `"additive"`), `spin` rad/s, `maxParticles`. Each key
   * applies on its own; one the engine does not take is logged once and ignored.
   */
  emit(preset: ParticlePreset, at: Vec3, params?: Record<string, unknown>): void
  /**
   * A one-shot instance of a particle effect (docs/VFX.md) at a point, removed when it has finished.
   * `effect` is a key of `scene.assets` whose kind is `"effect"`, or `"builtin:smoke"` (and the other
   * presets: `fire`, `sparks`, `dust`, `steam`, `drips`, `debris`, `glow`). `params` sets the effect's
   * declared params. An effect the scene did not load is ignored with a `particles-effect-unknown` warning.
   * @since 0.6.1
   */
  play(effect: string, at: Vec3, params?: Record<string, ParticleParamValue>): void
  /**
   * Sets a param of an effect instance: the calling entity's own `particles` component, or `target`'s
   * (an entity id or handle). Takes effect on the next tick. False (with a `particles-param-unknown`
   * warning, once) when there is no such instance, the effect declares no such param, or the value does
   * not fit its type.
   * @since 0.6.1
   */
  setParam(name: string, value: ParticleParamValue, target?: string | EntityHandle): boolean
  /**
   * Spawns `count` extra particles now on every emitter of an effect instance (the calling entity's, or
   * `target`'s), or only on the emitter named `emitter`, on top of its rate and bursts. Capped by each
   * emitter's capacity. False when there is no such instance or emitter.
   * @since 0.6.1
   */
  burst(count: number, target?: string | EntityHandle, emitter?: string): boolean
}
```

Import: `import type { ParticlesHandle } from "@argus/api"`

## Members

| Member | Signature | Description |
|---|---|---|
| `emit` | `emit(preset: ParticlePreset, at: Vec3, params?: Record<string, unknown>): void` | One-shot emit of a preset at a point, with parameter overrides in `@argus/gameplay`'s `ParticleParams` names: `rate`, `burst`, `lifetime` `[min, max]` s, `speed` `[min, max]` m/s, `size` `[start, end]` m, `color` / `colorEnd` hex, `opacity` `[start, end]`, `gravity` (m/s² along -Y: positive falls), `drag`, `spreadDeg`, `direction`, `blend` (`"alpha"` \| `"additive"`), `spin` rad/s, `maxParticles`. Each key applies on its own; one the engine does not take is logged once and ignored. |
| `play` | `play(effect: string, at: Vec3, params?: Record<string, ParticleParamValue>): void` | A one-shot instance of a particle effect (docs/VFX.md) at a point, removed when it has finished. `effect` is a key of `scene.assets` whose kind is `"effect"`, or `"builtin:smoke"` (and the other presets: `fire`, `sparks`, `dust`, `steam`, `drips`, `debris`, `glow`). `params` sets the effect's declared params. An effect the scene did not load is ignored with a `particles-effect-unknown` warning. @since 0.6.1 |
| `setParam` | `setParam(name: string, value: ParticleParamValue, target?: string \| EntityHandle): boolean` | Sets a param of an effect instance: the calling entity's own `particles` component, or `target`'s (an entity id or handle). Takes effect on the next tick. False (with a `particles-param-unknown` warning, once) when there is no such instance, the effect declares no such param, or the value does not fit its type. @since 0.6.1 |
| `burst` | `burst(count: number, target?: string \| EntityHandle, emitter?: string): boolean` | Spawns `count` extra particles now on every emitter of an effect instance (the calling entity's, or `target`'s), or only on the emitter named `emitter`, on top of its rate and bursts. Capped by each emitter's capacity. False when there is no such instance or emitter. @since 0.6.1 |

## Example

The tested fixture `fixtures/recipes/jump-pad-and-elevator/scenes/behaviors/camera-zone.ts`.

```ts
import type { Behavior } from "@argus/api"

/**
 * A trigger volume that retunes the camera while the player is inside it.
 *
 * The engine has no camera-zone concept and needs none: a volume, a `trigger` component and this.
 * Here the player's behaviour owns the camera (it re-sends its params when the view is turned), so
 * the zone tells it what to change rather than calling `ctx.camera.set` itself. In a scene where
 * nothing else writes the camera, the zone can call `ctx.camera.set(kind, params)` directly.
 */
interface Props {
  /** `ctx.camera.set` params to merge in on the way in, and on the way out. */
  inside?: Record<string, unknown>
  outside?: Record<string, unknown>
}

export default {
  onTrigger(ctx, trigger) {
    const params = trigger.entering ? ctx.props.inside : ctx.props.outside
    if (params) ctx.events.emit("camera-zone", { target: trigger.other.id, params })
  },
} satisfies Behavior<Record<string, never>, Props>
```
