Nodes/Difforum/Difforum · Schedule
ComfyUI Node

Difforum · Schedule

`0:(0.45), 60:(0.6)` is still the best way to time a shot

By chillithebillis·Created 4 months ago·Updated 11 days ago· 10
Difforum · Schedule
  • params
  • audio
  • schedule
  • info
◄schedule0:(0.45), 60:(0.6), 119:(0.45)►
◄easingease_in_out►

Keyframe schedules are the part of classic Deforum that aged best. 0:(0.45), 60:(0.6), 119:(0.45) is ugly, immediately legible, and infinitely more expressive than a single slider - you're describing a curve over time instead of a value. Difforum kept the syntax and rebuilt the parser, and the result is a node that hands that curve to anything in the pack.

What it does

You write keyframes as frame:(expression) pairs, comma separated. Between keys the value moves according to easing - linear, ease_in, ease_out, ease_in_out (default) or step for a hard jump. Frames can be given in seconds too, so 2s:(0.8) is fine.

The expressions are where it gets fun, and they're safe by construction: the pack evaluates them with a restricted AST walker, not eval(). You get t (frame), f (alias), s (seconds), fps, max_f, pi, e, tau, and a function library - sin cos tan abs sqrt exp log floor ceil round min max sign clamp clip lerp smoothstep, plus ternaries. So this all works:

0:(0.5 + 0.2*sin(2*pi*t/60))
0:(0.3 + 0.5*amp*amp)
0:(0 if t < 48 else (t - 48) * 0.5)
0:(smoothstep(0, 30, t) * 2.0)

The first is a smooth sway with a 60-frame period. The second is a schedule that gets wild during loud parts. The third holds still and then starts moving. The fourth eases in from zero - the difference between a move that reads as deliberate and one that starts with a jerk.

The audio part is the good part

Wire a Difforum_AudioAnalyzer into the optional audio input and every band becomes a variable you can use in the expression: amp, low, mid, high, onset, beat, all 0..1 per frame. That's the audio-reactive workflow with no expressions-of-the-week, and it's the reason this node exists rather than a plain curve editor. The classic uses are one-liners: 0:(1.0 + 0.06*low) to pump a zoom, 0:(0.35 + 0.4*beat) to punch sampler strength on the beat, 0:(clamp(2*low, 0.0, 0.9)) to keep the pump from clipping.

Inputs and outputs

params from Setup - that's what gives the schedule its frame count and fps, and every keyframe is resolved against max_frames, so a schedule written for a 5-second clip truncated into a 2-second one loses its tail rather than erroring. schedule is the text, easing the interpolation. Output schedule (DIFFORUM_SCHEDULE) goes into schedule sockets across the pack - sampler strength, camera axes on the expression-driven Camera node, and anything else that takes a curve. info reports the frame count and the min/max of the resolved curve, which is the fastest sanity check you have.

Install

ComfyUI Manager → search Difforum, or:

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

Restart. numpy only, no OpenCV needed, no models. The pack's docs/EXPRESSIONS.md is a genuinely useful cookbook - a table of copy-paste recipes for ramps, bounces, pulses, bass pumps and beat kicks - and it's short enough to read once before you invent your own formulas.

Where people get burned

Two failure modes, both boring. First, a curve that resolves outside the range the downstream node accepts: a denoise curve that hits 1.3 somewhere in the middle of the clip, a strength curve that goes negative. It won't error, it'll just produce a weird section of clip twenty minutes in. Watch the min/max in info, or plot it (see Schedule Plot).

Second, referencing an audio variable when no Audio Analyzer is connected. The names simply don't exist in the evaluator namespace, so keep the reactive version of a schedule in a separate node or comment it out - pasting low into a graph without audio is the single most common way people break an otherwise fine workflow.

And one thing that isn't a bug: camera fields elsewhere in the pack are per-frame increments, not absolute values, while strengths and cfg are absolute. The same 0:(0.5) means "zoom a bit every frame" in one place and "hold denoise at 0.5" in another. Read the tooltip on the socket you're feeding before you reuse a curve, because nothing in the UI stops you from using a perfectly valid schedule in the wrong unit.

CategoryDifforum/3 · Curves & Prompts

Inputs (4)

NameTypeDefaultDescription
paramsDIFFORUM_PARAMSFrom Setup: frame count, fps, width and height. Plug the same Setup everywhere.
scheduleSTRING0:(0.45), 60:(0.6), 119:(0.45)Values over time: 'frame:(value)', e.g. '0:(0.45), 60:(0.6)'. Frames can be '2s'. Expressions allowed: t = frame, amp/low/beat with audio.
easingCOMBOease_in_outHow values move between keys.
audiooptDIFFORUM_AUDIOFrom Audio Analyzer: per-frame loudness, bands and beats.

Outputs (2)

NameTypeDescription
scheduleDIFFORUM_SCHEDULE—
infoSTRING—