Nodes/Skoogeer-Noise/Image Smoke Simulation
ComfyUI Node

Image Smoke Simulation

Make an Image Dissolve Into Smoke, Without Leaving ComfyUI

By ttulttul·Created 9 months ago·Updated 3 months ago· 14
Image Smoke Simulation
  • image
  • mask
  • image
  • density_preview
  • velocity_preview
steps30
output_modefinal
dt1.00
resolution_scale0.50
force_count3
force_strength5.0
force_radius0.10
swirl_strength2.0
velocity_damping0.980
diffusion0.00
vorticity0.30
buoyancy1.50
ambient_updraft0.10
density_fade0.010
temperature_strength0.00
cooling_rate0.05
smoke_source_strength1.00
smoke_source_radius0.10
smoke_source_modeimage
seed0
wrap_modeclamp

Image Smoke Simulation runs a buoyancy-driven fluid simulation inside ComfyUI and uses your input image as the smoke itself. No diffusion model involved, no VAE round-trip, no API key. You feed it a photo and it comes out the other end smeared and drifting like it's being carried on a thermal column. It's the closest thing in this pack to a party trick, and also a genuinely useful way to get organic motion into a still image before you send it to an img2img pass or a video model.

The mechanism is the same stable-fluids recipe the rest of the pack's simulation nodes use: it keeps a velocity field, injects random forces ("sticks") each step, applies vorticity confinement so the flow curls into billowing shapes instead of going straight, and then semi-Lagrangian advects the color field through that velocity. On top of the plain advection, smoke mode adds buoyancy (a force scaled by temperature), an ambient updraft, and a density field that dissipates over time. The image's own luminance becomes that density in the default image source mode, which is why bright areas look like they're burning off first.

There are a lot of sliders here - this is the most intimidating node in the pack - but you can ignore most of them on a first pass. The ones that shape the result:

  • smoke_source_mode - image derives density from your input, random injects puffs, mask injects from a MASK input. Start with image; switch to mask when you want smoke to rise from one specific region.
  • steps - how many simulation steps run. More steps = more drift. Note that when output_mode is batch, this doubles as the batch size and you get every intermediate frame as an output image, which is a neat way to generate a flipbook for a video node.
  • buoyancy and vorticity - upward force and curl detail. Bump vorticity to get wispy, billowing smoke instead of a straight smear.
  • density_fade - how fast the smoke dissipates. Higher = lighter, more ephemeral look.
  • temperature_strength - hotter smoke rises faster. Zero by default, so the sim is purely mechanical until you turn it on.
  • resolution_scale - internal sim resolution. Drop it to 0.25–0.5 for speed; the smoke still looks fine, just chunkier.

The node returns three IMAGE outputs: the simulated image itself, plus density_preview and velocity_preview so you can see what the sim thinks it's doing. The previews are debug aids, but they're handy when you're dialing in the force settings.

Installing

This ships in the Skoogeer-Noise pack from ttulttul. Install it once and you get every node in the pack:

cd ComfyUI/custom_nodes
git clone https://github.com/ttulttul/Skoogeer-Noise

Restart ComfyUI, or find "Skoogeer-Noise" in ComfyUI Manager and let it do the same thing. Dependencies are just torch, numpy>=1.26, einops, and pyyaml - ComfyUI almost certainly has all of them already, and there are zero model files to download. The whole simulation is plain torch math running on your existing setup.

Gotchas

The sim runs on CPU tensors at resolution_scale resolution, so a big image at full scale with 200 steps will crawl. That's what resolution_scale is for. If your smoke just sits there, check density_fade (too high and it vanishes) and buoyancy (too low and there's no reason for it to move). And remember the folder needs to stay named Skoogeer-Noise - the pack's module path is custom_nodes.Skoogeer-Noise, so renaming the directory to avoid the dash is a one-way ticket to "module not found" errors. If you're on Flux.2-style models, none of this applies - this is a pure image-space node, which is exactly why it's the friendlier sibling of LatentSmokeSimulation.

Categoryimage/perturb

Inputs (23)

NameTypeDefaultDescription
imageIMAGEImage to simulate as smoke density/color.
stepsINT300–256Number of simulation steps (or batch size when output_mode='batch').
output_modeCOMBOfinalWhen 'batch', returns a batch of intermediate outputs after each step (1..steps).
dtFLOAT1.000–4Time step size used during advection.
resolution_scaleFLOAT0.500.25–1Internal simulation resolution scale (lower = faster).
force_countINT30–64Number of random force injections ('sticks') per step. When smoke_source_mode='random', also controls puff count.
force_strengthFLOAT5.00–256Linear force magnitude added to velocity (pixels / step).
force_radiusFLOAT0.100–1Normalized radius of influence for stick forces (0.1 = 10% of min(width,height)).
swirl_strengthFLOAT2.00–256Rotational component added around each stick position.
velocity_dampingFLOAT0.9800–1Velocity decay applied each step (lower = more viscous / quickly settles).
diffusionFLOAT0.000–1Optional velocity diffusion (Gaussian smoothing).
vorticityFLOAT0.300–10Vorticity confinement strength (adds billowing/swirl detail).
buoyancyFLOAT1.500–10Strength of upward buoyant force.
ambient_updraftFLOAT0.100–10Constant upward airflow added each step.
density_fadeFLOAT0.0100–1Density dissipation per step (higher = smoke dissipates faster).
temperature_strengthFLOAT0.000–10Initial temperature injection per step (hotter smoke rises more).
cooling_rateFLOAT0.050–1Temperature decay per step.
smoke_source_strengthFLOAT1.000–10Amount of smoke density injected each step.
smoke_source_radiusFLOAT0.100–1Radius of smoke injection (normalized). Used as puff radius in random mode; softens the source in image/mask modes.
smoke_source_modeCOMBOimageSmoke source mode: 'image' derives density from the input image; 'random' injects random puffs; 'mask' injects from a MASK input.
seedINT00–18446744073709550000Seed controlling random forces and random sources.
wrap_modeCOMBOclampHow advection samples outside the bounds.
maskoptMASKUsed when smoke_source_mode='mask' to define the emission region (resized to image resolution).

Outputs (3)

NameTypeDescription
imageIMAGE
density_previewIMAGE
velocity_previewIMAGE