Nodes/ComfyUI-MAINodes/H3 Motion Editor (timeline, masks, automation) [alpha]
ComfyUI Node

H3 Motion Editor (timeline, masks, automation) [alpha]

Paint where the de-rope should act

By matlowai·Created 17 days ago·Updated about 17 hours ago· 112
H3 Motion Editor (timeline, masks, automation) [alpha]
  • images
  • samples
  • hold_map
  • mask
  • envelopes
  • report
editor_state
oracle_hold_map
fps24
ramptrue
bridge8
invert_maskfalse
outside_blocksbaseline
paint_res512
hold_until_editedtrue

Alpha, and the most ambitious node in the pack: a DAW-style editor that lives right on the ComfyUI canvas. Where the classic pipeline trusts the oracle to decide where motion is too fast, H3 Motion Editor lets you decide - by dragging time blocks onto a timeline and painting the problem areas frame by frame. It compiles to the same hold_map and MASK wires everything downstream already eats, so it's a drop-in for the pipeline, not a fork of it.

The workflow

Queue once to load the filmstrip, then work on the node itself. With no blocks laid out yet and hold_until_edited on (default), the graph stops here after writing the filmstrip - nothing downstream runs - so you can't accidentally trigger the expensive regen before you've touched anything. Layout your blocks, then:

  • Drag bracket blocks on the timeline - multiple blocks, snapped to the model's token grid, with the jerk profile drawn underneath so you see what the oracle sees.
  • Click a block and paint the problem areas with brush and eraser, frame by frame, onion skin included.
  • Set per-block dials - hold, feather size, feather profile and direction, edge grow, temporal fade.
  • Toggle A on hold, feather, or strength to draw an automation envelope with draggable breakpoints, exactly like an automation lane in a DAW.

A block with no strokes regenerates its whole time span; strokes narrow it to the painted region. Queue again and only the regeneration side re-runs - the baseline stays cached, so edits are cheap to iterate.

Inputs that matter

  • images - the baseline frames on the world clock (required).
  • editor_state - the serialized state the GUI widget maintains (required, but you don't touch it by hand unless you're an agent).
  • samples - the baseline latent, which drives the jerk profile strip.
  • oracle_hold_map - wire the oracle to gate it; blocks with hold=0 use oracle holds.
  • outside_blocks - what the composite shows on frames no block covers: baseline or regenerated.
  • paint_res (512) - the mask compile width; the composite rescales to full res.

Outputs are the drop-ins: hold_map → H3 Time Smear, mask → H3 Motion Composite (enable mask_is_soft there - the mask comes out already feathered and envelope-scaled), envelopes for inspection, and a report that prices the pass before you run it.

The agent angle

The editor state is plain JSON with a documented contract in the node's docstring ({"v": 1, "blocks": [...]}). Agents can author that JSON directly and skip the GUI entirely - the compile step is the same either way. If that matters to you, it's one of the nicer things about this node: the GUI is a convenience surface, not the interface.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/matlowai/ComfyUI-MAINodes

or ComfyUI Manager → ComfyUI-MAINodes, restart. Category latent/minimax/motion. It's an output-capable node (it can stop the graph after the filmstrip), and it's alpha - the interactive widget is young, so don't be shocked if the GUI evolves.

Common gotchas

Remember the grid: blocks snap to token boundaries, so a block you meant to start at frame 40 can land on 43. And invert_mask flips the final mask if you'd rather paint keep-baseline regions instead of regen regions. If your re-queues suddenly re-run the baseline, you edited something upstream of the cache - the "only regen re-runs" promise holds as long as the baseline branch is untouched.

Categorylatent/minimax/motion

Inputs (11)

NameTypeDefaultDescription
imagesIMAGEbaseline frames (world clock)
editor_stateSTRINGserialized editor state; the GUI widget maintains this
samplesoptLATENTbaseline latent, for the jerk profile strip
oracle_hold_mapoptSTRINGwire the oracle to gate it; blocks with hold=0 use oracle holds
fpsoptINT241–120
rampoptBOOLEANtrue
bridgeoptINT80–20
invert_maskoptBOOLEANfalseflip the final mask (paint keep-baseline regions instead)
outside_blocksoptCOMBObaselinewhat the composite shows on frames no block covers
paint_resoptINT512128–1024mask compile width; the composite rescales to full res
hold_until_editedoptBOOLEANtruewith no blocks laid out yet, stop the graph here after the filmstrip is written (nothing downstream runs); lay out blocks and run again. Off = an empty editor passes the oracle's map through

Outputs (4)

NameTypeDescription
hold_mapSTRING
maskMASK
envelopesSTRING
reportSTRING