Nodes/ComfyUI-RAFT/Save MotionBrush
ComfyUI Node

Save MotionBrush

Save motion you can reuse — the point of the whole pack

By chaojie·Created 3 years ago·Updated 2 years ago· 28
Save MotionBrush
  • motion_brush
    save_categorysmoke
    save_namesmoke1

    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>.flo per frame pair - Middlebury-format flow fields any flow utility can read, if you want to work with the motion in other tools.
    • One <n>.png per 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 MotionBrush type.
    • 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 form smoke/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.

    CategoryRAFT

    Inputs (3)

    NameTypeDefaultDescription
    motion_brushMotionBrush
    save_categorySTRINGsmoke
    save_nameSTRINGsmoke1

    Outputs (0)

    No outputs