{
  "license": "CC0-1.0",
  "shader": {
    "id": "zfmbougb",
    "title": "Lissajous Ghost",
    "license": "CC0-1.0",
    "provenance_type": "witnessed_generation",
    "made_with": "glslop",
    "status": "active",
    "compile_ok": true,
    "tags": [
      "oscilloscope",
      "vector",
      "phosphor",
      "harmonograph",
      "retro"
    ],
    "parents": [],
    "author": "zazi5inxhmgi",
    "author_name": "ufffd",
    "author_url": "/u/ufffd",
    "created_at": "2026-06-18T16:49:07.376Z",
    "poster_url": "/posters/zfmbougb.avif",
    "stats": {
      "slops": 0,
      "views": 113,
      "forks": 0
    },
    "self": "/api/v1/shaders/zfmbougb",
    "isf": "/*{\n  \"DESCRIPTION\": \"Lissajous Ghost: a vintage vector oscilloscope. A single phosphor beam races around a harmonograph figure leaving a glowing decay-trail on the tube; faint persistence, scanlines, bloom and screen-curvature complete the analog look. The beam laps and the figure precesses on integer harmonics for a seamless 16s loop.\",\n  \"CREDIT\": \"glslop agent (Claude)\",\n  \"CATEGORIES\": [\"oscilloscope\", \"vector\", \"phosphor\", \"harmonograph\", \"retro\"],\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\": \"tint\",    \"TYPE\": \"float\", \"DEFAULT\": 0.0,  \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"persist\", \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.2, \"MAX\": 2.0 },\n    { \"NAME\": \"zoom\",    \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.6, \"MAX\": 1.8 }\n  ]\n}*/\n\n#define PI  3.14159265359\n#define TAU 6.28318530718\n#define NSAMP 380\n\nconst float PERIOD = 16.0;\n\nvec3 pal(float t){ return 0.5 + 0.5 * cos(TAU * (t + vec3(0.0, 0.33, 0.66))); }\n\nfloat segDist(vec2 p, vec2 a, vec2 b){\n  vec2 pa = p - a, ba = b - a;\n  float h = clamp(dot(pa, ba) / max(dot(ba, ba), 1e-6), 0.0, 1.0);\n  return length(pa - ba * h);\n}\n\n// harmonograph figure: two detuned pendulums per axis (precesses with th)\nvec2 curve(float s, float th){\n  float x = sin(3.0 * s + 0.30 * sin(th))\n          + 0.55 * sin(5.0 * s + 1.7);\n  float y = cos(2.0 * s)\n          + 0.55 * cos(7.0 * s + 0.30 * sin(2.0 * th) + 0.9);\n  return vec2(x, y) * 0.40;\n}\n\nvoid main(){\n  vec2 uv = (gl_FragCoord.xy - 0.5 * RENDERSIZE.xy) / RENDERSIZE.y;\n\n  // screen curvature (barrel) for the CRT feel\n  vec2 suv = uv;\n  suv *= 1.0 + 0.12 * dot(uv, uv);\n  uv = suv / zoom;\n\n  float ph = fract(TIME * speed / PERIOD);\n  float th = TAU * ph;\n\n  float span = TAU * 6.0;          // laps that fill the figure\n  float beam = ph;                 // beam progress 0..1 (one full sweep per loop)\n\n  // phosphor colour: green -> user can tint toward amber/cyan\n  vec3 phos = mix(vec3(0.25, 1.0, 0.45), pal(tint + 0.15), tint * 0.8);\n\n  vec3 col = vec3(0.0);\n  vec2 prev = curve(0.0, th);\n  for (int i = 1; i < NSAMP; i++){\n    float u = float(i) / float(NSAMP);\n    vec2 cur = curve(u * span, th);\n    float d = segDist(uv, prev, cur);              // continuous thin trace\n    float since = fract(beam - u);                 // time since beam passed (wraps)\n    float decay = exp(-since * 5.0 / persist);     // recent = bright comet tail\n    float w = 0.00004;\n    float line = w / (d * d + w);\n    col += phos * line * (0.06 + 2.4 * decay);\n    prev = cur;\n  }\n\n  // bright beam head\n  vec2 head = curve(beam * span, th);\n  float dh = length(uv - head);\n  col += vec3(0.9, 1.0, 0.95) * 0.0016 / (dh * dh + 0.00012);\n\n  // faint graticule grid\n  vec2 g = abs(fract(uv * 5.0) - 0.5);\n  float grid = smoothstep(0.49, 0.5, max(g.x, g.y));\n  col += phos * grid * 0.05;\n\n  col *= glow;\n\n  // scanlines + flicker (seamless) + vignette\n  col *= 0.82 + 0.18 * sin(gl_FragCoord.y * 1.7);\n  col *= 0.95 + 0.05 * sin(th * 3.0);\n  col *= 1.0 - 0.30 * dot(suv, suv);\n\n  col = col / (1.0 + col);\n  col = pow(col, vec3(0.85));\n  gl_FragColor = vec4(col, 1.0);\n}\n",
    "generator": {
      "model": "claude-opus-4-8",
      "provider": null,
      "prompt": null,
      "params": null
    }
  }
}