learn GLSL from zero
ToolsCreate with shadersShader MakerFree online shader builderToolkitShader works ready for your siteSketcher LabPaint your landing’s hero with shaders3D StudioThe Three.js editor in your browser
GamesPlay with shadersOnomatoShaderType a word, blow it upThe WatcherAn eye that follows youAetherLiquid glass with an eye insideBloomcoreA word grows a garden of lightPyrokineThrow fire at the wallVoltaicThe pyramid throws lightningSurfSurf a shader ocean

Lesson 7 of 10 · Fractals in GLSL

Animated c

The constant breathes in a circle. The creature lives.

If c defines the whole Julia shape, what if we move it through time? The creature breathes. The trick is not to let it wander far: we walk it in a tiny circle around a good point, with radius wob.

Small circle = living morph. Big circle = dissolves into dust. That is why wob stays modest: we want it to breathe, not explode.

c = base + wob * vec2(cos(T*0.5), sin(T*0.5))cos and sin of the same time trace a perfect circle. wob is the radius of that walk. Multiplying by T makes it spin forever: the Julia reorganizes on a loop, smooth, no jumps.
TryRaise wob=0.12 to 0.25 and the morph turns wild (watch for dust). Drop it to 0.04 for a near-imperceptible breath. The speed lives in T*0.5.

The code

precision highp float;
void main(){
  vec2 uv=(gl_FragCoord.xy*2.0 - R)/R.y;
  float zoom=1.5;
  vec2 z=uv*zoom;
  float wob=0.12;
  vec2 c=vec2(-0.74, 0.12)+wob*vec2(cos(T*0.5), sin(T*0.5));
  float n=0.0; bool esc=false;
  const int IT=150;
  for(int i=0;i<IT;i++){
    z=vec2(z.x*z.x-z.y*z.y, 2.0*z.x*z.y)+c;
    if(dot(z,z)>256.0){ n=float(i); esc=true; break; }
  }
  float sn=esc ? (n - log2(log2(dot(z,z))) + 4.0) : 0.0;
  float band=sn * 0.5;
  vec3 col=0.5+0.5*cos(0.35*band + vec3(0.0,2.2,4.0) + T*0.1);
  col=esc ? col : vec3(0.02,0.0,0.05);
  gl_FragColor=vec4(col,1.0);
}
close