Project_2026-02-08_00-06-39
GLSL shader by scry · created 2026-02-08 · updated 2026-02-09 · 10s loop · 7 passes
This page opens the shader in the ShaderKit browser GLSL editor: edit it live, fork it, or render it to video, GIF or images up to 8K. Also available as a full-screen view and an embeddable player.
Shader source (GLSL)
Common
#define pi acos(-1.)
#define deg pi/180. //1 degree
#define time iTime*2.*pi/10. //sin(time) loops 10 seconds
#define R iResolution.xy //shorthand
#define ar R.x/R.y //aspect ratio
#define M iMouse //shorthand
#define xm (M.xy/R) //normalized mouse
#define nm ((xm.xy-0.5)*vec2(ar,1.)+0.5) //aspect ratio correction
vec3 cs = vec3(1.,2.,3.);
mat2 r2d(float a) {
return mat2(cos(a),sin(a),-sin(a),cos(a));
}
// Linear to sRGB
vec3 linearToSRGB(vec3 c) {
return mix(
c * 12.92,
1.055 * pow(c, vec3(1.0/2.4)) - 0.055,
step(0.0031308, c)
);
}
// sRGB to linear
vec3 sRGBToLinear(vec3 c) {
return mix(
c / 12.92,
pow((c + 0.055) / 1.055, vec3(2.4)),
step(0.04045, c)
);
}
// HSV to RGB
vec3 hsv2rgb(vec3 c) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
// RGB to HSV
vec3 rgb2hsv(vec3 c) {
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
// Color palette (common technique for shaders)
vec3 palette(float t, vec3 a, vec3 b, vec3 c, vec3 d) {
return a + b * cos(6.28318 * (c * t + d));
}
// Luminance (perceived brightness)
float luminance(vec3 color) {
return dot(color, vec3(0.299, 0.587, 0.114));
}
// Mix colors in HSV space
vec3 mixHSV(vec3 c1, vec3 c2, float t) {
vec3 hsv1 = rgb2hsv(c1);
vec3 hsv2 = rgb2hsv(c2);
vec3 hsv = mix(hsv1, hsv2, t);
return hsv2rgb(hsv);
}
Buffer A (iChannel0)
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec2 velocity = vec2(0.0);
// Initialize or update particle position
vec2 particlePos = texture(iChannel0, uv).xy;
// First frame initialization
if (iFrame < 1) {
// Initialize particle in circular pattern based on UV
float angle = uv.x * 2.0 * pi;
float radius = 0.3;
particlePos = vec2(cos(angle), sin(angle)) * radius;
} else {
// Update particle: orbit around center
vec2 center;
if (iMouse.z > 0.5) {
center = (xm - 0.5) * vec2(ar, 1.0);
} else {
center = vec2(0.0);
}
vec2 toCenter = center - particlePos;
float dist = length(toCenter);
// Attraction force towards center
float attractionStrength = 0.00002+iMouse.z*0.8;
// Tiny repulsion from exact center to prevent collapse
if (dist < 0.05) {
attractionStrength *= -0.3;
}
vec2 attraction = normalize(toCenter) * attractionStrength * 0.016;
// Apply attraction
velocity += attraction;
// Repulsion from walls in iChannel2
vec2 pixelSize = 1.0 / iResolution.xy;
float wallThreshold = 0.3; // Values above this are considered walls
// Sample iChannel2 at particle position
vec2 particleUV = (particlePos / vec2(ar, 1.0)) + 0.5;
float centerWall = texture(iChannel2, particleUV).r;
// Sample gradient around particle to find wall direction
vec2 wallGradient = vec2(0.);
float sampleRadius = 3.0;
for (float dy = -1.0; dy <= 1.0; dy += 1.0) {
for (float dx = -1.0; dx <= 1.0; dx += 1.0) {
if (dx == 0.0 && dy == 0.0) continue;
vec2 offset = vec2(dx, dy) * pixelSize * sampleRadius;
float wallValue = texture(iChannel2, particleUV + offset).r;
if (wallValue > wallThreshold) {
wallGradient += vec2(dx, dy) * wallValue;
}
}
}
// Apply mild repulsion away from walls
float repulsionMildness = 0.002;
velocity -= normalize(wallGradient + vec2(0.00001)) * length(wallGradient) * repulsionMildness;
// Attraction to walls in iChannel4
vec2 wallGradient4 = vec2(0.);
for (float dy = -1.0; dy <= 1.0; dy += 1.0) {
for (float dx = -1.0; dx <= 1.0; dx += 1.0) {
if (dx == 0.0 && dy == 0.0) continue;
vec2 offset = vec2(dx, dy) * pixelSize * sampleRadius;
float wallValue = texture(iChannel4, particleUV + offset).r;
if (wallValue > wallThreshold) {
wallGradient4 += vec2(dx, dy) * wallValue;
}
}
}
// Apply attraction towards iChannel4 walls
float attractionStrength4 = -0.0005;
velocity += normalize(wallGradient4 + vec2(0.00001)) * length(wallGradient4) * attractionStrength4;
// Attraction/repulsion from other particles
float repulsionStrength = +0.00004;
for (float i = 0.0; i < 1.0; i += 0.01) {
vec2 otherUV = vec2(i, 0.5);
if (abs(otherUV.x - uv.x) < 0.001) continue; // Skip self
vec2 otherPos = texture(iChannel0, otherUV).xy;
vec2 toOther = particlePos - otherPos;
float otherDist = length(toOther);
if (otherDist > 0.001) {
// Attraction at medium/long range
if (otherDist > 0.03) {
velocity -= normalize(toOther) * 0.000002 / (otherDist + 0.1);
} else {
// Repulsion at close range to prevent collapse
velocity += normalize(toOther) * repulsionStrength / (otherDist * otherDist + 0.02);
}
}
}
particlePos += velocity;
}
// Store particle position in RG channels
fragColor = vec4(particlePos, 0.0, 1.0);
}
Buffer B (iChannel1)
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec2 p = (uv - 0.5) * vec2(ar, 1.0);
// Resolution-independent particle size
float particleSize = 5.0 / iResolution.y;
vec3 col = vec3(0.0);
// Sample all particles from iChannel0 and render
for (float i = 0.0; i < 1.0; i += 0.01) {
vec2 sampleUV = vec2(i, 0.5);
vec2 particlePos = texture(iChannel0, sampleUV).xy;
// Draw particle as circle
float dist = length(p - particlePos);
float particle = smoothstep(particleSize * 1.3, particleSize * 0.2, dist);
col += vec3(1.0, 0.5, 0.2) * particle;
}
col += vec3(0.02, 0.03, 0.05); // Background
fragColor = vec4(col, 1.0);
}
Buffer C (iChannel2)
// Hash function for noise
float hash(vec2 p) {
return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord.xy / iResolution.xy;
// Get previous state
float state = texture(iChannel2, uv).r;
// Initialize on first frame with random noise
if (iFrame < 2) {
//if (mod(float(iFrame), 520.) == 0.) {
//state = hash(uv * 100.0 + vec2(0.1));
state *= 0.;
} else {
// Sample neighborhood (3x3 kernel)
float sum = 0.0;
vec2 pixelSize = 1.0 / iResolution.xy;
for (int y = -1; y <= 1; y++) {
for (int x = -1; x <= 1; x++) {
vec2 offset = vec2(float(x), float(y)) * pixelSize;
sum += texture(iChannel2, uv + offset).r;
}
}
// Smooth cellular automata rule
float avg = sum / 9.0;
// Smooth transition: values near 0.5 survive, extremes die
state = smoothstep(0.24, 0.42, avg) * (1.0 - smoothstep(0.2, 0.7, avg));
state = mix(state, avg, 0.2); // Blend with average for smoothness
}
vec3 col = vec3(state);
col += texture(iChannel1,uv).rrr*0.3;
fragColor = vec4(col, 1.0);
}
Buffer D (iChannel3)
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec3 col = texture(iChannel2,uv).rgb;
vec3 b = texture(iChannel3,uv).rgb;
col = clamp(col-0.02,0.,1.);
col += b*0.9;
//col += mix(col,b,0.9);
fragColor = vec4(col, 1.0);
}
Buffer E (iChannel4)
// Hash function for noise
float hash(vec2 p) {
return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord.xy / iResolution.xy;
// Get previous state
float state = texture(iChannel4, uv).r;
// Initialize on first frame with random noise
if (iFrame < 2) {
//if (mod(float(iFrame), 520.) == 0.) {
state = hash(uv * 100.0 + vec2(0.1));
//state *= 0.;
} else {
// Sample neighborhood (3x3 kernel)
float sum = 0.0;
vec2 pixelSize = 1.0 / iResolution.xy;
for (int y = -1; y <= 1; y++) {
for (int x = -1; x <= 1; x++) {
vec2 offset = vec2(float(x), float(y)) * pixelSize;
sum += texture(iChannel4, uv + offset).r;
}
}
// Smooth cellular automata rule
float avg = sum / 9.0;
// Smooth transition: values near 0.5 survive, extremes die
state = smoothstep(0.25, 0.399, avg) * (1.0 - smoothstep(0.22, 0.7, avg));
state = mix(state, avg, 0.3); // Blend with average for smoothness
}
vec3 col = vec3(state);
col -= texture(iChannel5,uv).rrr*0.3;
col += texture(iChannel2,uv).rrr;
fragColor = vec4(col, 1.0);
}
Buffer F (iChannel5)
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec2 p = (uv - 0.5) * vec2(ar, 1.0);
// Resolution-independent particle size
float particleSize = 5.0 / iResolution.y;
vec3 col = vec3(0.0);
// Sample all particles from iChannel0 and render
for (float i = 0.0; i < 1.0; i += 0.01) {
vec2 sampleUV = vec2(i, 0.5);
vec2 particlePos = texture(iChannel0, sampleUV).xy;
// Draw particle as circle
float dist = length(p - particlePos);
float particle = smoothstep(particleSize * 2., particleSize * 1., dist);
col += vec3(1.0, 0.5, 0.2) * particle;
}
col += vec3(0.02, 0.03, 0.05); // Background
fragColor = vec4(col, 1.0);
}
Image
Not used
More shaders by scry
- Project_2026-08-15_18-22-06
- Project_2026-08-14_16-45-00
- Project_2026-07-24_15-10-23
- Project_2026-07-15_03-18-26
- Glass of Orange Juice (raymarched)
- Project_2026-07-13_00-53-50
- Project_2026-07-10_16-39-54
- Popcorn ceiling
- Project_2026-06-20_15-32-19
- Project_2026-06-25_12-22-43
- Visual Enhancer
- Project_2026-06-24_11-11-39
Browse all public shaders · All shaders by scry · ShaderKit home
Unread comments
×Projects with new comments. Click to open and read.