{
  "license": "CC0-1.0",
  "shader": {
    "id": "8gz94nqz",
    "title": "Harbor Lights",
    "license": "CC0-1.0",
    "provenance_type": "witnessed_generation",
    "made_with": "claude-code",
    "status": "active",
    "compile_ok": true,
    "tags": [
      "neon",
      "water",
      "reflection",
      "minimal",
      "night",
      "refraction"
    ],
    "parents": [
      "hz8a83uz"
    ],
    "author": "zazi5inxhmgi",
    "author_name": "ufffd",
    "author_url": "/u/ufffd",
    "created_at": "2026-06-20T07:32:17.576Z",
    "poster_url": "/posters/8gz94nqz.avif",
    "stats": {
      "slops": 0,
      "views": 121,
      "forks": 0
    },
    "self": "/api/v1/shaders/8gz94nqz",
    "isf": "/*{\n  \"DESCRIPTION\": \"Wet neon — a few neon signs smeared into dark rippling water, wavering and broken by the surface waves.\",\n  \"CREDIT\": \"claude-opus-4-8\",\n  \"INPUTS\": [\n    { \"NAME\": \"ripple\", \"TYPE\": \"float\", \"DEFAULT\": 0.5, \"MIN\": 0.0, \"MAX\": 1.5 },\n    { \"NAME\": \"waves\",  \"TYPE\": \"float\", \"DEFAULT\": 34.0, \"MIN\": 12.0, \"MAX\": 70.0 },\n    { \"NAME\": \"glow\",   \"TYPE\": \"float\", \"DEFAULT\": 0.8, \"MIN\": 0.2, \"MAX\": 1.6 },\n    { \"NAME\": \"speed\",  \"TYPE\": \"float\", \"DEFAULT\": 1.0, \"MIN\": 0.0, \"MAX\": 3.0 }\n  ]\n}*/\n\nfloat hash(vec2 p){ p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); }\nfloat noise(vec2 p){\n  vec2 i = floor(p), f = fract(p); f = f * f * (3.0 - 2.0 * f);\n  float a = hash(i), b = hash(i + vec2(1.0, 0.0)), c = hash(i + vec2(0.0, 1.0)), d = hash(i + vec2(1.0, 1.0));\n  return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);\n}\n\n// a soft neon column of colour `col` centred at x = cx\nvec3 bar(float x, float cx, float w, vec3 col){\n  float d = (x - cx) / w;\n  return col * exp(-d * d);\n}\n\nvec3 lights(float x){\n  vec3 c = vec3(0.0);\n  c += bar(x, 0.20, 0.045, vec3(1.0, 0.10, 0.65));   // magenta\n  c += bar(x, 0.40, 0.030, vec3(0.10, 0.95, 1.0));   // cyan\n  c += bar(x, 0.58, 0.055, vec3(0.45, 1.0, 0.20));   // green\n  c += bar(x, 0.80, 0.035, vec3(1.0, 0.55, 0.05));   // amber\n  return c;\n}\n\nvoid main(){\n  vec2 uv = gl_FragCoord.xy / RENDERSIZE;\n  float t = TIME * speed;\n  float depth = 1.0 - uv.y;                 // 0 at top, 1 at bottom (deeper into reflection)\n\n  // multi-octave horizontal wander (the reflection sways with the swell), stronger deeper down\n  float wob = 0.055 * sin(uv.y * 9.0 - t * 1.3)\n            + 0.030 * sin(uv.y * 21.0 + t * 0.8)\n            + 0.025 * (noise(vec2(uv.y * 7.0, t * 0.7)) - 0.5);\n  wob *= ripple * (0.25 + 1.1 * depth);\n  float x = uv.x + wob;\n\n  // horizontal smear — neon bleeds sideways on the wet surface\n  vec3 col = lights(x) * 0.5 + lights(x - 0.018) * 0.25 + lights(x + 0.018) * 0.25;\n\n  // ripple bands break the columns into wavy horizontal streaks\n  float band = sin(uv.y * waves + 4.5 * sin(uv.x * 2.5 + t * 0.6) - t * 2.0);\n  band += 0.5 * sin(uv.y * waves * 2.3 - t * 3.0);   // finer secondary ripple\n  band = 0.5 + 0.5 * clamp(band, -1.0, 1.0);\n  col *= 0.18 + 1.2 * pow(band, 2.2);\n  col *= 0.45 + 0.55 * depth;\n\n  // specular glints where the surface crests catch the light\n  float crest = pow(band, 8.0);\n  col += col * crest * 0.8;\n\n  col *= glow;\n  col += (lights(x) * 0.5 + lights(x - 0.018) * 0.25 + lights(x + 0.018) * 0.25) * 0.07;  // faint core\n  col = col / (1.0 + 0.5 * col);\n  col = pow(max(col, 0.0), vec3(0.85));\n  gl_FragColor = vec4(col, 1.0);\n}\n",
    "generator": {
      "model": "claude-opus-4-8",
      "provider": "anthropic",
      "prompt": null,
      "params": null
    }
  }
}