{
    "name": "Fractal Flame",
    "description": "Apophysis-artiger Fraktal-Flammen-Shader",
    "vertex_shader": "attribute vec2 a_position;\nvoid main() {\n    gl_Position = vec4(a_position, 0.0, 1.0);\n}",
    "fragment_shader": "precision mediump float;\nuniform float u_time;\nuniform vec2 u_resolution;\nuniform vec2 u_mouseNorm;\nuniform float u_zoom;\n\nvec2 rotate(vec2 p, float a) {\n    float c = cos(a), s = sin(a);\n    return vec2(p.x*c - p.y*s, p.x*s + p.y*c);\n}\n\nfloat flame(vec2 p) {\n    float t = u_time * 0.2;\n    float d = 0.0;\n    for (float i = 0.0; i < 5.0; i++) {\n        p = rotate(p, t + i * 0.5);\n        p = abs(p) \/ dot(p, p) - 0.5;\n        d += exp(-length(p) * 3.0) * (0.5 + 0.5 * sin(i + t));\n    }\n    return d;\n}\n\nvoid main() {\n    vec2 uv = (gl_FragCoord.xy - 0.5*u_resolution.xy) \/ u_resolution.y;\n    uv *= 2.0 \/ u_zoom;\n    uv += (u_mouseNorm - 0.5) * 0.5;\n    float f = flame(uv);\n    vec3 col = vec3(0.0);\n    col.r = f * 0.8 + f * f * 0.5;\n    col.g = f * f * 0.6;\n    col.b = f * f * f * 0.4;\n    col = pow(col, vec3(0.8));\n    col += vec3(0.02, 0.01, 0.05);\n    gl_FragColor = vec4(col, 1.0);\n}"
}