Nodes/ComfyUI-DNode/🎥 Lissajous Camera Shake (V1)
ComfyUI Node

🎥 Lissajous Camera Shake (V1)

Your AI Video Is Too Still — This Node Gives It a Pulse

By Derryyyyyy·Created 6 months ago·Updated 6 months ago· 49
🎥 Lissajous Camera Shake (V1)
  • images
  • IMAGE
  • trajectory_json
intensity0.40
zoom_factor1.05
fps30
seed42

You generate a talking-head or digital-human clip and it comes out technically perfect and completely dead. No breathing, no micro-drift, just a face reciting lines like it's waiting for the teleprompter to load. That stiffness is exactly what DNode_CameraShakeLissajous is built for: it adds the subtle, low-frequency handheld drift that makes real footage feel alive, as a post-processing step on frames you already generated.

What it actually does

The name says Lissajous, and the math is... loosely Lissajous. Instead of one textbook figure-eight, the code sums four low-frequency sine waves (0.033, 0.1, 0.2, and 0.3 Hz), each given a random amplitude between about 5 and 16 pixels and a random direction angle, all seeded deterministically. An ease-out envelope keeps the motion from spiking at cycle edges. The result is organic drift around the exact center of the frame - never the "slowly drifting off to the corner" problem that plain noise-based shakes have - and it reads as a person holding a camera, not a machine vibrating.

Mechanically, each frame gets a 2D affine transform: a slight scale-in (that's what zoom_factor is really doing) plus a per-frame dx/dy offset, applied with bilinear sampling and border padding. It operates on the already-decoded frame batch, so it's cheap and VRAM-light - the expensive part, the video model itself, happened upstream.

The author's stated target is digital humans and talking-head avatars, and that's a genuine niche. Generation-time camera control exists (AnimateDiff's MotionLoRA zoom and pan comes to mind), but that's baked into the sample and tied to one model. This node works on anything - Wan, LTX, AnimateDiff output, even real footage. That model-agnostic "add it afterward" quality is its whole trick.

The inputs that matter

Five inputs, and you'll realistically touch two or three:

  • images - your video frame sequence. The batch dimension is treated as time, so feed the whole clip, not a single frame.
  • intensity (default 0.40, range 0–5) - the shake magnitude. The default genuinely is the right starting point; this is meant to be subtle. Push it toward 1 and you're making a handheld disaster movie.
  • zoom_factor (default 1.05, range 1–2) - edge protection, not a zoom effect. The node scales in slightly before translating so the borders never show. Leave it alone.
  • fps (default 30) - sets the physical motion period. Get this wrong and the wobble runs at the wrong speed.
  • seed (default 42) - the trajectory's random state. Same seed, same shake, every time.

Outputs: the shaken IMAGE (same shape and batch count, so it wires straight into whatever saves or combines your video) and trajectory_json, a STRING holding the per-frame dx/dy path. Pipe that into a text-display node if you want to reproduce the exact same camera move on another clip or just see what it decided to do.

Installing it

Dead simple, and this is the rare pack with no real dependencies. There's no requirements.txt - it only uses torch and numpy, which ComfyUI already ships with - and nothing to download.

cd ComfyUI/custom_nodes
git clone https://github.com/Derryyyyyy/ComfyUI-DNode.git

Restart ComfyUI, and you'll find the node under DNode🎥 Lissajous Camera Shake (V1). (Or install it via ComfyUI Manager by searching "ComfyUI-DNode" and updating.) The README even documents a manual install that amounts to "create a folder and drop __init__.py in it."

Gotchas worth knowing

  • Don't drop zoom_factor to 1.0. With no scale-in, the translation pushes the sampling window past the image edge and you get smeared border pixels. That's the "edge protection" the README warns about, and it's the most common way people trip on this node.
  • It's translation-only. dtheta is hardcoded to zero in the trajectory - there's no roll, so you won't get full shaky-cam-with-rotation. This is gentle breathing drift, and it doesn't pretend otherwise.
  • Determinism is a feature and a trap. Same seed equals identical shake on every clip, so if your batch of videos starts feeling copy-pasted, vary the seed.
  • Set fps to your real generation rate. The whole motion-cycle timing depends on it.

If your talking-head output still reads as a mannequin after this, the problem isn't the camera - it's eyelid blink, gaze, or lip sync. But for that last stretch of "alive," a 0.4-intensity drift is about the cheapest trick in the toolkit.

CategoryDNode

Inputs (5)

NameTypeDefaultDescription
imagesIMAGE
intensityFLOAT0.400–5
zoom_factorFLOAT1.051–2
fpsFLOAT301–120
seedINT420–4294967295

Outputs (2)

NameTypeDescription
IMAGEIMAGE
trajectory_jsonSTRING