👾 ToyShader Render
Run real Shadertoy GLSL shaders inside your ComfyUI graph
- iChannel0
- iChannel1
- iChannel2
- iChannel3
- IMAGE
- DEPTH
The name is accurate for once: this is a toy. But it's a genuinely fun one. ToyShader Render is a ComfyUI node that compiles and runs Shadertoy-style GLSL shaders on your GPU, then hands you back an animated image batch - plus, experimentally, a depth map. No diffusion model involved, no API, no key. If you've ever watched a Shadertoy demo of a kaleidoscope or a burning city and wished you could drop it into a workflow as a background plate or a moving texture, this is the pack for that.
Because it renders into the ComfyUI graph, its output plugs into everything else: feed the frames to a video-combine node for a loop file, or use them as a source for compositing. It's procedural, not generative - a different tool for a different job.
How it works
This isn't WebGL in a browser and it isn't CPU emulation. It renders with moderngl, a real OpenGL 3.3+ binding, into an offscreen framebuffer. The interesting part is the compatibility wrapper: for each frame the node injects Shadertoy's standard uniforms (iTime, iResolution, iFrame, iChannel0–3), defines a mainImage(...) entry point, and - the clever bit - wraps pow, smoothstep, and clamp in overloads that tolerate the sloppy mixed-vector calls that normally fail compilation. The upshot: copy a Shadertoy shader, paste it, and it usually just compiles. The pack ships 26 presets (clouds, fire, ocean, city flythroughs, "Zippy Zaps") so you can see it work before you touch any code.
The inputs that matter
preset- a dropdown built from the.glsland.txtfiles in the pack'sshaders/folder. Drop your own files in there and they show up (after a restart, see below).main_codeandbuffer_a_code- optional strings you can type into or wire in (Shader Code Input is made for this).main_codeoverrides the preset.buffer_a_codeis the multipass trick: its shader renders first into a texture that becomesiChannel0for the main pass.frame_countandfps- the animation's length; time advances as frame/fps.speedandscale- speed multipliesiTime; scale zooms the fragment coordinate around screen center.depth_var,depth_scale,invert_depth- the experimental depth feature.depth_varis the name of a variable in your shader holding depth (sayd). The node injects code that encodes that value into the alpha channel, then pulls it out as a grayscale map;depth_scaletunes the response andinvert_depthflips it.tex_0_builtin–tex_3_builtinandiChannel0–iChannel3- texture sources for the channels. Priority: an external image input wins, then a builtin procedural texture (noise, clouds, wood, checkerboard…), then a white fallback.
Outputs
Two of them, IMAGE and DEPTH - and both are batches of frame_count frames, not single images. That's the most common beginner stumble: the IMAGE output is a video, which is why the node also saves an animated WebP preview to its own thumbnail so you see the loop without doing anything. To get a file, wire IMAGE into a video combine (VHS Video Combine, or a Save Animated WebP node). DEPTH is the same frames as 3-channel grayscale.
Install
In ComfyUI Manager, search "ToyShaders", or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/jav12z/ComfyUI-ToyShaders
cd ComfyUI-ToyShaders
pip install -r requirements.txt
Restart ComfyUI. The dependency that actually matters is moderngl (the rest of requirements.txt is just numpy and Pillow).
Common issues
- OpenGL context errors - the real one. Moderngl needs an OpenGL 3.3+ context. On a desktop machine with a GPU you're fine. On a headless Linux server you'll get a context-creation failure; the renderer tries a standalone context, then an EGL backend, and if both fail every frame comes back black. If you're headless, install Mesa EGL or run under xvfb.
- New shader files don't appear in
preset. The list is scanned when the node loads, so restart ComfyUI (or reload the workflow) after dropping a file intoshaders/. - Depth output all black.
depth_varmust exactly match a variable in your shader, and this feature genuinely doesn't work with every shader - it's flagged experimental in the README for a reason. - Wired-in
main_codesilently ignored. If the string is under about ten characters the node treats it as empty and falls back to the preset. An empty or stub box does nothing. - Watch the resolution math.
frame_count× width × height is a lot of GPU work. 24 frames at 512² is smooth; don't expect 4096² for hundreds of frames to be instant.
ToyShader is a hobby project - the author announced it on r/comfyui in late 2025 and built it with heavy help from an AI coding assistant, and it shows in the best way: small, single-purpose, generous with presets, honest about its experimental bits. One reminder before you ship anything: the engine is MIT-licensed, but shader code lifted from Shadertoy is usually CC BY-NC-SA, so respect the original artists if you go commercial.
Inputs (20)
| Name | Type | Default | Description |
|---|---|---|---|
| width | INT | 51264–4096 | — |
| height | INT | 51264–4096 | — |
| frame_count | INT | 24 | — |
| fps | INT | 24 | — |
| preset | COMBO | 26 options: 301's Fire Shader - Remix 3 , Cloud Ten, Kelp Forest_fishes, Oceanic , Tiled Gilded Rainbow Tunnel, Tokyo , +20 | |
| speed | FLOAT | 1.0 | — |
| scale | FLOAT | 1.0 | — |
| depth_var | STRING | — | |
| depth_scale | FLOAT | 0.1000.001–10 | — |
| invert_depth | BOOLEAN | false | — |
| tex_0_builtin | COMBO | 9 options: none, Noise White (Mono), Noise White (RGB), Noise Blue (Approx), Bayer 8x8 (Dithering), Clouds (Organic), +3 | |
| tex_1_builtin | COMBO | 9 options: none, Noise White (Mono), Noise White (RGB), Noise Blue (Approx), Bayer 8x8 (Dithering), Clouds (Organic), +3 | |
| tex_2_builtin | COMBO | 9 options: none, Noise White (Mono), Noise White (RGB), Noise Blue (Approx), Bayer 8x8 (Dithering), Clouds (Organic), +3 | |
| tex_3_builtin | COMBO | 9 options: none, Noise White (Mono), Noise White (RGB), Noise Blue (Approx), Bayer 8x8 (Dithering), Clouds (Organic), +3 | |
| main_codeopt | STRING | — | |
| buffer_a_codeopt | STRING | — | |
| iChannel0opt | IMAGE | — | |
| iChannel1opt | IMAGE | — | |
| iChannel2opt | IMAGE | — | |
| iChannel3opt | IMAGE | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |
| DEPTH | IMAGE | — |