Save MotionBrush
Save motion you can reuse — the point of the whole pack
- motion_brush
Freeze the motion so you never compute it twice
Optical flow is expensive enough that you don't want to recompute it every time you experiment. Save MotionBrush is the shelf: it takes a motion brush and writes it to disk under ComfyUI/output/motionbrush/, where it lives as a reusable .npy file - plus some human-readable extras. This is what turns "I ran RAFT on a smoke clip" into "I own a library of smoke motions."
Here's the mental model the author is working with. In the commercial world, Runway's Multi-Motion Brush lets you paint motion onto an image and animate it. The open-source equivalent needs a transportable representation of "this is how these pixels moved," and the .npy motion brush is that representation. The companion pack ComfyUI-DragNUWA reads these files with its BrushMotion node and paints them onto your own images to drive an SVD-based animation. This pack saves the brush; DragNUWA spends it.
What it writes
Point it at a motion brush and it creates output/motionbrush/<save_category>/<save_name>/ containing:
<save_name>.npy- the whole flow batch as float32. This is the brush itself, the file every other tool loads.- One
<n>.floper frame pair - Middlebury-format flow fields any flow utility can read, if you want to work with the motion in other tools. - One
<n>.pngper frame - the color-coded visualization, so the folder is self-documenting when you stumble on it a month later.
The inputs that matter
Only three, and two of them are naming:
- motion_brush - the data. Expects the
MotionBrushtype. - save_category - a folder name, default
smoke. Think of this as the collection: one folder per kind of motion. - save_name - the file name, default
smoke1. Together they formsmoke/smoke1, which is exactly the default path Load MotionBrush already points at.
One honest gotcha, straight from the source: RAFT Run outputs the OPTICAL_FLOW type, and this node's socket is typed MotionBrush - ComfyUI won't let you wire them directly. The author's own "Save MotionBrush To Disk" workflow bridges the gap through the companion DragNUWA pack's converter nodes (e.g. LoadMotionBrushFromOpticalFlowWithoutModel), which can also take flow straight from the Unimatch_OptFlowPreprocessor in comfyui_controlnet_aux. So in practice: get OPTICAL_FLOW from anywhere - this pack's RAFT Run, Unimatch, whatever - convert it with a DragNUWA node, and save. Or feed it an existing brush from Load MotionBrush if you're reorganizing your library. The .npy format is the lingua franca; it doesn't care which model produced the motion.
It's an output node with no return values - the workflow just ends here, which is fine and intended.
Install
Same as the rest of the pack: ComfyUI Manager → search ComfyUI-RAFT, or git clone https://github.com/chaojie/ComfyUI-RAFT into custom_nodes and restart. If you want the converter nodes for feeding it from optical flow, you'll also want the companion ComfyUI-DragNUWA pack - it's a bigger install (a separate drag_nuwa_svd.pth checkpoint), so only grab it when you actually want to animate.
Notes
Watch your disk: a 512×512 brush costs about 2 MB per frame pair in float32, so a 14-frame clip is roughly 26 MB of .npy. Also, since the dropdown in Load MotionBrush is built when that node is added, a brush you just saved won't appear there until you refresh or re-add the node - worth knowing before you think the save failed.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| motion_brush | MotionBrush | — | |
| save_category | STRING | smoke | — |
| save_name | STRING | smoke1 | — |
Outputs (0)
No outputs