Latent Mesh Drag
Warp your latent like a cloth instead of dumping noise on it
- latent
- mask
- latent
Most "perturbation" nodes in ComfyUI work by adding noise. Latent Mesh Drag does something rarer: it picks a handful of control points on a coarse mesh laid over your latent, drags them around, and interpolates the result into a smooth displacement field. Your features don't get covered in static - they get pushed. Think cloth being tugged at a few corners, or that Photoshop liquify tool if it lived inside the VAE's latent space.
That distinction matters. Because the warp is spatial rather than additive, it tends to survive the trip through the sampler with its structure intact. Where people actually reach for this: shifting anatomy or posing slightly in img2img, breaking up a too-stiff composition between two sampling passes, or adding that subtle "melted / under stress" look that no Gaussian-noise node can fake. If you're on SD-style models, remember the drag distances are in latent pixels - multiply by ~8 to think in image pixels, so the default drag_max of 4 is already moving things about 32 image pixels.
The inputs that matter
The node is refreshingly shallow - it only needs latent and seed to do something interesting. The controls you'll actually touch:
points(default 12) - how many mesh vertices get dragged. Too many and the warp turns into noise; 8–20 is the sweet spot for a readable distortion.drag_min/drag_max(defaults 0 / 4) - the range of drag distances in latent pixels.drag_min0 with a biggerdrag_maxgives organic variation; set both close together for a uniform push.direction- degrees, with0=up,90=right,180=down,270=left.-1(the default) lets each point pick a random direction.stroke_width- set this above 0 and you're not warping the whole latent anymore; the warp gets confined to narrow brush-stroke channels aligned with the drag direction. That's a nifty trick for a directional "painted streak" effect rather than a global liquify.
The interpolation options are worth one glance: displacement_interpolation defaults to bicubic, but bspline gives noticeably smoother, more organic warps (with spline_passes controlling how many smoothing iterations). sampling_interpolation is just how the source is resampled when the warp lands - bilinear is fine to leave alone.
The only output is a LATENT with the same shape as your input, so it slots straight back into the pipeline wherever the original latent was going. There's an optional mask input too: when provided, the warp only happens inside the masked region (the mask gets resized to latent resolution). And if your latent carries a noise_mask, that gets warped along with it - handy for inpaint workflows where you want the inpaint region deformed the same way as the content.
Installing it
This ships in the Skoogeer-Noise pack. Easiest route is ComfyUI Manager: search "Skoogeer-Noise" and install. Or do it by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/ttulttul/Skoogeer-Noise
Restart ComfyUI. Dependencies are just torch, numpy, einops, and pyyaml - all things ComfyUI already has, so there are no model downloads and no API keys. If you run it on a Flux.2 checkpoint, wrap it with Unpatchify Flux.2 Latent before and Patchify Flux.2 Latent after, or the 2x2 patchified channels will make the warp behave oddly.
Common issues
The usual complaints are about the effect being invisible or too violent. Invisible usually means drag_max is too small for your resolution - remember the latent-pixel scaling. Too violent means drop points, widen the drag_min/drag_max spread, or reach for a mask to localize it. Since there's no mix dial on this node (the README's sibling nodes have one, this doesn't - the input list really is just what's above), your fade-in control is a mask or running it with a low-res source. It's deterministic per seed, so once you find a good one, it'll replay.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| latent | LATENT | Latent to warp spatially using a random mesh drag. | |
| seed | INT | 00–18446744073709550000 | Seed controlling which mesh points are dragged and by how much. |
| points | INT | 120–2048 | Number of mesh vertices to randomly drag. |
| drag_min | FLOAT | 0.00–128 | Minimum drag distance (latent pixels). |
| drag_max | FLOAT | 4.00–128 | Maximum drag distance (latent pixels). |
| direction | FLOAT | -1-1–360 | Drag direction in degrees (0=up, 90=right, 180=down, 270=left). Set to -1 to allow random directions. |
| stroke_width | FLOAT | -1-1–4096 | When >0, limits the warp to narrow brush-stroke channels aligned with the direction (one per dragged mesh point; stroke centers are jittered when direction is fixed). Units are latent pixels. Set to -1 to disable. |
| maskopt | MASK | Optional mask (often image-sized) to limit the warp to masked areas. The mask is resized to latent resolution (bicubic when downscaling). | |
| displacement_interpolationopt | COMBO | bicubic | How to interpolate the sparse mesh drags into a full displacement field. Use 'bspline' for smoother, more organic warps. |
| spline_passesopt | INT | 20–16 | Only used when displacement_interpolation = 'bspline'. More passes = smoother warp. |
| sampling_interpolationopt | COMBO | bilinear | How to sample the source tensor when applying the warp (bilinear/bicubic/nearest). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| latent | LATENT | — |