Config File Format (.sha.json)¶
This page describes the raw JSON config format. Most users will find it easier to use the Config panel in the UI instead — this reference is for those who prefer editing the file directly.
Naming Convention¶
The config file must share the same base name as your shader:
- Shader file:
example.glsl - Config file:
example.sha.json
Place them in the same directory. To generate a config automatically, run Shader Studio: Generate Config for GLSL File from the command palette.
Basic Example¶
A single-pass shader with no inputs:
Multi-Pass Example¶
Image reads from BufferA, BufferA reads keyboard input:
{
"version": "1.0",
"passes": {
"Image": {
"inputs": {
"iChannel0": { "source": "BufferA", "type": "buffer" }
}
},
"BufferA": {
"path": "bufferA.glsl",
"inputs": {
"iChannel1": { "type": "keyboard" }
}
}
}
}
Texture Input Example¶
Bind an image file to a channel:
{
"version": "1.0",
"passes": {
"Image": {
"inputs": {
"iChannel0": { "path": "textures/noise.png", "type": "texture" }
}
}
}
}
Video Input Example¶
Bind a video file:
{
"version": "1.0",
"passes": {
"Image": {
"inputs": {
"iChannel0": { "path": "videos/timelapse.mp4", "type": "video" }
}
}
}
}
Audio Input Example¶
Bind an audio file. The texture provides FFT frequency data (row 0) and waveform data (row 1), matching Shadertoy's audio format:
{
"version": "1.0",
"passes": {
"Image": {
"inputs": {
"iChannel0": {
"type": "audio",
"path": "music/track.mp3",
"startTime": 0,
"endTime": 30
}
}
}
}
}
Access in GLSL:
float fft = texture(iChannel0, vec2(uv.x, 0.25)).r; // FFT row
float wave = texture(iChannel0, vec2(uv.x, 0.75)).r; // Waveform row
Cubemap Input Example¶
Bind a T-cross layout cubemap image. The channel is bound as a samplerCube:
{
"version": "1.0",
"passes": {
"Image": {
"inputs": {
"iChannel0": {
"type": "cubemap",
"path": "textures/skybox.png",
"filter": "mipmap"
}
}
}
}
}
Access in GLSL (channel must be declared as samplerCube):
Script-Driven Uniforms¶
Add a script field to run a TypeScript or JavaScript file that computes custom uniform values each frame. The script exports named values; their types are inferred automatically:
{
"version": "1.0",
"script": "uniforms.ts",
"scriptMaxPollingFps": 30,
"passes": {
"Image": { "inputs": {} }
}
}
Example uniforms.ts:
Available context variables: iTime, iFrame, iResolution, iMouse, iDate, iChannelTime, iSampleRate.
Supported uniform types: float, vec2, vec3, vec4, bool.
Resolution Settings¶
Pin a resolution to the config so it applies whenever the shader is opened:
{
"version": "1.0",
"passes": {
"Image": {
"resolution": {
"scale": 1,
"aspectRatio": "16:9"
},
"inputs": {}
}
}
}
Fixed pixel dimensions:
Fixed dimensions are the base size. scale still applies if you set both:
This renders at 640 × 360.
Buffer passes use a simpler fixed-size resolution:
Passes¶
| Pass | Description |
|---|---|
| Image | Main output pass (required, always present) |
| BufferA–D | Intermediate render passes. Each renders to its own framebuffer and can be read by other passes. |
| Common | Shared GLSL code included in all passes. Useful for shared functions and constants. |
Each non-Image pass needs a path field pointing to its .glsl file. If the file doesn't exist, the visual editor offers a button to create it.
Channel Types¶
Each pass can bind up to 4 input channels (iChannel0 through iChannel3):
| Type | Fields | Description |
|---|---|---|
buffer |
source |
Read from another pass (e.g. "source": "BufferA") |
texture |
path, filter, wrap, vflip, grayscale |
Image file |
video |
path, filter, wrap, vflip |
Video file |
audio |
path, startTime, endTime |
Audio file with FFT/waveform texture |
cubemap |
path, filter, wrap, vflip |
T-cross cubemap image |
keyboard |
— | Key state input texture |
Texture / Video / Cubemap Options¶
| Field | Values | Description |
|---|---|---|
filter |
mipmap (default), linear, nearest |
Texture filtering |
wrap |
clamp (default), repeat |
Edge wrap mode |
vflip |
true / false |
Flip vertically |
grayscale |
true / false |
Texture only: convert to greyscale |
Buffer Self-Read¶
A buffer can read its own previous frame's output by binding itself as an input:
{
"BufferA": {
"path": "bufferA.glsl",
"inputs": {
"iChannel0": { "source": "BufferA", "type": "buffer" }
}
}
}
This is how Shadertoy-style feedback effects work (trails, fluid simulations, game of life).
File Paths¶
Paths in the config are relative to the config file's directory. Keep all referenced files (buffer .glsl files, textures, videos, audio) in the same directory or subdirectories.