ComfyUI Node

Shift Mask

Nudge a mask sideways — and watch it wrap around

By Quasimondo·Created 2 years ago·Updated about a year ago· 15
Shift Mask
  • mask
  • mask
x_offset0
y_offset0

The simplest node in this pack, and one of the most quietly useful: Shift Mask moves a mask by an X/Y offset. Two integers in, one mask out, no model, no dependencies beyond torch. You'd think every mask workflow has this - and honestly, ComfyUI's core should, but here we are, so it lives in Mario Klingemann's "I wrote it myself" grab-bag instead.

When do you need it? When your mask doesn't line up with your image. A subject mask that needs to sit a few pixels down, a stencil you're repeating across a tile, a region you want to offset for a second pass, or a mask you want to drift frame-by-frame for an animation. It's the kind of node you don't think about until you need it three times in one session.

How it works

Under the hood it's a single torch.roll - a circular shift. The mask's pixels move by the offset, and what falls off one edge wraps around to the other. That's the one behavioral detail you must internalize: this is not a crop-and-shift, it's a roll. Shift a mask 20px right and the left 20px of content reappears on the right edge.

That wrap-around is a feature if you're working with tiling textures or periodic patterns - it keeps the mask's area conserved, which is exactly what you want when the mask represents a bounded region being moved. It's a surprise if you expected a "cut and slide" behavior, where edges just move and the vacated area goes empty.

It handles both a single 2D mask and a batch (3D) tensor, shifting along the right dimensions either way.

The inputs that matter

  • mask - the mask to shift.
  • x_offset - horizontal shift in pixels. Negative moves left, positive moves right.
  • y_offset - vertical shift. Negative moves up, positive moves down.

Both are integers with a huge range (up to ±10000), and the wrap means even offsets larger than the mask's dimensions just roll multiple times - no error, no clipping.

One output: mask, the same size and dtype as the input.

Install

From the Quasimondo pack. ComfyUI Manager → search ComfyUI-QuasimondoNodes, or:

cd ComfyUI/custom_nodes
git clone https://github.com/Quasimondo/ComfyUI-QuasimondoNodes
cd ComfyUI-QuasimondoNodes
pip install -r requirements.txt

No models, no special dependencies - pure torch.

Where people get burned

The wrap-around is the one true trap. If you shift a face mask by a few pixels to realign it with an image, the rolled-over sliver on the opposite edge can create a faint phantom region that then gets processed by whatever consumes the mask. For small offsets it's usually invisible or irrelevant; for large ones it can genuinely bite. If you want a clipped shift (empty where the mask vacated), this isn't the node - you'd want to crop and pad instead.

Also, offsets are integers. If you're animating a mask drifting smoothly across frames, you'll want to derive integer offsets (or use a float-shift node elsewhere); this one steps in whole pixels. For a "slide a mask to align" job, though, it's exactly the tool, and you can stop re-implementing it with crop nodes.

Categoryimage

Inputs (3)

NameTypeDefaultDescription
maskMASK
x_offsetINT0-10000–10000
y_offsetINT0-10000–10000

Outputs (1)

NameTypeDescription
maskMASK