{"history":[{"breakpoints":[],"visible":true,"aspectRatio":1,"userDownsample":1,"layerType":"effect","type":"sdf_strip","usesPingPong":false,"texture":false,"animating":true,"mouseMomentum":0.05,"mouseSpring":0.07,"isMask":0,"compiledFragmentShaders":["#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision highp float;\nprecision highp int;\nin vec2 vTextureCoord;\nuniform sampler2D uTexture;uniform float uTime;uniform vec2 uMousePos;\nuniform vec2 uResolution;vec4 applyLayerMixAlpha(vec4 color, vec4 bg, float amount) {\nreturn mix(bg, color, amount);\n}uvec2 pcg2d(uvec2 v) {\nv = v * 1664525u + 1013904223u;\nv.x += v.y * v.y * 1664525u + 1013904223u;\nv.y += v.x * v.x * 1664525u + 1013904223u;\nv ^= v >> 16;\nv.x += v.y * v.y * 1664525u + 1013904223u;\nv.y += v.x * v.x * 1664525u + 1013904223u;\nreturn v;\n}float randFibo(vec2 p) {\nuvec2 v = floatBitsToUint(p);\nv = pcg2d(v);\nuint r = v.x ^ v.y;\nreturn float(r) / float(0xffffffffu);\n}float deband() {\nreturn (randFibo(gl_FragCoord.xy) - 0.5) / 255.0;\n}const float PI = 3.14159265359;\nconst float DISP_STEPS = 12.;\nconst vec3 viewDir = vec3(0,0, -4.25);ivec2 customTexSize;\nfloat customTexAspect;const mat3 ROT_Y_90 = mat3(\n0.0, 0.0, 1.0,\n0.0, 1.0, 0.0,\n-1.0, 0.0, 0.0\n);const mat3 ROT_Z_90 = mat3(\n0.0, -1.0, 0.0,\n1.0, 0.0, 0.0,\n0.0, 0.0, 1.0\n);const mat3 ROT_X_90 = mat3(\n1.0, 0.0, 0.0,\n0.0, 0.0, -1.0,\n0.0, 1.0, 0.0\n);mat3 rotY(float ang) {\nfloat c = cos(ang), s = sin(ang);\nreturn mat3(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c);\n}mat3 rotX(float ang) {\nfloat c = cos(ang), s = sin(ang);\nreturn mat3(1.0, 0.0, 0.0, 0.0, c, -s, 0.0, s, c);\n}mat3 rotZ(float ang) {\nfloat c = cos(ang), s = sin(ang);\nreturn mat3(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0);\n}vec3 twistY(vec3 p, float amount) {\nfloat c = cos(amount * p.y);\nfloat s = sin(amount * p.y);\nmat2 m = mat2(c, -s, s, c);\nreturn vec3(m * p.xz, p.y);\n}vec3 twistX(vec3 p, float amount) {\nfloat c = cos(amount * p.x);\nfloat s = sin(amount * p.x);\nmat2 m = mat2(c, -s, s, c);\nreturn vec3(p.x, m * p.yz);\n}vec3 getAdjustedP(vec3 p) {\nvec2 twist = vec2(0, 0);p.xy *= vec2(uResolution.x / uResolution.y, 1);p *= (1. + (0.0000 + 0.01) * 0.5);vec2 mousePos = mix(vec2(0), uMousePos - 0.5, 0.0700);\nvec2 axis = vec2(-1. * vec3(0.546337890625, 0.5763671875, 0.54).y - 1. + mousePos.y/PI, vec3(0.546337890625, 0.5763671875, 0.54).x + mousePos.x/PI) * 2.;float baseTime = uTime * 0.02;mat3 rotYMat = rotY(axis.y * PI);\nmat3 rotXMat = rotX(axis.x * PI);\nmat3 rotZMat = rotZ(vec3(0.546337890625, 0.5763671875, 0.54).z * 2.0 * PI);mat3 combinedRotation = rotZMat * rotYMat * rotXMat;p = combinedRotation * p;\np = mix(p, twistY(p, -1.0 * twist.y), step(0.0, abs(twist.y)));\np = mix(p, twistX(p, -1.0 * twist.x), step(0.0, abs(twist.x)));return p;\n}float sdfBox(vec3 p, vec3 b) {\nvec3 d = abs(p) - b;\nreturn length(max(d,0.0)) + min(max(d.x,max(d.y,d.z)),0.0);\n}float sdfStrip(vec3 p) {\nvec3 origP = p;\np *= ROT_Z_90;\np *= ROT_Y_90;float frequency = 0.5000 * 10.0;\nfloat amplitude = 0.5000 * 1.;float wave1 = sin(origP.x * frequency + uTime * 0.05) * amplitude;\nfloat wave2 = cos((origP.x + 0.5000) * frequency * 0.75 + uTime * 0.075) * amplitude;\nfloat wave3 = cos((p.x + 0.5000) * frequency * 0.75 + uTime * 0.075) * amplitude;\np.x += (wave1 + wave2) * 0.2;\np.y += (wave3) * 0.3;\nfloat d = sdfBox(p, vec3(0.1000 * 0.1, 20., 0.5200));\nreturn d;\n}float getMergedSDF(vec3 p) {\nreturn sdfStrip(getAdjustedP(p));\n}float fresnel(vec3 eyeVector, vec3 worldNormal, float power) {\nfloat NdotV = abs(dot(eyeVector, worldNormal));\nfloat width = fwidth(dot(eyeVector, worldNormal));\nfloat threshold = 0.2;\nfloat edgeDampFactor = smoothstep(threshold, -threshold, width);\nfloat fresnelFactor = 1.0 - NdotV;\nreturn pow(fresnelFactor, power) * mix(1., edgeDampFactor * 2., 0.5);\n}vec3 noFrostOrDispersion(vec3 rd, vec3 normal) {\nfloat ior = 1.0 / (1.0 + 0.5000 * 0.25);\nvec3 refractedRay = refract(rd, normal, ior);\nreturn texture(uTexture, vTextureCoord - refractedRay.xy).rgb;\n}vec3 frostOrDispersion(vec3 rd, vec3 normal) {\nvec3 refractionColor = vec3(0);\nfloat iorBase = 1. + 0.5000 * 0.25;vec3 dispCoefficients = vec3(0.03, 0.06, 0.1) * 0.2500 * 1.2;for(float i = 0.; i < DISP_STEPS; i++) {\nfloat step = i / DISP_STEPS;\nvec3 disp = step * dispCoefficients;\nvec3 ior = 1.0 / (iorBase + disp);vec3 refractedRayR = refract(rd, normal, ior.r);\nvec3 refractedRayG = refract(rd, normal, ior.g);\nvec3 refractedRayB = refract(rd, normal, ior.b);refractionColor.r += texture(uTexture, vTextureCoord - refractedRayR.xy).r;\nrefractionColor.g += texture(uTexture, vTextureCoord - refractedRayG.xy).g;\nrefractionColor.b += texture(uTexture, vTextureCoord - refractedRayB.xy).b;\n}return clamp(refractionColor / DISP_STEPS, 0.0, 1.0);\n}vec3 calculateNormal(vec3 p, float eps) {\nconst vec3 k0 = vec3(1.0, -1.0, -1.0);\nconst vec3 k1 = vec3(-1.0, -1.0, 1.0);\nconst vec3 k2 = vec3(-1.0, 1.0, -1.0);\nconst vec3 k3 = vec3(1.0, 1.0, 1.0);\nreturn normalize(\nk0 * getMergedSDF(p + k0 * eps) +\nk1 * getMergedSDF(p + k1 * eps) +\nk2 * getMergedSDF(p + k2 * eps) +\nk3 * getMergedSDF(p + k3 * eps)\n);\n}vec3 sampleTexture(vec3 rd, vec3 normal) {return frostOrDispersion(rd, normal);\nreturn noFrostOrDispersion(rd, normal);\n}float scene(vec3 p) {\nreturn max(0.0000000001, getMergedSDF(p) - (0.0000 * 0.5 + 0.01));\n}const int STEPS = 128;\nconst float MAX_DISTANCE = 100.0;vec4 rayMarch(vec3 ro, vec3 rd) {\nfloat pixelSize = 0.005;\nfloat traveled = 0.;\nvec3 entryPoint = vec3(0.0);\nvec3 entryNormal = vec3(0.0);\nfloat partialAlpha = 0.0;for (int i = 0; i < STEPS; ++i) {\nvec3 currentPos = ro + rd * traveled;\nfloat distance = scene(currentPos);\nfloat progress = float(i)/float(STEPS);\nfloat step = distance * mix(1., 2., progress);if (distance > MAX_DISTANCE) break;if (distance < pixelSize) {\npartialAlpha = 1.;\nentryPoint = currentPos;\nentryNormal = calculateNormal(entryPoint, pixelSize * 0.5);\nbreak;\n}traveled += max(step, pixelSize);\nif (traveled > MAX_DISTANCE) break;\n}if (partialAlpha == 0.0) {\nreturn texture(uTexture, vTextureCoord);\n}vec4 bg = texture(uTexture, vTextureCoord);vec3 samplePosition = mix(rd, entryPoint, 0.0000);\nvec3 refractionColor = sampleTexture(samplePosition, entryNormal);\nvec3 lightDir = vec3(((vec2(vec3(0.25, 0.25, -3).x, 1.-vec3(0.25, 0.25, -3).y) - 0.333) * 3.) - vec2(0.510986328125, 0.5029296875), vec3(0.25, 0.25, -3).z);\nvec3 normLightDir = normalize(lightDir);float lightAndShadow = dot(entryNormal, normLightDir);\nvec3 lightColor = mix(vec3(1), vec3(1, 1, 1), 1. - 0.0000);vec3 fresnelEffect = fresnel(rd, entryNormal, 8.0) * 0.5000 * vec3(1, 1, 1);vec3 halfwayDir = normalize(lightDir + rd);\nfloat specFactor = pow(max(dot(entryNormal, halfwayDir), 0.0), 64.0 * 0.5000 + 0.01);\nvec3 specularEffect = specFactor * 0.5000 * lightColor;vec3 combinedEffects = fresnelEffect + specularEffect;\nvec3 finalColor = mix(refractionColor, vec3(1, 1, 1) * lightAndShadow, 0.0000);\nfinalColor += combinedEffects;vec4 outputColor = applyLayerMixAlpha(vec4(finalColor, 1.), bg, partialAlpha);return outputColor;\n}out vec4 fragColor;void main() {\nvec4 col = vec4(0);if(0.5200 <= 0.0001) {\ncol = vec4(0);\nif(1 == 1) {\ncol = texture(uTexture, vTextureCoord);\n}\nfragColor = col;\nreturn;\n}vec2 pos = vec2(0.510986328125, 0.5029296875) + mix(vec2(0), (uMousePos-0.5), 0.0500);\nvec2 uv = vTextureCoord - pos;\nfloat fovFactor = tan(radians(20.) * 0.5);\nvec3 rd = vec3(uv * fovFactor, 0.5);\ncol = rayMarch(viewDir, rd);\nfloat dither = deband();\ncol += dither;\nfragColor = col;}"],"compiledVertexShaders":["#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision mediump float;in vec3 aVertexPosition;\nin vec2 aTextureCoord;uniform mat4 uMVMatrix;\nuniform mat4 uPMatrix;\nuniform mat4 uTextureMatrix;out vec2 vTextureCoord;\nout vec3 vVertexPosition;void main() {\ngl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);\nvTextureCoord = (uTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy;\n}"],"speed":0.5,"trackMouseMove":0.05,"trackMouse":0.07,"data":{"depth":false,"uniforms":{},"isBackground":false},"id":"card3_layer_0_sdf_strip","publicId":"3d_strip"},{"breakpoints":[],"visible":true,"aspectRatio":1,"userDownsample":1,"layerType":"effect","type":"texturize","usesPingPong":false,"texture":false,"animating":false,"mouseMomentum":0,"mouseSpring":0,"isMask":0,"compiledFragmentShaders":["#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision highp float;\nprecision highp int;in vec3 vVertexPosition;\nin vec2 vTextureCoord;uniform sampler2D uTexture;\nuniform float uTime;uvec2 pcg2d(uvec2 v) {\nv = v * 1664525u + 1013904223u;\nv.x += v.y * v.y * 1664525u + 1013904223u;\nv.y += v.x * v.x * 1664525u + 1013904223u;\nv ^= v >> 16;\nv.x += v.y * v.y * 1664525u + 1013904223u;\nv.y += v.x * v.x * 1664525u + 1013904223u;\nreturn v;\n}float randFibo(vec2 p) {\nuvec2 v = floatBitsToUint(p);\nv = pcg2d(v);\nuint r = v.x ^ v.y;\nreturn float(r) / float(0xffffffffu);\n}\nout vec4 fragColor;const float UV_MIN = 0.005;\nconst float UV_MAX = 0.995;float glitchMask(float noise, float amount) {\nreturn max(UV_MIN, sign(noise + amount - 1.0));\n}float centeredOffset(float noise, float amount) {\nreturn (noise * amount - amount / 2.0) / 5.0;\n}vec2 clampUv(vec2 value) {\nreturn clamp(value, vec2(UV_MIN), vec2(UV_MAX));\n}void main() {\nvec2 uv = vTextureCoord;\nfloat steppedTime = floor(uTime * 0.5) * 2.0;\nfloat timeRand1 = randFibo(vec2(steppedTime + 0.001, 0.5));\nfloat timeRand2 = randFibo(vec2(steppedTime + 1.001, 0.5));\nfloat sizeX = 0.5000 * 0.2 * timeRand1;\nfloat sizeY = 0.5000 * 0.2 * timeRand2;\nfloat floorY = floor(uv.y / sizeY) + UV_MIN;\nfloat floorX = floor(uv.x / sizeX) + UV_MIN;\nfloat phase = 0.0000 * 0.01;\nfloat chromab = 0.5000 * 0.75;\nfloat offset = 0.;vec2 blockSize = vec2(50.0, 50.0) * (1.0 - 0.5000);\nvec2 blockUV = floor(uv * blockSize) / blockSize;\nfloat blockRand = randFibo(blockUV);\nfloat blockTimeRand = timeRand1;\nfloat blockNoise = mix(\n1.,\nstep(0.8, randFibo(vec2(blockTimeRand, blockRand))),\n0.8000\n);float offsetX = 0.5000 * 0.5 * blockNoise;\nfloat offsetY = 0.0000 * 0.5 * blockNoise;float randY = randFibo(vec2(sin(floorY + offset + phase), 0.5));\nfloat randX = randFibo(vec2(cos(floorX + offset + phase), 0.5));\nfloat glitchModX = glitchMask(randY, 0.5000);\nfloat glitchModY = glitchMask(randX, 0.5000);float randOffX = randFibo(vec2(floorY + offset * glitchModX + phase, 0.7));\nfloat randOffY = randFibo(vec2(floorX + offset * glitchModY + phase, 0.9));\nfloat offX = centeredOffset(randOffX, offsetX);\nfloat offY = centeredOffset(randOffY, offsetY);offX = clamp(offX, -1.0, 1.0);\noffY = clamp(offY, -1.0, 1.0);uv.x = mix(uv.x, uv.x + offX * 2., glitchModX);\nuv.y = mix(uv.y, uv.y + offY * 2., glitchModY);float waveFreq = 30.0;\nfloat waveAmp = 0.005 * 0.2000;\nfloat timeOffset = uTime * 0.05;\nfloat sinY = sin((uv.y + 0.0000) * waveFreq * (1. - 0.5000) * 2. + timeOffset);\nfloat rogue = smoothstep(0., 2., sinY - 0.5) * 0.2 * 0.2000;\nfloat sinWaveX = sin(uv.y * waveFreq + uTime);\nfloat sinWaveY = sin(uv.x * waveFreq + uTime);\nuv.x += sinWaveX * waveAmp + rogue;\nuv.y += sinWaveY * waveAmp;\nfloat waveX = sinWaveX * waveAmp + rogue * chromab * 0.2;uv = clampUv(uv);vec4 color = texture(uTexture, uv);vec2 glitchOffset = vec2(offX, offY) * glitchModX * chromab;\nvec2 redOffset = clampUv(uv + vec2(-glitchOffset.x - waveX, -glitchOffset.y));\nvec2 blueOffset = clampUv(uv + vec2(glitchOffset.x + waveX, glitchOffset.y));color.r = texture(uTexture, redOffset).r;\ncolor.b = texture(uTexture, blueOffset).b;\nfragColor = color;}"],"compiledVertexShaders":["#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision mediump float;in vec3 aVertexPosition;\nin vec2 aTextureCoord;uniform mat4 uMVMatrix;\nuniform mat4 uPMatrix;\nuniform mat4 uTextureMatrix;out vec2 vTextureCoord;\nout vec3 vVertexPosition;void main() {\ngl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);\nvTextureCoord = (uTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy;\n}"],"speed":0.11,"data":{"depth":false,"uniforms":{},"isBackground":false},"id":"card3_layer_1_texturize","publicId":"glitch"},{"breakpoints":[],"visible":true,"aspectRatio":1,"userDownsample":1,"layerType":"effect","type":"outline","usesPingPong":false,"texture":false,"animating":false,"mouseMomentum":0,"mouseSpring":0,"isMask":0,"compiledFragmentShaders":["#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision highp float;\nin vec2 vTextureCoord;uniform sampler2D uTexture;\nuniform vec2 uResolution;\nvec3 blend (int blendMode, vec3 src, vec3 dst) {\nreturn src + dst;\n}\nvec4 applyLayerMix(vec4 color, vec4 bg, float amount) {\ncolor.rgb = mix(bg.rgb, color.rgb, amount);\ncolor.a = max(bg.a, amount);\nreturn color;\n}out vec4 fragColor;float luma(vec3 c) {\nreturn dot(c, vec3(0.299, 0.587, 0.114));\n}float interleavedGradientNoise(vec2 st) {\nreturn fract(52.9829189 * fract(dot(st, vec2(0.06711056, 0.00583715))));\n}void main() {\nvec2 uv = vTextureCoord;float thickness = 0.5000;vec2 pixel = (1.0 / uResolution) * max(thickness * 4.0, 0.001);\nfloat noise = interleavedGradientNoise(gl_FragCoord.xy);pixel *= mix(1.0, noise, 0.1);float tl = luma(texture(uTexture, uv + pixel * vec2(-1, -1)).rgb);\nfloat t = luma(texture(uTexture, uv + pixel * vec2( 0, -1)).rgb);\nfloat tr = luma(texture(uTexture, uv + pixel * vec2( 1, -1)).rgb);\nfloat l = luma(texture(uTexture, uv + pixel * vec2(-1, 0)).rgb);\nfloat r = luma(texture(uTexture, uv + pixel * vec2( 1, 0)).rgb);\nfloat bl = luma(texture(uTexture, uv + pixel * vec2(-1, 1)).rgb);\nfloat b = luma(texture(uTexture, uv + pixel * vec2( 0, 1)).rgb);\nfloat br = luma(texture(uTexture, uv + pixel * vec2( 1, 1)).rgb);float gx = -tl - 2.0 * l - bl + tr + 2.0 * r + br;\nfloat gy = -tl - 2.0 * t - tr + bl + 2.0 * b + br;\nfloat edge = length(vec2(gx, gy));float soft = max(1.0000 * 0.5, 0.001);\nedge = smoothstep(0.5000 - soft, 0.5000 + soft, edge);\nedge *= (0.5000 * 2.0);vec4 scene = texture(uTexture, uv);\nvec3 outline = vec3(1, 1, 1) * edge;\nvec3 blended = outline;blended = blend(1, outline, scene.rgb);vec4 col = applyLayerMix(vec4(blended, 1.0), scene, 0.2600);\nfragColor = col;}"],"compiledVertexShaders":["#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision mediump float;in vec3 aVertexPosition;\nin vec2 aTextureCoord;uniform mat4 uMVMatrix;\nuniform mat4 uPMatrix;\nuniform mat4 uTextureMatrix;out vec2 vTextureCoord;\nout vec3 vVertexPosition;void main() {\ngl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);\nvTextureCoord = (uTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy;\n}"],"trackMouse":0,"trackAxes":"xy","data":{"depth":false,"uniforms":{},"isBackground":false},"id":"card3_layer_2_outline","publicId":"outline"},{"layerType":"flattened","id":"card3_layer_3_flat","compiledFragmentShaders":["#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision highp float;\nin vec2 vTextureCoord;\nin vec3 vVertexPosition;\n\nuniform sampler2D uBgTexture;\nuniform vec2 uMousePos;\nuniform vec2 uResolution;\nuniform float uL0_ElemOpacity;\nuniform float uL1_Time;\nuniform float uL1_ElemOpacity;\nuniform float uL2_Time;\nuniform float uL2_ElemOpacity;\n\nconst float MAX_ITERATIONS = 32.0;\nconst int MAX_LEVEL = 4;\nconst float TAU = 6.28318530718;\n\nout vec4 fragColor;\n\nfloat interleavedGradientNoise_L0(vec2 st) {\nreturn fract(52.9829189 * fract(dot(st, vec2(0.06711056, 0.00583715))));\n}\nvec4 godRays_L0(vec2 st) {\nvec3 color = vec3(0);\nfloat decay = mix(0.89, 0.965, 0.7800);\nvec2 pos = vec2(0.3722460220318238, 0.6297429620563035) - mix(vec2(0), (vec2(1. - uMousePos.x, 1. - uMousePos.y) - 0.5), 0.0000);\nfloat weight = 1.0;\nvec2 stepDir = (pos - st) / MAX_ITERATIONS * (0.25 + min(1., 0.7800)) * 0.75;\nfloat noise = interleavedGradientNoise_L0(st * uResolution);\nvec2 sampleUv = st + stepDir * noise;\nvec2 perpDir = vec2(-stepDir.y, stepDir.x);\nfloat intensity = 2.8 * 0.9000;\nfor (float i = 0.0;\ni < MAX_ITERATIONS;\ni++) {\nfloat theta = i/MAX_ITERATIONS;\nsampleUv += stepDir + (perpDir * theta * sin((noise * 0.25) * (1.0 + theta) * 50.0)) * 0.0000 * 0.25;\nvec4 samp = texture(uBgTexture, sampleUv);\nfloat lum = dot(samp.rgb, vec3(0.299, 0.587, 0.114));\nfloat thresh = smoothstep(0.4000 - 0.1, 0.4000, lum);\ncolor += samp.rgb * thresh * weight * intensity;\nweight *= decay;\nif(weight < 0.05) break;\n}\nreturn vec4(color / MAX_ITERATIONS, 1.0);\n}\nuvec2 pcg2d(uvec2 v) {\nv = v * 1664525u + 1013904223u;\nv.x += v.y * v.y * 1664525u + 1013904223u;\nv.y += v.x * v.x * 1664525u + 1013904223u;\nv ^= v >> 16;\nv.x += v.y * v.y * 1664525u + 1013904223u;\nv.y += v.x * v.x * 1664525u + 1013904223u;\nreturn v;\n}\nfloat randFibo(vec2 p) {\nuvec2 v = floatBitsToUint(p);\nv = pcg2d(v);\nuint r = v.x ^ v.y;\nreturn float(r) / float(0xffffffffu);\n}\nfloat getBayerFromCoordLevelScaled_L1(vec2 pixelpos, float scale) {\nfloat finalBayer = 0.0;\nfloat finalDivisor = 0.0;\nfloat layerMult = 1.0;\nfor(float bayerLevel = float(MAX_LEVEL);\nbayerLevel >= 1.0;\nbayerLevel--) {\nfloat bayerSize = exp2(bayerLevel) * 0.5 / scale;\nvec2 bayercoord = mod(floor(pixelpos.xy / bayerSize), 2.0);\nlayerMult *= 4.0;\nfloat byxx2 = bayercoord.x * 2.0;\nfinalBayer += mix(byxx2, 3.0 - byxx2, bayercoord.y) / 3.0 * layerMult;\nfinalDivisor += layerMult;\n}\nreturn (finalBayer / finalDivisor - 0.006);\n}\nfloat getBayerNoise_L1(vec2 st, float delta, float scale) {\nvec2 center = uResolution * 0.5;\nvec2 centered = st * uResolution - center;\nvec2 offset = vec2(\nmod(delta * 0.618033988749895, 16.0),\nmod(delta * 0.381966011250105, 16.0)\n) * 20.;\nvec2 final = (centered + center + offset);\nreturn getBayerFromCoordLevelScaled_L1(final, scale);\n}\nvec3 dither_L1(vec3 color, vec2 st) {\nfloat delta = floor(uL1_Time);\nvec2 offset = vec2(randFibo(vec2(123,16) + delta), randFibo(vec2(56,96) + delta));\nfloat noise = 0.0;\nnoise = getBayerNoise_L1(st, delta, 0.5);\nfloat dither_threshold = max(0.0001, 0.5000);\nfloat num_levels = 1.0 / dither_threshold;\nreturn floor(color * num_levels + noise) / num_levels;\n}\nvec3 getColor_L2(int index) {\nswitch(index) {\ncase 0: return vec3(0, 0, 0);\ncase 1: return vec3(0.0196078431372549, 0.3411764705882353, 0.1803921568627451);\ncase 2: return vec3(0.043137254901960784, 0.5215686274509804, 0.2901960784313726);\ncase 3: return vec3(0.06274509803921569, 0.7137254901960784, 0.403921568627451);\ncase 4: return vec3(0.13333333333333333, 1, 0.6549019607843137);\ncase 5: return vec3(0.807843137254902, 1, 0.8666666666666667);\ndefault: return vec3(0.0);\n}\n}\nfloat getStop_L2(int index) {\nswitch(index) {\ncase 0: return 0.0000;\ncase 1: return 0.2000;\ncase 2: return 0.4000;\ncase 3: return 0.6000;\ncase 4: return 0.8000;\ncase 5: return 1.0000;\ndefault: return 0.0;\n}\n}\nfloat deband_L2() {\nreturn (randFibo(gl_FragCoord.xy) - 0.5) / 255.0;\n}\nfloat luma_L2(vec3 color) {\nreturn dot(color, vec3(0.299, 0.587, 0.114));\n}\nvec3 linear_from_srgb_L2(vec3 rgb) {\nreturn pow(max(rgb, vec3(0.0)), vec3(2.2));\n}\nvec3 srgb_from_linear_L2(vec3 lin) {\nreturn pow(max(lin, vec3(0.0)), vec3(1.0/2.2));\n}\nvec3 safeCbrt_L2(vec3 v) {\nreturn sign(v) * pow(abs(v), vec3(1.0/3.0));\n}\nvec3 oklab_mix_L2(vec3 lin1, vec3 lin2, float a) {\nconst mat3 kCONEtoLMS = mat3(\n0.4121656120, 0.2118591070, 0.0883097947,\n0.5362752080, 0.6807189584, 0.2818474174,\n0.0514575653, 0.1074065790, 0.6302613616);\nconst mat3 kLMStoCONE = mat3(\n4.0767245293, -1.2681437731, -0.0041119885,\n-3.3072168827, 2.6093323231, -0.7034763098,\n0.2307590544, -0.3411344290, 1.7068625689);\nvec3 lms1 = safeCbrt_L2(kCONEtoLMS*lin1);\nvec3 lms2 = safeCbrt_L2(kCONEtoLMS*lin2);\nvec3 lms = mix(lms1, lms2, a);\nlms *= 1.0 + 0.02 * a * (1.0 - a);\nreturn kLMStoCONE*(lms*lms*lms);\n}\nvec3 getGradientColor_L2(float position) {\nposition = clamp(position, 0.0, 1.0);\nint count = 6 - 1;\nfor (int i = 0;\ni < count;\ni++) {\nfloat colorPosition = getStop_L2(i);\nfloat nextColorPosition = getStop_L2(i + 1);\nif (position <= nextColorPosition) {\nfloat stopDelta = nextColorPosition - colorPosition;\nfloat mixFactor = clamp(stopDelta > 0.0001 ? (position - colorPosition) / stopDelta : 0.0, 0.0, 1.0);\nvec3 linStart = linear_from_srgb_L2(getColor_L2(i));\nvec3 linEnd = linear_from_srgb_L2(getColor_L2(i + 1));\nvec3 mixedLin = oklab_mix_L2(linStart, linEnd, mixFactor);\nreturn srgb_from_linear_L2(mixedLin);\n}\n}\nreturn getColor_L2(count);\n}\n\nvec4 computeLayer_L0(vec2 uv) {\nvec4 bg = texture(uBgTexture, uv);\nif(0.9000 <= 0.01) {\nvec4 color = bg;\nreturn color;\n}\nvec4 rays = godRays_L0(uv);\nrays.rgb *= vec3(1, 1, 1);\nvec4 color = vec4(bg.rgb + rays.rgb, bg.a + rays.r);\nreturn color;\n}\nvec4 computeLayer_L1(vec2 uv, vec4 prevLayerColor) {\nfloat delta = floor(uL1_Time);\nvec4 color = prevLayerColor;\ncolor.rgb = mix(color.rgb, dither_L1(color.rgb, vTextureCoord), 0.5000);\nreturn color;\n}\nvec4 computeLayer_L2(vec2 uv, vec4 prevLayerColor, float sharedDither) {\nvec4 color = prevLayerColor;\nif(color.a > 0.001) {\nfloat position = smoothstep(0., 1., luma_L2(color.rgb)) * (0.4000 * 2.);\nfloat posOffset = (dot(vec2(0.5, 0.5).x, vec2(0.5, 0.5).y) + 0.2600 + 0.0001) * 2.;\nposition -= (uL2_Time*0.01 + posOffset);\nfloat cycle = floor(position);\nbool reverse = 1.0000 > 0.5 && int(cycle) % 2 == 0;\nfloat animatedPos = reverse ? fract(-position) : fract(position);\nanimatedPos = reverse ? fract(-position) : fract(position);\nanimatedPos = clamp(animatedPos, 0.0, 1.0);\nvec3 gradientColor = getGradientColor_L2(animatedPos);\nfloat dither = sharedDither;\ngradientColor += dither;\nvec3 mixedColor = mix(color.rgb, gradientColor, 1.0000);\ncolor.rgb = mixedColor;\n}\nreturn color;\n;\n}\n\nvoid main() {\nvec2 uv = vTextureCoord;\nfloat sharedDither = deband_L2();\nvec4 result = vec4(0.0);\nvec4 c0 = computeLayer_L0(uv);\nc0 *= uL0_ElemOpacity;\nresult = c0 + result * (1.0 - c0.a);\nvec4 c1 = computeLayer_L1(uv, result);\nc1 *= uL1_ElemOpacity;\nresult = c1 + result * (1.0 - c1.a);\nvec4 c2 = computeLayer_L2(uv, result, sharedDither);\nc2 *= uL2_ElemOpacity;\nresult = c2 + result * (1.0 - c2.a);\nfragColor = result;\n}"],"compiledVertexShaders":["#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision highp float;\nin vec3 aVertexPosition;\nin vec2 aTextureCoord;\nuniform mat4 uMVMatrix;\nuniform mat4 uPMatrix;\nout vec2 vTextureCoord;\nout vec3 vVertexPosition;\nvoid main() {\ngl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);\nvVertexPosition = aVertexPosition;\nvTextureCoord = aTextureCoord;\n}"],"sublayers":[{"id":"c1608ff5-81d5-411d-9b29-4224d8d0205f","publicId":"god_rays","layerType":"effect","type":"godrays","sublayerIndex":0,"opacity":1,"animating":false},{"id":"2b4f0e9b-f07c-40ad-ba4b-c270b6ff3b44","publicId":"dither","layerType":"effect","type":"dither","sublayerIndex":1,"opacity":1,"animating":false,"texture":{"src":"/assets/unicorn/blue_noise_med.png","sampler":"uBlueNoise"}},{"id":"7ad15378-1e19-42ec-8443-65e86ef2f0a8","publicId":"gradient_map","layerType":"effect","type":"gradientMap","sublayerIndex":2,"opacity":1,"animating":false}],"data":{"uniforms":{"resolution":{"name":"uResolution","type":"2f","value":{"type":"Vec2","_x":1080,"_y":1080}},"mousePos":{"name":"uMousePos","type":"2f","value":{"type":"Vec2","_x":0.5,"_y":0.5}},"L0_elemOpacity":{"name":"uL0_ElemOpacity","type":"1f","value":1},"L1_time":{"name":"uL1_Time","type":"1f","value":0},"L1_elemOpacity":{"name":"uL1_ElemOpacity","type":"1f","value":1},"L2_time":{"name":"uL2_Time","type":"1f","value":0},"L2_elemOpacity":{"name":"uL2_ElemOpacity","type":"1f","value":1}},"textures":[{"sampler":"uBlueNoise","type":"media","src":"/assets/unicorn/blue_noise_med.png","sublayerIndex":1}],"timeUniforms":[],"mouseUniforms":[],"hasMouseTracking":false,"hasVideoSublayers":false,"estimatedSublayerWorkRaw":307.2855543593206,"occlusion":{"candidateLayers":0}},"states":{"appear":[],"scroll":[],"hover":[],"mousemove":[]},"breakpoints":[],"userDownsample":1,"visible":true},{"breakpoints":[],"visible":true,"aspectRatio":1,"userDownsample":1,"layerType":"effect","type":"blobTracking","usesPingPong":false,"texture":{"src":"/assets/unicorn/cjt-logo-mark_combined_1778012004068.png","sampler":"uCustomTexture"},"animating":false,"mouseMomentum":0,"mouseSpring":0,"isMask":0,"compiledFragmentShaders":["#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision highp float;\nprecision highp int;in vec2 vTextureCoord;\nuniform sampler2D uTexture;\nuniform sampler2D uPreviousFrameTexture;\nuniform vec2 uResolution;out vec4 fragColor;float luma(vec3 color) {\nreturn dot(color, vec3(0.299, 0.587, 0.114));\n}vec4 maskPass(vec2 uv) {\nvec2 texel = 1.0 / uResolution;vec4 current = texture(uTexture, uv);\nfloat currentLuma = luma(current.rgb);\nif (current.a < 0.005 && currentLuma < 0.005) return vec4(0.0);float l = luma(texture(uTexture, uv + vec2(-1.0, 0.0) * texel).rgb);\nfloat r = luma(texture(uTexture, uv + vec2( 1.0, 0.0) * texel).rgb);\nfloat t = luma(texture(uTexture, uv + vec2( 0.0,-1.0) * texel).rgb);\nfloat b = luma(texture(uTexture, uv + vec2( 0.0, 1.0) * texel).rgb);float gx = r - l;\nfloat gy = b - t;\nfloat gradMag = length(vec2(gx, gy));vec4 prevOutput = texture(uPreviousFrameTexture, uv);\nif (all(equal(prevOutput, vec4(0.0)))) {\nreturn vec4(0.0, currentLuma, gx * 0.5 + 0.5, gy * 0.5 + 0.5);\n}\nfloat prevLuma = prevOutput.g;\nvec2 prevGrad = (prevOutput.ba - 0.5) * 2.0;\nfloat prevGradMag = length(prevGrad);float lumaDiff = abs(currentLuma - prevLuma);\nfloat threshold = 0.6200 * 0.2;\nfloat lumaMotion = smoothstep(threshold, threshold + 0.15, lumaDiff);float magChange = abs(gradMag - prevGradMag);\nfloat structuralMotion = smoothstep(0.08, 0.5, magChange);\nfloat detected = max(lumaMotion, lumaMotion * structuralMotion);\ndetected = smoothstep(0.05, 0.4, detected);float prevDetected = prevOutput.r;\nfloat riseRate = 0.6;\nfloat fallRate = mix(0.5, 0.85, 0.4300);\ndetected = (detected > prevDetected)\n? mix(prevDetected, detected, riseRate)\n: prevDetected * fallRate;return vec4(detected, currentLuma, gx * 0.5 + 0.5, gy * 0.5 + 0.5);\n}void main() {\nvec2 uv = vTextureCoord;\nfragColor = maskPass(uv);\n}","#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision highp float;\nprecision highp int;in vec2 vTextureCoord;\nuniform sampler2D uTexture;\nuniform vec2 uResolution;out vec4 fragColor;vec2 getDirection(int i) {\nfloat angle = float(i) * 0.7853981634;\nreturn vec2(cos(angle), sin(angle));\n}vec4 peakPass(vec2 uv) {\nvec2 texel = 1.0 / uResolution;\nconst float ACTIVE_THRESHOLD = 0.02;\nconst float FILL_RADIUS = 6.0;\nvec4 centerSample = texture(uTexture, uv);\nfloat centerVal = centerSample.r;\nfloat quickMax = centerVal;\nquickMax = max(quickMax, texture(uTexture, uv + vec2(4.0, 0.0) * texel).r);\nquickMax = max(quickMax, texture(uTexture, uv + vec2(-4.0, 0.0) * texel).r);\nquickMax = max(quickMax, texture(uTexture, uv + vec2(0.0, 4.0) * texel).r);\nquickMax = max(quickMax, texture(uTexture, uv + vec2(0.0, -4.0) * texel).r);\nif (quickMax < ACTIVE_THRESHOLD * 0.5) {\nreturn vec4(0.0, 0.5, 0.5, 0.0);\n}\nfloat nearestActiveDist = FILL_RADIUS + 1.0;\nfloat maxVal = centerVal;\nvec2 gradient = vec2(0.0);\nif (centerVal > ACTIVE_THRESHOLD) {\nnearestActiveDist = 0.0;\n}\nfor (int i = 0; i < 8; i++) {\nvec2 dir = getDirection(i);\nfor (float d = 2.0; d <= FILL_RADIUS; d += 2.0) {\nvec2 offset = dir * d * texel;\nfloat v = texture(uTexture, uv + offset).r;\nif (v > ACTIVE_THRESHOLD) {\nnearestActiveDist = min(nearestActiveDist, d);\n}\nmaxVal = max(maxVal, v);\nif (v > 0.01) {\ngradient += dir * d * v;\n}\n}\n}\nfloat result = 0.0;\nif (nearestActiveDist <= FILL_RADIUS) {\nresult = 1.0 - smoothstep(FILL_RADIUS * 0.5, FILL_RADIUS, nearestActiveDist);\nresult *= mix(0.7, 1.0, smoothstep(0.0, 0.1, maxVal));\n}\nfloat gradLen = length(gradient);\nvec2 gradDir = (gradLen > 0.001) ? gradient / gradLen : vec2(0.0);\nvec2 gradEncoded = gradDir * 0.5 + 0.5;\nfloat peakness = (maxVal > ACTIVE_THRESHOLD && result > 0.02) ?\nclamp(maxVal / 0.2, 0.0, 1.0) : 0.0;\nreturn vec4(result, gradEncoded.x, gradEncoded.y, peakness);\n}void main() {\nvec2 uv = vTextureCoord;\nfragColor = peakPass(uv);\n}","#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision highp float;\nprecision highp int;in vec2 vTextureCoord;\nuniform sampler2D uTexture;\nuniform sampler2D uPreviousFrameTexture;\nuniform vec2 uResolution;out vec4 fragColor;const int MAX_BLOBS = 16;\nconst float GRID_SIZE = 8.0;\nconst float BLOB_SLOT_HEIGHT = 0.02;vec2 getBlobSlotUV(int blobIndex) {\nfloat slotX = (float(blobIndex) + 0.5) / 4.0000;\nreturn vec2(slotX, BLOB_SLOT_HEIGHT * 0.5);\n}bool isBlobSlot(vec2 uv) {\nreturn uv.y < BLOB_SLOT_HEIGHT;\n}int getBlobIndexForUV(vec2 uv) {\nreturn int(floor(uv.x * 4.0000));\n}bool isBlobStateAlive(vec4 state) {\nreturn state.z > 0.01 && state.w > 0.05 && state.x >= 0.0;\n}bool checkBlobCollision(vec2 cPos, int slotIndex, float minSpacing, bool checkLower, bool checkHigher) {\nif (checkLower) {\nfor (int j = 0; j < MAX_BLOBS; j++) {\nif (j >= slotIndex) break;\nif (j >= int(4.0000)) break;\nvec4 jState = textureLod(uPreviousFrameTexture, getBlobSlotUV(j), 0.0);\nif (!isBlobStateAlive(jState)) continue;\nif (length(cPos - jState.xy) < minSpacing) return true;\n}\n}\nif (checkHigher) {\nfor (int j = 0; j < MAX_BLOBS; j++) {\nint idx = slotIndex + 1 + j;\nif (idx >= int(4.0000)) break;\nvec4 jState = textureLod(uPreviousFrameTexture, getBlobSlotUV(idx), 0.0);\nif (!isBlobStateAlive(jState)) continue;\nif (length(cPos - jState.xy) < minSpacing) return true;\n}\n}\nreturn false;\n}vec4 sampleGridCell(vec2 cellCenter, vec2 cellSize, out vec2 sumPos2, out vec2 bestPeakPos) {\nconst int SAMPLE_COUNT = 25;\nfloat sumW = 0.0;\nvec2 sumPos = vec2(0.0);\nsumPos2 = vec2(0.0);\nfloat bestPeakStrength = 0.0;\nbestPeakPos = vec2(0.0);\nfor (int s = 0; s < SAMPLE_COUNT; s++) {\nfloat x = float(s % 5);\nfloat y = float(s / 5);\nvec2 offset = (vec2(x, y) / 4.0 - 0.5) * cellSize;\nvec2 samplePos = cellCenter + offset;\nif (samplePos.x < 0.0 || samplePos.x > 1.0 ||\nsamplePos.y < 0.0 || samplePos.y > 1.0) continue;vec4 peakData = texture(uTexture, samplePos);\nfloat fieldStrength = peakData.r;\nfloat peakness = peakData.a;\nif (fieldStrength > 0.01) {\nfloat w = fieldStrength * (1.0 + peakness * 0.3);\nsumW += w;\nsumPos += samplePos * w;\nsumPos2 += samplePos * samplePos * w;\nfloat peakScore = fieldStrength * (0.5 + peakness);\nif (peakScore > bestPeakStrength) {\nbestPeakStrength = peakScore;\nbestPeakPos = samplePos;\n}\n}\n}\nreturn vec4(sumW, sumPos.x, sumPos.y, bestPeakStrength);\n}vec4 slotPass(vec2 uv) {\nif (!isBlobSlot(uv)) return vec4(0.0);int slotIndex = getBlobIndexForUV(uv);\nif (slotIndex >= int(4.0000)) return vec4(0.0);vec2 slotUV = getBlobSlotUV(slotIndex);\nvec4 prevState = texture(uPreviousFrameTexture, slotUV);\nvec2 prevPos = prevState.xy;\nfloat prevSize = prevState.z;\nfloat prevConf = prevState.w;\nbool wasAlive = (prevSize > 0.01 && prevConf > 0.05 && prevPos.x >= 0.0);vec2 bestPos = vec2(-1.0);\nvec2 bestSize = vec2(0.0);\nfloat bestScore = 0.0;\nfloat cols = ceil(sqrt(4.0000));\nfloat rows = ceil(4.0000 / cols);\nfloat col = mod(float(slotIndex), cols);\nfloat row = floor(float(slotIndex) / cols);\nvec2 slotCenter = vec2((col + 0.5) / cols, (row + 0.5) / rows);\nfloat slotRadius = 0.5 / max(cols, rows);\nconst float MIN_SPACING = 0.07;\nconst float TRACK_RADIUS = 0.05;\nvec2 cellSize = vec2(1.0 / GRID_SIZE);for (int cell = 0; cell < 64; cell++) {\nint cx = cell % 8;\nint cy = cell / 8;\nvec2 cellCenter = (vec2(float(cx), float(cy)) + 0.5) / GRID_SIZE;\nvec2 sumPos2;\nvec2 bestPeakPos;\nvec4 sampleResult = sampleGridCell(cellCenter, cellSize, sumPos2, bestPeakPos);\nfloat sumW = sampleResult.x;\nvec2 sumPos = sampleResult.yz;\nfloat bestPeakStrength = sampleResult.w;if (sumW < 0.015) continue;vec2 cPos = sumPos / sumW;\nif (bestPeakStrength > 0.2) {\ncPos = mix(cPos, bestPeakPos, 0.05);\n}\nvec2 var = max(sumPos2 / sumW - cPos * cPos, vec2(0.0));\nfloat activity = clamp(sumW / 0.25, 0.0, 1.0);\nfloat minActivity = wasAlive ? 0.12 : 0.2;\nif (activity < minActivity) continue;float sizeScalar = sqrt(max(var.x, var.y)) * mix(1.5, 3.5, activity);\nfloat maxSize = mix(0.2, 1.2, 0.8700);\nsizeScalar = sizeScalar * maxSize;float distFromSelf = length(cPos - prevPos);\nif (checkBlobCollision(cPos, slotIndex, MIN_SPACING, true, false)) continue;\nif (wasAlive && distFromSelf > TRACK_RADIUS) continue;\nif (!wasAlive) {\nif (checkBlobCollision(cPos, slotIndex, MIN_SPACING, false, true)) continue;\n}float score = sumW * activity;\nfloat distFromSlot = length(cPos - slotCenter);\nfloat regionBonus = exp(-distFromSlot * distFromSlot / (slotRadius * slotRadius * 2.0));\nif (wasAlive) {\nscore *= exp(-distFromSelf * 2.0);\nscore *= (0.5 + 0.5 * regionBonus);\n} else {\nscore *= (0.8 + 0.2 * regionBonus);\n}\nif (score > bestScore) {\nbestScore = score;\nbestPos = cPos;\nbestSize = vec2(sizeScalar);\n}\n}vec2 newPos, newSize;\nfloat SPAWN_THRESHOLD = mix(0.12, 0.05, 0.4300);\nfloat TRACK_THRESHOLD = mix(0.06, 0.02, 0.4300);\nfloat acceptThreshold = wasAlive ? TRACK_THRESHOLD : SPAWN_THRESHOLD;\nfloat newConf = 0.0;\nfloat bestConf = clamp(bestScore * 8.0, 0.0, 1.0);\nconst float MIN_PEAK_STRENGTH = 0.02;\nfloat peakAtBest = 0.0;\nvec2 texel = 1.0 / uResolution;\nfor (int p = 0; p < 25; p++) {\nfloat px = float(p % 5) - 2.0;\nfloat py = float(p / 5) - 2.0;\nfloat pVal = texture(uTexture, bestPos + vec2(px, py) * texel * 2.0).r;\npeakAtBest = max(peakAtBest, pVal);\n}\nbool canAccept = bestScore > acceptThreshold && peakAtBest > MIN_PEAK_STRENGTH;if (canAccept) {\nif (wasAlive) {\nfloat smoothFactor = mix(1.0, 0.05, 0.8200);\nnewPos = mix(prevPos, bestPos, smoothFactor);\nnewSize = vec2(prevSize);\n} else {\nnewPos = bestPos;\nnewSize = bestSize;\n}\nnewConf = clamp(max(prevConf * 0.8, bestConf), 0.0, 1.0);\n} else {\nnewPos = vec2(-1.0);\nnewSize = vec2(0.0);\nnewConf = 0.0;\n}return vec4(newPos, newSize.x, newConf);\n}void main() {\nvec2 uv = vTextureCoord;\nfragColor = slotPass(uv);\n}","#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision highp float;\nprecision highp int;in vec2 vTextureCoord;\nuniform sampler2D uTexture;\nuniform sampler2D uBgTexture;\nuniform sampler2D uCustomTexture;\nuniform sampler2D uFontAtlas;uniform vec2 uResolution;out vec4 fragColor;const float FONT_COLS = 8.0;\nconst float FONT_ROWS = 8.0;const int FONT_START_CHAR = 32;\nconst int MAX_BLOBS = 16;\nconst float BLOB_SLOT_HEIGHT = 0.02;float median(float r, float g, float b) {\nreturn max(min(r, g), min(max(r, g), b));\n}float sampleChar(vec2 uv, int charCode) {\nint charIndex = charCode - FONT_START_CHAR;\nif (charIndex < 0 || charIndex >= 64) return 0.0;\nfloat col = mod(float(charIndex), FONT_COLS);\nfloat row = floor(float(charIndex) / FONT_COLS);\nfloat cellSize = 1.0 / 8.0;\nfloat x = (col + uv.x) * cellSize;\nfloat y = 1.0 - (row + 1.0 - uv.y) * cellSize;\nreturn textureLod(uFontAtlas, vec2(x, y), 0.0).r;\n}float renderDigit(vec2 uv, vec2 pos, vec2 size, int digit) {\nvec2 localUV = (uv - pos) / size;\nif (localUV.x < 0.0 || localUV.x > 1.0 || localUV.y < 0.0 || localUV.y > 1.0) {\nreturn 0.0;\n}\nint charCode = 48 + digit;\nfloat sdf = sampleChar(localUV, charCode);\nfloat edge = 0.7;\nfloat smoothing = 0.05;\nreturn smoothstep(edge - smoothing, edge + smoothing, sdf);\n}float renderChar(vec2 uv, vec2 pos, vec2 size, int charCode) {\nvec2 localUV = (uv - pos) / size;\nif (localUV.x < 0.0 || localUV.x > 1.0 || localUV.y < 0.0 || localUV.y > 1.0) {\nreturn 0.0;\n}\nfloat sdf = sampleChar(localUV, charCode);\nfloat edge = 0.6;\nfloat smoothing = 0.05;\nreturn smoothstep(edge - smoothing, edge + smoothing, sdf);\n}float renderFloat(vec2 uv, vec2 pos, vec2 charSize, float value) {\nfloat result = 0.0;\nfloat spacing = charSize.x * 0.35;\nfloat clamped = clamp(value, 0.0, 0.9999);\nint digits = int(clamped * 10000.0);\nint d1 = digits / 1000;\nint d2 = (digits / 100) % 10;\nint d3 = (digits / 10) % 10;\nint d4 = digits % 10;\nfloat startX = pos.x - spacing * 2.5;\nresult = max(result, renderDigit(uv, vec2(startX, pos.y), charSize, 0));\nresult = max(result, renderChar(uv, vec2(startX + spacing, pos.y), charSize, 46));\nresult = max(result, renderDigit(uv, vec2(startX + spacing * 2.0, pos.y), charSize, d1));\nresult = max(result, renderDigit(uv, vec2(startX + spacing * 3.0, pos.y), charSize, d2));\nresult = max(result, renderDigit(uv, vec2(startX + spacing * 4.0, pos.y), charSize, d3));\nresult = max(result, renderDigit(uv, vec2(startX + spacing * 5.0, pos.y), charSize, d4));\nreturn result;\n}vec2 getBlobSlotUV(int blobIndex) {\nfloat slotX = (float(blobIndex) + 0.5) / 4.0000;\nreturn vec2(slotX, BLOB_SLOT_HEIGHT * 0.5);\n}vec4 getBlobStateFromSlot(int i, sampler2D tex) {\nif (i >= int(4.0000)) return vec4(-1.0, -1.0, 0.0, 0.0);\nreturn textureLod(tex, getBlobSlotUV(i), 0.0);\n}bool isBlobStateActive(vec4 state) {\nreturn state.x >= 0.0 && state.z >= 0.01 && state.w >= 0.1;\n}float boxSDF(vec2 p, vec2 center, vec2 halfSize) {\nvec2 d = abs(p - center) - halfSize;\nfloat outside = length(max(d, 0.0));\nfloat inside = min(max(d.x, d.y), 0.0);\nreturn outside + inside;\n}float dashedLineSDF(vec2 p, vec2 a, vec2 b, float dashLength, float gapLength) {\nvec2 pa = p - a;\nvec2 ba = b - a;\nfloat lineLen = length(ba);\nfloat h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);\nfloat distAlongLine = h * lineLen;\nfloat period = dashLength + gapLength;\nfloat inPeriod = mod(distAlongLine, period);\nif (inPeriod > dashLength) return 1.0;\nreturn length(pa - ba * h);\n}float dottedLineSDF(vec2 p, vec2 a, vec2 b) {\nfloat dotLength = 0.004;\nfloat dotGap = 0.008;\nreturn dashedLineSDF(p, a, b, dotLength, dotGap);\n}float lineStyleDistance(vec2 p, vec2 a, vec2 b, float dashLength, float gapLength) {\nreturn dottedLineSDF(p, a, b);\n}void computeLineDistances(vec2 uvA, float aspectRatio, sampler2D tex, float maxConnectionDist, float dashLength, float gapLength, inout float minLineDist) {\nint blobCountInt = int(4.0000);\nfor (int i = 0; i < MAX_BLOBS; i++) {\nif (i >= blobCountInt) break;\nvec4 stateI = getBlobStateFromSlot(i, tex);\nif (!isBlobStateActive(stateI)) continue;\nvec2 posI = stateI.xy;\nvec2 posA = vec2(posI.x * aspectRatio, posI.y);\nfor (int j = 0; j < MAX_BLOBS; j++) {\nif (j <= i) continue;\nif (j >= blobCountInt) break;\nvec4 stateJ = getBlobStateFromSlot(j, tex);\nif (!isBlobStateActive(stateJ)) continue;\nvec2 posJ = stateJ.xy;\nvec2 posB = vec2(posJ.x * aspectRatio, posJ.y);\nif (length(posA - posB) > maxConnectionDist) continue;\nfloat lineD = lineStyleDistance(uvA, posA, posB, dashLength, gapLength);\nminLineDist = min(minLineDist, lineD);\n}\n}\n}float renderLabelIntensity(vec2 uvA, float aspectRatio, sampler2D tex) {\nfloat textResult = 0.0;\nfloat charHeight = mix(0.015, 0.05, 0.1800);\nvec2 charSize = vec2(charHeight, charHeight);\nint blobCountInt = int(4.0000);\nfor (int i = 0; i < MAX_BLOBS; i++) {\nif (i >= blobCountInt) break;\nvec4 state = getBlobStateFromSlot(i, tex);\nif (!isBlobStateActive(state)) continue;\nvec2 blobPos = state.xy;\nfloat blobSize = state.z * 0.5;\nvec2 labelPos = vec2(\nblobPos.x * aspectRatio - blobSize + charSize.x * 0.4,\nblobPos.y - blobSize + charSize.y * 0.4\n);\nfloat intensity = clamp(blobSize * 4.0, 0.0, 1.0);\nlabelPos.x += charSize.x;\ntextResult = max(textResult, renderFloat(uvA, labelPos, charSize, intensity));\n}\nreturn textResult;\n}vec2 blobStyleBoxData(vec2 uvA, vec2 centerA, vec2 halfSize) {\nfloat d = boxSDF(uvA, centerA, halfSize);\nreturn vec2(abs(d), d);\n}vec2 blobStyleCustomData(vec2 uvA, vec2 centerA, vec2 halfSize) {\nivec2 customTexSize = textureSize(uCustomTexture, 0);\nif (customTexSize.x <= 1 || customTexSize.y <= 1) {\nreturn blobStyleBoxData(uvA, centerA, halfSize);\n}float customTexAspect = float(customTexSize.x) / float(customTexSize.y);\nvec2 localUV = (uvA - centerA) / max(halfSize, vec2(0.0001));\nlocalUV.x /= customTexAspect;\nlocalUV = localUV * 0.5 + 0.5;if (localUV.x < 0.0 || localUV.x > 1.0 || localUV.y < 0.0 || localUV.y > 1.0) {\nreturn vec2(1.0);\n}vec4 sdColor = texture(uCustomTexture, localUV);\nfloat sd = median(sdColor.r, sdColor.g, sdColor.b);\nfloat signedDistance = (0.5 - sd) * min(halfSize.x * customTexAspect, halfSize.y) * 2.0;\nreturn vec2(abs(signedDistance), signedDistance);\n}vec4 drawPass(vec2 uv) {\nvec4 background = texture(uBgTexture, uv);\nif (background.a < 0.001) return vec4(0.0);float aspectRatio = uResolution.x / uResolution.y;\nfloat minBlobDist = 1.0;\nfloat minLineDist = 1.0;\nbool foundAny = false;\nint blobCountInt = int(4.0000);\nfor (int i = 0; i < MAX_BLOBS; i++) {\nif (i >= blobCountInt) break;\nvec4 state = getBlobStateFromSlot(i, uTexture);\nif (isBlobStateActive(state)) {\nfoundAny = true;\nbreak;\n}\n}\nif (!foundAny) {\nif (1 == 1) {\nreturn background;\n}\nreturn vec4(0.0);\n}\nvec2 uvA = vec2(uv.x * aspectRatio, uv.y);\nfloat lineWidth = 0.2000 * 0.005;\nfloat dashLength = 0.015;\nfloat gapLength = 0.01;\nfloat minFillDist = 1.0;\nfor (int i = 0; i < MAX_BLOBS; i++) {\nif (i >= blobCountInt) break;\nvec4 state = getBlobStateFromSlot(i, uTexture);\nif (!isBlobStateActive(state)) continue;\nvec2 blobPos = state.xy;\nfloat blobSize = state.z * 0.5;\nvec2 centerA = vec2(blobPos.x * aspectRatio, blobPos.y);\nvec2 halfSize = vec2(blobSize);\nfloat blobD = 1.0;\nvec2 blobData = vec2(1.0);\nblobData = blobStyleCustomData(uvA, centerA, halfSize);\nblobD = blobData.x;\nminBlobDist = min(minBlobDist, blobD);\nminFillDist = min(minFillDist, blobData.y);\n}\ncomputeLineDistances(uvA, aspectRatio, uTexture, 0.5000, dashLength, gapLength, minLineDist);float connectionWidth = lineWidth;\nfloat blobLineWidth = lineWidth * 5.0;\nfloat blobResult = 1.0 - smoothstep(blobLineWidth * 0.5, blobLineWidth * 1.5, minBlobDist);\nfloat fillResult = 0.0;\nfillResult = (minFillDist < 0.0) ? 0.1500 : 0.0;\nfloat lineResult = 0.0;lineResult = 1.0 - smoothstep(connectionWidth * 0.5, connectionWidth * 1.5, minLineDist);float textResult = 0.0;\ntextResult = renderLabelIntensity(uvA, aspectRatio, uTexture);\nfloat result = max(max(max(blobResult, lineResult), fillResult), textResult);vec3 finalColor;\nfinalColor = mix(background.rgb, vec3(0.13333333333333333, 1, 0.6549019607843137), result * 1.0000);float finalAlpha = background.a;\nreturn vec4(finalColor, finalAlpha);\n}void main() {\nvec2 uv = vTextureCoord;\nvec4 color = drawPass(uv);\nfragColor = color;}"],"compiledVertexShaders":["#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision mediump float;in vec3 aVertexPosition;\nin vec2 aTextureCoord;uniform mat4 uMVMatrix;\nuniform mat4 uPMatrix;\nuniform mat4 uTextureMatrix;out vec2 vTextureCoord;\nout vec3 vVertexPosition;void main() {\ngl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);\nvTextureCoord = (uTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy;\n}"],"data":{"downSample":0.25,"depth":false,"uniforms":{},"isBackground":false,"passes":[{"prop":"pass","value":1,"downSample":0.25,"passDescription":"Find candidate blob peaks in the motion field."},{"prop":"pass","value":2,"downSample":0.25,"needsPreviousFrame":"pass","passDescription":"Assign detected peaks to persistent blob slots."},{"prop":"pass","value":3,"includeBg":true,"passDescription":"Render tracked blobs, links, and labels over the background."}],"needsPreviousFrame":"pass","texture":{"src":"/assets/unicorn/font_atlas.png","sampler":"uFontAtlas"}},"id":"card3_layer_4_blobTracking","publicId":"blob_tracking"},{"breakpoints":[],"visible":true,"aspectRatio":1,"userDownsample":1,"layerType":"effect","type":"blobTracking","usesPingPong":false,"texture":false,"animating":false,"mouseMomentum":0,"mouseSpring":0,"isMask":0,"compiledFragmentShaders":["#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision highp float;\nprecision highp int;in vec2 vTextureCoord;\nuniform sampler2D uTexture;\nuniform sampler2D uPreviousFrameTexture;\nuniform vec2 uResolution;out vec4 fragColor;float luma(vec3 color) {\nreturn dot(color, vec3(0.299, 0.587, 0.114));\n}vec4 maskPass(vec2 uv) {\nvec2 texel = 1.0 / uResolution;vec4 current = texture(uTexture, uv);\nfloat currentLuma = luma(current.rgb);\nif (current.a < 0.005 && currentLuma < 0.005) return vec4(0.0);float l = luma(texture(uTexture, uv + vec2(-1.0, 0.0) * texel).rgb);\nfloat r = luma(texture(uTexture, uv + vec2( 1.0, 0.0) * texel).rgb);\nfloat t = luma(texture(uTexture, uv + vec2( 0.0,-1.0) * texel).rgb);\nfloat b = luma(texture(uTexture, uv + vec2( 0.0, 1.0) * texel).rgb);float gx = r - l;\nfloat gy = b - t;\nfloat gradMag = length(vec2(gx, gy));vec4 prevOutput = texture(uPreviousFrameTexture, uv);\nif (all(equal(prevOutput, vec4(0.0)))) {\nreturn vec4(0.0, currentLuma, gx * 0.5 + 0.5, gy * 0.5 + 0.5);\n}\nfloat prevLuma = prevOutput.g;\nvec2 prevGrad = (prevOutput.ba - 0.5) * 2.0;\nfloat prevGradMag = length(prevGrad);float lumaDiff = abs(currentLuma - prevLuma);\nfloat threshold = 0.5000 * 0.2;\nfloat lumaMotion = smoothstep(threshold, threshold + 0.15, lumaDiff);float magChange = abs(gradMag - prevGradMag);\nfloat structuralMotion = smoothstep(0.08, 0.5, magChange);\nfloat detected = max(lumaMotion, lumaMotion * structuralMotion);\ndetected = smoothstep(0.05, 0.4, detected);float prevDetected = prevOutput.r;\nfloat riseRate = 0.6;\nfloat fallRate = mix(0.5, 0.85, 0.5000);\ndetected = (detected > prevDetected)\n? mix(prevDetected, detected, riseRate)\n: prevDetected * fallRate;return vec4(detected, currentLuma, gx * 0.5 + 0.5, gy * 0.5 + 0.5);\n}void main() {\nvec2 uv = vTextureCoord;\nfragColor = maskPass(uv);\n}","#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision highp float;\nprecision highp int;in vec2 vTextureCoord;\nuniform sampler2D uTexture;\nuniform vec2 uResolution;out vec4 fragColor;vec2 getDirection(int i) {\nfloat angle = float(i) * 0.7853981634;\nreturn vec2(cos(angle), sin(angle));\n}vec4 peakPass(vec2 uv) {\nvec2 texel = 1.0 / uResolution;\nconst float ACTIVE_THRESHOLD = 0.02;\nconst float FILL_RADIUS = 6.0;\nvec4 centerSample = texture(uTexture, uv);\nfloat centerVal = centerSample.r;\nfloat quickMax = centerVal;\nquickMax = max(quickMax, texture(uTexture, uv + vec2(4.0, 0.0) * texel).r);\nquickMax = max(quickMax, texture(uTexture, uv + vec2(-4.0, 0.0) * texel).r);\nquickMax = max(quickMax, texture(uTexture, uv + vec2(0.0, 4.0) * texel).r);\nquickMax = max(quickMax, texture(uTexture, uv + vec2(0.0, -4.0) * texel).r);\nif (quickMax < ACTIVE_THRESHOLD * 0.5) {\nreturn vec4(0.0, 0.5, 0.5, 0.0);\n}\nfloat nearestActiveDist = FILL_RADIUS + 1.0;\nfloat maxVal = centerVal;\nvec2 gradient = vec2(0.0);\nif (centerVal > ACTIVE_THRESHOLD) {\nnearestActiveDist = 0.0;\n}\nfor (int i = 0; i < 8; i++) {\nvec2 dir = getDirection(i);\nfor (float d = 2.0; d <= FILL_RADIUS; d += 2.0) {\nvec2 offset = dir * d * texel;\nfloat v = texture(uTexture, uv + offset).r;\nif (v > ACTIVE_THRESHOLD) {\nnearestActiveDist = min(nearestActiveDist, d);\n}\nmaxVal = max(maxVal, v);\nif (v > 0.01) {\ngradient += dir * d * v;\n}\n}\n}\nfloat result = 0.0;\nif (nearestActiveDist <= FILL_RADIUS) {\nresult = 1.0 - smoothstep(FILL_RADIUS * 0.5, FILL_RADIUS, nearestActiveDist);\nresult *= mix(0.7, 1.0, smoothstep(0.0, 0.1, maxVal));\n}\nfloat gradLen = length(gradient);\nvec2 gradDir = (gradLen > 0.001) ? gradient / gradLen : vec2(0.0);\nvec2 gradEncoded = gradDir * 0.5 + 0.5;\nfloat peakness = (maxVal > ACTIVE_THRESHOLD && result > 0.02) ?\nclamp(maxVal / 0.2, 0.0, 1.0) : 0.0;\nreturn vec4(result, gradEncoded.x, gradEncoded.y, peakness);\n}void main() {\nvec2 uv = vTextureCoord;\nfragColor = peakPass(uv);\n}","#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision highp float;\nprecision highp int;in vec2 vTextureCoord;\nuniform sampler2D uTexture;\nuniform sampler2D uPreviousFrameTexture;\nuniform vec2 uResolution;out vec4 fragColor;const int MAX_BLOBS = 16;\nconst float GRID_SIZE = 8.0;\nconst float BLOB_SLOT_HEIGHT = 0.02;vec2 getBlobSlotUV(int blobIndex) {\nfloat slotX = (float(blobIndex) + 0.5) / 3.0000;\nreturn vec2(slotX, BLOB_SLOT_HEIGHT * 0.5);\n}bool isBlobSlot(vec2 uv) {\nreturn uv.y < BLOB_SLOT_HEIGHT;\n}int getBlobIndexForUV(vec2 uv) {\nreturn int(floor(uv.x * 3.0000));\n}bool isBlobStateAlive(vec4 state) {\nreturn state.z > 0.01 && state.w > 0.05 && state.x >= 0.0;\n}bool checkBlobCollision(vec2 cPos, int slotIndex, float minSpacing, bool checkLower, bool checkHigher) {\nif (checkLower) {\nfor (int j = 0; j < MAX_BLOBS; j++) {\nif (j >= slotIndex) break;\nif (j >= int(3.0000)) break;\nvec4 jState = textureLod(uPreviousFrameTexture, getBlobSlotUV(j), 0.0);\nif (!isBlobStateAlive(jState)) continue;\nif (length(cPos - jState.xy) < minSpacing) return true;\n}\n}\nif (checkHigher) {\nfor (int j = 0; j < MAX_BLOBS; j++) {\nint idx = slotIndex + 1 + j;\nif (idx >= int(3.0000)) break;\nvec4 jState = textureLod(uPreviousFrameTexture, getBlobSlotUV(idx), 0.0);\nif (!isBlobStateAlive(jState)) continue;\nif (length(cPos - jState.xy) < minSpacing) return true;\n}\n}\nreturn false;\n}vec4 sampleGridCell(vec2 cellCenter, vec2 cellSize, out vec2 sumPos2, out vec2 bestPeakPos) {\nconst int SAMPLE_COUNT = 25;\nfloat sumW = 0.0;\nvec2 sumPos = vec2(0.0);\nsumPos2 = vec2(0.0);\nfloat bestPeakStrength = 0.0;\nbestPeakPos = vec2(0.0);\nfor (int s = 0; s < SAMPLE_COUNT; s++) {\nfloat x = float(s % 5);\nfloat y = float(s / 5);\nvec2 offset = (vec2(x, y) / 4.0 - 0.5) * cellSize;\nvec2 samplePos = cellCenter + offset;\nif (samplePos.x < 0.0 || samplePos.x > 1.0 ||\nsamplePos.y < 0.0 || samplePos.y > 1.0) continue;vec4 peakData = texture(uTexture, samplePos);\nfloat fieldStrength = peakData.r;\nfloat peakness = peakData.a;\nif (fieldStrength > 0.01) {\nfloat w = fieldStrength * (1.0 + peakness * 0.3);\nsumW += w;\nsumPos += samplePos * w;\nsumPos2 += samplePos * samplePos * w;\nfloat peakScore = fieldStrength * (0.5 + peakness);\nif (peakScore > bestPeakStrength) {\nbestPeakStrength = peakScore;\nbestPeakPos = samplePos;\n}\n}\n}\nreturn vec4(sumW, sumPos.x, sumPos.y, bestPeakStrength);\n}vec4 slotPass(vec2 uv) {\nif (!isBlobSlot(uv)) return vec4(0.0);int slotIndex = getBlobIndexForUV(uv);\nif (slotIndex >= int(3.0000)) return vec4(0.0);vec2 slotUV = getBlobSlotUV(slotIndex);\nvec4 prevState = texture(uPreviousFrameTexture, slotUV);\nvec2 prevPos = prevState.xy;\nfloat prevSize = prevState.z;\nfloat prevConf = prevState.w;\nbool wasAlive = (prevSize > 0.01 && prevConf > 0.05 && prevPos.x >= 0.0);vec2 bestPos = vec2(-1.0);\nvec2 bestSize = vec2(0.0);\nfloat bestScore = 0.0;\nfloat cols = ceil(sqrt(3.0000));\nfloat rows = ceil(3.0000 / cols);\nfloat col = mod(float(slotIndex), cols);\nfloat row = floor(float(slotIndex) / cols);\nvec2 slotCenter = vec2((col + 0.5) / cols, (row + 0.5) / rows);\nfloat slotRadius = 0.5 / max(cols, rows);\nconst float MIN_SPACING = 0.07;\nconst float TRACK_RADIUS = 0.05;\nvec2 cellSize = vec2(1.0 / GRID_SIZE);for (int cell = 0; cell < 64; cell++) {\nint cx = cell % 8;\nint cy = cell / 8;\nvec2 cellCenter = (vec2(float(cx), float(cy)) + 0.5) / GRID_SIZE;\nvec2 sumPos2;\nvec2 bestPeakPos;\nvec4 sampleResult = sampleGridCell(cellCenter, cellSize, sumPos2, bestPeakPos);\nfloat sumW = sampleResult.x;\nvec2 sumPos = sampleResult.yz;\nfloat bestPeakStrength = sampleResult.w;if (sumW < 0.015) continue;vec2 cPos = sumPos / sumW;\nif (bestPeakStrength > 0.2) {\ncPos = mix(cPos, bestPeakPos, 0.05);\n}\nvec2 var = max(sumPos2 / sumW - cPos * cPos, vec2(0.0));\nfloat activity = clamp(sumW / 0.25, 0.0, 1.0);\nfloat minActivity = wasAlive ? 0.12 : 0.2;\nif (activity < minActivity) continue;float sizeScalar = sqrt(max(var.x, var.y)) * mix(1.5, 3.5, activity);\nfloat maxSize = mix(0.2, 1.2, 0.5000);\nsizeScalar = sizeScalar * maxSize;float distFromSelf = length(cPos - prevPos);\nif (checkBlobCollision(cPos, slotIndex, MIN_SPACING, true, false)) continue;\nif (wasAlive && distFromSelf > TRACK_RADIUS) continue;\nif (!wasAlive) {\nif (checkBlobCollision(cPos, slotIndex, MIN_SPACING, false, true)) continue;\n}float score = sumW * activity;\nfloat distFromSlot = length(cPos - slotCenter);\nfloat regionBonus = exp(-distFromSlot * distFromSlot / (slotRadius * slotRadius * 2.0));\nif (wasAlive) {\nscore *= exp(-distFromSelf * 2.0);\nscore *= (0.5 + 0.5 * regionBonus);\n} else {\nscore *= (0.8 + 0.2 * regionBonus);\n}\nif (score > bestScore) {\nbestScore = score;\nbestPos = cPos;\nbestSize = vec2(sizeScalar);\n}\n}vec2 newPos, newSize;\nfloat SPAWN_THRESHOLD = mix(0.12, 0.05, 0.5000);\nfloat TRACK_THRESHOLD = mix(0.06, 0.02, 0.5000);\nfloat acceptThreshold = wasAlive ? TRACK_THRESHOLD : SPAWN_THRESHOLD;\nfloat newConf = 0.0;\nfloat bestConf = clamp(bestScore * 8.0, 0.0, 1.0);\nconst float MIN_PEAK_STRENGTH = 0.02;\nfloat peakAtBest = 0.0;\nvec2 texel = 1.0 / uResolution;\nfor (int p = 0; p < 25; p++) {\nfloat px = float(p % 5) - 2.0;\nfloat py = float(p / 5) - 2.0;\nfloat pVal = texture(uTexture, bestPos + vec2(px, py) * texel * 2.0).r;\npeakAtBest = max(peakAtBest, pVal);\n}\nbool canAccept = bestScore > acceptThreshold && peakAtBest > MIN_PEAK_STRENGTH;if (canAccept) {\nif (wasAlive) {\nfloat smoothFactor = mix(1.0, 0.05, 0.8000);\nnewPos = mix(prevPos, bestPos, smoothFactor);\nnewSize = vec2(prevSize);\n} else {\nnewPos = bestPos;\nnewSize = bestSize;\n}\nnewConf = clamp(max(prevConf * 0.8, bestConf), 0.0, 1.0);\n} else {\nnewPos = vec2(-1.0);\nnewSize = vec2(0.0);\nnewConf = 0.0;\n}return vec4(newPos, newSize.x, newConf);\n}void main() {\nvec2 uv = vTextureCoord;\nfragColor = slotPass(uv);\n}","#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision highp float;\nprecision highp int;in vec2 vTextureCoord;\nuniform sampler2D uTexture;\nuniform sampler2D uBgTexture;\nuniform sampler2D uFontAtlas;uniform vec2 uResolution;out vec4 fragColor;const float FONT_COLS = 8.0;\nconst float FONT_ROWS = 8.0;const int FONT_START_CHAR = 32;\nconst int MAX_BLOBS = 16;\nconst float BLOB_SLOT_HEIGHT = 0.02;float sampleChar(vec2 uv, int charCode) {\nint charIndex = charCode - FONT_START_CHAR;\nif (charIndex < 0 || charIndex >= 64) return 0.0;\nfloat col = mod(float(charIndex), FONT_COLS);\nfloat row = floor(float(charIndex) / FONT_COLS);\nfloat cellSize = 1.0 / 8.0;\nfloat x = (col + uv.x) * cellSize;\nfloat y = 1.0 - (row + 1.0 - uv.y) * cellSize;\nreturn textureLod(uFontAtlas, vec2(x, y), 0.0).r;\n}float renderDigit(vec2 uv, vec2 pos, vec2 size, int digit) {\nvec2 localUV = (uv - pos) / size;\nif (localUV.x < 0.0 || localUV.x > 1.0 || localUV.y < 0.0 || localUV.y > 1.0) {\nreturn 0.0;\n}\nint charCode = 48 + digit;\nfloat sdf = sampleChar(localUV, charCode);\nfloat edge = 0.7;\nfloat smoothing = 0.05;\nreturn smoothstep(edge - smoothing, edge + smoothing, sdf);\n}float renderChar(vec2 uv, vec2 pos, vec2 size, int charCode) {\nvec2 localUV = (uv - pos) / size;\nif (localUV.x < 0.0 || localUV.x > 1.0 || localUV.y < 0.0 || localUV.y > 1.0) {\nreturn 0.0;\n}\nfloat sdf = sampleChar(localUV, charCode);\nfloat edge = 0.6;\nfloat smoothing = 0.05;\nreturn smoothstep(edge - smoothing, edge + smoothing, sdf);\n}float renderFloat(vec2 uv, vec2 pos, vec2 charSize, float value) {\nfloat result = 0.0;\nfloat spacing = charSize.x * 0.35;\nfloat clamped = clamp(value, 0.0, 0.9999);\nint digits = int(clamped * 10000.0);\nint d1 = digits / 1000;\nint d2 = (digits / 100) % 10;\nint d3 = (digits / 10) % 10;\nint d4 = digits % 10;\nfloat startX = pos.x - spacing * 2.5;\nresult = max(result, renderDigit(uv, vec2(startX, pos.y), charSize, 0));\nresult = max(result, renderChar(uv, vec2(startX + spacing, pos.y), charSize, 46));\nresult = max(result, renderDigit(uv, vec2(startX + spacing * 2.0, pos.y), charSize, d1));\nresult = max(result, renderDigit(uv, vec2(startX + spacing * 3.0, pos.y), charSize, d2));\nresult = max(result, renderDigit(uv, vec2(startX + spacing * 4.0, pos.y), charSize, d3));\nresult = max(result, renderDigit(uv, vec2(startX + spacing * 5.0, pos.y), charSize, d4));\nreturn result;\n}vec2 getBlobSlotUV(int blobIndex) {\nfloat slotX = (float(blobIndex) + 0.5) / 3.0000;\nreturn vec2(slotX, BLOB_SLOT_HEIGHT * 0.5);\n}vec4 getBlobStateFromSlot(int i, sampler2D tex) {\nif (i >= int(3.0000)) return vec4(-1.0, -1.0, 0.0, 0.0);\nreturn textureLod(tex, getBlobSlotUV(i), 0.0);\n}bool isBlobStateActive(vec4 state) {\nreturn state.x >= 0.0 && state.z >= 0.01 && state.w >= 0.1;\n}float boxSDF(vec2 p, vec2 center, vec2 halfSize) {\nvec2 d = abs(p - center) - halfSize;\nfloat outside = length(max(d, 0.0));\nfloat inside = min(max(d.x, d.y), 0.0);\nreturn outside + inside;\n}float lineSDF(vec2 p, vec2 a, vec2 b) {\nvec2 pa = p - a;\nvec2 ba = b - a;\nfloat h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);\nreturn length(pa - ba * h);\n}float dashedLineSDF(vec2 p, vec2 a, vec2 b, float dashLength, float gapLength) {\nvec2 pa = p - a;\nvec2 ba = b - a;\nfloat lineLen = length(ba);\nfloat h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);\nfloat distAlongLine = h * lineLen;\nfloat period = dashLength + gapLength;\nfloat inPeriod = mod(distAlongLine, period);\nif (inPeriod > dashLength) return 1.0;\nreturn length(pa - ba * h);\n}float cornersSDF(vec2 p, vec2 center, vec2 halfSize, float cornerLen) {\nvec2 d = abs(p - center);\nfloat minDist = 1.0;\nvec2 tl = center + vec2(-halfSize.x, -halfSize.y);\nminDist = min(minDist, lineSDF(p, tl, tl + vec2(cornerLen, 0.0)));\nminDist = min(minDist, lineSDF(p, tl, tl + vec2(0.0, cornerLen)));\nvec2 tr = center + vec2(halfSize.x, -halfSize.y);\nminDist = min(minDist, lineSDF(p, tr, tr + vec2(-cornerLen, 0.0)));\nminDist = min(minDist, lineSDF(p, tr, tr + vec2(0.0, cornerLen)));\nvec2 bl = center + vec2(-halfSize.x, halfSize.y);\nminDist = min(minDist, lineSDF(p, bl, bl + vec2(cornerLen, 0.0)));\nminDist = min(minDist, lineSDF(p, bl, bl + vec2(0.0, -cornerLen)));\nvec2 br = center + vec2(halfSize.x, halfSize.y);\nminDist = min(minDist, lineSDF(p, br, br + vec2(-cornerLen, 0.0)));\nminDist = min(minDist, lineSDF(p, br, br + vec2(0.0, -cornerLen)));\nreturn minDist;\n}float lineStyleDistance(vec2 p, vec2 a, vec2 b, float dashLength, float gapLength) {\nreturn dashedLineSDF(p, a, b, dashLength, gapLength);\n}void computeLineDistances(vec2 uvA, float aspectRatio, sampler2D tex, float maxConnectionDist, float dashLength, float gapLength, inout float minLineDist) {\nint blobCountInt = int(3.0000);\nfor (int i = 0; i < MAX_BLOBS; i++) {\nif (i >= blobCountInt) break;\nvec4 stateI = getBlobStateFromSlot(i, tex);\nif (!isBlobStateActive(stateI)) continue;\nvec2 posI = stateI.xy;\nvec2 posA = vec2(posI.x * aspectRatio, posI.y);\nfor (int j = 0; j < MAX_BLOBS; j++) {\nif (j <= i) continue;\nif (j >= blobCountInt) break;\nvec4 stateJ = getBlobStateFromSlot(j, tex);\nif (!isBlobStateActive(stateJ)) continue;\nvec2 posJ = stateJ.xy;\nvec2 posB = vec2(posJ.x * aspectRatio, posJ.y);\nif (length(posA - posB) > maxConnectionDist) continue;\nfloat lineD = lineStyleDistance(uvA, posA, posB, dashLength, gapLength);\nminLineDist = min(minLineDist, lineD);\n}\n}\n}float renderLabelIntensity(vec2 uvA, float aspectRatio, sampler2D tex) {\nfloat textResult = 0.0;\nfloat charHeight = mix(0.015, 0.05, 0.2000);\nvec2 charSize = vec2(charHeight, charHeight);\nint blobCountInt = int(3.0000);\nfor (int i = 0; i < MAX_BLOBS; i++) {\nif (i >= blobCountInt) break;\nvec4 state = getBlobStateFromSlot(i, tex);\nif (!isBlobStateActive(state)) continue;\nvec2 blobPos = state.xy;\nfloat blobSize = state.z * 0.5;\nvec2 labelPos = vec2(\nblobPos.x * aspectRatio - blobSize + charSize.x * 0.4,\nblobPos.y - blobSize + charSize.y * 0.4\n);\nfloat intensity = clamp(blobSize * 4.0, 0.0, 1.0);\nlabelPos.x += charSize.x;\ntextResult = max(textResult, renderFloat(uvA, labelPos, charSize, intensity));\n}\nreturn textResult;\n}vec2 blobStyleCornersData(vec2 uvA, vec2 centerA, vec2 halfSize) {\nfloat outlineD = cornersSDF(uvA, centerA, halfSize, min(0.02, halfSize.x * 0.5));\nfloat fillD = boxSDF(uvA, centerA, halfSize);\nreturn vec2(outlineD, fillD);\n}vec4 drawPass(vec2 uv) {\nvec4 background = texture(uBgTexture, uv);\nif (background.a < 0.001) return vec4(0.0);float aspectRatio = uResolution.x / uResolution.y;\nfloat minBlobDist = 1.0;\nfloat minLineDist = 1.0;\nbool foundAny = false;\nint blobCountInt = int(3.0000);\nfor (int i = 0; i < MAX_BLOBS; i++) {\nif (i >= blobCountInt) break;\nvec4 state = getBlobStateFromSlot(i, uTexture);\nif (isBlobStateActive(state)) {\nfoundAny = true;\nbreak;\n}\n}\nif (!foundAny) {\nif (1 == 1) {\nreturn background;\n}\nreturn vec4(0.0);\n}\nvec2 uvA = vec2(uv.x * aspectRatio, uv.y);\nfloat lineWidth = 0.2000 * 0.005;\nfloat dashLength = 0.015;\nfloat gapLength = 0.01;\nfloat minFillDist = 1.0;\nfor (int i = 0; i < MAX_BLOBS; i++) {\nif (i >= blobCountInt) break;\nvec4 state = getBlobStateFromSlot(i, uTexture);\nif (!isBlobStateActive(state)) continue;\nvec2 blobPos = state.xy;\nfloat blobSize = state.z * 0.5;\nvec2 centerA = vec2(blobPos.x * aspectRatio, blobPos.y);\nvec2 halfSize = vec2(blobSize);\nfloat blobD = 1.0;\nvec2 blobData = vec2(1.0);\nblobData = blobStyleCornersData(uvA, centerA, halfSize);\nblobD = blobData.x;\nminBlobDist = min(minBlobDist, blobD);\nminFillDist = min(minFillDist, blobData.y);\n}\ncomputeLineDistances(uvA, aspectRatio, uTexture, 0.5000, dashLength, gapLength, minLineDist);float connectionWidth = lineWidth;\nfloat blobLineWidth = lineWidth;\nfloat blobResult = 1.0 - smoothstep(blobLineWidth * 0.5, blobLineWidth * 1.5, minBlobDist);\nfloat fillResult = 0.0;\nfillResult = (minFillDist < 0.0) ? 0.1500 : 0.0;\nfloat lineResult = 0.0;lineResult = 1.0 - smoothstep(connectionWidth * 0.5, connectionWidth * 1.5, minLineDist);float textResult = 0.0;\ntextResult = renderLabelIntensity(uvA, aspectRatio, uTexture);\nfloat result = max(max(max(blobResult, lineResult), fillResult), textResult);vec3 finalColor;\nfinalColor = mix(background.rgb, vec3(0.13333333333333333, 1, 0.6549019607843137), result * 1.0000);float finalAlpha = background.a;\nreturn vec4(finalColor, finalAlpha);\n}void main() {\nvec2 uv = vTextureCoord;\nvec4 color = drawPass(uv);\nfragColor = color;}"],"compiledVertexShaders":["#version 300 es\n// Copyright (c) Unicorn Studio. Licensed under the Unicorn Studio Commercial License.\n// Unauthorized copying, redistribution, or use in competing products is prohibited.\nprecision mediump float;in vec3 aVertexPosition;\nin vec2 aTextureCoord;uniform mat4 uMVMatrix;\nuniform mat4 uPMatrix;\nuniform mat4 uTextureMatrix;out vec2 vTextureCoord;\nout vec3 vVertexPosition;void main() {\ngl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);\nvTextureCoord = (uTextureMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy;\n}"],"data":{"downSample":0.25,"depth":false,"uniforms":{},"isBackground":false,"passes":[{"prop":"pass","value":1,"downSample":0.25,"passDescription":"Find candidate blob peaks in the motion field."},{"prop":"pass","value":2,"downSample":0.25,"needsPreviousFrame":"pass","passDescription":"Assign detected peaks to persistent blob slots."},{"prop":"pass","value":3,"includeBg":true,"passDescription":"Render tracked blobs, links, and labels over the background."}],"needsPreviousFrame":"pass","texture":{"src":"/assets/unicorn/font_atlas.png","sampler":"uFontAtlas"}},"id":"card3_layer_5_blobTracking","publicId":"blob_tracking1"}],"options":{"name":"Card 3","fps":60,"dpi":1.5,"scale":1,"includeLogo":false,"isProduction":false,"flatten":true},"version":"2.1.12","id":"AUexYtG0E4ugxEiIHq3b"}