# Shader Toy previews GLSL inside Visual Studio Code, with a Shadertoy uniform set

> stevensona/shader-toy is a Visual Studio Code extension that renders a live WebGL preview of a GLSL shader in a split editor, with Shadertoy-style uniforms, texture channels, cubemaps, includes and keyboard input. Audio input is experimental and does not work from inside the editor.

**stevensona/shader-toy** — Shadertoy-like live preview for GLSL shaders in Visual Studio Code

- Repository: https://github.com/stevensona/shader-toy
- Website: https://marketplace.visualstudio.com/items?itemName=stevensona.shader-toy
- Stars: 722 · Forks: 58
- Language: TypeScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/stevensona-shader-toy

## A split view with a fullscreen quad and your fragment shader

Shader Toy is a Visual Studio Code extension that shows a live WebGL preview of a GLSL shader, in the same spirit as shadertoy.com. The entry point is a command, `Shader Toy: Show GLSL Preview`, which you can run from the Command Palette or from the context menu inside a text editor.

What the command does to your workspace is specific. It splits the view and displays a fullscreen quad with your shader applied. The shader is expected to have a `void main()` entry point, or, if that is unavailable, `void mainImage(out vec4, in vec2)`, where the first parameter is the output colour and the second is the fragment's screen position. That second signature is the Shadertoy convention, and it is what makes ports from shadertoy.com work with little editing.

The compatibility is not incidental. The extension documents a shader ported from shadertoy.com as an example, and the difference in that example is that `gl_FragCoord` replaces the equivalent value, since the coordinate convention differs between the two environments. The uniform names follow the same convention, which is why a shader written for shadertoy.com often runs here after one or two substitutions.

The extension is published on the Visual Studio Marketplace as `stevensona.shader-toy`, is written in TypeScript, and carries the MIT licence.

## A static preview command for multi-pass shaders

The second command is `Shader Toy: Show Static GLSL Preview`, and the difference between the two is the point of it. The static preview does not react to changing editors, while the live one does.

The reason the static variant exists is multi-pass work. An arbitrary number of static preview views can be open at the same time, and the documentation describes this as enabling a unique workflow for editing shaders that rely on multiple passes. A shader that samples the output of another shader, or that feeds one pass into the next, needs the first pass to be fixed while the second is edited. With only the live preview, every view is wired to the editor you are typing in, and you cannot hold one pass still.

So the two commands cover two different working modes. The live preview is for iterating on a single shader, where you want the result to update as you type. The static preview is for composing a pipeline of passes, where you want several compiled outputs on screen at once, each pinned to the state of a file at the time it was opened.

That is a small design decision with a real consequence for how you organise a multi-pass project in the editor, and it is worth knowing about before you start splitting files.

## The uniform set follows shadertoy naming

The available uniforms are listed explicitly, and they are the Shadertoy set: `iResolution`, `iGlobalTime` which is also available as `iTime`, `iTimeDelta`, `iFrame`, `iMouse`, `iMouseButton`, `iDate`, `iSampleRate`, `iChannelN` with N in the range zero to nine, and `iChannelResolution[]`.

Matching the names matters more than the count. A shader that uses `iGlobalTime` and `iResolution` ported from shadertoy.com runs unchanged, which removes the most tedious part of moving a shader between environments. A shader written for raw WebGL, which would use `uTime` and `uResolution` as ordinary uniform names, needs renaming.

The time uniforms come in two forms because the two ecosystems differ slightly. `iGlobalTime` is the time since the shader started, and `iTime` is an alias for it, while `iTimeDelta` gives the time since the previous frame. `iFrame` counts frames, `iDate` is the current date, and `iMouse` and `iMouseButton` carry pointer state.

For channels, `iChannelN` is a sampler and `iChannelResolution[]` reports the size of each one, so a shader that adapts to its texture dimensions can do so without knowing the sizes in advance.

## Texture channels, cubemap wildcards and the power of two rule

Texture inputs are declared with a directive at the top of the shader, one line per channel:

```glsl
#iChannel0 "file://duck.png"
#iChannel1 "https://66.media.tumblr.com/tumblr_mcmeonhR1e1ridypxo1_500.jpg"
#iChannel2 "file://other/shader.glsl"
#iChannel2 "self"
#iChannel4 "file://music/epic.mp3"
```

That single mechanism covers local images, remote images, another shader's result, the previous frame of the same shader through `self`, and audio. The caveat the documentation repeats is that power of two texture sizes are generally what you want, and the reason is the WebGL standard, which is why many sampling options only work with textures whose width and height are powers of two.

Sampling behaviour is set with a second directive on the same channel:

```glsl
#iChannel0::MinFilter "NearestMipMapNearest"
#iChannel0::MagFilter "Nearest"
#iChannel0::WrapMode "Repeat"
```

Cubemaps are a variation on the same idea. The path contains a wildcard and the type is stated explicitly:

```glsl
#iChannel0 "file://cubemaps/yokohama_{}.jpg" // Note the wildcard '{}'
#iChannel0::Type "CubeMap"
```

The wildcard is resolved by substitution from one of four sets, the short directions, the compass names, the `px`, `nx`, `py`, `ny`, `pz`, `nz` forms, or the `posx`, `negx` style forms. If any of the six files cannot be found, the next set is tried, starting from the first. One constraint on local paths: to use relative paths you have to open a folder in Visual Studio Code.

## Audio input does not work from inside the editor

Audio support is marked experimental, is disabled by default, and has to be enabled with the `Enable Audio Input` setting. The limitation is stated directly: audio input is not supported from within Visual Studio Code, because ffmpeg is not shipped with Visual Studio Code. To use audio in your shaders you have to generate a standalone version and host a local server so that local files can be loaded, or fiddle with your browser's security settings.

That is a substantial caveat for anyone writing audio reactive shaders, and it is worth reading as part of the feature rather than as a bug. The extension can play a file, but not a file sitting next to your project, unless you take the whole build out of the editor.

When a channel does carry audio, the type is inferred from the file extension, and the channel becomes a texture two pixels high and 512 pixels wide, with the width adjustable through the `Audio Domain Size` setting. The first row of that texture holds the audio frequency spectrum and the second row holds the waveform, which is a neat trick: a shader reads spectrum and waveform the same way it reads any other texture, through `iChannelN`.

Keyboard input works differently. You prepend `#iKeyboard` to the shader, and the extension exposes `isKeyPressed(int)`, `isKeyReleased(int)`, `isKeyDown(int)` and `isKeyToggled(int)`, along with constants such as `Key_A` to `Key_Z`, `Key_0` to `Key_9`, `Key_UpArrow`, `Key_LeftArrow` and `Key_Shift`.

## Includes, custom uniforms and the three settings that matter

Files can be pulled into a shader with an include directive, using a C-like syntax:

```glsl
#include "some/shared/code.glsl"
#include "other/local/shader_code.glsl"
#include "d:/some/global/code.glsl"
```

The included files may not define a `void main()` function, so they are for utility functions and constant definitions. The paths can be relative or absolute, including a drive letter, which is what makes a shared library of helpers practical on Windows.

Custom uniforms are declared with an `iUniform` directive, and the initial value plus an optional range decide what the editor shows you:

```glsl
#iUniform float my_scalar = 1.0 in { 0.0, 5.0 } // This will expose a slider to edit the value
#iUniform float my_discreet_scalar = 1.0 in { 0.0, 5.0 } step 0.2 // This will expose a slider incrementing at 0.2
#iUniform float other_scalar = 5.0 // This will expose a text field to give an arbitrary value
#iUniform color3 my_color = color3(1.0) // This will be editable as a color picker
```

A vec2 exposes two text fields and a vec4 with a range exposes four sliders. There is also a first person camera, `iViewMatrix`, which stays identity unless the shader uses the `#iFirstPersonControls` directive, and then WASD moves, `R` and `F` move up and down, `Q` and `E` roll, and the arrow keys pitch and yaw. The custom uniform feature is marked experimental and subject to change.

Three settings control the preview itself. `shader-toy.forceAspectRatio` takes two numbers, defaulting to zero, and setting either to zero or a negative value ignores it. `shader-toy.webglVersion` chooses between `Default` and `WebGL2`, where the default prefers WebGL2 but falls back to WebGL1, and WebGL2 uses GLSL 300 ES and enables the `#iVertex` directive. And `shader-toy.showCompileErrorsAsDiagnostics` is on by default, which surfaces compile errors as editor diagnostics rather than only in the preview.

## Conclusion

shader-toy fits a GLSL author who wants a live preview beside the source without leaving Visual Studio Code, especially one working on multi-pass shaders or porting code from shadertoy.com, and it fits a team already standardised on VS Code. It does not fit a web developer working in a browser, and it does not fit anyone who needs audio reactive shaders to work straight from the extension, because that path requires a standalone build and a local server. Check three things before you rely on it: the release history, since the newest tagged release is v0.10.15 from 2020-12-22 while the manifest reads 0.11.4 and the last push was on 2026-07-08, the WebGL version your shader needs, since the default prefers WebGL2 and falls back to WebGL1, and the fact that relative paths for local textures need an open folder in the editor.

## FAQ

### How do I open a GLSL preview in Visual Studio Code with shader-toy?

Run the `Shader Toy: Show GLSL Preview` command from the Command Palette or from the editor context menu. It splits the view and renders your shader on a fullscreen quad, using `void main()` or `void mainImage(out vec4, in vec2)` as the entry point.

### What is the difference between the live and the static GLSL preview?

The static preview does not react to changing editors, and an arbitrary number of static previews can be open at once. That is what lets you edit a shader that relies on multiple passes while holding the other passes fixed.

### Which uniforms does shader-toy provide?

The Shadertoy set: `iResolution`, `iGlobalTime` and its alias `iTime`, `iTimeDelta`, `iFrame`, `iMouse`, `iMouseButton`, `iDate`, `iSampleRate`, `iChannelN` for N between zero and nine, and `iChannelResolution[]`.

### Can shader-toy use audio input in Visual Studio Code?

Not from within the editor. Audio input is experimental, disabled by default, and it needs a standalone build with a local server because ffmpeg is not shipped with Visual Studio Code. The channel becomes a two pixel high texture whose first row is the frequency spectrum and second row the waveform.

### How do I load a local texture into a shader-toy channel?

Declare it at the top of the shader with a directive such as `#iChannel0 "file://duck.png"`, and note that relative paths require a folder to be open in Visual Studio Code. Sampling options are set with the `::MinFilter`, `::MagFilter` and `::WrapMode` suffixes on the same channel.

## Sources

- [License: MIT](https://github.com/stevensona/shader-toy/blob/master/LICENSE)
- [Project website](https://marketplace.visualstudio.com/items?itemName=stevensona.shader-toy)
- [README](https://github.com/stevensona/shader-toy/blob/master/README.md)
- [Releases](https://github.com/stevensona/shader-toy/releases)
- [stevensona/shader-toy on GitHub](https://github.com/stevensona/shader-toy)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/stevensona-shader-toy
