ComfyUI Node

UR Region Editor

Draw a removal region by hand, keyframe by keyframe

By fengwk·Created 2 months ago·Updated 2 months ago· 0
UR Region Editor
    • regions_json
    • canvas_width
    • canvas_height
    • region_count
    regions_json[]
    canvas_width768
    canvas_height512
    default_frame_index0

    The mask has to come from somewhere. In the detailing world you get it from a detector; in the UniversalRemove world you can get it from this node - a mouse. UR Region Editor is the interactive front end of the pack: a canvas where you draw rectangles, circles, or polygons directly on your frames, scrub through a video timeline to set keyframes, and walk away with a clean regions_json string that describes exactly what should be removed and when.

    This is the node you reach for when there's no detector for your target - a watermark, a subtitle, a logo, a person standing where they shouldn't be. Manual masking, in other words, but with the video dimension built in: you're not drawing one mask, you're drawing keyframe masks.

    How it works

    The node is a thin backend that normalizes and re-emits JSON; the real magic lives in its web extension (region_editor.js). When the node is on your canvas you get the drawing tools: rectangle, circle, polygon, plus select/delete and clear. You can load a local image or video as the editing background - and here's the important part - the background is only for interactive positioning. It is not baked into the workflow, and it is not the source of truth. What actually survives in the workflow, and what gets sent downstream, is the regions_json text.

    You'll also get a frame scrubber, and you can write the current video-time frame number onto a region as its keyframe. That's what turns a drawing into "this region applies starting at frame 40."

    The inputs and outputs that matter

    Three inputs, and honestly only two of them are yours to think about:

    • regions_json - starts as []. You can also paste a hand-written regions array in here, edit it, and the canvas will render it. This is how the node stays portable.
    • canvas_width / canvas_height - set these to match your actual frame batch dimensions. This is the one that bites people (below).
    • default_frame_index - assigned to any region you draw without picking a keyframe.

    Outputs: regions_json (the normalized array, with a frame_index filled in on every region), canvas_width and canvas_height (echoed back for convenience), and region_count so you can sanity-check that you drew what you think you drew.

    The natural wire is regions_json → UR Regions To Mask Batch, which turns your keyframe scribbles into a mask for every frame of the batch.

    Why hand-drawing still makes sense

    The KB's detailing essay is right that automation is the whole game - until it isn't. Detectors find faces and hands and people; they do not find the watermark in the corner or the subtitle strip at the bottom. For one-off targets, a 30-second manual trace beats training or prompting anything. And unlike a plain inpainting mask, a keyframed region editor means the mask moves when the object moves, so a video removal doesn't require re-drawing 300 frames.

    Common issues

    The big one: canvas dimensions not matching your frame batch. Draw a box on a 768×512 canvas, feed it to frames that are actually 1280×720, and your mask lands in the wrong place entirely - the coordinates are absolute. Match canvas_width/height to your upstream frame size before you start drawing.

    The second gotcha is the portability illusion. The background image/video doesn't travel with the workflow - send your workflow to a friend and they'll see the regions floating over a blank canvas. The masks still render correctly because they're driven by regions_json against their frame batch, but the pretty backdrop you drew on is gone. If the JSON is hand-edited later and the editor can't parse it, the front end quietly falls back to an empty canvas rather than crashing - check the browser console if your regions suddenly vanish.

    CategoryUniversal Remove

    Inputs (4)

    NameTypeDefaultDescription
    regions_jsonSTRING[]
    canvas_widthINT76864–8192
    canvas_heightINT51264–8192
    default_frame_indexINT00–1000000

    Outputs (4)

    NameTypeDescription
    regions_jsonSTRING
    canvas_widthINT
    canvas_heightINT
    region_countINT