Taos API Reference
    Preparing search index...

    Type Alias ModifierNode

    ModifierNode:
        | { type: "gravity"; strength: number }
        | { type: "drag"; coefficient: number }
        | { type: "force"; direction: [number, number, number]; strength: number }
        | { type: "swirl_force"; speed: number; strength: number }
        | { type: "vortex"; strength: number }
        | {
            type: "curl_noise";
            scale: number;
            strength: number;
            timeScale: number;
            octaves?: number;
        }
        | {
            type: "turbulence";
            scale: number;
            strength: number;
            timeScale: number;
            octaves?: number;
        }
        | {
            type: "wind";
            direction: [number, number, number];
            strength: number;
            turbulence: number;
            scale: number;
            timeScale: number;
        }
        | {
            type: "point_attractor";
            position: [number, number, number];
            space: ModifierSpace;
            strength: number;
            radius: number;
        }
        | {
            type: "radial_force";
            center: [number, number, number];
            space: ModifierSpace;
            strength: number;
        }
        | { type: "speed_limit"; max: number }
        | { type: "size_random"; min: number; max: number }
        | { type: "size_over_lifetime"; start: number; end: number }
        | {
            type: "size_by_speed";
            speedMin: number;
            speedMax: number;
            sizeMin: number;
            sizeMax: number;
        }
        | { type: "rotation_rate"; rate: number }
        | { type: "rotation_over_lifetime"; start: number; end: number }
        | {
            type: "color_over_lifetime";
            startColor: [number, number, number, number];
            endColor: [number, number, number, number];
        }
        | { type: "alpha_over_lifetime"; start: number; end: number }
        | {
            type: "box_color";
            min: [number, number, number];
            max: [number, number, number];
            space: ModifierSpace;
        }
        | { type: "velocity_color" }
        | {
            type: "bounds_kill";
            min: [number, number, number];
            max: [number, number, number];
            space: ModifierSpace;
        }
        | {
            type: "plane_collision";
            center: [number, number, number];
            normal: [number, number, number];
            space: ModifierSpace;
            bounce: number;
            friction: number;
            kill: boolean;
        }
        | {
            type: "sphere_collision";
            center: [number, number, number];
            radius: number;
            space: ModifierSpace;
            bounce: number;
            friction: number;
            kill: boolean;
            dynamic?: boolean;
        }
        | {
            type: "block_collision";
            bounce: number;
            friction: number;
            kill: boolean;
            stick?: boolean;
        }
        | { type: "sdf_attractor"; strength: number; offset: number }
        | {
            type: "sdf_collision";
            bounce: number;
            friction: number;
            kill: boolean;
        }
        | { type: "expression"; graph: ExpressionGraph
        | ExprNodeGraph }
        | { type: "sdf_stick"; threshold?: number }

    Per-frame behavior applied to live particles in the update compute pass.

    Type Declaration

    • { type: "gravity"; strength: number }

      Constant downward acceleration applied to velocity.y.

    • { type: "drag"; coefficient: number }

      Exponential velocity damping: v -= v * coefficient * dt each step.

    • { type: "force"; direction: [number, number, number]; strength: number }

      Constant directional acceleration along direction scaled by strength.

    • { type: "swirl_force"; speed: number; strength: number }

      Time-rotating XZ acceleration; speed sets rotation rate, strength the magnitude.

    • { type: "vortex"; strength: number }

      Solid-body rotation in XZ around the emitter — tangential force grows with radius.

    • {
          type: "curl_noise";
          scale: number;
          strength: number;
          timeScale: number;
          octaves?: number;
      }

      Divergence-free turbulent flow (FBM curl noise). scale is spatial frequency, timeScale drifts the field, octaves (≥1) sums frequencies for richer detail.

    • {
          type: "turbulence";
          scale: number;
          strength: number;
          timeScale: number;
          octaves?: number;
      }

      Plain vector noise — cheaper than curl_noise but not divergence-free (particles may collect into sinks). Useful for jitter/chaos.

    • {
          type: "wind";
          direction: [number, number, number];
          strength: number;
          turbulence: number;
          scale: number;
          timeScale: number;
      }

      Directional force whose strength is modulated by low-frequency noise, giving gusts. turbulence in [0,1] mixes constant vs. noise-modulated strength.

    • {
          type: "point_attractor";
          position: [number, number, number];
          space: ModifierSpace;
          strength: number;
          radius: number;
      }

      Pulls particles toward position with linear falloff to zero at radius. space chooses between absolute world coords and an offset from the emitter origin.

    • {
          type: "radial_force";
          center: [number, number, number];
          space: ModifierSpace;
          strength: number;
      }

      Pushes particles outward from center (negative strength = pull inward). space chooses between absolute world coords and an offset from the emitter origin.

    • { type: "speed_limit"; max: number }

      Clamps |velocity| to max; useful to cap runaway accumulation from forces.

    • { type: "size_random"; min: number; max: number }

      Per-particle stable random size in [min, max] — same slot always gets the same size.

    • { type: "size_over_lifetime"; start: number; end: number }

      Interpolates particle size from startend over the particle's lifetime.

    • {
          type: "size_by_speed";
          speedMin: number;
          speedMax: number;
          sizeMin: number;
          sizeMax: number;
      }

      Maps |velocity| in [speedMin, speedMax] to size in [sizeMin, sizeMax]; out-of-range clamps.

    • { type: "rotation_rate"; rate: number }

      Constant angular velocity (radians/sec) added to sprite rotation each frame.

    • { type: "rotation_over_lifetime"; start: number; end: number }

      Interpolates sprite rotation (radians) from startend over lifetime.

    • {
          type: "color_over_lifetime";
          startColor: [number, number, number, number];
          endColor: [number, number, number, number];
      }

      Interpolates RGBA color from startColorendColor over lifetime.

    • { type: "alpha_over_lifetime"; start: number; end: number }

      Interpolates only the alpha channel over lifetime — cheaper than a full color curve.

    • {
          type: "box_color";
          min: [number, number, number];
          max: [number, number, number];
          space: ModifierSpace;
      }

      While the particle is inside the box [min, max], sets its RGB to the normalized position within the box (each axis mapped to 0..1). Alpha is preserved. Particles outside the box are left unchanged. space chooses between absolute world coords and an offset from the emitter origin.

    • { type: "velocity_color" }

      Sets RGB to normalize(abs(velocity)) — each channel is the fraction of the velocity's magnitude carried by that axis. Alpha is preserved. Particles with zero velocity are left unchanged.

    • {
          type: "bounds_kill";
          min: [number, number, number];
          max: [number, number, number];
          space: ModifierSpace;
      }

      Kills particles that leave the axis-aligned bounding box [min, max]. space chooses between absolute world coords and an offset from the emitter origin (the box is translated as a whole; its axes stay world-aligned).

    • {
          type: "plane_collision";
          center: [number, number, number];
          normal: [number, number, number];
          space: ModifierSpace;
          bounce: number;
          friction: number;
          kill: boolean;
      }

      Half-space collider: a plane through center with the given normal. Particles on the negative-normal side are pushed back to the surface. If kill is true the particle dies on contact and bounce/friction are ignored; otherwise bounce in [0,1] is the coefficient of restitution along the normal and friction in [0,1] damps the tangential component. space chooses how center is interpreted; normal is always a direction.

    • {
          type: "sphere_collision";
          center: [number, number, number];
          radius: number;
          space: ModifierSpace;
          bounce: number;
          friction: number;
          kill: boolean;
          dynamic?: boolean;
      }

      Spherical collider: particles inside the sphere are pushed out and reflected. bounce / friction / kill semantics match plane_collision. space chooses how center is interpreted.

      • type: "sphere_collision"
      • center: [number, number, number]
      • radius: number
      • space: ModifierSpace
      • bounce: number
      • friction: number
      • kill: boolean
      • Optionaldynamic?: boolean

        When true the collider's center + radius are read from a per-frame uniform (set via ParticlePass.setSphereCollider) instead of being baked in as constants, so the sphere can move at runtime to track e.g. a physics body. center / radius here seed the initial value; radius 0 disables it.

    • {
          type: "block_collision";
          bounce: number;
          friction: number;
          kill: boolean;
          stick?: boolean;
      }

      Heightmap collider. Three contact modes, checked in order:

      • kill: true — particle dies on contact (fires on_death + splits).
      • stick: true — particle freezes in place for the rest of its life: velocity is stored as a unit-length "impact direction" and the PARTICLE_FLAG_STUCK flag is set. The update loop then skips movement/force modifiers and the sprite renderer reorients the quad to face that direction (snow settling on terrain).
      • default — bounces off the surface treating it as a (0,1,0) ground plane; bounce/friction follow plane_collision semantics.

      Requires the particle pass to bind a heightmap (handled automatically when this modifier is present). kill takes precedence over stick.

    • { type: "sdf_attractor"; strength: number; offset: number }

      Pulls particles toward the surface of the bound ParticleGraphConfig.sdf. Uses the SDF gradient as the attraction direction and the signed distance as a per-step pull magnitude, so particles converge onto the surface and slow down as they near it. offset shifts the target surface outward (positive) or inward (negative) in world units — useful for "halo" hovering or for negative SDF effects.

    • { type: "sdf_collision"; bounce: number; friction: number; kill: boolean }

      SDF collider for the bound ParticleGraphConfig.sdf. Particles whose sampled distance is negative (inside the surface) are pushed back along the gradient with the same bounce / friction / kill semantics as plane_collision.

    • { type: "expression"; graph: ExpressionGraph | ExprNodeGraph }

      Runs an expression graph as a modifier. Accepts either the compact AST form (ExpressionGraph from particle_expr.ts) or the flat node-graph form (ExprNodeGraph from particle_expr_graph.ts); the two are disambiguated structurally ('actions' in graph vs 'nodes' in graph) and both lower to the same WGSL. Use the AST form when hand-coding for brevity; use the node-graph form when constructing from the visual editor or when callers want to preserve the explicit wiring for visualization. Order in the surrounding modifiers list matters: an expression placed after gravity sees the updated velocity, etc.

    • { type: "sdf_stick"; threshold?: number }

      Sticks particles to the bound ParticleGraphConfig.sdf surface on contact. When the particle's signed distance falls to threshold or below (default 0 = strictly inside), the particle is snapped onto the surface along the SDF gradient and its velocity is zeroed. Run after sdf_attractor and integration-affecting modifiers (gravity, drag, noise) in the modifier list so the snap wins for the frame; with velocity pinned at zero, the next integration step keeps the position at the surface, so stuck particles stay stuck for the rest of their lifetime. Other modifiers (color/size over lifetime) continue to apply. Use a small positive threshold (e.g. 0.005) to grab fast-moving particles that would otherwise tunnel past the surface in a single step.