Nodes/ComfyUI-Whisker-Nodes/Whisker: Offset Image
ComfyUI Node

Whisker: Offset Image

The mechanical half of making a seamless tile

By nerdywhiskers·Created 5 months ago·Updated a day ago· 1
Whisker: Offset Image
  • image
  • offset_image
  • seam_mask
offset_x0
offset_y0
mask_thickness10
mask_blur0.0

If you've ever tried to make a generated image tile, you know the drill: the left edge doesn't line up with the right, and no amount of prompt magic fixes it. The honest way to make an image you already have seamless is the offset-and-inpaint trick - roll the image so the two offending edges meet in the middle, inpaint the seam, roll it back, done. offset_image is the mechanical half of that, and it's the rare node where the output you actually care about is the mask, not the shifted picture.

The ideal solution, note, is to generate tileable from the start by toggling circular padding at generation time - that's the "tiling" checkbox in A1111 and the seamless-tiling nodes in ComfyUI. Post-fixing a non-tiling image is the fallback. But fallback is exactly what this is for: you already generated, you're not re-rolling, and inpainting the seam keeps every other pixel bit-identical (something no instruction-editing model offers you).

How it works

It's refreshingly small. torch.roll shifts the image by offset_x and offset_y pixels, wrapping content from one edge around to the opposite - a true tile-style shift, not a crop-and-fill. Then it draws a seam_mask centered on the actual wrap line (computed modulo the image size, so it lands correctly even for offsets larger than the image), with mask_thickness controlling the band width and mask_blur feathering its edges with a Gaussian.

That seam mask is the whole point: it marks exactly the pixels where the texture repeats discontinuously, which is the region you want to feed to an inpainting model.

The few settings you'll touch

  • offset_x / offset_y - the shift in pixels. For a classic seamless tile you roll by roughly half the width or height, so both edges meet mid-image. Negative values work fine; roll the image back later with the negated offset.
  • mask_thickness - how wide the seam band is. Start around 10–20; too thin and the inpaint won't cover the visible discontinuity, too thick and you blur across genuinely different texture.
  • mask_blur - feather the mask edges so the inpainted region blends rather than showing a hard boundary.

Outputs are offset_image and seam_mask. It's batch-safe: feed it a frame batch and you get one shifted batch plus a seam mask repeated per frame, which makes it usable for video loops too.

Wiring it into inpainting

Roll the image, take seam_mask, feed both into a masked-inpainting setup (the mask routes to the inpaint/denoise step; the shifted image is your source), generate, then roll the result back by the negative offset. Two bonus behaviors to know: if an offset is 0, no mask is drawn on that axis, so offsetting only X gets you a tileable horizontal strip; and the mask renders even when the offset is bigger than the image, thanks to that modulo.

Installing it

It's part of the Whisker pack, so install once:

cd ComfyUI/custom_nodes
git clone https://github.com/nerdywhiskers/ComfyUI-Whisker-Nodes.git
pip install -r ComfyUI-Whisker-Nodes/requirements.txt

ComfyUI Manager users can just search "ComfyUI-Whisker-Nodes". Restart and you'll find it under Add Node → whisker-nodes. Unlike the pack's background-removal nodes, this one is pure PyTorch - no model downloads, no transformers, nothing heavy. That's the nicest thing about it: it's instant.

Categorywhisker-nodes

Inputs (5)

NameTypeDefaultDescription
imageIMAGE
offset_xINT0-8192–8192
offset_yINT0-8192–8192
mask_thicknessINT101–512
mask_blurFLOAT0.00–50

Outputs (2)

NameTypeDescription
offset_imageIMAGE
seam_maskMASK