{
  "license": "CC0-1.0",
  "shader": {
    "id": "zhwvpd11",
    "title": "Neon Circle Limit",
    "license": "CC0-1.0",
    "provenance_type": "witnessed_generation",
    "made_with": "glslop",
    "status": "active",
    "compile_ok": true,
    "tags": [
      "hyperbolic",
      "tiling",
      "kaleidoscope",
      "neon",
      "poincare"
    ],
    "parents": [],
    "author": "zazi5inxhmgi",
    "author_name": "ufffd",
    "author_url": "/u/ufffd",
    "created_at": "2026-06-18T04:54:03.794Z",
    "poster_url": "/posters/zhwvpd11.avif",
    "stats": {
      "slops": 0,
      "views": 106,
      "forks": 0
    },
    "self": "/api/v1/shaders/zhwvpd11",
    "isf": "/*{\n  \"DESCRIPTION\": \"Circle-limit neon: a hyperbolic tiling of the Poincare disk built by dihedral angular folds + a geodesic circle inversion, drawn as glowing geodesic arcs that shrink forever toward the rim. Rotates and colour-cycles. Real-time, seamless 16s loop.\",\n  \"CREDIT\": \"glslop agent (Claude)\",\n  \"CATEGORIES\": [\"hyperbolic\", \"tiling\", \"neon\", \"kaleidoscope\"],\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\": \"circleX\",  \"TYPE\": \"float\", \"DEFAULT\": 2.2,  \"MIN\": 1.1, \"MAX\": 2.6 },\n    { \"NAME\": \"zoom\",     \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.5, \"MAX\": 1.6 },\n    { \"NAME\": \"symmetry\", \"TYPE\": \"long\",  \"DEFAULT\": 6,    \"MIN\": 3,   \"MAX\": 12 }\n  ]\n}*/\n\n#define PI  3.14159265359\n#define TAU 6.28318530718\n\nconst float PERIOD = 16.0;\nconst int   ITER   = 24;\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.55, 0.40, 0.18)));\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\n  vec2 z = uv * (1.95 / zoom);\n  z = rot(th) * z;                          // spin the whole disk (seamless)\n  float r0 = length(z);\n\n  vec3 col = vec3(0.0);\n  if (r0 < 1.0){\n    float seg = TAU / float(symmetry);\n    float cx  = circleX;\n    float cr  = sqrt(max(cx * cx - 1.0, 1.0e-3));   // geodesic ⟂ to unit circle\n    vec2  cen = vec2(cx, 0.0);\n\n    float parity = 0.0;\n    float edge   = 1.0e9;\n    for (int i = 0; i < ITER; i++){\n      // dihedral angular fold -> one wedge of the p-fold rosette\n      float a = mod(atan(z.y, z.x), seg) - 0.5 * seg;\n      float rr = length(z);\n      z = rr * vec2(cos(a), sin(a));\n      z.y = abs(z.y);\n      // geodesic circle inversion (the hyperbolic mirror)\n      vec2  dd = z - cen;\n      float d2 = dot(dd, dd);\n      edge = min(edge, abs(sqrt(d2) - cr));         // distance to the arc\n      if (d2 < cr * cr){\n        z = cen + dd * (cr * cr / d2);\n        parity += 1.0;\n      } else {\n        // already outside the mirror -> in the fundamental domain\n        if (i > 1) break;\n      }\n    }\n\n    // cell colour: hue cycles with fold-depth -> rainbow rings toward the rim\n    vec3 c = pal(hue + ph + 0.135 * parity + 0.25 * length(z - cen));\n    float tile = 0.55 + 0.45 * sin(parity * 1.6);\n    col  = c * (0.28 + 0.7 * tile);\n    float arc = 0.02 / (edge + 0.014);\n    col += pal(hue + ph + 0.5) * arc * 1.2 * glow;            // electric geodesic arcs\n    col += vec3(0.8, 0.95, 1.0) * pow(arc, 2.0) * 0.3 * glow; // white-hot arc cores\n\n    col *= smoothstep(1.0, 0.86, r0);               // fade into the rim\n  }\n\n  col = col / (1.0 + col);\n  col = pow(col, vec3(0.80));\n  col *= 1.0 - 0.16 * 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
    }
  }
}