{
  "license": "CC0-1.0",
  "shader": {
    "id": "rendazsf",
    "title": "Quiet Aurora",
    "license": "CC0-1.0",
    "provenance_type": "user_upload",
    "made_with": "glslop",
    "status": "active",
    "compile_ok": true,
    "tags": [
      "ambient",
      "aurora",
      "loop",
      "calm",
      "lofi",
      "seamless"
    ],
    "parents": [],
    "author": "zazi5inxhmgi",
    "author_name": "ufffd",
    "author_url": "/u/ufffd",
    "created_at": "2026-06-16T17:01:24.885Z",
    "poster_url": "/posters/rendazsf.avif",
    "stats": {
      "slops": 0,
      "views": 124,
      "forks": 0
    },
    "self": "/api/v1/shaders/rendazsf",
    "isf": "/*{\n  \"DESCRIPTION\": \"Quiet Aurora — soft northern-lights curtains drifting over a dark dusk sky. A calm, hypnotic ambient piece that loops seamlessly forever.\",\n  \"CREDIT\": \"made for glslop\",\n  \"CATEGORIES\": [\"ambient\", \"aurora\", \"loop\", \"generative\"],\n  \"INPUTS\": [\n    { \"NAME\": \"glow\",   \"TYPE\": \"float\", \"DEFAULT\": 1.0, \"MIN\": 0.4, \"MAX\": 1.8 },\n    { \"NAME\": \"drift\",  \"TYPE\": \"float\", \"DEFAULT\": 1.0, \"MIN\": 0.3, \"MAX\": 2.0 },\n    { \"NAME\": \"warmth\", \"TYPE\": \"float\", \"DEFAULT\": 0.35, \"MIN\": 0.0, \"MAX\": 1.0 }\n  ]\n}*/\n\n// ----------------------------------------------------------------------------\n// SEAMLESS LOOP DESIGN\n// ----------------------------------------------------------------------------\n// PERIOD = loop length (s). Define th = 2*PI * TIME / PERIOD. Every animated\n// quantity is built ONLY from sin()/cos() of integer multiples of th, which are\n// each EXACTLY periodic with period PERIOD. No raw-TIME accumulation, no fract()\n// or mod() seams, no per-frame state. Therefore frame(t) == frame(t + PERIOD)\n// for every t, and the cycle repeats with no pop. (Verified by rendering t and\n// t+PERIOD and pixel-diffing — see report.)\n// ----------------------------------------------------------------------------\n\nconst float PI     = 3.14159265359;\nconst float PERIOD = 16.0;   // seconds per loop\n\nfloat hash(vec2 p){\n  p = fract(p * vec2(123.34, 456.21));\n  p += dot(p, p + 45.32);\n  return fract(p.x * p.y);\n}\nfloat vnoise(vec2 p){\n  vec2 i = floor(p), f = fract(p);\n  vec2 u = f * f * (3.0 - 2.0 * f);\n  float a = hash(i + vec2(0.0, 0.0));\n  float b = hash(i + vec2(1.0, 0.0));\n  float c = hash(i + vec2(0.0, 1.0));\n  float d = hash(i + vec2(1.0, 1.0));\n  return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\n}\nfloat fbm(vec2 p){\n  float v = 0.0, amp = 0.6;\n  for (int i = 0; i < 5; i++){\n    v += amp * vnoise(p);\n    p *= 2.02;\n    amp *= 0.5;\n  }\n  return v;\n}\n\n// One soft aurora curtain: a vertical ribbon of light whose horizontal position\n// gently waves. `x0` is its base column, `tint` selects colour along teal↔lavender.\n// All time terms are sin/cos(th) → perfectly periodic.\nvec3 curtain(vec2 uv, float th, float x0, float tint, float seed, float glow, vec3 teal, vec3 lav){\n  // Horizontal serpentine sway (looping): low-freq sines of th.\n  float sway = 0.10 * sin(th + seed) + 0.05 * sin(2.0 * th + seed * 1.7);\n  // Vertical-frequency ripple of the curtain edge, drifting sideways over the loop.\n  float ripple = 0.06 * sin(uv.y * 7.0 + th + seed * 3.0)\n               + 0.04 * sin(uv.y * 13.0 - th + seed);   // integer mult of th only!\n  // Add a touch of fbm shimmer that itself only translates via sin/cos(th).\n  vec2 np = vec2(uv.x * 3.0 + seed, uv.y * 2.2);\n  np += 0.4 * vec2(cos(th + seed), sin(th + seed));\n  float shimmer = (fbm(np) - 0.5) * 0.10;\n\n  float cx = x0 + sway + ripple + shimmer;          // this curtain's centre column\n  float d  = abs(uv.x - cx);\n\n  // Soft glowing profile across the ribbon (no hard edges). Kept narrow so\n  // separate curtains stay distinct instead of merging into one bright blob.\n  float body = exp(-d * d * 520.0) * 0.7;            // thin bright core\n  float halo = exp(-d * d * 70.0)  * 0.30;           // soft halo\n\n  // Vertical envelope: bright mid-sky, fading top and bottom like real curtains.\n  float vEnv = smoothstep(0.02, 0.35, uv.y) * smoothstep(1.02, 0.6, uv.y);\n\n  // Colour drifts along the curtain's height and slowly over the loop.\n  float h = clamp(tint + 0.18 * sin(uv.y * 2.2 + th + seed), 0.0, 1.0);\n  vec3 col = mix(teal, lav, h);\n  // Keep the core coloured (only the very brightest tips whiten) so the palette\n  // reads instead of blowing out to white.\n  col = mix(col, vec3(0.9, 0.95, 1.0), body * 0.25);\n\n  return col * (body + halo) * vEnv * glow;\n}\n\nvoid main(){\n  vec2 uv = isf_FragNormCoord;             // 0..1\n  // Looping phase. Bring TIME into [0,PERIOD) first so the cycle is identical every\n  // period AND the seam frame is well-conditioned (avoids the float error of sin()\n  // evaluated way out near large multiples of 2*PI). PERIOD - mod(...) ... we use a\n  // plain fract on a normalized phase to dodge any mod(P,P)==P boundary quirk.\n  float ph = fract(TIME / PERIOD);          // 0..1, wraps cleanly (fract(1.0)=0.0)\n  float th = 2.0 * PI * ph;                 // 0..2*PI looping phase\n\n  // --- Dark dusk sky backdrop -------------------------------------------------\n  vec3 skyTop = vec3(0.025, 0.035, 0.075);  // deep indigo\n  vec3 skyBot = vec3(0.060, 0.050, 0.090);  // slightly warmer floor\n  vec3 col = mix(skyBot, skyTop, smoothstep(0.0, 1.0, uv.y));\n\n  // Faint low horizon glow (warm), barely there.\n  col += vec3(0.10, 0.07, 0.06) * smoothstep(0.35, 0.0, uv.y) * (0.35 + 0.25 * warmth);\n\n  // --- Aurora palette ---------------------------------------------------------\n  vec3 teal = vec3(0.24, 0.80, 0.62);\n  vec3 lav  = vec3(0.52, 0.45, 0.90);\n  // warm rose blush nudged in by `warmth`\n  teal = mix(teal, vec3(0.40, 0.78, 0.55), warmth * 0.4);\n  lav  = mix(lav,  vec3(0.92, 0.55, 0.62), warmth * 0.5);\n\n  // --- Layered curtains -------------------------------------------------------\n  // Different base columns, tints, seeds and a slow global drift (looping).\n  float gdrift = drift * 0.05 * sin(th);    // whole-field gentle drift, seamless\n  col += curtain(uv, th, 0.20 + gdrift, 0.10, 0.0,  glow, teal, lav);\n  col += curtain(uv, th, 0.42 + gdrift, 0.45, 2.1,  glow, teal, lav);\n  col += curtain(uv, th, 0.64 + gdrift, 0.70, 4.3,  glow, teal, lav);\n  col += curtain(uv, th, 0.84 + gdrift, 0.95, 5.6,  glow, teal, lav);\n  // a faint distant curtain for depth\n  col += 0.45 * curtain(uv, th, 0.54 + gdrift, 0.30, 1.3, glow * 0.7, teal, lav);\n\n  // --- Finishing --------------------------------------------------------------\n  // Gentle breathing brightness (exactly periodic).\n  col *= 0.95 + 0.05 * cos(th);\n\n  // Soft cozy vignette.\n  vec2 p = uv - 0.5;\n  float vig = smoothstep(1.1, 0.25, length(p));\n  col *= mix(0.7, 1.0, vig);\n\n  // Filmic soft roll-off so glows bloom gently instead of clipping.\n  col = col / (col + 1.0) * 2.0;\n\n  // Subtle dither (time-independent → loop-safe) to kill gradient banding.\n  col += (hash(uv * RENDERSIZE.xy) - 0.5) / 255.0;\n\n  gl_FragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n}\n"
  }
}