Nodes/msch-comfyui-nodes/Pointillism Effect (Video)
ComfyUI Node

Pointillism Effect (Video)

Your photo as forty thousand dancing dots — the video version of that pointillism trend

By mariobilly·Created a day ago·Updated a day ago· 0
Pointillism Effect (Video)
  • image
  • audio
  • video
  • frames
  • dots_mask
frames48
fps24
hold_frames2
frame_drop0.00
saturation1.35
contrast1.15
density40.0
point_size2.5
size_variation0.50
size_by_darkness0.00
edge_softness0.30
color_jitter0.05
dot_opacity1.00
distributionrandom
backgroundwhite
background_color#FFFFFF
distortion0.35
distortion_scale3.5
ink_bleed0.15
paper_grain0.12
seed0
animate_seedtrue

You've seen the look: a photo rebuilt as thousands of colored dots over white paper, the dots subtly re-scattering frame by frame with a steppy, stop-motion pulse. It blew up on socials as a filter, and PointillismEffect (display "Pointillism Effect (Video)") turns that same recipe into a single ComfyUI node - input a still or a clip, get a VIDEO out, no diffusion model, no weights, nothing to download. It's the video/stylize entry in the MSCH Nodes pack, and it's a genuinely good example of a procedural effect that most people assume needs a checkpoint.

How it works

The node scatters dots across the frame, each one sampling its color from the pixel beneath it, then animates the whole field. The motion is the clever part: with animate_seed on (default), the dot layout re-scatters every frame under a new seed - that's the shimmer. Two knobs then add the signature stutter. hold_frames (default 2) keeps each layout for 2–3 frames instead of re-scattering every single frame, which is what produces that stop-motion, frame-dropped feel. frame_drop adds an irregular stutter - a random chance a scheduled re-scatter is skipped - so the pulse doesn't tick like a metronome. Everything is pure PyTorch on the GPU, roughly 10 ms per 1024px frame once warm, and frames render one at a time so long clips don't accumulate in RAM.

The rest of the controls shape the print: density is dots per 1000 pixels (default 40 at 1024² ≈ 42,000 dots - crank toward 60–120 for a fuller image), point_size is dot radius, size_variation and size_by_darkness add irregularity and a stipple feel, distortion warps dots along a paper-fibre field so they stop being perfect circles, and ink_bleed/paper_grain sell the ink-on-paper finish. saturation and contrast are boosted before sampling (the recipe this is built on says more colour reads better), and background picks paper white, black, custom, or original - which keeps the photo faintly visible under the dots.

Wiring it

Feed image: a single still (it's animated for frames frames at fps) or an existing frame batch. Three outputs come back: video (native VIDEO - plug straight into Save Video), frames (the same frames as an IMAGE batch, for Video Combine or further nodes), and dots_mask (per-frame dot coverage: 1 = dot, 0 = paper) if you want to composite the dots over something else. Optional audio is muxed into the video output.

Install

It's one of 35 nodes in the unified MSCH Nodes pack - no separate repo, and unlike some stylizers it needs no model files. ComfyUI Manager search "MSCH Nodes" / msch-comfyui-nodes, or:

cd ComfyUI/custom_nodes
git clone https://github.com/mariobilly/msch-comfyui-nodes.git
cd msch-comfyui-nodes
python -m pip install -r requirements.txt

Then restart ComfyUI.

Gotchas

Two practical ones. Odd image dimensions get trimmed by a pixel so H.264 can encode them - if your source is odd-sized, don't chase the missing row. And the defaults are tuned for the still-photo look; if you're stylizing an actual video clip (Load Video → Pointillism → Save Video), set hold_frames to 1 so the motion reads continuously rather than stuttering your source's real movement into chop. Want the clean vector look from those grid posts? Kill distortion, ink_bleed, and paper_grain - pure dots, no paper.

Categoryvideo/stylize

Inputs (24)

NameTypeDefaultDescription
imageIMAGEA still image (animated for `frames` frames) or a frame batch.
framesINT481–4096Frames to generate from a still image. Ignored when the input is already a batch.
fpsFLOAT241–120
hold_framesINT21–30Keep each dot layout for this many frames. 1 = new dots every frame, 2-3 = the post's frame-drop stutter.
frame_dropFLOAT0.000–0.9Random chance a frame repeats the previous layout (irregular stutter).
saturationFLOAT1.350–3Boost colours before sampling (the post says: more colour, better).
contrastFLOAT1.150.2–3
densityFLOAT40.00.5–500Dots per 1000 pixels. 1024x1024 @ 40 = ~42k dots.
point_sizeFLOAT2.50.5–64Dot radius in pixels.
size_variationFLOAT0.500–1Random +/- radius variation (width variation).
size_by_darknessFLOAT0.000–1Bigger dots in dark areas, smaller in light (stipple feel).
edge_softnessFLOAT0.300–1
color_jitterFLOAT0.050–1Random per-dot colour variation.
dot_opacityFLOAT1.000–1
distributionCOMBOrandom2 options: random, jittered_grid
backgroundCOMBOwhitewhite = the post's Hidden image mode. original keeps the photo under the dots.
background_colorSTRING#FFFFFF
distortionFLOAT0.350–1Warps the dots with a paper-fibre field so they stop being perfect circles.
distortion_scaleFLOAT3.51–200Size in px of the warp features.
ink_bleedFLOAT0.150–1Softens dots like ink soaking into paper.
paper_grainFLOAT0.120–1
seedINT00–18446744073709550000
animate_seedBOOLEANtrueRe-scatter the dots over time (the animate-random-seed step). Off = frozen dot layout.
audiooptAUDIOOptional soundtrack muxed into the video output.

Outputs (3)

NameTypeDescription
videoVIDEOConnect to Save Video.
framesIMAGEThe same frames as an IMAGE batch (for Create Video / Video Combine).
dots_maskMASKPer-frame dot coverage (1 = dot, 0 = paper).