/**
 * Minified by jsDelivr using Terser v5.48.0.
 * Original file: /npm/fluid-bg@0.3.0/dist/fluid-bg.iife.js
 *
 * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
 */
"use strict";var FluidBg=(()=>{var e=Object.defineProperty,n=Object.getOwnPropertyDescriptor,t=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i={};((n,t)=>{for(var a in t)e(n,a,{get:t[a],enumerable:!0})})(i,{DEFAULT_BASE:()=>E,DEFAULT_HASH:()=>A,FluidBgElement:()=>P,buildSrc:()=>z,defineFluidBg:()=>O,ensureEmbed:()=>M,fluidBackground:()=>S,mountNative:()=>C,warnIfBackgroundHidden:()=>L});var l=["noise","flow","cellular","gyroid","truchet","interfere","kaleido","lines","grid","golden","smoke","crystal","honeycomb","bloom","sweep","marble","plaid","curtain","stitch","pursuit","chladni","cassini","topo"],o=["aurora","sunset","ocean","dusk","ember","mint","iris","chrome"],s=[[[.035,.063,.16],[.05,.42,.45],[.27,.78,.55],[.96,.74,.84]],[[.1,.045,.18],[.52,.12,.42],[.93,.4,.25],[.99,.84,.52]],[[.02,.05,.14],[.04,.29,.5],[.18,.66,.76],[.78,.96,.91]],[[.085,.078,.2],[.35,.22,.55],[.7,.49,.77],[.97,.8,.87]],[[.035,.02,.02],[.49,.1,.1],[.9,.45,.13],[.98,.9,.72]],[[.03,.13,.11],[.12,.43,.35],[.45,.83,.67],[.93,.99,.95]],[[.04,.03,.1],[.27,.14,.62],[.4,.62,.95],[.92,.86,.99]]],r=["square","hex","ascii","dither","glitch"],f=["none","glass","metal","sand","liquid","molten"],d=["normal","multiply","screen","add","difference","overlay"],c=[{label:"BOREALIS",field:0,p:[.4,2,3.5,.03,1,10,0,0,30,0,0,1]},{label:"AFTERGLOW",field:1,p:[.5,1.6,4,.03,1,10,0,1,21,0,0,1]},{label:"TIDE",field:1,p:[.5,1.5,5,.03,1,10,0,2,48,0,0,1]},{label:"TWILIGHT",field:0,p:[.35,2.3,3,.03,1,10,0,3,12,0,0,1]},{label:"MAGMA",field:0,p:[.45,1.8,4.5,.03,1,10,0,4,52,0,0,1]},{label:"MERIDIAN",field:1,p:[.5,1.6,5,.03,1,10,0,5,66,0,0,1]},{label:"NEBULA",field:2,p:[.4,1.9,7,.03,1,8,0,6,40,0,0,1]},{label:"PLASMA",field:1,p:[.7,1.2,8,.04,1,10,0,0,71,0,0,1]},{label:"VELVET",field:0,p:[.3,2.6,2,.02,1,10,0,3,18,0,0,1]},{label:"CORAL",field:2,p:[.45,1.8,7,.03,1,10,0,1,33,0,0,1]},{label:"GLACIER",field:0,p:[.4,2.2,3,.03,1,10,0,2,25,0,0,1]},{label:"ONYX",field:2,p:[.4,1.9,8,.03,1,8,0,7,60,0,0,1]},{label:"WEAVE",field:3,p:[.4,1.6,5,.03,1,10,0,5,40,0,0,1]},{label:"CIRCUIT",field:4,p:[.3,2,4,.02,1,10,0,7,22,0,0,1]},{label:"RIPPLE",field:5,p:[.5,1.4,5,.03,1,10,0,2,30,0,0,1]},{label:"MANDALA",field:6,p:[.35,1.5,6,.03,1,10,0,6,55,0,0,1]},{label:"STRATA",field:7,p:[.3,1.6,3,.02,1,10,0,3,28,0,0,1]},{label:"MESH",field:8,p:[.3,1.8,4,.02,1,10,0,5,33,0,0,1]},{label:"SUNFLOWER",field:9,p:[.3,1.4,5,.02,1,10,0,4,44,0,0,1]},{label:"RIBBON",field:3,p:[.3,1.55,4.8,.02,4,9,1,2,28,0,0,.5625]},{label:"VORTEX",field:6,p:[.34,1.18,7.2,.02,6,10,1,5,61,0,0,.5625]},{label:"ABYSS",field:0,p:[.22,2.25,7.6,.03,5,8,1,2,87,0,0,.5625]},{label:"NOVA",field:5,p:[.32,1.18,6.4,.02,4,7,1,7,52,0,0,.5625]},{label:"PIXELBEAM",field:1,screen:3,thresh:.46,p:[.45,1.6,4,0,7,10,0,4,40,0,0,1]},{label:"SMOKE",field:10,cols:["#040414","#0a3a7a","#0484fc","#c2dbdc"],p:[.38,1.3,3,.015,1,10,0,0,30,0,0,1]},{label:"GILDED",field:0,material:5,cols:["#0a0602","#6b3a05","#e8940f","#ffdf8a"],p:[.28,.6,3.5,.015,1,10,0,0,47,0,0,1]},{label:"MERCURY",field:0,material:5,cols:["#020204","#1c1a2e","#5a5670","#e8e0f2"],p:[.28,.7,4,.015,1,10,0,0,61,0,0,1]},{label:"BLOOM",field:13,cols:["#c2b830","#e04a12","#e8489a","#f2ead8"],p:[.35,.95,2.5,.14,1,10,0,0,24,0,0,1]},{label:"HORIZON",field:14,cols:["#0d0b2e","#552a8a","#f27059","#ffd9a0"],p:[.3,1.2,3.2,.05,1,10,0,0,33,0,0,1]},{label:"SUMI",field:15,p:[.3,1.5,5,.02,1,10,0,6,41,0,0,1]},{label:"TARTAN",field:16,p:[.35,1.4,3.5,.02,1,10,0,4,26,0,0,1]},{label:"VEIL",field:17,p:[.4,1.4,4,.03,1,10,0,5,63,0,0,1]},{label:"FILAMENT",field:18,cols:["#070512","#4a1f7a","#e05c10","#ffe8b0"],p:[.3,.95,5,.02,1,10,0,0,44,0,0,1]},{label:"GYRE",field:19,cols:["#0a0714","#3a2a7e","#b0489a","#ffe9b0"],p:[.35,1.15,4.5,.02,1,10,0,0,54,0,0,1]},{label:"CYMATIC",field:20,cols:["#0b0907","#4a3418","#c99b3f","#fff4d8"],p:[.85,1.3,4.2,.02,1,10,0,0,57,0,0,1]},{label:"CASSINI",field:21,cols:["#0a0f2e","#274690","#e8a33d","#fdf6e3"],p:[.4,1.2,5.5,.02,1,10,0,0,41,0,0,1]},{label:"ESCHER",field:4,lens:4,cols:["#0c0a08","#4a3b23","#b98a3c","#f5ead2"],p:[.3,1.4,3,.02,1,10,0,0,52,0,0,1]},{label:"FILIGREE",field:11,lens:6,cols:["#07030e","#22084a","#6a2a9c","#f5c34e"],p:[.3,1.45,3.5,.02,1,10,0,0,71,0,0,1]},{label:"SHORELINE",field:1,lens:11,cols:["#03121c","#0e4664","#4fb3a8","#f2e2b6"],p:[.35,2.2,6,.02,1,10,0,0,18,0,0,1]},{label:"ROSETTE",field:12,lens:12,cols:["#0b0d14","#2f3648","#8a8f99","#efe6d0"],p:[.3,.9,4,.02,1,10,0,0,63,0,0,1]},{label:"RELIEF",field:22,cols:["#0b0709","#3d1c2a","#c2557e","#f6d5e2"],p:[.45,1.6,4,.02,1,10,0,0,34,0,0,1]}],u=8294400,h=["none","square","invert","mobius","droste","hyperbolic","julia","cube","exp","sine","joukowski","newton","modular"];function p(e){return 3===(e=String(e).replace("#","")).length&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]),[parseInt(e.substr(0,2),16)/255,parseInt(e.substr(2,2),16)/255,parseInt(e.substr(4,2),16)/255]}function m(e){return 65536*Math.round(255*e[0])+256*Math.round(255*e[1])+Math.round(255*e[2])}function g(e,n){return"number"==typeof n?n>=0&&n<e.length?Math.round(n):-1:e.indexOf(String(n).toLowerCase())}var v={field:0,field2:0,blend:0,layerMix:0,field3:0,blend2:0,layerMix2:0,screen:0,material:0,sym:0,lens:0,lensAmt:1,pal:0,cols:null,speed:.6,zoom:1.6,warp:4.5,grain:.06,pixel:1,dot:10,dots:0,thresh:.5,seed:null};var b=class{constructor(e,n={}){if(!e||1!==e.nodeType)throw new Error("fluid-core: container must be an element");this.container=e,this.doc=e.ownerDocument,this.state=Object.assign({},v),this._applyParams(n),null==this.state.seed&&(this.state.seed=3+89*Math.random()),this.canvas=this.doc.createElement("canvas"),this.canvas.style.cssText="display:block;width:100%;height:100%;",e.appendChild(this.canvas),this.t=0,this._raf=null,this._last=0,this._destroyed=!1,this._visible=!0,this._needsPaint=!0;let t="function"==typeof matchMedia&&matchMedia("(prefers-reduced-motion: reduce)").matches&&!1!==n.respectReducedMotion;this._playing=!n.paused&&!t,this._initGL(),this._ro="function"==typeof ResizeObserver?new ResizeObserver(()=>{this._needsPaint=!0,this._kick()}):null,this._ro&&this._ro.observe(e),this._io="function"==typeof IntersectionObserver?new IntersectionObserver(e=>{this._visible=!(!e[0]||!e[0].isIntersecting),this._kick()}):null,this._io&&this._io.observe(e),this._onVis=()=>this._kick(),this.doc.addEventListener("visibilitychange",this._onVis),this._onLost=e=>{e.preventDefault(),this._stopLoop()},this._onRestored=()=>{this._initGL(),this._needsPaint=!0,this._kick()},this.canvas.addEventListener("webglcontextlost",this._onLost),this.canvas.addEventListener("webglcontextrestored",this._onRestored),this._kick()}set(e){return this._applyParams(e),this._needsPaint=!0,this._kick(),this}play(){return this._playing=!0,this._kick(),this}pause(){return this._playing=!1,this._kick(),this}get playing(){return this._playing}shareUrl(e="https://fluid.krackeddevs.com/",n=!1){let t=this.state,a=this.canvas.clientHeight>0?this.canvas.clientWidth/this.canvas.clientHeight:1,i=[+t.speed.toFixed(2),+t.zoom.toFixed(2),+t.warp.toFixed(1),+t.grain.toFixed(3),Math.round(t.pixel),Math.round(t.dot),t.dots?1:0,t.pal,+t.seed.toFixed(2),.8,.85,+a.toFixed(4),0,n?1:0,t.field,t.screen,0,0,Math.round(t.sym||0),0];8===t.pal&&i.push(m(t.cols[0]),m(t.cols[1]),m(t.cols[2]),m(t.cols[3]));let l=+(t.thresh-.5).toFixed(2);if(0!==l){for(;i.length<24;)i.push(0);i.push(l)}if((t.layerMix||0)>.001){for(;i.length<25;)i.push(0);i.push(t.field2||0,t.blend||0,Math.round(100*t.layerMix))}let o=(t.layerMix||0)>.001&&(t.layerMix2||0)>.001;if((t.material||0)>0){for(;i.length<28;)i.push(0);i.push(Math.round(t.material))}if((t.lens||0)>0&&Math.round(100*(null==t.lensAmt?1:t.lensAmt))>=1){for(;i.length<29;)i.push(0);i.push(Math.round(t.lens),Math.round(100*(null==t.lensAmt?1:t.lensAmt)))}if(o){for(;i.length<29;)i.push(0);29===i.length&&i.push(0,100),i.push(t.field3||0,t.blend2||0,Math.round(100*t.layerMix2))}let s=8===t.pal?24:12;for(;i.length>s&&0===i[i.length-1];)i.pop();return e+"#p="+i.join(",")}toDataURL(e="image/png",n){return this._resize(),this._render(),this.canvas.toDataURL(e,n)}destroy(){this._destroyed=!0,this._stopLoop(),this._ro&&this._ro.disconnect(),this._io&&this._io.disconnect(),this.doc.removeEventListener("visibilitychange",this._onVis),this.canvas.removeEventListener("webglcontextlost",this._onLost),this.canvas.removeEventListener("webglcontextrestored",this._onRestored);let e=this.gl&&this.gl.getExtension("WEBGL_lose_context");if(e)try{e.loseContext()}catch{}this.canvas.parentNode&&this.canvas.parentNode.removeChild(this.canvas)}_applyParams(e){let n=this.state;if(null!=e.look){let t=c.find(n=>n.label.toLowerCase()===String(e.look).toLowerCase());if(!t)throw new Error('fluid-core: unknown look "'+e.look+'"');let a=t.p;n.speed=a[0],n.zoom=a[1],n.warp=a[2],n.grain=a[3],n.pixel=a[4],n.dot=a[5],n.dots=a[6],n.pal=a[7],n.seed=a[8],n.field=t.field||0,n.screen=t.screen||0,n.material=t.material||0,n.lens=t.lens||0,n.lensAmt=null!=t.lensAmt?t.lensAmt:1,n.thresh=null!=t.thresh?t.thresh:.5,t.cols&&(n.pal=8,n.cols=t.cols.map(p))}if(null!=e.field){let t=g(l,e.field);if(t<0)throw new Error('fluid-core: unknown field "'+e.field+'" — valid: '+l.join(", "));n.field=t}function t(e,t,a,i,o){if(!1===e||e&&0===e.mix)return n[a]=0,n[i]=0,void(n[o]=0);let s=g(l,null!=e.field?e.field:0),r=g(d,null!=e.blend?e.blend:"screen");if(s<0)throw new Error("fluid-core: unknown "+t+".field — valid: "+l.join(", "));if(r<0)throw new Error("fluid-core: unknown "+t+".blend — valid: "+d.join(", "));n[a]=s,n[i]=r,n[o]=null!=e.mix?Math.max(0,Math.min(1,e.mix)):.5}if(null!=e.layer&&t(e.layer,"layer","field2","blend","layerMix"),null!=e.layer2&&t(e.layer2,"layer2","field3","blend2","layerMix2"),null!=e.colors){if(!Array.isArray(e.colors)||4!==e.colors.length)throw new Error("fluid-core: colors must be 4 hex stops, dark -> light");n.pal=8,n.cols=e.colors.map(p)}else if(null!=e.palette){let t=g(o,e.palette);if(t<0)throw new Error('fluid-core: unknown palette "'+e.palette+'" — valid: '+o.join(", "));n.pal=t}if(null!=e.screen){let t="none"===e.screen?0:g(r,e.screen);if(t<0)throw new Error("fluid-core: unknown screen — valid: "+r.join(", "));n.screen=t,null==e.pixel&&null==e.look&&t>0&&n.pixel<=1.5&&(n.pixel=6)}if(null!=e.material){let t=g(f,e.material);if(t<0)throw new Error("fluid-core: unknown material — valid: "+f.join(", "));n.material=t}if(null!=e.lens){let t=g(h,e.lens);if(t<0)throw new Error("fluid-core: unknown lens — valid: "+h.join(", "));n.lens=t}for(let t of["speed","zoom","warp","grain","pixel","dot","dots","thresh","sym","seed","lensAmt"])null!=e[t]&&(n[t]=+e[t]);(n.lens||0)>0&&!(n.lensAmt>0)&&(n.lensAmt=1)}_initGL(){let e=this.canvas.getContext("webgl",{preserveDrawingBuffer:!0})||this.canvas.getContext("experimental-webgl",{preserveDrawingBuffer:!0});if(!e)throw new Error("fluid-core: WebGL is not available");this.gl=e,e.getExtension("OES_standard_derivatives");let n=(n,t)=>{let a=e.createShader(n);if(e.shaderSource(a,t),e.compileShader(a),!e.getShaderParameter(a,e.COMPILE_STATUS))throw new Error("fluid-core shader: "+e.getShaderInfoLog(a));return a},t=e.createProgram();e.attachShader(t,n(e.VERTEX_SHADER,"attribute vec2 a_pos;\nvoid main(){ gl_Position = vec4(a_pos, 0.0, 1.0); }")),e.attachShader(t,n(e.FRAGMENT_SHADER,'#extension GL_OES_standard_derivatives : enable\nprecision highp float;\nuniform vec2  u_res;\nuniform float u_time;\nuniform float u_seed;\nuniform float u_scale;\nuniform float u_warp;\nuniform int u_lens;\nuniform float u_lensAmt;\nuniform float u_sym;\nuniform float u_pixel;\nuniform float u_dots;\nuniform float u_dot;\nuniform float u_dither;\nuniform float u_grain;\nuniform int   u_pal;\nuniform vec3  u_c0;\nuniform vec3  u_c1;\nuniform vec3  u_c2;\nuniform vec3  u_c3;\nuniform sampler2D u_tex;\nuniform float u_hasTex;\nuniform float u_texAspect;\nuniform float u_liq;\nuniform float u_mix;\nuniform float u_split;\nuniform int   u_field;\nuniform int   u_field2;\nuniform int   u_blend;\nuniform float u_layerMix;\nuniform int   u_field3;\nuniform int   u_blend2;\nuniform float u_layerMix2;\nuniform int   u_screen;\nuniform int   u_material;\nuniform sampler2D u_glyph;\nuniform sampler2D u_mask;\nuniform float u_hasMask;\nuniform vec3  u_maskBg;\nuniform vec3  u_maskBg2;\nuniform float u_maskGrad;\nuniform vec2  u_pan;\nuniform vec2  u_mouse;\nuniform float u_mouseAmt;\nuniform int   u_mouseMode;\nuniform float u_rec;\n\nfloat hash(vec2 p){\n  /* precision-safe: no huge sin args, stable on mobile GPUs + long sessions */\n  p = fract(p * 0.3183099 + fract(u_seed * 0.1031) + 0.1);\n  p *= 17.0;\n  return fract(p.x * p.y * (p.x + p.y));\n}\nfloat vnoise(vec2 p){\n  vec2 i = floor(p); vec2 f = fract(p);\n  f = f * f * (3.0 - 2.0 * f);\n  float a = hash(i);\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, f.x), mix(c, d, f.x), f.y);\n}\nfloat fbm(vec2 p){\n  float v = 0.0; float a = 0.5;\n  for(int i = 0; i < 5; i++){\n    v += a * vnoise(p);\n    p = p * 2.03 + vec2(11.7, 5.9);\n    a *= 0.5;\n  }\n  return v;\n}\n\n\nvec2 hash22(vec2 p){\n  return vec2(hash(p), hash(p + vec2(37.2, 17.3)));\n}\n\n/* hex cell center for the point p (in cell units) */\nvec2 hexCenter(vec2 p){\n  vec2 r = vec2(1.0, 1.7320508);\n  vec2 h = r * 0.5;\n  vec2 a = mod(p, r) - h;\n  vec2 b = mod(p - h, r) - h;\n  vec2 gv = dot(a, a) < dot(b, b) ? a : b;\n  return p - gv;\n}\n\n/* field B: curl of a noise potential -> divergence-free flow (fluid swirl).\n   drift is the same bounded (d1,d2) the noise field uses, applied to the\n   potential domain so the swirl morphs at the same visible rate. */\nvec2 fgrad(vec2 p, vec2 off){\n  float e = 0.06;\n  float gx = fbm(p + vec2(e, 0.0) + off) - fbm(p - vec2(e, 0.0) + off);\n  float gy = fbm(p + vec2(0.0, e) + off) - fbm(p - vec2(0.0, e) + off);\n  return vec2(gx, gy) / (2.0 * e);\n}\n/* spread: push a mid-clustered field value out toward 0 and 1 around its midpoint, so a\n   custom palette uses its FULL range. fbm/sum fields pile up near 0.5 and otherwise hide\n   the end stops; geometric fields already span the range and are left alone. */\nfloat spreadF(float v, float g){ return clamp((v - 0.5) * g + 0.5, 0.0, 1.0); }\n/* complex arithmetic on vec2 (x + iy) — the math-lens layer works on the complex plane */\nvec2 cmul(vec2 a, vec2 b){ return vec2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); }\nvec2 cdiv(vec2 a, vec2 b){ float d = dot(b, b) + 1e-6; return vec2(dot(a, b), a.y * b.x - a.x * b.y) / d; }\nfloat fieldFlow(vec2 p, float t){\n  /* curl-noise flow that reorganizes in place. Two spatially-varying warps,\n     modulated by different time frequencies, reshape the flow potential locally\n     (never a uniform translation), and there is no global drift on the output —\n     so the streams keep reforming instead of the whole field panning. */\n  float amt = 0.6 + u_warp * 0.25;\n  vec2 wa = vec2(fbm(p * 0.6 + 11.0), fbm(p * 0.6 + 27.0)) - 0.5;\n  vec2 wb = vec2(fbm(p * 0.9 + 41.0), fbm(p * 0.9 + 63.0)) - 0.5;\n  vec2 sp = p + wa * (1.1 * sin(t * 0.13)) + wb * (1.0 * cos(t * 0.091));\n  vec2 g = fgrad(sp, vec2(0.0));\n  vec2 curl = vec2(g.y, -g.x);\n  return spreadF(fbm(p + curl * amt), 2.0);\n}\n\n/* field C: Worley/Voronoi cellular noise (warp blends cells <-> edges) */\nfloat fieldCellular(vec2 p, float t){\n  vec2 ip = floor(p);\n  vec2 fp = fract(p);\n  float f1 = 9.0; float f2 = 9.0;\n  for (int j = -1; j <= 1; j++){\n    for (int i = -1; i <= 1; i++){\n      vec2 g = vec2(float(i), float(j));\n      vec2 o = hash22(ip + g);\n      o = 0.5 + 0.5 * sin(t * 0.5 + 6.2831 * o);\n      vec2 d = g + o - fp;\n      float dd = dot(d, d);\n      if (dd < f1){ f2 = f1; f1 = dd; }\n      else if (dd < f2){ f2 = dd; }\n    }\n  }\n  f1 = sqrt(f1); f2 = sqrt(f2);\n  float cells = 1.0 - f1;\n  float edges = f2 - f1;\n  return mix(cells, edges, clamp(u_warp / 9.0, 0.0, 1.0));\n}\n/* field D: gyroid — a 3D gyroid sliced through time; interwoven organic bands.\n   warp adds a self-fold so the weave thickens/curls. */\nfloat fieldGyroid(vec2 p, float t){\n  vec3 q = vec3(p * 1.4, t * 0.3);\n  float g = sin(q.x) * cos(q.y) + sin(q.y) * cos(q.z) + sin(q.z) * cos(q.x);\n  g += (0.15 + u_warp * 0.12) * sin(2.0 * g + length(p));\n  return 0.5 + 0.5 * sin(g * 1.6);\n}\n\n/* field E: truchet — random corner arcs per cell -> woven maze / circuit lines.\n   bands follow the 0.5-radius arcs; warp packs them tighter. */\nfloat truchetCell(vec2 p, float h){\n  vec2 fp = fract(p);\n  if (h < 0.5){ fp.x = 1.0 - fp.x; }\n  float d = min(length(fp), length(fp - 1.0));\n  d = abs(d - 0.5);\n  float bands = 4.0 + u_warp * 2.5;\n  return 0.5 + 0.5 * cos(d * bands * 6.2831853 - u_time * 1.5);\n}\nfloat fieldTruchet(vec2 p, float t){ return truchetCell(p, hash(floor(p))); }\n\n/* field F: interference — overlapping ripple sources -> moire rings.\n   warp raises the ripple frequency (denser moire). */\nfloat fieldInterf(vec2 p, float t){\n  float v = 0.0;\n  for (int i = 0; i < 4; i++){\n    float fi = float(i);\n    vec2 c = 1.2 * vec2(sin(t * 0.2 + fi * 1.7), cos(t * 0.17 + fi * 2.3));\n    float freq = 5.0 + u_warp * 2.0 + fi * 1.6;\n    v += sin(length(p - c) * freq - t * 1.2 + fi);\n  }\n  return 0.5 + 0.5 * (v / 4.0);\n}\n\n/* field G: kaleidoscope — fold the angle into mirrored sectors over fbm.\n   warp adds sectors (3 -> ~9) for a denser mandala. */\nfloat fieldKaleido(vec2 p, float t){\n  float ang = atan(p.y, p.x);\n  float rad = length(p);\n  float sectors = 3.0 + floor(u_warp * 0.7);\n  float seg = 6.2831853 / sectors;\n  ang = mod(ang, seg);\n  ang = abs(ang - 0.5 * seg);\n  vec2 q = vec2(cos(ang), sin(ang)) * rad;\n  return spreadF(fbm(q * 1.6 + vec2(t * 0.35, t * 0.12)), 1.6);\n}\n\n/* field H: lines — rotated parallel bands; warp rotates + tightens them, a gentle\n   wave keeps them from being dead-straight */\nfloat fieldLines(vec2 p, float t){\n  float ang = u_warp * 0.35;\n  float c = cos(ang), s = sin(ang);\n  vec2 q = vec2(c * p.x - s * p.y, s * p.x + c * p.y);\n  float freq = 5.0 + u_warp * 1.4;\n  return 0.5 + 0.5 * sin(q.x * freq + t * 0.6 + 0.6 * sin(q.y * 0.7 + t * 0.5));\n}\n\n/* field I: grid — two crossed sine rulings -> a clean lattice; warp sets density */\nfloat fieldGrid(vec2 p, float t){\n  float freq = 4.0 + u_warp * 1.4;\n  float gx = sin(p.x * freq + t * 0.5);\n  float gy = sin(p.y * freq - t * 0.5);\n  float lines = max(gx, gy);            /* bright where either ruling peaks */\n  float nodes = gx * gy;                /* brightest at the crossings */\n  return spreadF(0.5 + 0.5 * mix(lines, nodes, 0.35), 1.5);\n}\n\n/* field J: golden — phyllotaxis / sunflower via the Vogel model (golden angle).\n   seed index ~ r^2; the golden angle 2.39996 rad spaces the spiral arms. */\nfloat fieldGolden(vec2 p, float t){\n  float r = length(p) * (1.3 + u_warp * 0.18);\n  float a = atan(p.y, p.x);\n  float n = r * r;\n  float spiral = cos(a - n * 2.39996323 + t * 0.55);\n  float rings = cos(n * 3.14159265 - t * 0.28);\n  return 0.5 + 0.5 * spiral * rings;\n}\nfloat fieldSmoke(vec2 p, float t){\n  /* volumetric smoke: two-step domain-warped fbm for billowing bodies + finer\n     wisps, dark-biased so the bulk falls into shadow. The warp layers are driven\n     by small bounded multi-phase sways at different rates, so the body churns in\n     place instead of sliding as a sheet; precision-safe. */\n  float w = max(u_warp, 1.0);\n  vec2 a1 = vec2(sin(t * 0.2), cos(t * 0.17)) * 0.8;\n  vec2 a2 = vec2(cos(t * 0.15), sin(t * 0.24)) * 0.8;\n  vec2 q = vec2(fbm(p + a1), fbm(p + vec2(5.2, 1.3) - a2));\n  vec2 r = vec2(fbm(p + w * 0.42 * q + vec2(1.7, 9.2) + a2),\n               fbm(p + w * 0.42 * q + vec2(8.3, 2.8) - a1));\n  float body = fbm(p + w * 0.5 * r);\n  float fine = fbm(p * 2.4 + r * 1.6 + a1 * 0.4);\n  float d = body * 0.72 + fine * 0.28;\n  return pow(clamp((d - 0.15) * 1.65, 0.0, 1.0), 1.6);\n}\n\n/* field L: quasicrystal — sum of plane-wave gratings at evenly spaced angles gives crisp\n   N-fold rotational symmetry (the classic 5-fold quasicrystal). warp picks the order. */\nfloat fieldQuasi(vec2 p, float t){\n  float n = 5.0 + floor(u_warp * 0.6);\n  float v = 0.0;\n  for (int i = 0; i < 12; i++){\n    float on = step(float(i), n - 0.5);\n    float a = 3.14159265 * float(i) / max(n, 1.0);\n    v += on * cos((p.x * cos(a) + p.y * sin(a)) * 8.0 + t * 0.65);\n  }\n  return spreadF(0.5 + 0.5 * (v / n), 1.5);\n}\n\n/* field M: honeycomb — a true hexagonal lattice (reuses hexCenter from the hex screen).\n   each cell pulses from its own hash, with crisp hexagonal walls between cells. warp = density. */\nfloat fieldHoneycomb(vec2 p, float t){\n  vec2 hp = p * (1.3 + u_warp * 0.35);\n  vec2 c = hexCenter(hp);\n  vec2 gv = hp - c;\n  float hd = max(abs(gv.x), max(abs(0.5 * gv.x + 0.8660254 * gv.y), abs(-0.5 * gv.x + 0.8660254 * gv.y)));\n  float cell = 0.5 + 0.5 * sin(hash(c) * 6.2831853 + t * 0.7);\n  float wall = smoothstep(0.40, 0.48, hd);\n  return mix(cell, 0.04, wall);\n}\n\n/* smooth 4-stop designer gradient (dark -> light) */\nvec3 ramp4(float t, vec3 a, vec3 b, vec3 c, vec3 d){\n  t = clamp(t, 0.0, 1.0);\n  vec3 col = mix(a, b, smoothstep(0.0, 0.34, t));\n  col = mix(col, c, smoothstep(0.33, 0.67, t));\n  col = mix(col, d, smoothstep(0.66, 1.0, t));\n  return col;\n}\nvec3 palChrome(float f){\n  float band = sin(f * 22.0);\n  vec3 c = vec3(0.10 + 0.82 * f) * (0.78 + 0.22 * band);\n  float edge = pow(1.0 - abs(band), 4.0);\n  vec3 sheen = 0.5 + 0.5 * cos(6.28318 * (f * 3.0 + vec3(0.0, 0.33, 0.67)));\n  return c + sheen * edge * 0.22;\n}\n\n/* bloom engine (13): a true mesh gradient — the 4 palette stops live at drifting 2D\n   anchor points and blend by distance, instead of riding the 1D ramp. bloomW returns\n   the 4 normalized blob weights; the scalar field (for dither/material/mask edges) is\n   the weighted ramp position, the colour stage blends the stop colours directly. */\nvec2 bloomAnchor(int i, float t){\n  float fi = float(i);\n  float aa = u_seed * 0.61803 + fi * 2.399963;              /* golden-angle ring: guaranteed spread */\n  float rr = 1.05 + 0.35 * sin(u_seed * 1.3 + fi * 2.1);\n  vec2 base = vec2(cos(aa), sin(aa)) * rr;\n  float w1 = 0.05 + 0.023 * fi;                             /* non-commensurate drift rates */\n  float w2 = 0.041 + 0.017 * fi;\n  return base + vec2(sin(t * w1 + aa * 3.0), cos(t * w2 + aa * 1.7)) * 0.45;\n}\nvec4 bloomW(vec2 p, float t){\n  /* wobble the domain so blob edges go organic instead of perfectly radial */\n  vec2 q = p + (vec2(fbm(p * 0.7 + t * 0.04), fbm(p * 0.7 + vec2(4.1, 7.7) - t * 0.03)) - 0.5) * u_warp * 0.35;\n  vec4 w;\n  w.x = exp(-dot(q - bloomAnchor(0, t), q - bloomAnchor(0, t)) * 1.4);\n  w.y = exp(-dot(q - bloomAnchor(1, t), q - bloomAnchor(1, t)) * 1.4);\n  w.z = exp(-dot(q - bloomAnchor(2, t), q - bloomAnchor(2, t)) * 1.4);\n  w.w = exp(-dot(q - bloomAnchor(3, t), q - bloomAnchor(3, t)) * 1.4);\n  return w / max(w.x + w.y + w.z + w.w, 0.0008);\n}\nfloat fieldBloom(vec2 p, float t){\n  vec4 w = bloomW(p, t);\n  return dot(w, vec4(0.02, 0.35, 0.68, 0.98));\n}\n/* sweep engine (14): the colour ramp laid CORNER-TO-CORNER across the frame -\n   dark stop top-left, light stop bottom-right - with the boundary wobbled by\n   drifting noise so it stays alive. Warp = wobble depth, Zoom = wobble size. */\nfloat fieldSweep(vec2 p, float t){\n  vec2 uv = p / (u_scale * 3.0);            /* undo the domain scale: frame coords */\n  float tt = dot(uv, vec2(0.7071, -0.7071)) / 1.4142 + 0.5;\n  float wob = (fbm(p * 0.9 + vec2(t * 0.05, 3.7 - t * 0.04)) - 0.5) * u_warp * 0.12;\n  return clamp(tt + wob, 0.0, 1.0);\n}\n/* marble engine (15): paper marbling — horizontal ink bands dragged through two\n   passes of combed fbm swirls (suminagashi). Warp = drag depth; the bands stay\n   readable as stripes while the swirls churn them. */\nfloat fieldMarble(vec2 p, float t){\n  vec2 a = vec2(sin(t * 0.11), cos(t * 0.09)) * 0.6;\n  vec2 q = vec2(fbm(p * 0.9 + a), fbm(p * 0.9 + vec2(3.1, 7.3) - a));\n  vec2 r = vec2(fbm(p * 1.3 + 2.2 * q + vec2(6.4, 1.9)),\n               fbm(p * 1.3 + 2.2 * q + vec2(0.7, 8.8)));\n  float band = sin((p.y + (r.x - 0.5) * u_warp * 1.6) * 5.0 + r.y * 4.0 + t * 0.15);\n  return 0.5 + 0.5 * band;\n}\n/* plaid engine (16): woven tartan — a three-frequency stripe sett per axis, crossed\n   like grid but richer, with an over/under weave shimmer at the thread crossings.\n   Warp = thread density. */\nfloat plaidSett(float x, float t){\n  float s = 0.45 * sin(x + t) + 0.35 * sin(x * 3.0 - t * 0.7) + 0.20 * sin(x * 7.0 + t * 0.4);\n  return 0.5 + 0.5 * s;\n}\nfloat fieldPlaid(vec2 p, float t){\n  vec2 q = p * (1.4 + u_warp * 0.35);\n  float sx = plaidSett(q.x, t * 0.25);\n  float sy = plaidSett(q.y, t * 0.20);\n  float over = 0.5 + 0.5 * sin(q.x * 6.0) * sin(q.y * 6.0);   /* weave: which thread is on top */\n  float v = mix(max(sx, sy), sx * sy, 0.4) * (0.82 + 0.18 * over);\n  return spreadF(clamp(v, 0.0, 1.0), 1.3);\n}\n/* curtain engine (17): aurora curtains — thin luminous verticals from ridged folds,\n   ruffled sideways by fbm and swaying, over a soft backglow. Warp = ruffle depth. */\nfloat fieldCurtain(vec2 p, float t){\n  vec2 q = vec2(p.x * 1.6, p.y * 0.35);              /* stretch: verticals dominate */\n  float ruff = fbm(vec2(q.x * 1.8 + t * 0.10, q.y + t * 0.05)) - 0.5;\n  float x = q.x + ruff * u_warp * 0.5 + sin(q.y * 1.3 + t * 0.22) * 0.35;\n  float ridge = pow(1.0 - abs(sin(x * 2.2 + t * 0.10)), 2.2);\n  float glow = fbm(vec2(x * 0.7, q.y * 0.8 - t * 0.07));\n  return clamp(ridge * 0.85 + glow * 0.35, 0.0, 1.0);\n}\n/* stitch engine (18): curve stitching — the Boole / Cremona times-table. 64 pegs on a\n   ring of radius 1.1; the peg at angle a is threaded to angle k*a. The chord family\n   envelope is the epicycloid with k-1 cusps (k=2 cardioid, k=3 nephroid). Threads =\n   min distance to any chord; the caustic glow is the chord-density sum, brightest\n   where chords crowd — so the cusped envelope emerges exactly like physical string\n   art. The exterior is circle-inverted through the peg ring, so the web reflects\n   into a full-frame halo of circular arcs — a rose window. Warp = k (2 -> 8: the\n   species changes entirely); k also drifts with t so the figure morphs live while\n   the ring slowly turns. */\nfloat stitchSegD(vec2 p, vec2 a, vec2 b){\n  vec2 pa = p - a; vec2 ba = b - a;\n  float h = clamp(dot(pa, ba) / max(dot(ba, ba), 0.0001), 0.0, 1.0);\n  return length(pa - ba * h);\n}\nfloat fieldStitch(vec2 p, float t){\n  float rot = t * 0.05 + u_seed * 0.13;\n  float k = 0.85 + u_warp * 0.9 + fract(u_seed * 0.377) * 0.7 + 0.6 * sin(t * 0.07);\n  float lenO = length(p);\n  if (lenO > 1.1){ p *= 1.21 / dot(p, p); }          /* circle-invert the exterior: the web reflects into a halo */\n  float minD = 9.0; float glow = 0.0;\n  for (int i = 0; i < 64; i++){\n    float a = float(i) * 0.09817477;         /* 2*pi/64 */\n    vec2 A = 1.1 * vec2(cos(a + rot), sin(a + rot));\n    vec2 B = 1.1 * vec2(cos(k * a + rot), sin(k * a + rot));\n    float d = stitchSegD(p, A, B);\n    minD = min(minD, d);\n    glow += exp(-d * 22.0);\n  }\n  float thread = 1.0 - smoothstep(0.0, 0.045, minD); /* the strings themselves */\n  float caust = 1.0 - exp(-glow * 0.3);              /* density caustic: the envelope */\n  float v = 0.12 + 0.62 * caust + 0.34 * thread;     /* lit floor + caustic + strings */\n  float rim = exp(-abs(lenO - 1.1) * 24.0);          /* the peg ring */\n  v = max(v, rim * 0.9);\n  return clamp(v, 0.0, 1.0);\n}\n/* pursuit engine (19): whirling polygons - Lucas mice. Ring j+1 joins the points a\n   fraction f along ring j edges: one step = rotate phi + shrink s about the centroid,\n   a discrete similarity whose orbit closure is a logarithmic spiral. Warp = f (chase\n   fraction); seed picks n in {3..6} + orientation; deep rings spin faster (inward whirl). */\nfloat fieldPursuit(vec2 p, float t){\n  float nf = 3.0 + mod(floor(u_seed + 0.5), 4.0);              /* polygon order n */\n  float an = 3.14159265 / nf;                                   /* half face-sector angle */\n  float c = cos(2.0 * an), sn = sin(2.0 * an);\n  float fr = 0.03 + u_warp * 0.04;                              /* pursuit fraction from Warp */\n  float fmax = 0.5 - sqrt(max(0.25 - 0.1638 / (1.0 - c), 0.0)); /* keep shrink s >= 0.82 */\n  float f = min(fr, fmax);\n  float phi = atan(f * sn / (1.0 - f + f * c));                 /* per-ring whirl angle */\n  float s = sqrt(1.0 - 2.0 * f * (1.0 - f) * (1.0 - c));        /* per-ring shrink */\n  float r = length(p), a0 = atan(p.y, p.x);\n  float th = u_seed * 0.7853 + t * 0.12;                        /* whole-nest precession */\n  float dth = phi + (fr - f) * 1.2 + t * 0.0072;                /* deep rings spin faster */\n  float A = 2.3 * cos(an);                                      /* outer apothem: equal circumradius */\n  float minD = 1000.0, depth = 0.0;\n  for (int j = 0; j < 22; j++){\n    float b = mod(a0 - th + an, 2.0 * an) - an;                 /* fold angle into one face sector */\n    float sd = r * cos(b) - A;                                  /* regular n-gon outline SDF */\n    minD = min(minD, abs(sd));\n    depth += step(sd, 0.0);                                     /* rings containing p -> terraced ground */\n    th += dth; A *= s;\n  }\n  float v = 0.05 + 0.028 * depth + 0.20 * exp(-minD * 6.0) + 0.22 * exp(-r * r * 1.5);\n  return clamp(mix(v, 1.0, smoothstep(0.05, 0.012, minD) * 0.95), 0.0, 1.0);\n}\n/* chladni engine (20): square-plate eigenmodes — the sand figures of a vibrating\n   plate. u_mn(x,y) = cos(m pi x)cos(n pi y) - cos(n pi x)cos(m pi y); sand collects\n   on the nodal set u = 0, drawn as thin bright lines. A resonance sweep crossfades\n   two adjacent mode pairs so the nodal web migrates and reconnects through avoided\n   crossings, like sand sliding between resonances.\n   Warp = eigenmode order: line count and topology change, not just density. */\nfloat chlPlate(vec2 q, float m, float n, float s){\n  float a = cos(m * 3.14159265 * q.x) * cos(n * 3.14159265 * q.y);\n  float b = cos(n * 3.14159265 * q.x) * cos(m * 3.14159265 * q.y);\n  return (a - b) + s * (a + b);   /* classic "-" family + a seed pinch of "+" */\n}\nfloat fieldChladni(vec2 p, float t){\n  vec2 q = p * 0.5 + vec2(fract(u_seed * 0.127), fract(u_seed * 0.211)); /* plate coords; seed shifts origin */\n  float m = 1.0 + floor(u_warp * 0.6);       /* warp = mode order (m <= 6, n <= 9: precision-safe) */\n  float n = m + 2.0;                         /* n != m or the "-" family vanishes identically */\n  float s = 0.35 * fract(u_seed * 0.61);     /* per-seed mix of the symmetric family */\n  float a = t * 0.13 + u_seed * 0.9;         /* resonance sweep phase */\n  float u = cos(a) * chlPlate(q, m, n, s) + sin(a) * chlPlate(q, m + 1.0, n + 1.0, s);\n  float L = 1.0 - smoothstep(0.0, 0.07 + 0.05 * m, abs(u)); /* sand: bright where u ~ 0; width tracks |grad| ~ pi m */\n  return clamp(L * 0.80 + 0.40 * (0.5 + 0.45 * u), 0.0, 1.0);\n}\n/* cassini engine (21): polynomial lemniscates — the level sets of the 2D log-\n   potential Phi(p) = (1/4) sum log|p - c_k| of four drifting foci (|P(z)| = c for\n   P(z) = prod(z - z_k): Cassini ovals, pinching through Bernoulli figure-eights at\n   the saddles as levels cross the zeros of P prime). Foci orbit on non-commensurate\n   ellipses so ovals merge and split; Warp = contour density + constellation spread. */\nvec2 casFocus(int i, float t){\n  float fi = float(i);\n  float aa = u_seed * 0.7853 + fi * 2.399963;               /* golden-angle ring: never collinear */\n  float rr = (0.5 + 0.3 * sin(u_seed * 1.7 + fi * 2.6)) * (0.8 + u_warp * 0.06);\n  float w1 = 0.083 + 0.034 * fi;                            /* non-commensurate orbit rates */\n  float w2 = 0.107 + 0.027 * fi;\n  return vec2(cos(aa), sin(aa)) * rr + vec2(sin(t * w1 + aa * 2.1), cos(t * w2 + aa * 1.3)) * 0.4;\n}\nfloat fieldCassini(vec2 p, float t){\n  /* harmonic away from the foci; the 0.05 epsilon caps the log singularity */\n  float phi = log(length(p - casFocus(0, t)) + 0.05)\n            + log(length(p - casFocus(1, t)) + 0.05)\n            + log(length(p - casFocus(2, t)) + 0.05)\n            + log(length(p - casFocus(3, t)) + 0.05);\n  phi *= 0.25;\n  float v = 0.5 + 0.5 * cos(phi * (0.6 + u_warp * 1.8) - t * 0.55);   /* shells radiate steadily outward */\n  return spreadF(v, 1.4);\n}\n/* topo engine (22): topographic contour map — an fbm heightfield sliced into N\n   elevation isolines, per-pixel (fract of the level index, fwidth-antialiased) so\n   no marching squares is needed. Every 5th line is a major contour: thicker and\n   brighter, like a survey map. Line brightness rides the elevation, so the palette\n   light stops crown the peaks while the basin floor stays at stop 0. Warp = terrain\n   ruggedness (domain warp); the landmass drifts slowly under the frame. */\nfloat fieldTopo(vec2 p, float t){\n  vec2 drift = vec2(t * 0.035, -t * 0.022);\n  vec2 q = vec2(fbm(p * 0.8 + drift), fbm(p * 0.8 + vec2(4.7, 2.3) - drift));\n  float h = fbm(p * 0.85 + (q - 0.5) * (u_warp * 0.55) + drift * 0.6);\n  /* stretch fbm mid-pile into a full elevation range. NOT clamped: a clamp flattens the\n     extremes onto exactly one level, and a plateau sitting on a contour fills solid. */\n  float e = (h - 0.18) * 1.55;\n  float lv = e * 14.0;\n  float fr = fract(lv);\n  float dist = min(fr, 1.0 - fr);                /* distance to the nearest contour, in level units */\n  float w = max(fwidth(lv), 0.0008);\n  float line = 1.0 - smoothstep(0.0, w * 1.4, dist);\n  float major = step(mod(floor(lv + 0.5), 5.0), 0.5);   /* every 5th level: survey-map accent */\n  line = max(line, (1.0 - smoothstep(0.0, w * 2.6, dist)) * (0.75 * major));\n  /* cliffs pack more contours than a pixel can resolve — fade them out instead of\n     letting the lines merge into a solid blob (a survey map thins out on scarps) */\n  line *= 1.0 - smoothstep(0.22, 0.5, w);\n  return clamp(line * (0.30 + 0.70 * clamp(e, 0.0, 1.0)), 0.0, 1.0);\n}\n\n/* ordered (Bayer) dither thresholds, recursive 2x2 -> 4x4 -> 8x8, WebGL1-safe */\nfloat bayer2(vec2 a){ a = floor(a); return fract(a.x * 0.5 + a.y * a.y * 0.75); }\nfloat bayer4(vec2 a){ return bayer2(0.5 * a) * 0.25 + bayer2(a); }\nfloat bayer8(vec2 a){ return bayer4(0.5 * a) * 0.25 + bayer2(a); }\n/* evaluate any engine by index — lets the base + a second Layer share the field switch.\n   out disp = noise-domain displacement (only the noise engine fills it; used by the photo melt). */\nfloat fieldOf(int eng, vec2 p, float t, out vec2 disp){\n  float d1 = 1.8 * sin(t * 0.12) + 1.2 * cos(t * 0.067);\n  float d2 = 1.8 * cos(t * 0.10) + 1.2 * sin(t * 0.084);\n  disp = vec2(0.5);\n  if (eng == 1){ return fieldFlow(p, t); }\n  else if (eng == 2){ return fieldCellular(p, t); }\n  else if (eng == 3){ return fieldGyroid(p, t); }\n  else if (eng == 4){ return fieldTruchet(p, t); }\n  else if (eng == 5){ return fieldInterf(p, t); }\n  else if (eng == 6){ return fieldKaleido(p, t); }\n  else if (eng == 7){ return fieldLines(p, t); }\n  else if (eng == 8){ return fieldGrid(p, t); }\n  else if (eng == 9){ return fieldGolden(p, t); }\n  else if (eng == 10){ return fieldSmoke(p, t); }\n  else if (eng == 11){ return fieldQuasi(p, t); }\n  else if (eng == 12){ return fieldHoneycomb(p, t); }\n  else if (eng == 13){ return fieldBloom(p, t); }\n  else if (eng == 14){ return fieldSweep(p, t); }\n  else if (eng == 15){ return fieldMarble(p, t); }\n  else if (eng == 16){ return fieldPlaid(p, t); }\n  else if (eng == 17){ return fieldCurtain(p, t); }\n  else if (eng == 18){ return fieldStitch(p, t); }\n  else if (eng == 19){ return fieldPursuit(p, t); }\n  else if (eng == 20){ return fieldChladni(p, t); }\n  else if (eng == 21){ return fieldCassini(p, t); }\n  else if (eng == 22){ return fieldTopo(p, t); }\n  vec2 m1 = vec2(d1, d2);\n  vec2 m2 = vec2(d2, -d1);\n  vec2 q = vec2(fbm(p + m1 * 0.5), fbm(p + vec2(5.2, 1.3) + m2 * 0.5));\n  disp = vec2(\n    fbm(p + u_warp * q + vec2(1.7, 9.2) + m1),\n    fbm(p + u_warp * q + vec2(8.3, 2.8) + m2)\n  );\n  return spreadF(fbm(p + u_warp * disp), 1.5);\n}\n/* field-level layer blend: composite engine b over engine a. amt = layer strength. */\nfloat blendField(float a, float b, int mode, float amt){\n  float r;\n  if (mode == 1){ r = a * b; }                                            /* multiply */\n  else if (mode == 2){ r = 1.0 - (1.0 - a) * (1.0 - b); }                 /* screen */\n  else if (mode == 3){ r = min(a + b, 1.0); }                            /* add */\n  else if (mode == 4){ r = abs(a - b); }                                 /* difference */\n  else if (mode == 5){ r = a < 0.5 ? 2.0 * a * b : 1.0 - 2.0 * (1.0 - a) * (1.0 - b); } /* overlay */\n  else { r = b; }                                                        /* 0 = normal */\n  return mix(a, r, amt);\n}\n/* material finish: treat the field as a height map (screen-space gradient -> normal) and\n   re-light the palette colour as glass / metal / sand / liquid / molten. mat 0 = off.\n   fv = the raw field value — molten draws its ribbons on its level sets. */\nvec3 shadeMaterial(int mat, vec3 base, vec3 N, float fv){\n  vec3 L = normalize(vec3(0.4, 0.7, 0.6));\n  vec3 H = normalize(L + vec3(0.0, 0.0, 1.0));\n  float ndl = max(dot(N, L), 0.0);\n  float ndh = max(dot(N, H), 0.0);\n  float fres = pow(1.0 - max(N.z, 0.0), 2.5);\n  vec3 col = base;\n  if (mat == 1){          /* glass — dark refractive body, bright fresnel rim + sharp spec */\n    col = base * (0.35 + 0.25 * ndl) + fres * (base + 0.7) + pow(ndh, 80.0) * 1.5;\n  } else if (mat == 2){   /* metal — chrome: env reflection (sky/ground by N.y) + hot spec */\n    vec3 env = mix(base * 0.15 + 0.02, base * 0.7 + 0.55, smoothstep(-0.6, 0.6, N.y));\n    col = env + pow(ndh, 40.0) * 2.0 + fres * 0.5;\n  } else if (mat == 3){   /* sand — matte grain + soft ambient occlusion, no spec */\n    float ao = clamp(0.5 + 0.5 * N.z, 0.0, 1.0);\n    col = base * (0.4 + 0.6 * ndl) * ao + (hash(gl_FragCoord.xy * 1.91) - 0.5) * 0.18;\n  } else if (mat == 4){   /* liquid — wet sheen: glossy spec + fresnel highlights */\n    col = base * (0.5 + 0.4 * ndl) + pow(ndh, 28.0) * 1.3 + fres * 0.4 * (base + 0.3);\n  } else if (mat == 5){   /* molten — liquid metal: near-black body, luminous ribbons riding\n                             the fold CONTOURS (level sets of the field — smooth curves even\n                             where the per-pixel normals are noisy), hot specular core */\n    float ph = fv * 12.56637;                               /* ~2 ribbons per field octave */\n    float s1 = 0.5 + 0.5 * sin(ph);\n    float s2 = 0.5 + 0.5 * sin(ph * 2.618 + 1.7);\n    float bands = pow(s1, 12.0) * 1.35 + pow(s2, 34.0) * 0.85;\n    float sheen = pow(s1, 3.0) * 0.20;                      /* wide under-glow so the body reads as metal */\n    vec3 tint = base / max(max(base.r, max(base.g, base.b)), 0.12);  /* palette hue at full brightness */\n    col = base * 0.12 + 0.012\n        + tint * (bands + sheen) * (0.75 + 0.25 * ndl)\n        + tint * pow(ndh, 60.0) * 1.6\n        + fres * tint * 0.15;\n  }\n  return col;\n}\nvoid main(){\n  /* 0 - before/after: left of the split shows the untouched source */\n  if (u_hasTex > 0.5 && u_split > 0.001 && gl_FragCoord.x < u_res.x * u_split){\n    vec2 st0 = gl_FragCoord.xy / u_res;\n    float ca0 = u_res.x / u_res.y;\n    vec2 t0 = st0 - 0.5;\n    if (ca0 > u_texAspect){ t0.y *= u_texAspect / ca0; }\n    else { t0.x *= ca0 / u_texAspect; }\n    t0 += 0.5 + u_pan;\n    gl_FragColor = vec4(texture2D(u_tex, clamp(t0, 0.0, 1.0)).rgb, 1.0);\n    return;\n  }\n\n  /* 1 - screen geometry: square (default) / hex / ascii — quantize coords */\n  float csA = max(u_pixel, 8.0);\n  vec2 fc = gl_FragCoord.xy;\n  if (u_screen == 1){\n    float cs = max(u_pixel, 3.0);\n    fc = hexCenter(fc / cs) * cs;\n  } else if (u_screen == 2){\n    fc = (floor(fc / csA) + 0.5) * csA;\n  } else if (u_screen == 3){\n    float cd = max(u_pixel, 3.0);\n    fc = (floor(fc / cd) + 0.5) * cd;\n  } else if (u_screen == 4){\n    float cg = max(u_pixel, 4.0);\n    fc = (floor(fc / cg) + 0.5) * cg;\n  } else if (u_pixel > 1.5){\n    fc = (floor(fc / u_pixel) + 0.5) * u_pixel;\n  }\n\n  /* 2 - field: centered uv normalized by the geometric mean of w,h so forms stay\n     isotropic (square stays square) AND the SAME amount of field shows at every\n     aspect ratio — a portrait reveals more vertically instead of zooming in.\n     (1:1 is unchanged: sqrt(s*s) == s) */\n  float mn = sqrt(u_res.x * u_res.y);\n  vec2 uv = (fc - 0.5 * u_res) / mn;\n  vec2 p = uv * u_scale * 3.0;\n  /* cursor effect: mode 1=ripple 2=lens 3=vortex 4=push */\n  if (u_mouseAmt > 0.001 && u_mouseMode > 0){\n    vec2 mUv = (u_mouse * u_res - 0.5 * u_res) / mn;\n    vec2 dv = uv - mUv;\n    float md = length(dv);\n    if (u_mouseMode == 1){\n      vec2 nz = vec2(fbm(dv * 6.0 + u_time * 0.3), fbm(dv * 6.0 + vec2(7.3, 2.1) - u_time * 0.25)) - 0.5;\n      float env = exp(-md * 9.0);\n      float wave = cos((md + nz.x * 0.12) * 30.0 - u_time * 2.0);\n      vec2 dir = normalize(dv / max(md, 0.0008) + nz * 0.9);\n      p += dir * wave * env * u_mouseAmt * 0.08;\n    } else if (u_mouseMode == 2){\n      float env = exp(-md * 5.0);\n      p -= dv * env * u_mouseAmt * 0.5;\n    } else if (u_mouseMode == 3){\n      float angle = u_mouseAmt * 3.0 * exp(-md * 4.0);\n      float ca = cos(angle), sa = sin(angle);\n      p += vec2(dv.x * ca - dv.y * sa, dv.x * sa + dv.y * ca) - dv;\n    } else if (u_mouseMode == 4){\n      float env = exp(-md * 5.0);\n      p += normalize(dv / max(md, 0.0008)) * env * u_mouseAmt * 0.28;\n    }\n  }\n  /* time evolution: small, bounded, multi-frequency sway. The old large single-\n     frequency offset translated the whole field like a rigid sheet; mixing low\n     amplitudes at non-commensurate rates makes the field churn in place instead,\n     and staying sin-bounded keeps it precision-safe over long sessions. */\n  vec2 disp = vec2(0.5);\n  float f;\n  /* symmetry modifier: fold the field coordinate into N mirrored wedges -> instant mandala\n     of whatever engine is selected. u_sym < 2 leaves it untouched. */\n  if (u_sym >= 1.5){\n    float ka = atan(p.y, p.x);\n    float kr = length(p);\n    float kseg = 6.2831853 / u_sym;\n    ka = mod(ka, kseg);\n    ka = abs(ka - 0.5 * kseg);\n    p = vec2(cos(ka), sin(ka)) * kr;\n  }\n  /* math lens: named transforms of the complex plane, applied to the domain BOTH\n     engine layers sample — any engine seen through curved space. Normalized to the\n     zoom (w ~ unit disk) so a lens reads the same at every scale; u_lensAmt blends\n     identity -> transformed coords. All outputs are magnitude-bounded so precision\n     survives long sessions. */\n  if (u_lens > 0 && u_lensAmt > 0.001){\n    float lsc = u_scale * 1.5;\n    vec2 w = p / lsc;\n    vec2 lw = w;\n    if (u_lens == 1){\n      /* square: conformal power map z^2 renormalized to |z| — angles double, the\n         plane wraps twice around the origin, radii keep their scale */\n      lw = cmul(w, w) / max(length(w), 0.001);\n    } else if (u_lens == 2){\n      /* invert: circle inversion z -> R^2 z / |z|^2 — inside and outside of the\n         R-ring trade places (an anticonformal involution) */\n      lw = w * (0.30 / max(dot(w, w), 0.004));\n    } else if (u_lens == 3){\n      /* mobius: disk automorphism z -> (z - a)/(1 - conj(a) z); the pole a orbits\n         slowly, so the whole space breathes hyperbolically around it */\n      vec2 a = vec2(cos(u_time * 0.07), sin(u_time * 0.09)) * 0.45;\n      lw = cdiv(w - a, vec2(1.0, 0.0) - cmul(vec2(a.x, -a.y), w));\n      lw = clamp(lw, -8.0, 8.0);   /* the pole at 1/conj(a) is reachable with cursor warps */\n    } else if (u_lens == 4){\n      /* droste: log-polar spiral self-similarity (Escher). exp(rot(log z)) with a\n         22.5-degree twist couples radius to angle; a slow post-rotation animates\n         the spiral without unbounded zoom (log-radius stays in a fixed band) */\n      vec2 lg = vec2(log(max(length(w), 0.003)), atan(w.y, w.x));\n      lg = cmul(lg, vec2(0.92388, 0.38268));\n      float dr = lg.y + u_time * 0.04;\n      lw = exp(lg.x) * vec2(cos(dr), sin(dr));\n    } else if (u_lens == 5){\n      /* hyperbolic: radial blow-up of the Poincare-disk metric factor 1/(1 - |z|^2)\n         — the pattern compresses without limit toward a circular horizon */\n      lw = w / (1.06 - min(dot(w, w), 1.0));\n    } else if (u_lens == 6){\n      /* julia: iterate z -> z^2 + c and sample the engine at the folded orbit; c\n         rides the |c| = 0.7885 circle (seed picks the spot, drifting through the\n         Mandelbrot boundary) so the folding is always near-chaotic */\n      float cp = u_seed * 2.4 + u_time * 0.02;\n      vec2 c = vec2(cos(cp), sin(cp)) * 0.7885;\n      vec2 z = w * 0.8;\n      for (int k = 0; k < 7; k++){\n        if (dot(z, z) > 4.0){ break; }\n        z = cmul(z, z) + c;\n      }\n      lw = clamp(z, -2.0, 2.0);\n    } else if (u_lens == 7){\n      /* cube: conformal power map z^3 renormalized to |z| — angles triple, the\n         plane wraps three times around the origin */\n      lw = cmul(cmul(w, w), w) / max(dot(w, w), 0.001);\n    } else if (u_lens == 8){\n      /* exp: the exponential map — vertical lines become circles, horizontal\n         strips unroll into radial fans; a slow x-drift breathes the radius */\n      float ex = exp((w.x + 0.15 * sin(u_time * 0.09)) * 1.1) * 0.5;\n      float ey = w.y * 2.0 + u_time * 0.03;\n      lw = ex * vec2(cos(ey), sin(ey));\n    } else if (u_lens == 9){\n      /* sine: sin(z) = sin x cosh y + i cos x sinh y — a doubly-folded conformal\n         lattice; every engine gains mirror periodicity (no cosh/sinh in ES 1.00)  */\n      vec2 q = vec2(w.x * 2.5, w.y * 1.6);\n      float chy = (exp(q.y) + exp(-q.y)) * 0.5;\n      float shy = (exp(q.y) - exp(-q.y)) * 0.5;\n      lw = vec2(sin(q.x) * chy, cos(q.x) * shy) * 0.55;\n    } else if (u_lens == 10){\n      /* joukowski: z + c^2/z — the airfoil transform of aerodynamics; circles\n         near the pole become wing profiles, far field stays put */\n      lw = w + 0.30 * w / max(dot(w, w), 0.02);\n    } else if (u_lens == 11){\n      /* newton: basins of the Newton iteration for z^3 = r — the fractal shores where\n         three attractors meet; the target root-circle slowly rotates */\n      float nph = u_seed * 1.3 + u_time * 0.05;\n      vec2 nr = vec2(cos(nph), sin(nph));\n      vec2 z = w * 1.4;\n      for (int k = 0; k < 5; k++){\n        vec2 z2 = cmul(z, z);\n        z = z - cdiv(cmul(z, z2) - nr, 3.0 * z2);\n        z = clamp(z, -3.0, 3.0);\n      }\n      lw = z;\n    } else {\n      /* modular: fold into the SL(2,Z) fundamental domain (|Re z| < 1/2, |z| > 1\n         via T: z->z+1 and S: z->-1/z) — the hyperbolic tessellation of number theory */\n      vec2 z = vec2(w.x * 1.4 + u_time * 0.02, abs(w.y * 1.4) + 0.08);\n      for (int k = 0; k < 6; k++){\n        z.x = z.x - floor(z.x + 0.5);\n        float zz = dot(z, z);\n        if (zz < 1.0){ z = vec2(-z.x, z.y) / max(zz, 0.01); }\n      }\n      lw = clamp(z, -4.0, 4.0);\n    }\n    p = mix(p, lw * lsc, u_lensAmt);\n  }\n  /* base layer, then optionally composite a 2nd and 3rd engine on the same domain\n     (Layers). Each blends onto the accumulated result, not onto the base, so the stack\n     reads top-down exactly as the tray draws it. */\n  f = fieldOf(u_field, p, u_time, disp);\n  if (u_layerMix > 0.001){\n    vec2 disp2;\n    f = blendField(f, fieldOf(u_field2, p, u_time, disp2), u_blend, u_layerMix);\n  }\n  if (u_layerMix2 > 0.001){\n    vec2 disp3;\n    f = blendField(f, fieldOf(u_field3, p, u_time, disp3), u_blend2, u_layerMix2);\n  }\n  if (u_hasTex > 0.5 && u_field != 0){\n    float d1 = 1.8 * sin(u_time * 0.12) + 1.2 * cos(u_time * 0.067);\n    float d2 = 1.8 * cos(u_time * 0.10) + 1.2 * sin(u_time * 0.084);\n    disp = vec2(fbm(p + vec2(1.7, 9.2) + d1), fbm(p + vec2(8.3, 2.8) + d2));\n  }\n  f = smoothstep(0.08, 0.92, f); /* gentle spread — keep gradients smooth */\n\n  /* 3 - photo blend: cover-fit, liquified by disp, luminance into f */\n  if (u_hasTex > 0.5){\n    vec2 st = fc / u_res;\n    float ca = u_res.x / u_res.y;\n    vec2 tuv = st - 0.5;\n    if (ca > u_texAspect){ tuv.y *= u_texAspect / ca; }\n    else { tuv.x *= ca / u_texAspect; }\n    tuv += 0.5 + u_pan;\n    tuv += (disp - 0.5) * u_liq * 0.25;\n    vec3 ts = texture2D(u_tex, clamp(tuv, 0.0, 1.0)).rgb;\n    float lum = dot(ts, vec3(0.299, 0.587, 0.114));\n    f = mix(f, lum, u_mix);\n  }\n\n  /* 4 - palette: Chrome is procedural; every other palette (presets + custom)\n       is a 4-stop ramp fed by colour uniforms set on the JS side.\n       Bloom (13) blends the stop COLOURS by blob weight — orange meets blue\n       directly instead of detouring through the middle of the ramp. */\n  vec3 col;\n  if (u_field == 13 && u_hasTex < 0.5 && u_pal != 7){\n    vec4 bw = bloomW(p, u_time);\n    col = bw.x * u_c0 + bw.y * u_c1 + bw.z * u_c2 + bw.w * u_c3;\n  }\n  else if (u_pal == 7){ col = palChrome(f); }\n  else           { col = ramp4(f, u_c0, u_c1, u_c2, u_c3); }\n  /* soft highlight bloom for a premium glow */\n  col += smoothstep(0.72, 1.0, f) * 0.12;\n  /* 4b - material finish: field gradient -> normal, re-light as glass/metal/sand/liquid */\n  if (u_material > 0){\n    vec2 grd = vec2(dFdx(f), dFdy(f)) * u_res.y * 0.06;\n    col = shadeMaterial(u_material, col, normalize(vec3(-grd, 1.0)), f);\n  }\n\n  /* 5 - halftone in real (un-pixelated) coords (square screen only) */\n  if (u_dots > 0.5 && u_screen == 0){\n    vec2 g = mod(gl_FragCoord.xy, u_dot) - 0.5 * u_dot;\n    float lum = dot(col, vec3(0.299, 0.587, 0.114));\n    float radius = 0.5 * u_dot * sqrt(clamp(lum, 0.0, 1.0)) * 0.92;\n    float dm = 1.0 - smoothstep(radius - 0.8, radius + 0.8, length(g));\n    col = mix(col * 0.12, col * 1.12, dm);\n  }\n\n  /* 5b - ascii: cell brightness picks a glyph from the atlas */\n  if (u_screen == 2){\n    float lum = clamp(dot(col, vec3(0.299, 0.587, 0.114)), 0.0, 1.0);\n    float gi = floor(lum * 9.999);\n    vec2 cl = fract(gl_FragCoord.xy / csA);\n    vec2 guv = vec2((gi + cl.x) / 10.0, 1.0 - cl.y);\n    col *= texture2D(u_glyph, guv).r;\n  }\n\n  /* 5c - ordered dither: quantize the field to a 2-tone palette (c1 -> c3).\n     Threshold biases the field so the bright dots grow denser or sparser. */\n  if (u_screen == 3){\n    float cd = max(u_pixel, 3.0);\n    float bit = step(bayer8(gl_FragCoord.xy / cd), clamp(f + (u_dither - 0.5), 0.0, 1.0));\n    col = mix(u_c1, u_c3, bit);\n  }\n\n  /* 5d - glitch: chromatic-aberration on the field contours, black elsewhere (RGB channel split) */\n  if (u_screen == 4){\n    float lev = clamp(0.5 + (u_dither - 0.5) * 0.6, 0.18, 0.82);  /* Threshold shifts which contour shows */\n    float bw = 0.018;                                            /* narrow band -> thin sparse contours on black */\n    col = vec3(\n      1.0 - smoothstep(bw, bw * 2.6, abs(f - (lev - 0.05))),\n      1.0 - smoothstep(bw, bw * 2.6, abs(f - lev)),\n      1.0 - smoothstep(bw, bw * 2.6, abs(f - (lev + 0.05)))\n    );\n  }\n\n  /* 6 - grain + vignette */\n  float grPhase = mix(mod(floor(u_time * 10.0), 61.0) * 1.7, 23.0, u_rec);\n  float gr = hash(gl_FragCoord.xy * 0.731 + grPhase) - 0.5;\n  col += gr * u_grain * mix(1.0, 0.28, u_rec);\n  col *= 1.0 - 0.22 * dot(uv, uv);\n\n  /* 7 - text/logo mask: the living field fills the letters, clean bg outside.\n       The background is solid u_maskBg, or a vertical A->B gradient when u_maskGrad. */\n  if (u_hasMask > 0.5){\n    float mk = texture2D(u_mask, vec2(gl_FragCoord.x / u_res.x, 1.0 - gl_FragCoord.y / u_res.y)).r;\n    vec3 mbg = mix(u_maskBg, u_maskBg2, u_maskGrad * (1.0 - gl_FragCoord.y / u_res.y));\n    col = mix(mbg, col, smoothstep(0.42, 0.58, mk));\n  }\n\n  gl_FragColor = vec4(col, 1.0);\n}')),e.linkProgram(t),e.useProgram(t);let a=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,a),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,3,-1,-1,3]),e.STATIC_DRAW);let i=e.getAttribLocation(t,"a_pos");e.enableVertexAttribArray(i),e.vertexAttribPointer(i,2,e.FLOAT,!1,0,0),this.U={},["u_res","u_time","u_seed","u_scale","u_warp","u_sym","u_pixel","u_dots","u_dot","u_dither","u_grain","u_pal","u_c0","u_c1","u_c2","u_c3","u_tex","u_hasTex","u_texAspect","u_liq","u_mix","u_split","u_field","u_field2","u_blend","u_layerMix","u_field3","u_blend2","u_layerMix2","u_screen","u_material","u_lens","u_lensAmt","u_glyph","u_pan","u_mouse","u_mouseAmt","u_mouseMode","u_rec","u_mask","u_hasMask","u_maskBg","u_maskBg2","u_maskGrad"].forEach(n=>{this.U[n]=e.getUniformLocation(t,n)});let l=n=>{e.activeTexture(e.TEXTURE0+n);let t=e.createTexture();return e.bindTexture(e.TEXTURE_2D,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,1,1,0,e.RGBA,e.UNSIGNED_BYTE,new Uint8Array([0,0,0,255])),t};l(0),e.uniform1i(this.U.u_tex,0),e.activeTexture(e.TEXTURE1);let o=e.createTexture();e.bindTexture(e.TEXTURE_2D,o),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL,!1),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,function(e){let n=" .:-=+*#%@",t=e.createElement("canvas");t.width=280,t.height=28;let a=t.getContext("2d");a.fillStyle="#000",a.fillRect(0,0,t.width,t.height),a.fillStyle="#fff",a.font="bold "+Math.round(28*.82)+"px ui-monospace, Menlo, Consolas, monospace",a.textAlign="center",a.textBaseline="middle";for(let e=0;e<10;e++)a.fillText(n.charAt(e),28*e+14,15);return t}(this.doc)),e.uniform1i(this.U.u_glyph,1),l(2),e.uniform1i(this.U.u_mask,2),e.activeTexture(e.TEXTURE0)}_resize(){let e=this.container.clientWidth||1,n=this.container.clientHeight||1,t=Math.min(("number"==typeof devicePixelRatio?devicePixelRatio:1)||1,2);e*n*t*t>u&&(t=Math.max(1,Math.sqrt(u/(e*n))));let a=Math.max(1,Math.round(e*t)),i=Math.max(1,Math.round(n*t));(this.canvas.width!==a||this.canvas.height!==i)&&(this.canvas.width=a,this.canvas.height=i)}_render(){let e=this.gl,n=this.U,t=this.state;if(!e||e.isContextLost())return;let a=this.canvas.clientWidth>0?this.canvas.width/this.canvas.clientWidth:1;e.viewport(0,0,this.canvas.width,this.canvas.height),e.uniform2f(n.u_res,this.canvas.width,this.canvas.height),e.uniform1f(n.u_time,this.t),e.uniform1f(n.u_seed,t.seed),e.uniform1f(n.u_scale,t.zoom),e.uniform1f(n.u_warp,t.warp),e.uniform1f(n.u_sym,t.sym),e.uniform1i(n.u_lens,Math.round(t.lens||0)),e.uniform1f(n.u_lensAmt,null==t.lensAmt?1:t.lensAmt),e.uniform1f(n.u_pixel,t.pixel<=1.5?1:t.pixel*a),e.uniform1f(n.u_dots,t.dots),e.uniform1f(n.u_dot,t.dot*a),e.uniform1f(n.u_dither,t.thresh),e.uniform1f(n.u_grain,t.grain),e.uniform1i(n.u_pal,t.pal);let i=8===t.pal&&t.cols?t.cols:s[t.pal]||s[0];e.uniform3f(n.u_c0,i[0][0],i[0][1],i[0][2]),e.uniform3f(n.u_c1,i[1][0],i[1][1],i[1][2]),e.uniform3f(n.u_c2,i[2][0],i[2][1],i[2][2]),e.uniform3f(n.u_c3,i[3][0],i[3][1],i[3][2]),e.uniform1f(n.u_hasTex,0),e.uniform1f(n.u_texAspect,1),e.uniform1f(n.u_liq,.8),e.uniform1f(n.u_mix,.85),e.uniform1f(n.u_split,0),e.uniform1i(n.u_field,t.field),e.uniform1i(n.u_field2,t.field2||0),e.uniform1i(n.u_blend,t.blend||0),e.uniform1f(n.u_layerMix,t.layerMix||0),e.uniform1i(n.u_field3,t.field3||0),e.uniform1i(n.u_blend2,t.blend2||0),e.uniform1f(n.u_layerMix2,(t.layerMix||0)>.001&&t.layerMix2||0),e.uniform1i(n.u_screen,t.screen),e.uniform1i(n.u_material,t.material||0),e.uniform2f(n.u_pan,0,0),e.uniform2f(n.u_mouse,.5,.5),e.uniform1f(n.u_mouseAmt,0),e.uniform1i(n.u_mouseMode,1),e.uniform1f(n.u_rec,0),e.uniform1f(n.u_hasMask,0),e.uniform3f(n.u_maskBg,.05,.05,.06),e.uniform3f(n.u_maskBg2,.16,.16,.27),e.uniform1f(n.u_maskGrad,0),e.drawArrays(e.TRIANGLES,0,3)}_shouldAnimate(){return!this._destroyed&&this._playing&&0!==this.state.speed&&this._visible&&"hidden"!==this.doc.visibilityState}_kick(){if(!this._destroyed)if(this._shouldAnimate()){if(null==this._raf){this._last=0;let e=n=>{if(this._raf=null,!this._shouldAnimate())return void(this._needsPaint&&this._paintOnce());let t=this._last?Math.min((n-this._last)/1e3,.1):0;this._last=n,this.t+=t*this.state.speed,this._resize(),this._render(),this._needsPaint=!1,this._raf=requestAnimationFrame(e)};this._raf=requestAnimationFrame(e)}}else this._needsPaint&&this._paintOnce()}_paintOnce(){this._destroyed||(this._resize(),this._render(),this._needsPaint=!1)}_stopLoop(){null!=this._raf&&(cancelAnimationFrame(this._raf),this._raf=null)}};function _(e){return e=Math.max(0,Math.round(e)),[Math.floor(e/65536)%256/255,Math.floor(e/256)%256/255,e%256/255]}function w(e){let n=e=>{let n=Math.max(0,Math.min(255,Math.round(255*e))).toString(16);return n.length<2?"0"+n:n};return"#"+n(e[0])+n(e[1])+n(e[2])}var x=(e,n,t)=>Math.min(t,Math.max(n,Math.round(e))),y=l.length-1;function k(e){let n=String(e||""),t=n.indexOf("#p=");t>=0?n=n.slice(t+3):0===n.indexOf("p=")?n=n.slice(2):"#"===n.charAt(0)&&(n=n.slice(1));let a=n.split(",").map(parseFloat);if(a.length<12||a.some(isNaN))return null;let i={speed:a[0],zoom:a[1],warp:a[2],grain:a[3],pixel:Math.round(a[4]),dot:Math.round(a[5]),dots:Math.round(a[6])?1:0,seed:a[8],ar:a[11]>=.3&&a[11]<=3?a[11]:1,field:a.length>14?x(a[14],0,y):0,screen:a.length>15?x(a[15],0,4):0,sym:a.length>18?x(a[18],0,12):0,thresh:a.length>24?Math.max(0,Math.min(1,.5+a[24])):.5,material:a.length>28?x(a[28],0,5):0,lens:a.length>29?x(a[29],0,12):0,lensAmt:a.length>30?Math.max(0,Math.min(1,a[30]/100)):1},l=x(a[7],0,8);if(8===l){let e=a.length>23?[_(a[20]),_(a[21]),_(a[22]),_(a[23])]:s[0];i.colors=e.map(w)}else i.palette=l;let o=a.length>27?Math.max(0,Math.min(1,a[27]/100)):0;if(o>.001){i.layer={field:a.length>25?x(a[25],0,y):0,blend:a.length>26?x(a[26],0,5):0,mix:o};let e=a.length>33?Math.max(0,Math.min(1,a[33]/100)):0;e>.001&&(i.layer2={field:a.length>31?x(a[31],0,y):0,blend:a.length>32?x(a[32],0,5):0,mix:e})}return i}var E="https://fluid.krackeddevs.com",A="#p=0.5,1.5,5.5,0.03,1,10,0,0,18,0,0,1.7778,0,1,1",T=13;function M(e){let n=e||A;"#"===n.charAt(0)&&(n=n.slice(1)),0===n.indexOf("p=")&&(n=n.slice(2)),/^[0-9.,\-]*$/.test(n)||(n=A.replace(/^#p=/,""));let t=n.split(",");for(;t.length<=T;)t.push("0");return t[T]="1","#p="+t.join(",")}function z(e={}){let n=(e.base||E).replace(/\/+$/,"");return/^https?:\/\//i.test(n)||(n=E.replace(/\/+$/,"")),n+"/"+M(e.hash)}function q(e){if(!e)return!1;let n=getComputedStyle(e).backgroundColor;if(!n||"transparent"===n)return!1;let t=n.match(/^rgba?\(([^)]+)\)/i);if(!t)return!0;let a=t[1].split(",");return(a.length>=4?parseFloat(a[3]):1)>0}var R=!1;function L(e){R||"undefined"==typeof document||"undefined"==typeof getComputedStyle||e>=0||(q(document.body)||q(document.documentElement))&&(R=!0,console.warn("[fluid-bg] A `fixed` background sits at z-index "+e+", but the page background (on <body>/<html>) is opaque and paints over it, so you'll see nothing (often a black screen). Make the page background transparent — e.g. `html, body { background: transparent }` — or raise the z-index above your page background. See https://github.com/enonforetsam/fluid/tree/master/fluid-bg#using-fixed-keep-the-page-background-transparent"))}function C(e,n){return function(e,n){return new b(e,n)}(e,k(M(n))||k(A))}function F(e,n){if("iframe"!==n.mode)try{let t=C(e,n.hash);return{mode:"native",cleanup:()=>t.destroy(),mount:t}}catch{}let t=function(e){let n=document.createElement("iframe");return n.src=e,n.title="Fluid background",n.loading="lazy",n.setAttribute("aria-hidden","true"),n.setAttribute("tabindex","-1"),n.style.cssText="border:0;display:block;width:100%;height:100%;pointer-events:none;",n}(z(n));return e.appendChild(t),{mode:"iframe",cleanup:()=>t.remove()}}function S(e,n={}){if(n.fixed){let t=null==n.z||isNaN(Number(n.z))?-1:Number(n.z);L(t);let a=document.createElement("div");a.style.cssText="position:fixed;inset:0;overflow:hidden;pointer-events:none;z-index:"+t+";",(e||document.body).appendChild(a);let i=F(a,n);return{el:a,mode:i.mode,destroy:()=>{i.cleanup(),a.remove()},pause:i.mount?()=>{i.mount.pause()}:void 0,play:i.mount?()=>{i.mount.play()}:void 0}}let t=e||document.body;"static"===getComputedStyle(t).position&&(t.style.position="relative");let a=document.createElement("div");a.style.cssText="position:absolute;inset:0;width:100%;height:100%;overflow:hidden;pointer-events:none;",t.appendChild(a);let i=F(a,n);return{el:t,mode:i.mode,destroy:()=>{i.cleanup(),a.remove()},pause:i.mount?()=>{i.mount.pause()}:void 0,play:i.mount?()=>{i.mount.play()}:void 0}}var D,P=class extends HTMLElement{constructor(){super(...arguments),this.handle=null,this.renderedKey=""}static get observedAttributes(){return["hash","fixed","z","base","mode"]}connectedCallback(){if(this.render(),this.hasAttribute("fixed")){let e=this.getAttribute("z");L(null==e?-1:Number(e))}}disconnectedCallback(){this.handle&&(this.handle.destroy(),this.handle=null),this.renderedKey=""}attributeChangedCallback(){this.isConnected&&this.render()}render(){let e=this.getAttribute("z"),n=null==e||isNaN(Number(e))?-1:Number(e),t=this.getAttribute("hash")||void 0,a=this.getAttribute("base")||void 0,i="iframe"===this.getAttribute("mode")?"iframe":"native",l=[t,a,i,n,this.hasAttribute("fixed")].join("|");if(l===this.renderedKey)return;this.renderedKey=l;let o=this.shadowRoot||this.attachShadow({mode:"open"});this.handle&&(this.handle.destroy(),this.handle=null),o.innerHTML="<style>:host{display:block;position:relative;width:100%;height:100%}:host([fixed]){position:fixed;inset:0;width:100vw;height:100vh;pointer-events:none;overflow:hidden;z-index:"+n+'}</style><div style="position:absolute;inset:0"></div>';let s=o.lastElementChild;this.handle=S(s,{hash:t,base:a,mode:i})}};function O(e="fluid-bg"){"undefined"!=typeof customElements&&!customElements.get(e)&&customElements.define(e,P)}return"undefined"!=typeof window&&"undefined"!=typeof customElements&&O(),D=i,((i,l,o,s)=>{if(l&&"object"==typeof l||"function"==typeof l)for(let r of t(l))!a.call(i,r)&&r!==o&&e(i,r,{get:()=>l[r],enumerable:!(s=n(l,r))||s.enumerable});return i})(e({},"__esModule",{value:!0}),D)})();
//# sourceMappingURL=/sm/47ce98d93ec360c57809134595666df279a04445e2c3f9c4fcdcc34690c4d16e.map