Nodes/Difforum/Difforum · Camera (expressions)
ComfyUI Node

Difforum · Camera (expressions)

The Deforum Math Syntax, Still Here and Still Useful

By chillithebillis·Created 4 months ago·Updated 11 days ago· 10
Difforum · Camera (expressions)
  • params
  • audio
  • translation_x_curve
  • translation_y_curve
  • translation_z_curve
  • rotation_3d_x_curve
  • rotation_3d_y_curve
  • rotation_3d_z_curve
  • zoom_curve
  • camera
  • info
◄mode2d►
◄fov40►
◄translation_x0:(0)►
◄translation_y0:(0)►
◄translation_z0:(0)►
◄rotation_3d_x0:(0)►
◄rotation_3d_y0:(0)►
◄rotation_3d_z0:(0.3)►
◄zoom0:(1.0 + 0.004*sin(2*pi*t/48))►

The Difforum pitch is "no camera expressions to write". They're right that most people shouldn't need them. But if you came from Deforum, this node is the comfort blanket: the same 0:(expr) syntax on seven axes, backed by a safe expression evaluator rather than eval().

The syntax

Each axis takes a Deforum-style schedule where the keys are frames and the values are expressions:

0:(0), 60:(2*sin(2*pi*t/30))

t is the current frame and s is seconds. pi, sin, cos, abs, min, max and friends are available. When audio is connected, so are the six bands - amp, low, mid, high, onset, beat.

Here's the part that trips people up, and it's the same trap as the original: values are per-frame increments, not positions. A constant translation_x = 0:(2) doesn't put the frame at x=2, it pans a bit every single frame, and the result accumulates through the feedback loop. That's the whole design - it's why a schedule of motions works at all - but it means "2" and "0.2" are wildly different moves. zoom follows the same logic: it's a per-frame scale factor, so 0:(1.0 + 0.004*sin(2*pi*t/48)) is a gentle breathing zoom, and 0:(1.01) is 1% closer every frame, which gets silly fast.

The default rotation_3d_z of 0:(0.3) is a nice illustration: a third of a degree of roll per frame, which over 120 frames is a full 36 degrees of rotation. Subtle constant, big cumulative result.

Inputs

Seven axes: translation_x, translation_y, translation_z (3D only), rotation_3d_x (tilt), rotation_3d_y (pan), rotation_3d_z (roll), and zoom. Plus:

  • mode - 2d or 3d, matching the rest of the pack. In 3D you want a depth map downstream or you're back to pseudo-3D.
  • fov (40) - lens field of view in degrees. 20–30 is long lens, 40 normal, 60+ wide. This matters more than people expect: it's what makes a dolly feel like a dolly rather than a zoom.
  • audio - makes the bands available inside expressions.
  • Seven *_curve sockets - a DIFFORUM_SCHEDULE (an Audio Curve, or a Schedule) replaces the text for that axis. This is the useful trick: write the shapes you like by hand, and hand the axis you want reactive over to a schedule you can tweak without touching the text.

Outputs

camera and info. camera overrides the Director's camera wherever it plugs in - Feedback Sampler, Guide Frames, Storyboard, Camera → Prompt, Camera Export. The info string is worth reading at least once per session; it reports the resulting motion range, which is how you catch "I typed 2 instead of 0.2" before rendering.

Install

Manager → search "Difforum", or:

cd ComfyUI/custom_nodes && git clone https://github.com/chillithebillis/Difforum.git difforum

Restart. numpy and a built-in AST evaluator - notably no eval(), which is a real difference from the 2022-era scripts people copy expressions out of.

Where people get burned

Motion through space needs depth. Pan, roll and zoom are in-plane and work on a flat image; dolly, orbit and tilt are camera-in-a-room moves, and without a depth map the engine falls back to a pseudo-3D affine - dolly becomes zoom. It works, it just won't have the parallax you're picturing, and the report says so.

The other one is continuity across transition. Expressions are per-frame increments, so a discontinuity in the expression is a jump in the image. If you build a move out of piecewise segments, ease them into each other or you'll get a visible snap - which is the same problem the Camera (keys) node solves with its own transition slider.

CategoryDifforum/2 · Direction

Inputs (18)

NameTypeDefaultDescription
paramsDIFFORUM_PARAMSFrom Setup: frame count, fps, width and height. Plug the same Setup everywhere.
modeCOMBO2d2d = flat moves; 3d = parallax with a depth map.
fovFLOAT401–170Lens field of view in degrees. 20-30 long lens, 40 normal, 60+ wide.
translation_xSTRING0:(0)Horizontal move per frame. Deforum syntax: '0:(0), 60:(2*sin(t/10))'; t = frame.
translation_ySTRING0:(0)Vertical move per frame, same syntax.
translation_zSTRING0:(0)Forward (+) / back (-) per frame. 3D only.
rotation_3d_xSTRING0:(0)Tilt, degrees per frame. 3D only.
rotation_3d_ySTRING0:(0)Pan (turn), degrees per frame. 3D only.
rotation_3d_zSTRING0:(0.3)Roll, degrees per frame.
zoomSTRING0:(1.0 + 0.004*sin(2*pi*t/48))Scale per frame. 1.0 = none, 1.01 = 1% closer each frame.
audiooptDIFFORUM_AUDIOAudio curves usable in expressions: amp, low, mid, high, onset, beat.
translation_x_curveoptDIFFORUM_SCHEDULEA schedule (Audio Curve, Schedule) that replaces the text for this axis.
translation_y_curveoptDIFFORUM_SCHEDULEA schedule that replaces the text for this axis.
translation_z_curveoptDIFFORUM_SCHEDULEA schedule that replaces the text for this axis.
rotation_3d_x_curveoptDIFFORUM_SCHEDULEA schedule that replaces the text for this axis.
rotation_3d_y_curveoptDIFFORUM_SCHEDULEA schedule that replaces the text for this axis.
rotation_3d_z_curveoptDIFFORUM_SCHEDULEA schedule that replaces the text for this axis.
zoom_curveoptDIFFORUM_SCHEDULEA schedule that replaces the text for this axis.

Outputs (2)

NameTypeDescription
cameraDIFFORUM_CAMERA—
infoSTRING—