ComfyUI Node

Texture Offset

Shift, rotate, and check seams without re-rendering

By amtarr·Created 9 months ago·Updated 4 months ago· 58
Texture Offset
  • image
  • image
  • edge_mask
offset_x0.00
offset_y0.00
rotation0
wrap_moderepeat
edge_mask_width0.10

Texture Offset does one deceptively useful thing: it shifts your texture by a fraction, rotates it, or both - and keeps the result seamless if you want it to. The classic use is seam testing. A texture can look perfectly tileable in a flat view and still show a hard seam the moment it repeats, because you never looked at the offset boundary. Shifting by half a tile exposes exactly that.

You also reach for it when a texture comes out of a generator pointing the wrong way, when a normal map needs its orientation fixed, or when you want to nudge a detail pattern into alignment with your UVs without firing up an image editor.

How it works

The node applies three things, in order: offset, then rotation. The interesting part is the wrap_mode, because it changes the math:

  • repeat - the offset uses torch.roll, which is a true circular wrap: pixels falling off one edge reappear on the other, no sampling artifacts. Rotation in this mode tiles the image 3×3, rotates, then crops the center back - which is exactly why rotation stays seamless here.
  • clamp - edges are stretched rather than wrapped, via grid sampling with border padding. Good for bordered images, useless for tiling.
  • mirror - reflects at the edges, which creates symmetric patterns.

The second output, edge_mask, is a white-highlighted mask of the transformed edge regions - useful if you want to know where the operation affected things (for example, to feed into an inpainting pass later).

Inputs worth touching

  • offset_x / offset_y (−1.0 to 1.0, as a fraction of width/height) - 0.5 shifts by exactly half, which is the seam test you'll actually run. The repeat wrap is the one to keep on for tileable textures.
  • rotation (−360° to 360°) - degrees. With repeat enabled, this is the only place you can rotate a texture in this pack and keep it seamless.
  • wrap_mode - repeat, clamp, or mirror, as above.
  • edge_mask_width (0.0–0.5) - how wide the edge-mask highlight extends.

Outputs are image and edge_mask, both IMAGE.

Installing it

Texture Offset ships in ComfyUI-TextureAlchemy. In ComfyUI Manager, search "Texture Alchemy", install, restart. By hand:

cd ComfyUI/custom_nodes
git clone https://github.com/amtarr/ComfyUI-TextureAlchemy
# restart ComfyUI

No extra Python dependencies and no model files - pure PyTorch. It's under Add Node → Texture Alchemist → Texture. (The README's copy-the-ComfyUI_PBR_MaterialProcessor-folder instruction is stale - that's the pack's old name, so use Manager or git clone.)

Where people get burned

The most common mistake is leaving wrap_mode on repeat when you don't want circular wrapping - say, offsetting a decal or a bordered texture. You'll get pixels bleeding across edges that were supposed to stay put; switch to clamp. The other trap: offsets are fractions, not pixels. offset_x = 0.5 isn't "move right by 50 pixels", it's "move by half the image", so on a 2048 map it's a 1024-pixel shift. That's the right model for seam testing, just know what the numbers mean. Combine it with the pack's Texture Tiler - offset by half, then tile 2×2, and any remaining seam is immediately visible.

CategoryTexture Alchemist/Texture

Inputs (6)

NameTypeDefaultDescription
imageIMAGE
offset_xFLOAT0.00-1–1Horizontal offset (-1.0 to 1.0, fraction of width)
offset_yFLOAT0.00-1–1Vertical offset (-1.0 to 1.0, fraction of height)
rotationFLOAT0-360–360Rotation in degrees (0-360)
wrap_modeCOMBOrepeatWrapping mode for edges: repeat (tile), clamp (extend), mirror (reflect)
edge_mask_widthFLOAT0.100–0.5Edge mask width (0-0.5, fraction of image) - shows affected areas

Outputs (2)

NameTypeDescription
imageIMAGE
edge_maskIMAGE