ComfyUI Node

Panner

Slide a texture around — the cheapest animation in the pack

By CoiiChan·Created about a year ago·Updated about a year ago· 2
Panner
  • imga
  • IMAGE
formulax_shift = -pint1 y_shift = -pint2 height, width = imga.shape[1:3] new_x = np.clip(np.arange(width) + x_shift, 0, width - 1) new_y = np.clip(np.arange(height) + y_shift, 0, height - 1) X, Y = np.meshgrid(new_x, new_y) result = imga[:, Y, X, :]
pint10
pint20

Panner shifts an image by a whole number of pixels in X and Y. That's it - no wrap-around, no scaling, no interpolation. It's the translate operation, exposed as two integer sliders: pint1 for the X offset, pint2 for the Y offset. Think of it as the node that slides a texture or a UV map around the canvas without resampling.

Where this shines is in the pack's texture-mapping chain. The recipe: generate a UV map, pan it, then sample a texture through it with Texture Sampler. Panning the UV map reads as the texture gliding across the surface - and because the pan is a pure integer shift of coordinates, you get a perfectly crisp slide with zero blur. That's the trick that makes "moving material" effects in ComfyUI trivial.

How it works

The formula builds a shifted index grid and gathers:

x_shift = -pint1
y_shift = -pint2
new_x = np.clip(np.arange(width) + x_shift, 0, width - 1)
new_y = np.clip(np.arange(height) + y_shift, 0, height - 1)
result = imga[:, Y, X, :]

Two details matter. First, the signs are inverted (-pint1), so a positive X value moves the image left - the classic "positive offset pushes content the opposite way" confusion that trips people up for exactly one workflow. Second, the coordinates are clamped to valid bounds rather than wrapped, so content that slides off one edge simply dies at the border. No seamless loop; if you want a scroll that repeats, you need a tiling source.

Inputs and outputs

  • formula - the pan script, pre-filled and editable.
  • imga - the image to pan.
  • pint1 - X offset in pixels (negative values allowed; the tooltip says "X-Axis Pixel(s)").
  • pint2 - Y offset in pixels.

One IMAGE output.

Install

ComfyUI Manager → search "FuncAsTexture", or:

cd ComfyUI/custom_nodes
git clone https://github.com/CoiiChan/ComfyUI-FuncAsTexture-CoiiNode
# restart ComfyUI

No models, no requirements.txt. Category: FunctionAsTexture.

Notes

  • Integer pixels only. No fractional offsets, so you can't do sub-pixel drift. For animation you'll be stepping a frame at a time - which is exactly what you want for crisp movement.
  • The border behavior is "clamp," not "wrap." Sliding an image 100px right leaves a 100px strip of the edge color (from the clamped coordinates) on the left. If you need that strip transparent, you'll want to build a mask of the moved region.
  • Pan a UV map, not just images. The imga input is agnostic - feeding it the output of UV Coordinate Generator (or any coordinate field) before a Texture Sampler is the workflow this node was built for.
  • Resolution mismatch rules don't apply here - single image input, so none of the two-image shape errors.

Panner is the pack's most direct "utility" node: no math to wrap your head around, just a directional shift with an inverted-sign quirk. It's the one you'll wire into an animation loop when you want the texture moving.

CategoryFunctionAsTexture

Inputs (4)

NameTypeDefaultDescription
formulaSTRINGx_shift = -pint1 y_shift = -pint2 height, width = imga.shape[1:3] new_x = np.clip(np.arange(width) + x_shift, 0, width - 1) new_y = np.clip(np.arange(height) + y_shift, 0, height - 1) X, Y = np.meshgrid(new_x, new_y) result = imga[:, Y, X, :]
imgaoptIMAGEOptional ,Reference size ,Default =(1,512,512,3)
pint1optINT0Optional(INT),X-Axis Pixel(s).
pint2optINT0Optional(INT),Y-Axis Pixel(s).

Outputs (1)

NameTypeDescription
IMAGEIMAGE