Optical Flow Particle System β‘π ‘π π £π
Spawn particles that ride the motion in your video
- masks
- images
- IMAGE
This one's a genuine visual effect rather than a utility node: it watches how pixels move between frames of a video and spawns particles that get pushed along by that motion. Point it at footage of someone waving their arms, water flowing, or a car driving past, and you get a particle trail that follows the actual movement in the shot - not a random sparkle overlay, an overlay that's physically tied to what's happening on screen.
Under the hood this is optical flow: the classic computer-vision technique for estimating per-pixel motion between consecutive frames. RyanOnTheInside gives you a choice of algorithms rather than locking you into one.
How it works
It computes optical flow across your images sequence using whichever flow_method you pick, filters out flow below your thresholds so static background doesn't spawn particles, and then emits, ages, and renders particles whose movement is driven by that flow field. A masks input constrains where particles are allowed to spawn - combine it with a subject mask if you only want particles coming off a person rather than the whole frame.
The inputs and outputs that matter
images(IMAGE, required) - the sequence to compute flow from, and the frames the particles get composited onto.masks(MASK, required) - restricts where particles can spawn; the node also exposes the usual mask post-processing set (invert,subtract_original,grow_with_blur) on top of it.flow_method-DIS,Farneback,LucasKanade, orPyramidalLK. These are standard optical-flow algorithms with the usual trade-offs: Farneback is dense and smooth but slower; Lucas-Kanade variants track sparse points and are faster but less complete; DIS is a modern dense method tuned for speed. If you're not sure, Farneback is the safest general-purpose starting point.flow_threshold(default 0.1) andmagnitude_threshold(default 0.05, relative to the frame's max flow) - both filter out weak/noisy motion so slow camera shake or compression artifacts don't spawn particles everywhere.num_particles(default 1000, up to 10000),particle_size(default 2px),particle_color(hex, default#FFFFFF),particle_opacity(default 0.5) - the look of the particles.flow_multiplier(default 1, 0.1β5) - how strongly detected motion pushes particles;initial_velocity(default 1) - their starting speed when spawned;particle_lifetime(default 20 frames) - how long each one lives before disappearing.- Output - a single
IMAGEsequence.
How to install it
Via ComfyUI Manager: search "RyanOnTheInside," install, restart. By hand:
cd ComfyUI/custom_nodes
git clone https://github.com/ryanontheinside/ComfyUI_RyanOnTheInside.git
cd ComfyUI_RyanOnTheInside
pip install -r requirements.txt
then restart. This node relies on OpenCV-family optical flow implementations that come in via requirements.txt - if the pack's dependencies didn't install cleanly, this is one of the nodes most likely to error at load time rather than at runtime.
Common issues & troubleshooting
No particles appear at all. The most common cause is flow_threshold/magnitude_threshold filtering out everything - if your source footage has subtle or slow motion, the defaults may simply never trigger. Lower both before assuming the node is broken, and double check your masks input isn't accidentally all-black.
Particles cluster in the wrong place or ignore obvious motion. Try a different flow_method - Lucas-Kanade-family methods track sparse feature points and can miss motion in low-texture regions (a plain wall, a solid-color shirt) that Farneback or DIS would pick up as dense flow.
Effect looks chaotic or noisy on handheld/shaky footage. Optical flow can't distinguish camera shake from subject motion - if your source isn't stabilized, raise the thresholds to filter out the shake, or stabilize the footage upstream before this node.
Frame rate or particle count tanks performance. num_particles at the high end (thousands) combined with large frame sequences is genuinely expensive - this is a per-frame simulation and render, not a cheap filter, so budget accordingly on longer clips.
Inputs (16)
| Name | Type | Default | Description |
|---|---|---|---|
| masks | MASK | Input mask or sequence of masks to be processed (MASK type) | |
| strength | FLOAT | 1.000β1 | Overall strength of the mask effect (0.0 to 1.0) |
| invert | BOOLEAN | false | When enabled, inverts the mask output (black becomes white and vice versa) |
| subtract_original | FLOAT | 0.000β1 | Amount of the original mask to subtract from the result (0.0 to 1.0) |
| grow_with_blur | FLOAT | 0.00β10 | Amount of Gaussian blur to apply for mask growth (0.0 to 10.0) |
| images | IMAGE | Sequence of images to calculate optical flow from (IMAGE type) | |
| flow_method | COMBO | Algorithm used to calculate optical flow ('Farneback', 'LucasKanade', 'PyramidalLK') | |
| flow_threshold | FLOAT | 0.100β1 | Minimum flow magnitude to consider (0.0 to 1.0) |
| magnitude_threshold | FLOAT | 0.050β1 | Relative threshold for flow magnitude as fraction of maximum (0.0 to 1.0) |
| num_particles | INT | 1000100β10000 | Total number of particles in the system (100 to 10000) |
| particle_size | INT | 21β50 | Size of each particle in pixels (1 to 50) |
| particle_color | STRING | #FFFFFF | Color of particles in hex format (e.g., '#FFFFFF') |
| particle_opacity | FLOAT | 0.50β1 | Transparency of particles (0.0 to 1.0) |
| flow_multiplier | FLOAT | 1.00.1β5 | Multiplier for optical flow influence (0.1 to 5.0) |
| particle_lifetime | INT | 201β100 | Number of frames each particle exists (1 to 100) |
| initial_velocity | FLOAT | 1.00.1β5 | Starting speed of newly emitted particles (0.1 to 5.0) |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | β |