人物遮罩 · Character Mask
Mask Exactly One Character in a Panel Without Painting a Thing
- image
- mask
Two people in one panel, and only one of them came out wrong. In any normal workflow you now go and paint a mask by hand, or run SAM and hope, or crop and stitch and lose the corners. SodaCharacterMask skips all of that: your storyboard already knows where each character stands in each panel, so the mask is geometry, not art. It generates a feathered soft mask around one named character in one named panel, and it deliberately carves out the other character standing next to them.
How it actually works
A Soda Storyboard page stores, per panel, which characters appear and roughly where - the same boxes the pack uses to compile the layout prompt. This node asks the core library (soda-storyboard) for that character's silhouette inside the panel, grows it by margin, blurs the edge by feather, and subtracts the neighbouring characters' regions so you don't stencil your paint over the other person's shoulder.
The scope widget is the part that trips people, and it's worth reading the author's own tooltip: 格子 means "you're feeding me a cropped panel, so scale the mask to that image"; 整页 means "you're feeding me the whole page, so place the mask at the panel's coordinates." Get that backwards and the mask still runs - it just lands in the wrong place, stretched across the full page instead of sitting on the panel.
margin and feather are measured in original storyboard-canvas pixels, not in the pixels of whatever tensor you hand it. The defaults, 24 and 16, are sane for the boxed figures a storyboard produces; trim the margin if the character's silhouette already overlaps a neighbour and the two regions are fighting.
The inputs that matter, and the one output
You wire four things: image, page_info, then pick panel and character_id. page_info comes straight off the loader node (SodaLoadStoryboard or SodaLoadStoryboardPage) and is a serialized snapshot of the page geometry - it's what every finishing node in this pack eats.
panel is a string, not an int. You can type the reading-order number starting at 1 or the panel's id. The character dropdown follows whichever panel you picked, so set the panel first and the character second, otherwise you're choosing from the cast list of the wrong panel. Old workflows that stored a bare number still work - it's interpreted as reading order from 1.
character_id has to be a character that appears in that panel - it's matched against the page's own character entries, so a workflow borrowed from someone else's project will need the ids swapped for yours.
Output is one mask (MASK). Feed it into whatever your inpaint branch expects: VAEEncodeForInpaint, a latent-noise-mask, or an inpaint-model conditioning node. The whole point is that masked editing at a controlled denoise is the reliable way to fix one thing in a finished image without redrawing the rest, and this node just removes the "draw the mask" step.
Install
Same for the whole pack. You need Python 3.12+ and a ComfyUI new enough to know the moss_image text-encoder type, plus the soda-storyboard core library, which is a separate pip install and not optional.
cd ComfyUI/custom_nodes
git clone https://github.com/cOkieeman/ComfyUI-Soda-Storyboard
cd ComfyUI-Soda-Storyboard && python -m pip install --upgrade soda-storyboard
Windows portable, from the ComfyUI_windows_portable folder:
.\python_embeded\python.exe -m pip install -r .\ComfyUI\custom_nodes\ComfyUI-Soda-Storyboard\requirements.txt
Or install it from ComfyUI Manager by searching Soda Storyboard (registry id comfyui-soda-storyboard), which pulls the core library from PyPI for you. Restart afterwards.
Where people get burned
If the core library is missing or too old, the nodes still appear in the menu and fail when you queue. That's by design - the pack registers everything up front and throws an install hint at run time. Core below 0.4.1 also misjudges whether English translations are stale, so just install fresh.
The classic failure is a scope mismatch, described above, or feeding a page whose dimensions aren't a multiple of 16 - the pack refuses those on import rather than letting Flux2's latent quietly decode to 992×992. And if you crop a panel, redraw it, and then try to mask in page coordinates, remember the mask units belong to the storyboard canvas, so the numbers stay meaningful no matter how large your upscale is.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| page_info | STRING | — | |
| panel | STRING | 1 | — |
| character_id | STRING | — | |
| margin | INT | 240–512 | — |
| feather | INT | 160–256 | — |
| scope | COMBO | 格子 | 格子:输入切出的单格,遮罩缩放到单格尺寸。整页:输入完整页面,遮罩按页面坐标放置。 |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| mask | MASK | — |