Particle Renderer (PixiJS)
ComfyUI particle FX you play live, then hand Comfy a frame
- particle_color
- image
- image
This node is not what the name implies, and that's the thing worth knowing up front. Particle Renderer (PixiJS) doesn't generate anything with torch or a diffusion model. It runs a real-time particle system in your browser - smoke, sparks, glowing rays, a star-warp tunnel - lets you scrub the animation until a frame looks right, then hands that exact frame to the rest of your graph as a normal image. Think compositing/effects node, not generator. You reach for it when you want procedural VFX layered onto a render: a spark shower behind a subject, CRT title-card glitch, magical dust over a portrait, a ray-burst texture some other node will composite.
The core flow is interactive, and it's the one thing beginners bounce off: Play, then Stop & Capture, then run. Nothing happens if you just queue the prompt.
How it works
The Python side (particle_node.py) is a thin bridge. The real work lives in the browser: PixiJS v7 plus pixi-filters, bundled locally in web/lib/ - no CDN, no internet at runtime, and no pip dependencies to fight. That's a genuine relief in a world where half of ComfyUI is dependency hell. Rendering happens on an offscreen canvas; when you hit Stop & Capture, the frame is base64-encoded and POSTed to /particle/capture, where Python stores it as a PIL image in a dict keyed by node_id. When you queue the prompt, render() pulls that capture and returns it as a standard IMAGE tensor.
The clever bit is IS_CHANGED: it returns an md5 hash of the captured image, so ComfyUI only re-executes the node when you actually capture a new frame. Capture one frame, run it through your save/compositing stack, capture a better one, re-run - your queue doesn't churn on unchanged data.
The inputs that matter
Only a handful live on the widget list; the interesting controls are in the node's interactive panels:
particle_type-none,smoke,spark,ray,star_warp.noneexists for when you just want filters.particle_color- color of the currently selected stop on the color ramp.width/height- canvas size, 64–2048 px (default 512).particle_count- 10–2000 particles (default 200).node_id- the trap. Defaults toparticle_0, and it must be unique per node in a workflow. Drop in a second copy and both silently share a capture slot; one overwrites the other.image(optional) - a background image to composite the particles onto.
Everything else - emitters, color ramp, textures, letter shapes, the 12-ish filter library (glow, bloom, Kawase blur, pixelate, old-film, CRT, dot, drop shadow, motion blur, outline, RGB-split, zoom blur), blend modes, wind/swirl/turbulence - lives in the node's panels, not in the widget list. The output is a single image (IMAGE) tensor: wire it into Save Image, or feed it onward as a frame or background in a video/compositing stack.
Installing it
ComfyUI Manager: search comfyUI-particle-pixijs, install, restart. Or the manual route:
cd ComfyUI/custom_nodes
git clone https://github.com/ketle-man/comfyUI-particle-pixijs
Then restart ComfyUI. That's the whole install - no model downloads, no requirements.txt, no weights. You do need a WebGL-capable browser, since PixiJS renders client-side.
Gotchas & tips
- Play first, then Stop & Capture. Queue without a capture and you get a transparent/black frame.
- Textures: keep them small (64–256 px), square, ideally power-of-two, PNG/WebP with alpha, drawn in white or gray - your ramp color multiplies over them. A black-background texture renders as a visible rectangle.
- Background refreshes lag. The input image is cached when
render()runs, so changing theimageinput may not show until you re-queue. BG+Filter mode auto-queues a prompt on Play when it needs a fresh background. - Captures live in server memory until restart, and particle settings (textures, rotation) apply the moment you press Play.
star_warpuses its own 3D coordinates and ignores the full-scatter mode. And Add blending is your friend for anything meant to glow.
Honest assessment: this is a niche interactive utility with almost no community footprint - you won't find it in every workflow, and its 10-ish impressions a month reflect that. It's MIT-licensed, free of Python deps, and surprisingly fun for specific VFX jobs. If you need live-scrubbed particles, it's the rare node that just works.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| particle_type | COMBO | 5 options: none, smoke, spark, ray, star_warp | |
| particle_color | COLOR | #ffffff | — |
| width | INT | 51264–2048 | — |
| height | INT | 51264–2048 | — |
| particle_count | INT | 20010–2000 | — |
| node_id | STRING | particle_0 | — |
| imageopt | IMAGE | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |