Shader Plugin Developer Guide
Z uses a hardware-accelerated OpenGL 3.3 Core rendering engine. Create effects, transitions, color grades, and audio-reactive shaders by adding annotated .frag files under plugins/.
Create and reload a plugin
- Create a
.fragfile in any subfolder ofplugins/. - Add an
@nameannotation and the uniforms your shader needs. - In Z, choose Effects → Reload Plugins, then add or re-select the effect.
Reload is manual. Z scans plugins on launch and when you choose Effects → Reload Plugins; it does not watch files for changes automatically.
Overview & How It Works
When Z Video Editor launches, the C++ PluginManager scans the plugins/ folder and all its subdirectories. It parses top-of-file comment annotations to build GUI controls (sliders, checkboxes, keyframe tracks) and dynamically compiles GLSL shaders on the GPU.
No application rebuild is required. Edit a .frag file, choose Effects → Reload Plugins, then add or re-select the effect.
Folder Hierarchy & UI Tree Auto-Mapping
Subfolders inside plugins/ automatically map directly to nested categories in the editor's Effects browser panel:
Z/
└── plugins/
├── Color & FX/
│ └── my_film_grade.frag --> Appears under "Color & FX"
├── Glitch & Datamosh/
│ └── my_glitch.frag --> Appears under "Glitch & Datamosh"
└── Retro Gaming/
└── Rock Band/
└── my_rockband_fx.frag --> Appears under "Retro Gaming -> Rock Band"
Header Annotations (@param)
Place comment tags at the very top of your .frag file to define name, category, and UI controls:
| Annotation Tag | Syntax Example | Description |
|---|---|---|
@name |
// @name My Custom Effect |
Name displayed in the Effects Browser and Timeline clip inspector. |
@category |
// @category Retro Gaming/Rock Band |
Explicit tree category override (optional if in subfolder). |
@desc |
// @desc VHS tracking static filter |
Tooltip description displayed when hovered in UI. |
@param |
// @param var Label min max default [bool] |
Exposes a float uniform parameter as an interactive GUI control. |
Creating Toggle Switches (Booleans)
If you add bool to the end of a @param declaration, Z Video Editor renders it as an ON/OFF checkbox toggle switch instead of a slider:
// Syntax: // @param <uniformName> <Label> <min> <max> <default> bool // @param active Enable Glitch 0.0 1.0 1.0 bool uniform float active; // Evaluates to 1.0 when checked, 0.0 when unchecked
Engine Data Uniforms (Passed from Video Pass)
Z Video Engine passes a rich set of video, timeline, mouse, and audio spectrum data to all fragment shaders automatically on every render frame:
| Uniform Name | GLSL Type | Description & Data Range |
|---|---|---|
videoTexture |
sampler2D |
Primary input video frame texture (Texture Unit 0). |
videoTexture2 |
sampler2D |
Secondary video frame texture (used during cut transitions). |
feedbackTexture |
sampler2D |
Previous frame FBO texture (used for temporal ghosting & motion blur trails). |
time |
float |
Timeline playback position in seconds (e.g. 12.45). |
resolution |
vec2 |
Viewport dimensions in pixels (width, height) (e.g. 1920.0, 1080.0). |
aspect |
float |
Aspect ratio width / height (e.g. 1.77777 for 16:9). |
frameIndex |
int |
Exact timeline frame counter floor(time * 30.0). |
fps |
float |
Timeline target framerate (e.g. 30.0). |
mouse |
vec2 |
Normalized cursor position (x, y) in range [0.0, 1.0]. |
mouseX |
float |
Normalized cursor X coordinate [0.0, 1.0]. |
mouseY |
float |
Normalized cursor Y coordinate [0.0, 1.0]. |
mousePressed |
int |
Left mouse button state: 1 if pressed, 0 if released. |
audioBass |
float |
Realtime FFT Audio Bass energy amplitude [0.0 - 1.0]. |
audioMid |
float |
Realtime FFT Audio Midrange frequency amplitude [0.0 - 1.0]. |
audioTreble |
float |
Realtime FFT Audio Treble frequency amplitude [0.0 - 1.0]. |
audioVolume |
float |
Master audio RMS volume level [0.0 - 1.0]. |
progress |
float |
Transition cut progress [0.0 - 1.0]. |
Line-by-Line Code Tutorial 1: Color Grade & Time Wobble
Below is a complete, line-by-line annotated shader showing how color grading, luminance thresholding, and time-based sine wave warping work:
#version 330 core // Step 1: Define UI Header Annotations // @name Tutorial 1: Color & Time Wobble // @category Color & FX // @desc Line-by-line educational shader for color manipulation // @param wobbleSpeed Wobble Speed 0.1 5.0 1.0 // @param saturation Saturation Boost 0.0 2.0 1.2 // @param active Enable Filter 0.0 1.0 1.0 bool // Step 2: Declare standard inputs from vertex shader pass in vec2 TexCoord; // Normalized UV coordinates [0.0, 0.0] top-left to [1.0, 1.0] bottom-right out vec4 FragColor; // Final RGBA pixel color written to framebuffer // Step 3: Declare built-in video engine uniforms uniform sampler2D videoTexture; // Input video texture sampler uniform float time; // Timeline playback time in seconds uniform vec2 resolution; // Viewport width and height in pixels // Step 4: Declare custom user parameters defined in @param annotations uniform float wobbleSpeed; uniform float saturation; uniform float active; void main() { // Step 5: Read original source video pixel color at current TexCoord vec4 baseColor = texture(videoTexture, TexCoord); // Step 6: If active toggle is OFF (0.0), bypass shader and output raw video if (active < 0.5) { FragColor = baseColor; return; } // Step 7: Calculate horizontal UV offset using trigonometric sine wave vec2 uv = TexCoord; float wave = sin(uv.y * 20.0 + time * wobbleSpeed * 4.0) * 0.01; uv.x += wave; // Step 8: Sample video frame at distorted UV position vec4 color = texture(videoTexture, uv); // Step 9: Calculate perceptual luma using ITU-R BT.601 weights float luma = dot(color.rgb, vec3(0.299, 0.587, 0.114)); // Step 10: Interpolate between grayscale luma and color for saturation adjustment vec3 saturatedColor = mix(vec3(luma), color.rgb, saturation); // Step 11: Write final RGBA color output FragColor = vec4(saturatedColor, color.a); }
Line-by-Line Code Tutorial 2: Audio-Reactive FFT Pulse
This shader uses the video engine's audioBass, audioMid, and audioTreble uniforms to pulse colors and warp geometry in sync with background music audio:
#version 330 core // @name Tutorial 2: Audio FFT Visualizer // @category Motion & Audio // @desc Pulsating chromatic energy tied to audio bass and treble // @param bassScale Bass Zoom Scale 0.0 2.0 1.0 // @param active Enable Audio FX 0.0 1.0 1.0 bool in vec2 TexCoord; out vec4 FragColor; uniform sampler2D videoTexture; uniform float audioBass; // Realtime low-frequency FFT amplitude [0.0 - 1.0] uniform float audioTreble; // Realtime high-frequency FFT amplitude [0.0 - 1.0] uniform float bassScale; uniform float active; void main() { vec4 baseColor = texture(videoTexture, TexCoord); if (active < 0.5) { FragColor = baseColor; return; } vec2 centerUV = TexCoord - vec2(0.5); float dist = length(centerUV); float zoomFactor = 1.0 - (audioBass * 0.15 * bassScale); vec2 pulsedUV = centerUV * zoomFactor + vec2(0.5); vec4 pulsedColor = texture(videoTexture, pulsedUV); vec3 flash = vec3(0.8, 0.2, 1.0) * audioTreble * smoothstep(0.2, 0.5, dist); FragColor = vec4(pulsedColor.rgb + flash, baseColor.a); }
Line-by-Line Code Tutorial 3: Mouse-Interactive Ripple Shader
This shader uses mouse, mouseX, mouseY, and mousePressed to distort video around the interactive cursor position in realtime:
#version 330 core // @name Tutorial 3: Mouse Ripple Distortion // @category Distortion & Warp // @desc Interactive ripple centered on mouse cursor position // @param rippleRadius Ripple Radius 0.05 0.5 0.2 // @param active Enable Mouse Ripple 0.0 1.0 1.0 bool in vec2 TexCoord; out vec4 FragColor; uniform sampler2D videoTexture; uniform vec2 mouse; // Normalized cursor position (x, y) in [0.0, 1.0] uniform int mousePressed; // 1 when left mouse button is held down, 0 otherwise uniform float time; uniform float rippleRadius; uniform float active; void main() { vec4 baseColor = texture(videoTexture, TexCoord); if (active < 0.5) { FragColor = baseColor; return; } vec2 uv = TexCoord; vec2 dir = uv - mouse; float dist = length(dir); if (dist < rippleRadius) { float amp = (mousePressed == 1) ? 0.08 : 0.03; float wave = sin(dist * 50.0 - time * 10.0) * amp * (1.0 - dist / rippleRadius); uv += normalize(dir) * wave; } FragColor = texture(videoTexture, uv); }
Line-by-Line Code Tutorial 4: Bitwise XOR Hardware Glitch
This tutorial demonstrates how GPU bitwise integer operators (^, &, |) are used to simulate hardware digital frame corruptions:
#version 330 core // @name Tutorial 4: Bitwise XOR Hardware Glitch // @category Glitch & Datamosh // @desc Bitwise XOR integer bitmask corruption of RGB video channels // @param xorMask Red/Green Bitmask 0.0 255.0 128.0 // @param active Enable XOR Glitch 0.0 1.0 1.0 bool in vec2 TexCoord; out vec4 FragColor; uniform sampler2D videoTexture; uniform float xorMask; uniform float active; void main() { vec4 baseColor = texture(videoTexture, TexCoord); if (active < 0.5) { FragColor = baseColor; return; } uvec3 intColor = uvec3(baseColor.rgb * 255.0); uint maskVal = uint(clamp(xorMask, 0.0, 255.0)); uvec3 mask = uvec3(maskVal, maskVal / 2u, 0u); uvec3 xorColor = intColor ^ mask; vec3 finalRGB = vec3(xorColor) / 255.0; FragColor = vec4(finalRGB, baseColor.a); }