Expression
Animate any parameter with a line of math
- video
- keyframes
Every animation tool has the same boring problem: you want a parameter to move - drift up, pulse, wobble, ease in - and hand-keyframing 120 frames of it is drudgery. Expression is the shortcut. You type a formula, and it hands you a set of keyframes. sin(t*2)*10 is the default and it's a genuinely good place to start: a gentle oscillation you can wire into almost anything.
ComfyTV is jtydhr88's canvas app that turns ComfyUI into a full media workbench - ~190 stages, each its own node. Expression is one of its "parameter infrastructure" pieces: instead of animating pixels, it generates a stream of numbers that drives another stage's parameter. It's the math version of what After Effects expressions do for a slider.
How it works
The node evaluates your expression over time, where t is time in seconds (or frames - that's what rate and fps are for). The result is written as keyframes at your chosen rate. Two useful details:
- Wire an optional
videoin and it reads duration and fps from the source, so your animation exactly covers the clip without you doing the arithmetic. - There's a
seedfor deterministic pseudo-randomness, which matters more than you'd think - a seedednoise(t)expression gives you organic motion you can regenerate identically.
The output is keyframes (COMFYTV_TEXT), and that's the odd part if you're new here: this node's output isn't pixels or video, it's data to feed another stage's animated parameter.
The inputs that matter
- expression - your formula in
t. Keep it simple and readable; this is the whole node. - field - what the keyframes drive:
v,scale,opacity,x,y, orrotation. Pick the parameter you're animating so the downstream stage knows what the numbers mean. - rate (default 10) - keyframes per second. Higher = smoother, and costlier to the downstream stage.
- duration (default 5s) and fps (default 24) - overridden automatically if you wire in a video.
- seed - for deterministic randomness in the expression.
Every ComfyTV stage also carries hidden internal inputs (force_run_token, project_id, parent_output_id) populated by the frontend - that's the per-node Run plumbing. Leave them alone.
Installing it
ComfyTV installs as one pack - ComfyUI Manager, or:
cd ComfyUI/custom_nodes
git clone https://github.com/jtydhr88/ComfyTV
Full backend restart, then it's under ComfyTV → VideoFX. The one gotcha that bites people: on ComfyUI Desktop, macOS, or multiple installs, clone into the running instance by absolute path, confirm custom_nodes/ComfyTV/__init__.py (not a nested folder), and fully restart. The pack declares zero pip deps - mostly a frontend - though video stages lazily import PyAV, so pip install av if anything video-related errors.
Common issues
- Nothing animates - the keyframes went somewhere, but no downstream stage is consuming them. This node only produces data; you have to wire the
keyframesoutput into a parameter that accepts it. - Motion is way too fast or slow - that's
rateversus the clip's fps. Wiring the video in fixes this automatically; otherwise matchfpsto your footage. - Expression errors - formulas are evaluated as math over
t; a syntax slip fails fast. Test incrementally - start witht, then add the wobble.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| force_run_token | INT | 00–2147483647 | Internal — bumped on Run to invalidate ComfyUI's input cache. |
| project_id | STRING | Internal — populated by the projectStore on the frontend. | |
| parent_output_id | INT | 00–2147483647 | Internal — lineage parent set by spawn handlers on the frontend. |
| expression | STRING | sin(t*2)*10 | — |
| field | COMBO | v | 6 options: v, scale, opacity, x, y, rotation |
| rate | FLOAT | 101–60 | — |
| duration | FLOAT | 5.00.05–3600 | — |
| fps | FLOAT | 241–120 | — |
| seed | INT | 00–99999 | — |
| videoopt | COMFYTV_VIDEO | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| keyframes | COMFYTV_TEXT | — |