ComfyUI Node

toobusy Paint Canvas

Paint in ComfyUI instead of leaving the app every two minutes

By nicekriss·Created about a year ago·Updated 3 days ago· 16
toobusy Paint Canvas
    • image
    • painted_mask
    • canvas_data
    canvas_data{"version": 1, "layers": []}
    width1024
    height1024
    background#ffffff

    The classic img2img workflow has a rhythm problem: sketch in Krita, save, drag into ComfyUI, generate, export, go back to Krita to fix something, repeat until you want to throw the monitor out the window. toobusy Paint Canvas folds the paint app into the graph. It's an openCanvas-style node - brush, eraser, color picker, layers, zoom and pan, undo - that lives at the front of your workflow, and every queued run takes the current painting as its input.

    The use case isn't pretty art, and don't let that stop you. A rough scribble here is a composition and mask tool: sketch the layout, paint the area you want regenerated, and feed both the image and the painted mask straight into a ControlNet or img2img pass. The README frames it as folding "external paint app + save + Load Image round trip" into one node, and that's the entire value proposition - the iteration loop you'd spend a minute round-tripping now happens by hitting Queue.

    How it works

    The frontend serializes the whole document into canvas_data, a JSON string with one PNG data URL per layer. On each run the node's backend composites the visible layers over the background color with Pillow, and separately computes the painted area's alpha as a mask. Because the data lives in the workflow, your painting is preserved between sessions - reopen the workflow and it's still there.

    Inputs and outputs that matter

    • canvas_data - the serialized layers. The custom UI writes it; leave it alone unless you're building a workflow that programmatically edits it.
    • width / height - canvas size, defaults 1024×1024, 64–2048 in steps of 8.
    • background - the canvas fill color, default white. If you want a mask you can composite onto, this is the one to tune.

    Three outputs:

    • image - the composited canvas. Wire this into an img2img or ControlNet input.
    • painted_mask - a MASK of everything you actually painted, including erased areas. This is the sleeper feature; it makes region-controlled regeneration trivial.
    • canvas_data - the same JSON back out, so you can chain a second node or save the state.

    Installing it

    It's part of nicekriss/toobusy:

    cd ComfyUI/custom_nodes
    git clone https://github.com/nicekriss/toobusy.git toobusy
    

    or find "toobusy" in ComfyUI Manager, restart, and hard-refresh the browser (the drawing UI is frontend JS - this is the node where a stale cache most often shows up as a dead canvas). Dependencies are just Pillow, numpy and torch; no optional requirements file is involved.

    Where people get burned

    Two things. First, everything is embedded in the workflow JSON - every layer is a base64 PNG - so a serious painting makes a serious file. Keep layers modest for shared workflows. Second, the canvas caps at 2048px edge. For most front-of-graph scribbling that's plenty, but if you're doing detail work at high resolution, this is a layout tool, not your final art surface.

    The honest take: if you're already happy with external paint + load image, you don't need this. If the round-trip is the bottleneck in your iteration loop - and for most ControlNet-and-sketch workflows it is - this kills the friction in one node.

    Categorytoobusy/Plan

    Inputs (4)

    NameTypeDefaultDescription
    canvas_dataSTRING{"version": 1, "layers": []}
    widthINT102464–2048
    heightINT102464–2048
    backgroundSTRING#ffffff

    Outputs (3)

    NameTypeDescription
    imageIMAGE
    painted_maskMASK
    canvas_dataSTRING