Skip to content

Point Solver ​

One frame of particle physics: moves the particles it is given under gravity and any vector fields, ages and kills them, handles the comp boundary and collisions, and adds this frame's births from a Point Emitter. It lives inside a Solver, which carries the particles on to the next frame.

Category: Point Ops Menu path: Point Ops > Point Solver (builds the Solver around it)

A Point Solver always sits inside a Solver. The Point Solver moves the particles one frame; the Solver is what remembers them. Every frame, Solver In hands last frame's particles to points, the Point Solver moves them and adds the births arriving on emit, and the result goes to Solver Out — which hands it back to Solver In on the next frame. Picking Point Solver from the menu builds this for you, and so does adding a Point Emitter with auto-wire on.

Nodes placed after the Point Solver, inside the Solver, are rules that stick: a Select → Point Delete kills particles for good, a colour set on impact stays set. The same nodes placed after the Solver only change what is drawn on that frame.

A Point Solver outside a Solver shows a NO SOLVER badge: it still moves whatever it is given by one frame, but nothing carries the particles on, so they never get anywhere.

Ports ​

PortTypeDirectionDescription
pointspointsinputThe particles to move this frame — last frame's population, wired from Solver In. Points arriving without a life attribute get seedLife.
emitpointsinputRead every frame — whatever arrives is born. Normally a Point Emitter. A raw Grid here is a continuous curtain (a new copy of the grid every frame), which is legitimate if unusual.
forcesvectorField (multi-input)inputEvery connected field is summed. Fields are unit-less (−1 to 1); forceStrength converts the sum to acceleration. Connection order is the sum order (it does not matter).
collideshape (multi-input)inputShapes the particles collide with. Each collider is resolved in turn, not merged, so overlapping colliders each stay correct. Closed paths are solid; an open path is a thin wall you only hit through collideRadius. See Collision.
outpointsoutputThe live population, with velocity, age, life, stable ids and (Orient: Velocity) rotation.
diedpointsoutputThe particles removed this frame, at their final position and velocity, keeping the id they lived with. Each carries the groups diedOfAge, diedAtBoundary and diedOnCollision. See Death and secondary systems.

Parameters ​

ParamTypeDefaultDescription
gravityvec2, keyframeable0, 0Constant acceleration in px per second². Comp space is y-down, so (0, 800) pulls particles down the screen. The two axes are independent (not linked).
forceStrengthscalar, keyframeable500Converts the summed forces fields (−1 to 1) to px per second². One knob for all forces — scale an individual field with its own strength param or a Field Math node.
dragscalar, keyframeable0.05Fraction of velocity lost per second, 0–1, applied as (1 − drag)^dt. 0.05 is a gentle air; 0.5 is thick fluid; 1 stops everything immediately.
maxSpeedscalar, keyframeable0Speed cap in px per second. 0 = no cap.
substepsscalar1Integration steps per frame, 1–10. Raise it when a force field is tight or strong and particles start skipping through features.
boundaryenumNoneWhat happens at the comp rectangle: None, Kill (remove on exit), Bounce (reflect with bounce restitution), Wrap (exit one side, re-enter the other).
bouncescalar0.5Restitution for Bounce, 0–1. 1 keeps all speed on impact; 0 lands dead. Shown only in Bounce mode.
seedLifescalar0Life in frames given to points arriving on points without a life attribute — typically a Grid you started the Solver from. 0 = immortal.
killOnAgebooleanonOff: life is still written (so Age ramps keep working) but nothing dies of age — pair with a Kill boundary or the population grows forever.
orientenumNoneVelocity writes the rotation attribute (radians, the direction of travel) every frame — Clone To Points and Draw Instances then point each instance along its motion.
collideResponse (UI: "On Contact")enumBounceWhat contact does: Bounce (reflect, scaled by restitution), Slide (lose the into-surface motion, keep sliding), Stick (stop dead), Kill (remove). Hidden until a shape is wired to collide.
restitutionscalar, keyframeable0.40–1 bounciness against colliders. Distinct from bounce, which belongs to the comp-rect Boundary. Shown in Bounce only.
frictionscalar, keyframeable0.10–1 of the along-surface speed lost per contact. 0 slides forever, 1 stops sideways motion on touch. Shown for Bounce and Slide.
collideRadius (UI: "Particle Size")scalar, keyframeable0Particle thickness in px. 0 collides at the surface itself; above 0 keeps each centre that far off it, and is the only way an open path collides at all.
neighborRadius (UI: "Flock Range")scalar, keyframeable0How far a particle looks for neighbours, in px. 0 turns all three flocking rules off and skips the survey entirely.
separationscalar, keyframeable0px/s² pushing away from neighbours, weighted toward the closest. The rule that stops a dense cloud turning to mush.
alignmentscalar, keyframeable0px/s² steering toward the neighbourhood's average heading.
cohesionscalar, keyframeable0px/s² steering toward the neighbourhood's centre.
forceAttribute (UI: "Force Scale")string(empty)A per-point column multiplying this particle's response to gravity and fields — effectively an inverse mass. Empty, or a column that is not there, means every particle responds equally. Flocking is deliberately not scaled by it.
keepDeadFor (UI: "Keep Dead For")scalar0Frames a particle stays after it dies: frozen where it died, no longer aged or moved, tagged with the group dead and a deadAge count (0 on its death frame). It still appears on died once, on the frame it dies. Anything that follows particles by id — trails, connections, clones — keeps them for that long instead of losing them the instant they die, so a trail shrinks into the point where its particle died. Filter them out downstream with Apply To or Point Delete on dead. 0 = removed at once.
selection (UI: "Apply To")string(empty)Only the selected particles move. The rest keep their position and velocity but still age, die and bounce. Any group or attribute, with the usual rule and value — e.g. a frozen group set by a rule inside the Solver stops those particles for good, and @speed Less Than 20 holds the slow ones. Empty = every particle.

Expose Channels ​

When enabled (E button on node header), adds input ports that override params via edge connections:

PortTypeOverrides
gravity_invec2gravity
forceStrength_inscalarforceStrength
drag_inscalardrag
maxSpeed_inscalarmaxSpeed

How It Works ​

The step. Each frame (split into substeps equal steps of dt seconds) every particle does:

a  = gravity + forceStrength × Σ forces(p)      (each field sampled at the particle, −1..1)
v += a × dt        v ×= (1 − drag)^dt        |v| ≤ maxSpeed
p += v × dt

Then age advances one frame, particles whose age has reached their life are removed (when life > 0 and killOnAge is on), the boundary rule is applied, the frame's births from emit are appended (their sub-frame birth offset is pre-integrated so a fast stream stays smooth), and rotation is written if Orient is Velocity.

What is on the output. Standard particle attributes: velocity (px per frame, the stored unit even though the params are per second), age (frames), life (frames; 0 or less = immortal), plus everything the emitter inherited from its source. Every particle keeps the id it was born with until it dies; ids are never reused. The population reorders whenever a particle dies, so anything that must follow one particle — trails, labels, Select groups, Point Attributes' Random source — keys on @id, never on position in the list.

Starting points versus births. To start from existing points — "take this Grid and blow it apart" — wire them into Solver In's Start: that is the population on the first frame (immortal unless they carry life or you set seedLife). emit is read every frame and each frame's points are added as new particles. Use both: a grid that also sheds sparks.

Deterministic and scrub-anywhere. The Solver makes the state at frame N a pure function of the params, keyframes and upstream graph at every frame up to N. Playing forward advances one step per frame; jumping to a frame replays from the nearest stored frame; editing anything replays with the new settings. Exports match the viewport from any start frame. To have the system already running on the layer's first frame, set Pre-Roll on Solver In. The simulation runs on layer time: slide the clip and the whole system slides with it.

Collision. Anything wired to collide becomes solid. Each frame the solver builds a signed distance field per collider, and inside every sub-step a particle that has ended up within collideRadius of a surface is pushed back out along the surface normal and then answers to collideResponse. Only motion into a surface responds, so a particle sliding along one is not re-grabbed.

Two things follow from this that are worth knowing:

  • Closed shapes are solid; open shapes are thin walls. The inside test is a ray cast over closed paths, so a Line or an open curve has no interior and is collidable only through collideRadius, which reads as a wall of that thickness. A Rectangle, Circle or closed Editable Shape is solid as drawn.
  • substeps decides whether fast particles tunnel. Collision resolves inside the sub-step, so it is no longer only an accuracy knob: a particle moving further in one frame than a collider is thick will pass straight through at substeps 1. Raise it until the crossing stops, or give the collider more thickness.

Colliders are ordinary graph shapes, so they can be animated, and the solver is re-run at every replayed frame — scrubbing to a frame reproduces what playing to it produces, exactly as with forces.

Death and secondary systems. The died port emits exactly the particles that were removed on the current frame, each at the position it reached before being removed, and each still carrying every attribute it had in life plus the id it lived with. Wiring died into a second Point Emitter's Source with Velocity set to Inherit is the whole spawn-on-death idiom: embers off a dying spark, a burst where a particle hit something, a puff as one ages out.

Cause comes through as three groups, so the existing Apply To grammar filters them with no new concept — set a downstream node's selection to diedOnCollision for impact bursts, or diedOfAge for a gentle fade-out.

Two rules keep it honest:

  • An emitter whose Source is wired but empty births nothing. That is what makes this a spawn-on-death rather than a constant drip: on frames where nobody died, the secondary emitter is idle regardless of its Rate. An emitter with nothing wired still emits from the comp centre as before.
  • died is a per-frame transient. It is computed only when something is actually connected to it, and never on a motion-blur sub-frame, since a sub-frame extrapolates the integer state rather than re-running the frame.

Flocking. Separation, Alignment and Cohesion are params here rather than nodes, and that is deliberate. Every field in the graph is eval(x, y), but a flocking force depends on the other particles: two particles at the same position get different forces, alignment steers by neighbours' velocity which no field carries, and self-flocking is a feedback loop that a directed graph cannot express. A Separation node would wire to this one port and nowhere else. The neighbourhood itself is exposed as ordinary fields — see Points Field's Density and Flow outputs.

Each rule contributes a unit direction scaled by its strength, so a strength reads directly as px/s². The neighbourhood is surveyed once per frame against the population as it stood at the start of the step, which is what makes the result independent of row order: row order changes every time a particle dies, and an in-place sequential update would make a flock twitch as its population turns over.

Force Scale and buoyancy. There is no Buoyancy param, because buoyancy is not its own force. Point a forceAttribute at a column — a temperature written by Point Attributes, a size, an over-life ramp — set Gravity upward, and hot particles rise while cool ones stall. The same knob gives per-particle mass and per-particle wind response.

Motion blur. The Solver extrapolates motion-blur samples between frames along each particle's velocity, so blur streaks follow the motion.

Usage Examples ​

Basic: Fountain with gravity ​

Add a Point Emitter with auto-wire on: PointEmitter → [Solver In → PointSolver → Solver Out] → DrawPoints → Output. Set the emitter to direction −90, speed 600, spread 20, life 90, and the Point Solver's gravity to (0, 800).

Blow a grid apart ​

Grid (20 × 20) → Solver In.Start, RadialForce (repel) → PointSolver.forces, forceStrength 3000, drag 0.2. The grid is the first frame's population and explodes outward; keyframe the force's strength from 0 for a timed detonation.

Turbulence ​

Connect Noise.vectorField (Curl type) to forces alongside gravity. Raise forceStrength for wilder motion, drag to calm it. A Vortex field on the same port adds a swirl — the fields sum.

Bounce inside the comp ​

boundary: Bounce, bounce 0.6, gravity (0, 1200), emitter at the top of the frame. Particles drop, bounce and settle along the bottom edge.

Land particles on a shape ​

A particle system with gravity (0, 1200), then Rectangle → Transform2D → PointSolver.collide with the rectangle moved to the bottom of frame. Set collideResponse to Stick and particles pile up on it; Bounce with restitution 0.6 and they scatter off it. Swap the Rectangle for Text → TextToShape to pour particles over type.

Wire the logo shape to collide, set collideResponse to Slide, friction 0.2, gravity down. Particles fall in, slide down the interior walls and settle in the low points of the form.

Embers on impact ​

A particle system with a shape on collide and collideResponse Kill. The embers need their own population, so give the Solver a second value (+ add value on Solver In, value B), and inside the Solver wire PointSolver.died → PointEmitter (2).source → PointSolver (2).emit, Solver In's B → PointSolver (2).points, and PointSolver (2).out → Solver Out's B. Set the second emitter's Velocity to Inherit with a short Life. Every particle that hits the shape bursts into sparks that carry its momentum. Merge Points on Solver Out's Out and Out B draws both. Select diedOnCollision on the second emitter's source if the primary also kills on age and you only want impact bursts.

A flock ​

A particle system with Flock Range around 60, Separation 300, Alignment 400, Cohesion 200, and Drag near 0.3. Raise Separation until the cluster stops clumping, then Cohesion until it holds together. Orient set to Velocity plus Clone To Points gives shapes that point where they are going.

Rising smoke ​

Point Attributes writes a heat column from Age (curve 1 → 0), Gravity is set to (0, −400), and Force Scale reads heat. Fresh particles climb hard and slow as they cool. Add a Curl noise field on Forces for drift.

Already running at frame 0 ​

Set Pre-Roll 120 on Solver In. The first frame of the layer shows a fully developed system instead of the first few births.

Size and colour over life ​

Solver Out → PointAttributes (target: Scale, source: Age, Curve 1 → 0) → PointAttributes (target: Color, source: Age, Color Ramp white → orange → transparent) → DrawPoints.

Trails ​

Solver Out → PointTrail (trailLength 20, fade 1) → DrawShape (stroke only). Stable ids mean each particle owns one trail.

Arrows that face their motion ​

orient: Velocity, then Solver Out → CloneToPoints (shape: a small triangle) → DrawShape. Each instance rotates to its direction of travel.

Tips ​

  • y is down: positive gravity.y falls, negative rises.
  • One forceStrength scales every field on forces. To weight one field differently, use its own strength/amplitude param or a FieldMath multiply before the port.
  • substeps costs linearly — 2–3 fixes most tunnelling; 10 is for very stiff fields.
  • Turning killOnAge off with a None boundary grows the population without bound. Add Kill or a maxSpeed and check the count with Label Points or the Debug node.
  • Everything downstream that reads points works on particles unchanged: Clone To Points, Draw Instances, Connect Points, Label Points, Point Delete, Select, Attribute To Field, Point Trail.
  • Reset the simulation (the reset button / resetSimulation) after a fps change or when something looks stale — it only clears the accelerator cache, the result is the same.
  • Properties: Bounce appears only in Bounce mode.