Bring your Shadertoy code straight in
A Shadertoy shader is one mainImage function drawing to a flat canvas. VerkLabs doesn't ask you to rewrite it to get in the door — paste it in, and the uniforms it already expects (iTime, iResolution, iMouse, and more) are already there, waiting. What changes is what happens around it: that same shader can now run on a real 3D mesh, react to a mixed-down audio track instead of one texture, and sit inside a timed, multi-object scene — instead of being the whole scene by itself.
The built-in uniforms already exist
zero edits for most snippetsEvery shape's shader carries Shadertoy's standard globals before a single node is wired up - a snippet that only reaches for these compiles unmodified.
| On Shadertoy | Here, in VerkLabs | Why it matters |
|---|---|---|
| iTime | #define iTime time | Aliased to the same elapsed-seconds value every node already reads - not a separate clock. |
| iResolution | #define iResolution vViewPlaneSize | Matches .xy exactly. It's a vec2, not vec3 - code reading iResolution.z is the one thing that needs a small edit. |
| iFrame | #define iFrame frameCount | Same integer, starts at 0, increments once per frame. |
| iTimeDelta / iFrameRate | real uniforms, already declared | No alias needed - VerkLabs didn't have an equivalent, so these exist in their own right. |
| iMouse | real vec4 uniform | .xy current position, .zw where the mouse was last pressed, sign of .z tracks held/released - the two fields almost every pasted shader actually uses. |
| iDate | real vec4 uniform | Same layout: year, month (0-11), day, seconds since midnight. |
| iChannel0..3 | see step 3 | The one real adaptation - Shadertoy's channel textures map onto VerkLabs' own audio/image/video nodes instead of a fixed 4-slot picker. |
Pasting the code itself
one button wraps mainImage for youVerkLabs' nodes are typed GLSL functions, not fixed-signature callbacks - mainImage(out vec4, in vec2) doesn't fit that shape directly, so there's a dedicated button that wraps it.
- Open the burger menu → New Node from Code.
- Click Insert Shadertoy Template - it fills the textarea with a wrapper, placeholder name pre-selected so typing replaces it immediately:
vec4 shadertoyEffect(vec2 pos) { vec4 rgba; mainImage(rgba, pos * iResolution); return rgba; }
- Paste your mainImage body (and anything it calls) into the Helper Functions box below the wrapper - kept local to this one node, not mixed into the scene-wide Helper Code.
- Click Preview - VerkLabs parses the function signature itself to derive typed inputs/outputs, no separate name field to fill in.
Audio input, two ways
iChannel0-style, without hunting for a texture to uploadShadertoy's audio channel is a 512×2 texture - row 0 the frequency spectrum, row 1 the raw waveform. VerkLabs' audio-texture nodes cover the same shape, sourced live from a file, the microphone, or whatever's playing on the Runsheet - no separate texture upload step.
| On Shadertoy | Here, in VerkLabs | Why it matters |
|---|---|---|
| texture(iChannel0, vec2(uv.x, 0.0)) — spectrum row | Source Data · Audio Track (Texture), Microphone (Texture), Mix (Texture), Runsheet Track (Texture) | 512-wide, same resolution as Shadertoy's own audio texture, sampled the same way. |
| texture(iChannel0, vec2(uv.x, 1.0)) — waveform row | the matching (Waveform) node for each source above | A separate 1024-wide texture rather than a second row - wider, so a waveform read never falls into the gap between one frame's audio and the next. |
Any Audio track event on the Runsheet has an Expose as Uniform field. Type iChannel0 there, and that exact name becomes a real global uniform sampler2D in every shape's shader, active while that track is playing.
That means a pasted mainImage reaching for iChannel0 from deep inside a nested helper function just works - it's a genuine global, not something that has to be threaded through as a node input.
Two pasted shaders, zero name collisions
handled automaticallyShadertoy code leans on short, common helper names - hash21, rot2D, noise - because on Shadertoy each shader is the only thing in its own file. Paste two different snippets that both define hash21 into the same VerkLabs scene, and without help they'd collide the moment both compiled into one shader.
Every New Node from Code node's local helper functions are transparently namespaced behind the scenes - each one gets #define'd to a per-node-unique name right before it's used and #undef'd immediately after, so your pasted code keeps calling hash21 exactly as written, while the compiled shader sees two distinct functions underneath. Nothing to rename by hand, on your end.
5 · What a single shader gets, once it's in here
A Shadertoy shader is a closed loop: canvas in, canvas out. Drop the same code into VerkLabs and it's suddenly one piece of a larger, editable scene.
The same mainImage now shades an actual 3D object from the Builder tool - sphere, torus, custom lathe profile - not just a full-screen rectangle.
A color, a speed, a threshold you'd hand-tune and re-save on Shadertoy is now a node input - wire it to the mouse, the mic, a timeline, or leave it a plain number.
The Runsheet mixes several audio tracks and drives camera moves, parameters and overlays off exact frames or beats - a whole set, not one loop.
Several shapes, each with its own node graph (a pasted shader can be just one of them), sharing one scene, one camera, one timeline.
Nothing about getting in the door changes that: the shader still starts as the code you already wrote.
Why bring it here instead of leaving it on Shadertoy
The uniforms it already expects are already declared. Most snippets need the wrapper, not a rewrite.
Share a VerkLabs project the same way you'd share a Shadertoy URL - open it, see the live result, fork it.
No separate texture-upload step for iChannel0 - point it at a file, the mic, or whatever's playing on the Runsheet.
Combine it with other objects, a camera path, and a timed audio-visual show - all in the same free, no-install browser tab.