Coupled Oscillator Automata
GLSL shader by scry · created 2026-01-08 · updated 2026-01-12 · 10s loop · 4 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));
}
Buffer A (iChannel0)
#define NEIGHBOR_MODE 2 // 0=4-dir, 1=3x3, 2=5x5, 3=7x7, 4=9x9
vec3 px2(vec2 uv) {
return texture(iChannel2,uv).rgb;
}
vec3 px1(vec2 uv) {
return texture(iChannel1,uv).rgb;
}
vec3 px(vec2 uv) {
return texture(iChannel0,uv).rgb;
}
vec3 getPhase(vec2 uv) {
return px(uv)*pi*2.;
}
vec3 getPhaseDifference(vec2 uv, float angle) {
vec2 texel = 1.0 / iResolution.xy;
vec3 center = getPhase(uv);
vec3 diff = vec3(0.);
float count = 0.;
#if NEIGHBOR_MODE == 0
// 4-directional (up/down/left/right)
for (int i = 0; i < 4; i++) {
vec2 offset = vec2(i == 0 ? 1. : (i == 1 ? -1. : 0.),
i == 2 ? 1. : (i == 3 ? -1. : 0.));
vec2 rotatedOffset = offset * r2d(angle);
diff += sin(getPhase(uv + rotatedOffset * texel) - center);
count += 1.;
}
#else
#if NEIGHBOR_MODE == 1
const int radius = 1; // 3x3
#elif NEIGHBOR_MODE == 2
const int radius = 2; // 5x5
#elif NEIGHBOR_MODE == 3
const int radius = 3; // 7x7
#elif NEIGHBOR_MODE == 4
const int radius = 4; // 9x9
#else
const int radius = 1;
#endif
for (int y = -radius; y <= radius; y++) {
for (int x = -radius; x <= radius; x++) {
if (x == 0 && y == 0) continue;
vec2 offset = vec2(float(x), float(y));
vec2 rotatedOffset = offset * r2d(angle);
diff += sin(getPhase(uv + rotatedOffset * texel) - center);
count += 1.;
}
}
#endif
diff /= count;
return diff;
}
vec3 getNeighbors(vec2 uv) {
return getPhase(uv) + getPhaseDifference(uv, 0.);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec2 tv = uv;
uv -= 0.5;
uv.x *= ar;
vec3 col = vec3(0.);
vec3 phase = getPhase(tv);
vec3 neighbors = getNeighbors(tv);
// Calculate curl (rotation) from phase gradients
vec2 texel = 1.0 / iResolution.xy;
//vec3 dx = getPhase(tv + vec2(texel.x, 0.)) - getPhase(tv - vec2(texel.x, 0.));
//vec3 dy = getPhase(tv + vec2(0., texel.y)) - getPhase(tv - vec2(0., texel.y));
//vec3 curl = vec3(dy.x - dx.y, dy.y - dx.z, dy.z - dx.x);
//phase += 0.01 + curl * 0.001;
vec3 phase1 = px1(tv)*pi*2.;
vec3 phase2 = px2(tv)*pi*2.;
phase = phase+getPhaseDifference(tv, 45.) + sin(phase1 - phase) * 0.002;
phase += 0.02;
phase += sin(phase2 - phase) * 0.1; // subtle influence from iChannel2
//phase -= curl*0.1;
phase = mix(phase*1.05-0.005,phase1*1.04-0.5,0.03);
if (iFrame < 10) {
phase = (uv.xxx*4.+uv.y*9.+sin(uv.x*30.)+sin(uv.y*30.))*2.;
//phase = sin(uv.x)*0.2+uv.xxx;
}
phase += smoothstep(0.1,0.,length(uv-nm+0.5))*M.z*1.;
col = fract(phase/(pi*2.));
fragColor = vec4(col, 1.0);
}
Buffer B (iChannel1)
#define NEIGHBOR_MODE 4 // 0=4-dir, 1=3x3, 2=5x5, 3=7x7, 4=9x9
vec3 px0(vec2 uv) {
return texture(iChannel0,uv).rgb;
}
vec3 px(vec2 uv) {
return texture(iChannel1,uv).rgb;
}
vec3 getPhase(vec2 uv) {
return px(uv)*pi*2.;
}
vec3 getPhaseDifference(vec2 uv, float angle) {
vec2 texel = 1.0 / iResolution.xy;
vec3 center = getPhase(uv);
vec3 diff = vec3(0.);
float count = 0.;
#if NEIGHBOR_MODE == 0
// 4-directional (up/down/left/right)
for (int i = 0; i < 4; i++) {
vec2 offset = vec2(i == 0 ? 1. : (i == 1 ? -1. : 0.),
i == 2 ? 1. : (i == 3 ? -1. : 0.));
vec2 rotatedOffset = offset * r2d(angle);
diff += sin(getPhase(uv + rotatedOffset * texel) - center);
count += 1.;
}
#else
#if NEIGHBOR_MODE == 1
const int radius = 1; // 3x3
#elif NEIGHBOR_MODE == 2
const int radius = 2; // 5x5
#elif NEIGHBOR_MODE == 3
const int radius = 3; // 7x7
#elif NEIGHBOR_MODE == 4
const int radius = 4; // 9x9
#else
const int radius = 1;
#endif
for (int y = -radius; y <= radius; y++) {
for (int x = -radius; x <= radius; x++) {
if (x == 0 && y == 0) continue;
vec2 offset = vec2(float(x), float(y));
vec2 rotatedOffset = offset * r2d(angle);
diff += sin(getPhase(uv + rotatedOffset * texel) - center);
count += 1.;
}
}
#endif
diff /= count;
return diff;
}
vec3 getNeighbors(vec2 uv) {
return getPhase(uv) + getPhaseDifference(uv, 0.);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec2 tv = uv;
uv -= 0.5;
uv.x *= ar;
vec3 col = vec3(0.);
vec3 phase = getPhase(tv);
vec3 neighbors = getNeighbors(tv);
// Calculate curl (rotation) from phase gradients
vec2 texel = 1.0 / iResolution.xy;
//vec3 dx = getPhase(tv + vec2(texel.x, 0.)) - getPhase(tv - vec2(texel.x, 0.));
//vec3 dy = getPhase(tv + vec2(0., texel.y)) - getPhase(tv - vec2(0., texel.y));
//vec3 curl = vec3(dy.x - dx.y, dy.y - dx.z, dy.z - dx.x);
//phase += 0.01 + curl * 0.001;
vec3 phase0 = px0(tv)*pi*2.;
phase = phase+getPhaseDifference(tv, -45.) + sin(phase0 - phase) * 0.003;
phase -= 0.02;
//phase -= curl*0.1;
if (iFrame < 2) {
phase = (uv.xxx*4.+uv.y*9.+sin(uv.x*30.)+sin(uv.y*30.))*2.;
//phase = sin(uv.x)*0.2+uv.xxx;
}
phase += smoothstep(0.1,0.,length(uv-nm+0.5))*M.z*1.;
col = fract(phase/(pi*2.));
fragColor = vec4(col, 1.0);
}
Buffer C (iChannel2)
#define NEIGHBOR_MODE 1 // 0=4-dir, 1=3x3, 2=5x5, 3=7x7, 4=9x9
vec3 px0(vec2 uv) {
return texture(iChannel0,uv).rgb;
}
vec3 px1(vec2 uv) {
return texture(iChannel1,uv).rgb;
}
vec3 px(vec2 uv) {
return texture(iChannel2,uv).rgb;
}
vec3 getPhase(vec2 uv) {
return px(uv)*pi*2.;
}
vec3 getPhaseDifference(vec2 uv, float angle) {
vec2 texel = 1.0 / iResolution.xy;
vec3 center = getPhase(uv);
vec3 diff = vec3(0.);
float count = 0.;
#if NEIGHBOR_MODE == 0
// 4-directional (up/down/left/right)
for (int i = 0; i < 4; i++) {
vec2 offset = vec2(i == 0 ? 1. : (i == 1 ? -1. : 0.),
i == 2 ? 1. : (i == 3 ? -1. : 0.));
vec2 rotatedOffset = offset * r2d(angle);
diff += sin(getPhase(uv + rotatedOffset * texel) - center);
count += 1.;
}
#else
#if NEIGHBOR_MODE == 1
const int radius = 1; // 3x3
#elif NEIGHBOR_MODE == 2
const int radius = 2; // 5x5
#elif NEIGHBOR_MODE == 3
const int radius = 3; // 7x7
#elif NEIGHBOR_MODE == 4
const int radius = 4; // 9x9
#else
const int radius = 1;
#endif
for (int y = -radius; y <= radius; y++) {
for (int x = -radius; x <= radius; x++) {
if (x == 0 && y == 0) continue;
vec2 offset = vec2(float(x), float(y));
vec2 rotatedOffset = offset * r2d(angle);
diff += sin(getPhase(uv + rotatedOffset * texel) - center);
count += 1.;
}
}
#endif
diff /= count;
return diff;
}
vec3 getNeighbors(vec2 uv) {
return getPhase(uv) + getPhaseDifference(uv, 0.);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec2 tv = uv;
uv -= 0.5;
uv.x *= ar;
vec3 col = vec3(0.);
vec3 phase = getPhase(tv);
vec3 neighbors = getNeighbors(tv);
// Calculate curl (rotation) from phase gradients
vec2 texel = 1.0 / iResolution.xy;
//vec3 dx = getPhase(tv + vec2(texel.x, 0.)) - getPhase(tv - vec2(texel.x, 0.));
//vec3 dy = getPhase(tv + vec2(0., texel.y)) - getPhase(tv - vec2(0., texel.y));
//vec3 curl = vec3(dy.x - dx.y, dy.y - dx.z, dy.z - dx.x);
//phase += 0.01 + curl * 0.001;
vec3 phase0 = px0(tv)*pi*2.;
vec3 phase1 = px1(tv)*pi*2.;
phase = phase+getPhaseDifference(tv, -4.) + sin(phase0 - phase) * 0.003;
phase += 0.02;
phase += sin(phase1 - phase) * 0.02; // subtle influence from iChannel1
//phase -= curl*0.1;
if (iFrame < 2) {
phase = (uv.xxx*4.+uv.y*9.+sin(uv.x*30.)+sin(uv.y*30.))*2.;
//phase = sin(uv.x)*0.2+uv.xxx;
}
phase += smoothstep(0.1,0.,length(uv-nm+0.5))*M.z*1.;
col = fract(phase/(pi*2.));
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.