PIXELATE (JOV_GL)
Pixelate that actually holds up — blocky retro without the shimmer
- image
- RGBA
- RGB
- MASK
Pixelation is one of those effects every image editor does badly by default: it averages or resamples in a way that smears rather than reads as "retro blocky." This node does the classic shader version - it snaps the sample coordinates to a grid before sampling, so each block is a clean, flat sample of the original at that spot. No smearing, no bleed, just honest Minecraft-chic blocks. It's a one-input, one-knob node, and it's the most straightforward way to get that look inside a ComfyUI workflow instead of bouncing out to another tool.
How it works
The shader divides the UV by a cell size derived from amount, floors the result to snap onto a grid, and samples the image at the snapped coordinates. Because it's a pure per-pixel GPU operation, it re-renders instantly as you drag the slider, which makes it great for dialing in exactly how aggressive the effect is. The amount input (default 32, range 0–255) is the block size in pixels - bigger number, bigger blocks. The aspect ratio is handled internally, so blocks stay square-ish rather than stretching into rectangles.
The inputs
- image - RGB, RGBA, or MASK input.
- amount - the block size, default 32. This is the entire creative control, and honestly that's the right design for this effect.
Outputs are the pack standard: RGBA, RGB, and MASK. The MASK output is surprisingly useful - pixelating a mask gives you chunky "stepped" selections that read as deliberate graphic design rather than accidental noise.
Install
One-time pack install. Via ComfyUI Manager, search Jovi_GLSL; or:
cd ComfyUI/custom_nodes
git clone https://github.com/Amorano/Jovi_GLSL.git
cd Jovi_GLSL
pip install -r requirements.txt
Restart ComfyUI. Standard pack deps (PyOpenGL, glfw, opencv-contrib-python, cozy_comfyui from git), needs an OpenGL context. No models, no keys. Under **JOVI_GLSL 🌈 → COLOR`.
Gotchas
The amount tooltip says "Pixel data range allowed," which is a copy-paste from the posterize node - it's a block size, not a range. And a tip for the look people actually want: pixelate after you've done your heavy color work, because downsampling wipes out fine detail and there's no undo inside a single node. Also, at extreme amounts (way above your image's resolution) you get a handful of giant blocks, which is either a fun poster look or a sign you overshot.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| imageopt | IMAGE | RGB(A) image | |
| amountopt | FLOAT | 32.00–255 | Pixel data range allowed |
| FRAGMENTopt | STRING | // name: PIXELATE // desc: Pixelate input image // category: COLOR uniform sampler2D image; // | RGB(A) image uniform float amount; // 32;0;255;0.1 | Pixel data range allowed void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv = fragCoord / iResolution.xy; float d = 1.0 / amount; float ar = iResolution.x / iResolution.y; float u = floor( uv.x / d ) * d; float v = floor( uv.y / d ) * (ar / amount); fragColor = texture( image, vec2( u, v ) ); } | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| RGBA | IMAGE | Full channel [RGBA] image. If there is an alpha, the image will be masked out with it when using this output. |
| RGB | IMAGE | Three channel [RGB] image. There will be no alpha. |
| MASK | MASK | Single channel mask output. |