bEpic Image Viewer Roto
Draw a mask like it's Nuke, get a MASK tensor out
- image
- roto_mask
- image
Sometimes a segmentation model just won't give you the edge you want. SAM clicks land close, BiRefNet grabs the wrong thing entirely, and what you actually need is to draw the outline yourself - precisely, on top of the actual image. That's the whole point of bEpic Image Viewer Roto: it brings proper Nuke-style rotoscoping into ComfyUI, so you draw splines in the viewer and get a clean MASK tensor out the other end.
If you've spent time in VFX software, this feels familiar immediately. You add the node, wire an image in, run once to push it to the viewer's tab, then draw Bezier shapes over the picture. Each shape can carry feathering, opacity, per-shape invert, and you can stack layers that union together (Nuke's default) with a global blur/dilate/erode on top. When the workflow runs, the node rasterizes all of that into a float mask at your input image's resolution. That mask plugs straight into an inpaint, a compositing step, a regional prompt, or anything else that wants a MASK - which is where the "why would I reach for this over SAM" answer lives: this is for when you need your edge, not the model's best guess.
How it works
The clever bit is how your doodles survive a workflow save. The shapes are serialized as coordinates normalized against the image - (0,0) top-left, (1,1) bottom-right - into a hidden roto_data widget. That means the whole drawing travels inside the workflow JSON; save, share, reopen, and your matte is still there, resolution-independent. On the backend, roto_raster.py turns that JSON into a [N, H, W] mask batch at the resolution of whatever image you fed in. Bezier segments are tessellated and scan-filled, feathering is built with a distance-transform ramp, and everything is wrapped so a malformed or empty payload yields a black mask rather than a crash - an unused Roto node is harmless to leave wired up.
Inputs and outputs
You set exactly two things:
- image - anything with pixels (IMAGE or MASK); it's shown in the viewer and copied through untouched.
- tab_name - the viewer tab the drawing lands on.
The roto_data field is optional and you should not hand-edit it - the viewer writes it for you, and the widget is hidden in the UI.
Outputs are roto_mask (the MASK you care about) and image (the input passed through, so the node can sit inline in a chain rather than forcing you to rewire). Note the output ordering: roto_mask is first, so slots link by index - don't go rearranging wiring on an existing workflow.
Installing and gotchas
Same story as the rest of the pack: ComfyUI Manager, search ComfyUI-ImageViewer, install, restart - or git clone https://github.com/szprivate/ComfyUI-ImageViewer into custom_nodes, pip install -r requirements.txt, restart, then open the viewer with the "Toggle bEpic Image Viewer" button in the top bar. Dependencies are just Pillow and numpy, both already in ComfyUI.
The mask only appears after a run, and it's black until you actually draw something. Also remember this is a manual tool - it's precise, but it's you doing the work. And note the license before any commercial use: personal and non-commercial is free, commercial is prohibited without the author's written permission.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| image | * | — | |
| tab_name | STRING | — | |
| roto_dataopt | STRING | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| roto_mask | MASK | — |
| image | * | — |