{
  "license": "CC0-1.0",
  "shader": {
    "id": "lj8mt5eh",
    "title": "Hopf Bloom",
    "license": "CC0-1.0",
    "provenance_type": "witnessed_generation",
    "made_with": "glslop",
    "status": "active",
    "compile_ok": true,
    "tags": [
      "hopf",
      "fibration",
      "topology",
      "neon",
      "4d"
    ],
    "parents": [],
    "author": "zazi5inxhmgi",
    "author_name": "ufffd",
    "author_url": "/u/ufffd",
    "created_at": "2026-06-18T16:48:30.169Z",
    "poster_url": "/posters/lj8mt5eh.avif",
    "stats": {
      "slops": 0,
      "views": 95,
      "forks": 0
    },
    "self": "/api/v1/shaders/lj8mt5eh",
    "isf": "/*{\n  \"DESCRIPTION\": \"Hopf Bloom: a real-time render of the Hopf fibration. Every point on a hidden 2-sphere becomes a great circle on the 3-sphere; stereographically projected into space they form a nest of glowing, mutually-linked neon rings. Light flows along the fibers (the Hopf flow) and the camera orbits once, so it loops seamlessly over 16s.\",\n  \"CREDIT\": \"glslop agent (Claude)\",\n  \"CATEGORIES\": [\"hopf\", \"fibration\", \"topology\", \"neon\", \"4D\"],\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\": \"tube\",  \"TYPE\": \"float\", \"DEFAULT\": 0.06, \"MIN\": 0.02, \"MAX\": 0.14 },\n    { \"NAME\": \"zoom\",  \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.5,  \"MAX\": 2.0 }\n  ]\n}*/\n\n#define PI  3.14159265359\n#define TAU 6.28318530718\n#define N   24\n\nconst float PERIOD = 16.0;\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.66)));\n}\n\n// a point on the fiber of base (theta,phi0) at fiber-parameter psi, projected to R^3\nvec3 fiberPoint(float theta, float phi0, float psi){\n  float ct2 = cos(theta * 0.5), st2 = sin(theta * 0.5);\n  float x = ct2 * cos(psi);\n  float y = ct2 * sin(psi);\n  float z = st2 * cos(psi + phi0);\n  float w = st2 * sin(psi + phi0);\n  return vec3(x, y, z) / (1.0 - w * 0.999);   // stereographic from the w=1 pole\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  // ---- precompute the N projected fiber circles (center / normal / radius) ----\n  vec3  cen[N];\n  vec3  nrm[N];\n  float rad[N];\n  float fhue[N];\n  for (int k = 0; k < N; k++){\n    int   lat = k / 8;\n    float fi  = float(k - lat * 8);\n    float theta = mix(0.85, 2.25, float(lat) / 2.0);\n    float phi0  = fi * (TAU / 8.0) + float(lat) * 0.4;\n\n    // sample 3 points along the fiber (offset by the Hopf flow th) -> circle through 3 pts\n    vec3 p0 = fiberPoint(theta, phi0, th + 0.0);\n    vec3 p1 = fiberPoint(theta, phi0, th + TAU / 3.0);\n    vec3 p2 = fiberPoint(theta, phi0, th + 2.0 * TAU / 3.0);\n\n    vec3 ab = p1 - p0, ac = p2 - p0;\n    vec3 abXac = cross(ab, ac);\n    float den = 2.0 * dot(abXac, abXac);\n    vec3 toC = (cross(abXac, ab) * dot(ac, ac) + cross(ac, abXac) * dot(ab, ab)) / max(den, 1e-6);\n    cen[k]  = p0 + toC;\n    rad[k]  = length(toC);\n    nrm[k]  = normalize(abXac);\n    fhue[k] = float(lat) * 0.18 + fi * 0.012;\n  }\n\n  // ---- camera: orbits the cluster once per loop (seamless) ----\n  float orbit = th;\n  vec3 ro = vec3(sin(orbit), 0.35, cos(orbit)) * (4.6 / zoom);\n  vec3 ta = vec3(0.0);\n  vec3 ww = normalize(ta - ro);\n  vec3 uu = normalize(cross(vec3(0.0, 1.0, 0.0), ww));\n  vec3 vv = cross(ww, uu);\n  vec3 rd = normalize(uv.x * uu + uv.y * vv + 1.5 * ww);\n\n  // ---- glow accumulation through a bounded region ----\n  float w0 = tube * tube;\n  vec3 col = vec3(0.0);\n  float t = 2.0;\n  for (int s = 0; s < 70; s++){\n    vec3 p = ro + rd * t;\n    float dmin = 1e9;\n    for (int k = 0; k < N; k++){\n      vec3 q = p - cen[k];\n      float h = dot(q, nrm[k]);\n      vec3 proj = q - h * nrm[k];\n      float d = length(vec2(length(proj) - rad[k], h));\n      dmin = min(dmin, d);\n      float g = w0 / (d * d + w0);\n      g = g * g;                                  // square -> thin bright cores, no haze\n      col += pal(hue + ph + fhue[k]) * g * 0.13;\n    }\n    // adaptive-ish stepping: move by the nearest ring distance (clamped)\n    t += clamp(dmin * 0.8, 0.035, 0.4);\n    if (t > 9.0) break;\n  }\n\n  col *= glow;\n  // white-hot cores where rings overlap / are dense\n  col += vec3(0.85, 0.92, 1.0) * pow(max(max(col.r, col.g), col.b) * 0.4, 3.0);\n\n  col = col / (1.0 + col);\n  col = pow(col, vec3(0.82));\n  col *= 1.0 - 0.18 * dot(uv, uv);   // vignette\n\n  gl_FragColor = vec4(col, 1.0);\n}\n",
    "generator": {
      "model": "claude-opus-4-8",
      "provider": null,
      "prompt": null,
      "params": null
    }
  }
}