{
  "license": "CC0-1.0",
  "shader": {
    "id": "kpgyyvk3",
    "title": "Iridescent Apollonian Foam",
    "license": "CC0-1.0",
    "provenance_type": "witnessed_generation",
    "made_with": "glslop",
    "status": "active",
    "compile_ok": true,
    "tags": [
      "fractal",
      "apollonian",
      "neon",
      "bubbles",
      "iridescent"
    ],
    "parents": [],
    "author": "zazi5inxhmgi",
    "author_name": "ufffd",
    "author_url": "/u/ufffd",
    "created_at": "2026-06-18T03:36:42.207Z",
    "poster_url": "/posters/kpgyyvk3.avif",
    "stats": {
      "slops": 0,
      "views": 121,
      "forks": 0
    },
    "self": "/api/v1/shaders/kpgyyvk3",
    "isf": "/*{\n  \"DESCRIPTION\": \"Apollonian neon: a fold+inversion Apollonian fractal of nested glowing bubbles, surface-raymarched with electric orbit-trap colour and hot rim light. Slowly breathes and tumbles. Real-time, seamless 16s loop.\",\n  \"CREDIT\": \"glslop agent (Claude); Apollonian DE after Inigo Quilez\",\n  \"CATEGORIES\": [\"fractal\", \"raymarch\", \"neon\", \"apollonian\"],\n  \"INPUTS\": [\n    { \"NAME\": \"speed\",     \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.0, \"MAX\": 3.0 },\n    { \"NAME\": \"glow\",      \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.3, \"MAX\": 3.0 },\n    { \"NAME\": \"hue\",       \"TYPE\": \"float\", \"DEFAULT\": 0.0,  \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"kparam\",    \"TYPE\": \"float\", \"DEFAULT\": 1.25, \"MIN\": 1.0, \"MAX\": 1.6 },\n    { \"NAME\": \"zoom\",      \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.5, \"MAX\": 2.0 },\n    { \"NAME\": \"iterCount\", \"TYPE\": \"long\",  \"DEFAULT\": 8,    \"MIN\": 4,   \"MAX\": 12 }\n  ]\n}*/\n\n#define PI  3.14159265359\n#define TAU 6.28318530718\n\nconst float PERIOD = 16.0;\nconst int   MAXI   = 12;\nconst int   STEPS  = 100;\n\nmat2 rot(float a){ float c = cos(a), s = sin(a); return mat2(c, -s, s, c); }\n\nvec3 pal(float t){\n  return 0.5 + 0.5 * cos(TAU * (t + vec3(0.0, 0.33, 0.67)));\n}\n\n// Apollonian DE (fold into [-1,1] + sphere inversion). orb = orbit trap for colour.\nfloat map(vec3 p, float s, mat2 Rt, out vec4 orb){\n  p.xz = Rt * p.xz;                  // rigid tumble (conservative)\n  float scale = 1.0;\n  orb = vec4(1000.0);\n  for (int i = 0; i < MAXI; i++){\n    if (i >= iterCount) break;\n    p = -1.0 + 2.0 * fract(0.5 * p + 0.5);\n    float r2 = dot(p, p);\n    orb = min(orb, vec4(abs(p), r2));\n    float k = s / r2;\n    p *= k;\n    scale *= k;\n  }\n  return 0.25 * abs(p.y) / scale;\n}\n\nvoid main(){\n  vec2 uv = (gl_FragCoord.xy - 0.5 * RENDERSIZE.xy) / RENDERSIZE.y;\n\n  float ph = fract(TIME * speed / PERIOD);\n  float th = TAU * ph;\n  float s = kparam + 0.06 * sin(th);          // breathe the packing\n  mat2 Rt = rot(0.5 + 0.4 * sin(th));         // rigid tumble (seamless)\n\n  // orbiting camera\n  float camDist = 2.6 * zoom;\n  float az = th;\n  float el = 0.30 + 0.18 * sin(th);\n  vec3 ro = camDist * vec3(sin(az) * cos(el), sin(el), cos(az) * cos(el));\n  vec3 ta = vec3(0.0);\n  vec3 fwd = normalize(ta - ro);\n  vec3 rgt = normalize(cross(vec3(0.0, 1.0, 0.0), fwd));\n  vec3 upv = cross(fwd, rgt);\n  vec3 rd  = normalize(uv.x * rgt + uv.y * upv + 1.5 * fwd);\n\n  // ---- surface raymarch ----\n  float t = 0.01;\n  float tcap = camDist + 4.0;\n  vec4 orb = vec4(1000.0), orbHit = vec4(1000.0);\n  float te = 0.0;\n  bool hit = false;\n  for (int i = 0; i < STEPS; i++){\n    vec3 p = ro + rd * t;\n    vec4 o;\n    float d = map(p, s, Rt, o);\n    if (d < 0.0006 * t){ hit = true; orbHit = o; te = t; break; }\n    t += d * 0.75;\n    if (t > tcap) break;\n  }\n\n  vec3 col = vec3(0.0);\n\n  if (hit){\n    vec3 p = ro + rd * te;\n    vec2 k = vec2(1.0, -1.0);\n    float e = 0.0010;\n    vec4 o;\n    vec3 n = normalize(\n      k.xyy * map(p + k.xyy * e, s, Rt, o) +\n      k.yyx * map(p + k.yyx * e, s, Rt, o) +\n      k.yxy * map(p + k.yxy * e, s, Rt, o) +\n      k.xxx * map(p + k.xxx * e, s, Rt, o));\n\n    vec3 lig  = normalize(vec3(0.5, 0.8, 0.4));\n    float dif = max(dot(n, lig), 0.0);\n    float fres = pow(1.0 - max(dot(n, -rd), 0.0), 2.0);\n    float ao  = clamp(1.2 - orbHit.w * 1.6, 0.0, 1.0);  // crevice darkening\n\n    // thin-film iridescence: hue shifts with the orbit trap AND the view angle,\n    // so every bubble shimmers oil-slick rainbow toward its rim.\n    vec3 base = pal(hue + 0.5 * orbHit.x + 0.35 * orbHit.z + 0.40 * fres);\n\n    col += base * 0.16 * ao;\n    col += base * dif * 0.34 * ao;\n    col += base * fres * 3.2 * glow;                 // bright iridescent rims\n    col += vec3(1.0) * pow(fres, 4.0) * 0.9 * glow;  // hot specular edge\n    col *= exp(-0.10 * max(te - camDist + 1.5, 0.0));\n  }\n\n  // tone map\n  col = col / (1.0 + col);\n  col = pow(col, vec3(0.78));\n  col *= 1.0 - 0.22 * dot(uv, uv);\n\n  gl_FragColor = vec4(col, 1.0);\n}\n",
    "generator": {
      "model": "claude-opus-4-8",
      "provider": "Anthropic",
      "prompt": null,
      "params": null
    }
  }
}