with one click
shader-video
// Create shader visualizations and send as videos. Trigger words - shader, glsl, visualization, fractal, procedural art, trippy video.
// Create shader visualizations and send as videos. Trigger words - shader, glsl, visualization, fractal, procedural art, trippy video.
| name | shader-video |
| description | Create shader visualizations and send as videos. Trigger words - shader, glsl, visualization, fractal, procedural art, trippy video. |
Generate GLSL shader visualizations and render them to video for iMessage/Signal delivery.
# Render a shader to video (defaults: 4K, 6 seconds, high quality for iMessage)
~/.claude/skills/shader-video/scripts/render-shader shader.frag output.mov
# Fast preview (lower quality, smaller file)
~/.claude/skills/shader-video/scripts/render-shader shader.frag preview.mp4 --fast --width 720 --height 720
# Custom settings
~/.claude/skills/shader-video/scripts/render-shader shader.frag out.mov --duration 10 --width 1080 --height 1080
u_resolution, u_time).mov extension for QuickTime container with proper brandingFor best quality in iMessage, the script defaults to:
major_brand: qtCRITICAL: Use .mov extension, not .mp4. iMessage handles QuickTime-branded videos better.
Shaders should use these uniforms (glslViewer-compatible):
#version 330
uniform vec2 u_resolution; // Screen resolution in pixels
uniform float u_time; // Time in seconds
out vec4 fragColor; // Output color
void main() {
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
// Your shader code here
fragColor = vec4(uv, 0.5 + 0.5 * sin(u_time), 1.0);
}
The most interesting approach is evolving shaders through visual feedback:
This produces genuinely novel results because the shader evolves based on actual visual output rather than just code intuition.
The gold standard. Thousands of community shaders with full source code. Search by tags like "fractal", "raymarching", "voronoi", "procedural". Note: Shadertoy uses iTime, iResolution, fragCoord - translate to u_time, u_resolution, gl_FragCoord.
Patricio Gonzalez Vivo's interactive tutorial. Excellent for learning techniques: noise, fractals, patterns, shapes. Each chapter has editable examples.
The legendary shader artist. Deep dives on signed distance functions, smooth minimum, domain repetition, color palettes. His "useful functions" page is essential.
Another shader playground with different community. Good for finding weird experimental shaders that aren't on Shadertoy.
Shaders specifically designed for looping GIFs. Great for understanding how to create seamless animations.
Excellent shader tutorial videos. "An introduction to Shader Art Coding" is a great starting point for understanding the mindset.
Deep technical tutorials on raymarching, fractals, and procedural techniques. Very thorough explanations.
Live coding shader competitions. Watch artists create shaders from scratch in real-time. Great for learning creative process and shortcuts.
Minimalist shader editor focused on code golf (ultra-short shaders). See how much can be done in 280 characters.
JavaScript-based shader creation with a more accessible API. Good for understanding shader concepts before diving into raw GLSL.
When researching new shader ideas or looking for creative inspiration:
Curated gallery of 80+ beautiful GLSL shaders, each inspired by a celebrity/artist. Organized by effect type with full source code. Great for studying specific techniques: flow fields, reaction-diffusion, raymarching, physics simulations, bioluminescence, volumetric lighting. Browse the full gallery at radiant-shaders.com/gallery/all — click any shader to see the GLSL source and a live preview.
float sdCircle(vec2 p, float r) {
return length(p) - r;
}
float sdBox(vec2 p, vec2 b) {
vec2 d = abs(p) - b;
return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
}
vec2 repeat(vec2 p, float spacing) {
return mod(p + spacing * 0.5, spacing) - spacing * 0.5;
}
float smin(float a, float b, float k) {
float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);
return mix(b, a, h) - k * h * (1.0 - h);
}
vec3 palette(float t) {
vec3 a = vec3(0.5, 0.5, 0.5);
vec3 b = vec3(0.5, 0.5, 0.5);
vec3 c = vec3(1.0, 1.0, 1.0);
vec3 d = vec3(0.0, 0.33, 0.67);
return a + b * cos(6.28318 * (c * t + d));
}
float voronoi(vec2 p) {
vec2 n = floor(p);
vec2 f = fract(p);
float minDist = 8.0;
for (int y = -1; y <= 1; y++) {
for (int x = -1; x <= 1; x++) {
vec2 neighbor = vec2(float(x), float(y));
vec2 point = hash2(n + neighbor);
float d = length(f - neighbor - point);
minDist = min(minDist, d);
}
}
return minDist;
}
float fbm(vec2 p) {
float value = 0.0;
float amplitude = 0.5;
for (int i = 0; i < 6; i++) {
value += amplitude * noise(p);
p *= 2.0;
amplitude *= 0.5;
}
return value;
}
void main() {
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
float t = u_time;
float v = sin(uv.x * 10.0 + t) + sin(uv.y * 10.0 + t);
v += sin((uv.x + uv.y) * 10.0 + t);
v += sin(length(uv - 0.5) * 20.0 - t);
fragColor = vec4(vec3(sin(v), sin(v + 2.094), sin(v + 4.188)) * 0.5 + 0.5, 1.0);
}
void main() {
vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / u_resolution.y;
float a = atan(uv.y, uv.x);
float r = length(uv);
float v = a / 3.14159 + u_time * 0.1;
float w = 1.0 / r + u_time;
fragColor = vec4(vec3(fract(v * 5.0), fract(w * 2.0), fract(v * w)), 1.0);
}
For iMessage compatibility (defaults now optimized):
-tag:v hvc1 for iOS native playback-brand qt flagUse --fast flag for quick previews at lower quality.
ALWAYS save shader projects to ~/Movies/shaders/ with this structure:
~/Movies/shaders/
├── README.md # Index of all shader projects
├── project-name/ # kebab-case folder name
│ ├── shader-name.frag # The GLSL source code
│ ├── shader-name.mov # Rendered video (4K, QuickTime)
│ └── README.md # Description of technique & parameters
└── another-project/
├── effect.frag
├── effect.mov
└── README.md
Each project folder should contain:
.frag file - The GLSL fragment shader source.mov file - Rendered video (use .mov for iMessage compatibility)README.md - Brief description of the technique, inspiration source, and any tunable parametersExample README.md for a shader project:
# Murmurations
Boid flocking simulation inspired by r/generative.
## Technique
- Flow field from FBM noise for cohesive flock movement
- Multiple depth layers for parallax
- Dusk gradient background with vignette
## Parameters
- `numBirds` - Number of birds per layer (default: 80)
- `birdSize` - Size of bird chevrons (default: 0.015)
CRITICAL: render-shader has no built-in lock protection. When SDK sessions restart mid-render, multiple ffmpeg processes can write to the same .mov file simultaneously, causing "moov atom not found" corruption.
Always use a lock file when starting a render:
LOCKFILE="/tmp/render-shader-$(basename $OUTPUT).lock"
# Acquire lock (fail fast if already running)
if [ -f "$LOCKFILE" ]; then
echo "ERROR: Another render is already running for $OUTPUT (lock: $LOCKFILE)"
echo "Kill it first: kill $(cat $LOCKFILE) && rm $LOCKFILE"
exit 1
fi
echo $$ > "$LOCKFILE"
trap "rm -f $LOCKFILE" EXIT
~/.claude/skills/shader-video/scripts/render-shader shader.frag output.mov
To kill any existing render on the same output file before starting a new one:
LOCKFILE="/tmp/render-shader-$(basename $OUTPUT).lock"
if [ -f "$LOCKFILE" ]; then
OLD_PID=$(cat "$LOCKFILE")
echo "Killing existing render (PID $OLD_PID)..."
kill "$OLD_PID" 2>/dev/null
rm -f "$LOCKFILE"
sleep 1 # let ffmpeg flush/clean up
fi
If you see "moov atom not found" when playing a .mov:
ps aux | grep ffmpegpkill -f "ffmpeg.*output.mov"scripts/render-shader - Main rendering CLI (ModernGL backend)scripts/render-shader-metal - Metal GPU renderer with GLSL→Metal transpiler (experimental)scripts/depth-effects - Image-based VJ effects using depth/masksscripts/shader-template.frag - Starting point for new shadersRender times (M4 Pro, 4K 2160x2160, 6 seconds @ 30fps):
Metal vs ModernGL: Both perform similarly because ModernGL on macOS already uses Metal via translation layer. The bottleneck is:
Optimization tips:
--fast for previews (720p, lower bitrate)Apply VJ-style effects to photos using depth maps and segmentation masks:
# Effects that only need image + depth:
depth-effects parallax photo.jpg depth.png output.mp4
depth-effects pan photo.jpg depth.png output.mp4
depth-effects rutt-etra photo.jpg depth.png output.mp4
depth-effects pixelsort photo.jpg depth.png output.mp4
depth-effects pointcloud photo.jpg depth.png output.mp4
depth-effects datamosh photo.jpg depth.png output.mp4
# Effects that also need a mask:
depth-effects hologram photo.jpg depth.png mask.png output.mp4
depth-effects particles photo.jpg depth.png mask.png output.mp4
depth-effects chromatic photo.jpg depth.png mask.png output.mp4
# Options:
depth-effects parallax img.jpg depth.png out.mp4 --duration 6 --fps 30
Available effects:
Generate depth/mask with vision skill:
~/.claude/skills/vision/scripts/estimate-depth photo.jpg photo
~/.claude/skills/vision/scripts/segment-person photo.jpg photo
# Creates: photo_depth_gray.png, photo_mask.png