Files
hyperframes/docs/public/catalog/blocks/liquid-glass-widgets.json
github-actions[bot] faa4913c9e chore(catalog): publish generated catalog (#4340)
* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

* chore(catalog): publish generated catalog

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-10-10 19:13:01 +00:00

1 line
62 KiB
JSON

{"html":"<!doctype html>\n<html lang=\"en\">\n <head><base href=\"/public/catalog/items/liquid-glass-widgets/\">\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=1920, height=1080\" />\n <title>Liquid Glass Widgets</title>\n <script src=\"https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js\"></script>\n <script\n src=\"https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js\"\n integrity=\"sha384-CI3ELBVUz9XQO+97x6nwMDPosPR5XvsxW2ua7N1Xeygeh1IxtgqtCkGfQY9WWdHu\"\n crossorigin=\"anonymous\"\n ></script>\n <script data-hf-inlined-src=\"lib/liquid-glass.iife.js\">var LiquidGlass = (() => {\n var E = Object.defineProperty;\n var D = Object.getOwnPropertyDescriptor;\n var z = Object.getOwnPropertyNames;\n var N = Object.prototype.hasOwnProperty;\n var O = (m, e) => {\n for (var t in e) E(m, t, { get: e[t], enumerable: !0 });\n },\n H = (m, e, t, r) => {\n if ((e && typeof e == \"object\") || typeof e == \"function\")\n for (let n of z(e))\n !N.call(m, n) &&\n n !== t &&\n E(m, n, { get: () => e[n], enumerable: !(r = D(e, n)) || r.enumerable });\n return m;\n };\n var I = (m) => H(E({}, \"__esModule\", { value: !0 }), m);\n var Y = {};\n O(Y, {\n CSS_PROPERTY_MAP: () => _,\n DEFAULTS: () => w,\n GlassRendererGPU: () => y,\n LiquidGlassCanvas: () => R,\n });\n var w = {\n blurAmount: 0,\n refraction: 0.69,\n chromAberration: 0.05,\n edgeHighlight: 0.05,\n specular: 0,\n fresnel: 1,\n distortion: 0,\n cornerRadius: 65,\n zRadius: 40,\n opacity: 1,\n saturation: 0,\n tintStrength: 0,\n brightness: 0,\n shadowOpacity: 0.3,\n shadowSpread: 10,\n shadowOffsetY: 1,\n bevelMode: 0,\n },\n _ = {\n \"--lg-blur\": \"blurAmount\",\n \"--lg-refraction\": \"refraction\",\n \"--lg-chrom-aberration\": \"chromAberration\",\n \"--lg-edge-highlight\": \"edgeHighlight\",\n \"--lg-specular\": \"specular\",\n \"--lg-fresnel\": \"fresnel\",\n \"--lg-distortion\": \"distortion\",\n \"--lg-corner-radius\": \"cornerRadius\",\n \"--lg-z-radius\": \"zRadius\",\n \"--lg-opacity\": \"opacity\",\n \"--lg-saturation\": \"saturation\",\n \"--lg-tint\": \"tintStrength\",\n \"--lg-brightness\": \"brightness\",\n \"--lg-shadow-opacity\": \"shadowOpacity\",\n \"--lg-shadow-spread\": \"shadowSpread\",\n \"--lg-shadow-offset-y\": \"shadowOffsetY\",\n \"--lg-bevel-mode\": \"bevelMode\",\n },\n L = 6,\n T = 20;\n var q = `// Blit shader - copy texture with UV transform\n\nstruct BlitUniforms {\n scale: vec2f,\n offset: vec2f,\n}\n\n@group(0) @binding(0) var<uniform> u: BlitUniforms;\n@group(0) @binding(1) var texSampler: sampler;\n@group(0) @binding(2) var tex: texture_2d<f32>;\n\nstruct VertexOutput {\n @builtin(position) position: vec4f,\n @location(0) uv: vec2f,\n}\n\n@vertex\nfn vertexMain(@location(0) pos: vec2f) -> VertexOutput {\n var out: VertexOutput;\n out.uv = pos * 0.5 + 0.5;\n out.position = vec4f(pos, 0.0, 1.0);\n return out;\n}\n\n@fragment\nfn fragmentMain(in: VertexOutput) -> @location(0) vec4f {\n return textureSample(tex, texSampler, in.uv * u.scale + u.offset);\n}\n`,\n k = `// Blur shader - 9-tap Gaussian blur (single direction)\n\nstruct BlurUniforms {\n dir: vec2f,\n _pad: vec2f,\n}\n\n@group(0) @binding(0) var<uniform> u: BlurUniforms;\n@group(0) @binding(1) var texSampler: sampler;\n@group(0) @binding(2) var tex: texture_2d<f32>;\n\nstruct VertexOutput {\n @builtin(position) position: vec4f,\n @location(0) uv: vec2f,\n}\n\n@vertex\nfn vertexMain(@location(0) pos: vec2f) -> VertexOutput {\n var out: VertexOutput;\n out.uv = pos * 0.5 + 0.5;\n out.position = vec4f(pos, 0.0, 1.0);\n return out;\n}\n\n@fragment\nfn fragmentMain(in: VertexOutput) -> @location(0) vec4f {\n var s = textureSample(tex, texSampler, in.uv) * 0.227027;\n s += textureSample(tex, texSampler, in.uv + u.dir * 1.0) * 0.194594;\n s += textureSample(tex, texSampler, in.uv - u.dir * 1.0) * 0.194594;\n s += textureSample(tex, texSampler, in.uv + u.dir * 2.0) * 0.121622;\n s += textureSample(tex, texSampler, in.uv - u.dir * 2.0) * 0.121622;\n s += textureSample(tex, texSampler, in.uv + u.dir * 3.0) * 0.054054;\n s += textureSample(tex, texSampler, in.uv - u.dir * 3.0) * 0.054054;\n s += textureSample(tex, texSampler, in.uv + u.dir * 4.0) * 0.016216;\n s += textureSample(tex, texSampler, in.uv - u.dir * 4.0) * 0.016216;\n return s;\n}\n`,\n W = `// Glass shader - the core liquid glass effect\n\nstruct GlassUniforms {\n center: vec2f,\n size: vec2f,\n res: vec2f,\n radius: f32,\n pad: f32,\n refract: f32,\n chroma: f32,\n edgeHL: f32,\n spec: f32,\n fresnel: f32,\n distort: f32,\n alpha: f32,\n sat: f32,\n tint: f32,\n zRadius: f32,\n brightness: f32,\n shadowAlpha: f32,\n shadowSpread: f32,\n shadowOffY: f32,\n bevelMode: f32,\n _pad: vec2f,\n}\n\n@group(0) @binding(0) var<uniform> u: GlassUniforms;\n@group(0) @binding(1) var texSampler: sampler;\n@group(0) @binding(2) var bgTex: texture_2d<f32>;\n@group(0) @binding(3) var blurTex: texture_2d<f32>;\n\nstruct VertexOutput {\n @builtin(position) position: vec4f,\n @location(0) localPx: vec2f,\n @location(1) screenUV: vec2f,\n}\n\n@vertex\nfn vertexMain(@location(0) pos: vec2f) -> VertexOutput {\n var out: VertexOutput;\n let total = u.size + vec2f(u.pad * 2.0);\n out.localPx = pos * total;\n let px = u.center + pos * total;\n out.screenUV = vec2f(px.x / u.res.x, 1.0 - px.y / u.res.y);\n var ndc = (px / u.res) * 2.0 - 1.0;\n ndc.y = -ndc.y;\n out.position = vec4f(ndc, 0.0, 1.0);\n return out;\n}\n\n// Rounded-rect signed distance\nfn rrSDF(p: vec2f, b: vec2f, r: f32) -> f32 {\n let q = abs(p) - b + vec2f(r);\n return min(max(q.x, q.y), 0.0) + length(max(q, vec2f(0.0))) - r;\n}\n\n// Bevel height field\nfn bevelHeight(d: f32, zR: f32) -> f32 {\n if (d <= 0.0) { return 0.0; }\n if (d >= zR) { return zR; }\n return sqrt(d * (2.0 * zR - d));\n}\n\nfn hash(p: vec2f) -> f32 {\n return fract(sin(dot(p, vec2f(127.1, 311.7))) * 43758.5453);\n}\n\n@fragment\nfn fragmentMain(in: VertexOutput) -> @location(0) vec4f {\n let half_ = u.size * 0.5;\n let r = min(u.radius, min(half_.x, half_.y));\n let sdf = rrSDF(in.localPx, half_, r);\n\n // Anti-aliased mask\n let mask = 1.0 - smoothstep(-1.5, 0.5, sdf);\n\n let maxD = min(half_.x, half_.y);\n let inside = -sdf;\n let edge = smoothstep(maxD * 0.35, 0.0, inside);\n\n // Surface normal via bevel height field\n let zR = u.zRadius;\n let e = 2.0;\n let dC = inside;\n let dR = -rrSDF(in.localPx + vec2f(e, 0.0), half_, r);\n let dL = -rrSDF(in.localPx - vec2f(e, 0.0), half_, r);\n let dU = -rrSDF(in.localPx + vec2f(0.0, e), half_, r);\n let dD = -rrSDF(in.localPx - vec2f(0.0, e), half_, r);\n let hC = bevelHeight(dC, zR);\n let hR = bevelHeight(dR, zR);\n let hL = bevelHeight(dL, zR);\n let hU = bevelHeight(dU, zR);\n let hD = bevelHeight(dD, zR);\n let hGrad = vec2f(hR - hL, hU - hD) / (2.0 * e);\n let N = normalize(vec3f(-hGrad, 1.0));\n\n let depth = smoothstep(0.0, zR, inside);\n\n // Refraction - compute both modes and select\n let pxToUV = vec2f(1.0, -1.0) / u.res;\n let ior = 1.5;\n let refrPow = 1.0 - 1.0 / ior;\n let thickness = hC * 2.0;\n let thickNorm = thickness / max(zR * 2.0, 1.0);\n\n // Biconvex mode\n let exitRefr = hGrad * refrPow;\n let entryRefr = hGrad * refrPow;\n let throughRefr = entryRefr * thickNorm * 0.5;\n var refrPxBiconvex = (exitRefr + entryRefr + throughRefr) * u.refract * 30.0;\n let centerDir = -in.localPx / max(half_, vec2f(1.0));\n refrPxBiconvex += centerDir * u.refract * 4.0 * depth;\n\n // Dome mode\n let refrPxDome = -in.localPx * u.refract * depth * 0.35;\n\n // Select based on bevel mode\n let refrPx = select(refrPxBiconvex, refrPxDome, u.bevelMode >= 0.5);\n let refr = refrPx * pxToUV;\n\n // Micro-distortion noise\n let ns = in.localPx * 0.08;\n let absPxToUV = vec2f(1.0) / u.res;\n let micro = (vec2f(hash(ns), hash(ns + vec2f(37.0))) - 0.5) * u.distort * 4.0 * absPxToUV;\n\n // Chromatic aberration\n let caS = u.chroma * 18.0 * (edge * 0.7 + 0.3) * 2.0;\n let caD = N.xy * caS * pxToUV;\n let base = in.screenUV + refr + micro;\n\n // Sample textures (must be in uniform control flow)\n let sharpR = textureSample(bgTex, texSampler, base + caD).r;\n let sharpG = textureSample(bgTex, texSampler, base).g;\n let sharpB = textureSample(bgTex, texSampler, base - caD).b;\n let sharp = vec3f(sharpR, sharpG, sharpB);\n\n let blurR = textureSample(blurTex, texSampler, base + caD).r;\n let blurG = textureSample(blurTex, texSampler, base).g;\n let blurB = textureSample(blurTex, texSampler, base - caD).b;\n let blur = vec3f(blurR, blurG, blurB);\n\n // Edge-weighted blur mix\n let edgeMix = 1.0 - edge * 0.15;\n var col = mix(sharp, blur, edgeMix);\n\n // Brightness\n col *= 1.0 + u.brightness;\n\n // Saturation\n let lum = dot(col, vec3f(0.299, 0.587, 0.114));\n col = mix(vec3f(lum), col, 1.0 + u.sat);\n\n // Cool glass tint\n col = mix(col, col * vec3f(0.92, 0.95, 1.05), u.tint);\n col *= 1.0 + 0.06 * depth;\n\n // Fresnel\n let fres = pow(1.0 - abs(N.z), 4.0) * u.fresnel;\n\n // Specular highlights (multi-light Blinn-Phong)\n let V = vec3f(0.0, 0.0, 1.0);\n let L1 = normalize(vec3f(0.4, 0.7, 1.0));\n let H1 = normalize(L1 + V);\n let sp1 = pow(max(dot(N, H1), 0.0), 90.0);\n let L2 = normalize(vec3f(-0.3, -0.5, 1.0));\n let H2 = normalize(L2 + V);\n let sp2 = pow(max(dot(N, H2), 0.0), 50.0) * 0.3;\n let L3 = normalize(vec3f(0.1, 0.3, 1.0));\n let spB = pow(max(dot(N, L3), 0.0), 6.0) * 0.1;\n let L4 = normalize(vec3f(0.0, 0.9, 0.4));\n let H4 = normalize(L4 + V);\n let sp4 = pow(max(dot(N, H4), 0.0), 120.0) * 0.6;\n let totalSpec = (sp1 + sp2 + spB + sp4) * u.spec;\n\n // Inner border / stroke highlight\n let borderWidth = 1.5;\n let innerStroke = smoothstep(-borderWidth - 1.0, -borderWidth, sdf)\n * (1.0 - smoothstep(-1.0, 0.0, sdf));\n let topBias = 0.5 + 0.5 * (-in.localPx.y / half_.y);\n let innerStrokeFinal = innerStroke * (0.4 + 0.6 * topBias);\n\n // Edge highlight & inner glow\n let rim = edge * u.edgeHL * 0.22;\n let innerGlow = smoothstep(5.0, 0.0, -sdf) * u.edgeHL * 0.15;\n\n // Environment-like reflection (fake)\n let envRefl = (N.y * 0.5 + 0.5) * fres * 0.08;\n\n // Composite glass effect\n var fin = col;\n fin += vec3f(totalSpec);\n fin += vec3f(rim + innerGlow);\n fin += vec3f(innerStrokeFinal * u.edgeHL * 0.55);\n fin += vec3f(envRefl);\n fin = mix(fin, vec3f(1.0), fres * 0.2);\n\n // Shadow calculation (outside panel)\n let sdfShadow = rrSDF(in.localPx - vec2f(0.0, u.shadowOffY), half_, r);\n let shadowD = max(sdfShadow - 1.0, 0.0);\n let spread = max(u.shadowSpread, 1.0);\n let falloff = 1.0 / (spread * spread);\n let outerShadow = exp(-shadowD * shadowD * falloff) * 0.65;\n let contactShadow = exp(-shadowD * 0.08 / max(spread * 0.04, 0.01)) * 0.35;\n let shadow = (outerShadow + contactShadow) * u.shadowAlpha;\n\n // Select between shadow (outside) and glass (inside)\n let isOutside = sdf > 0.0;\n let finalColor = select(fin, vec3f(0.0), isOutside);\n let finalAlpha = select(mask * u.alpha, shadow, isOutside);\n\n return vec4f(finalColor, finalAlpha);\n}\n`,\n y = class {\n canvas;\n device = null;\n context = null;\n format = \"bgra8unorm\";\n blitPipeline = null;\n blurPipeline = null;\n glassPipeline = null;\n quadBuffer = null;\n panelBuffer = null;\n blitUniformBuffer = null;\n blurUniformBuffer = null;\n glassUniformBuffer = null;\n sampler = null;\n targetCache = new Map();\n activeTargets = null;\n bgTexture = null;\n bgTextureView = null;\n width = 0;\n height = 0;\n _initPromise = null;\n _initialized = !1;\n constructor() {\n ((this.canvas = document.createElement(\"canvas\")),\n (this.canvas.style.display = \"none\"),\n document.body.appendChild(this.canvas));\n }\n async init() {\n return this._initPromise\n ? this._initPromise\n : ((this._initPromise = this._doInit()), this._initPromise);\n }\n async _doInit() {\n if (!navigator.gpu) return (console.warn(\"WebGPU not supported\"), !1);\n let e = await navigator.gpu.requestAdapter();\n return e\n ? ((this.device = await e.requestDevice()),\n this.device\n ? ((this.context = this.canvas.getContext(\"webgpu\")),\n this.context\n ? ((this.format = navigator.gpu.getPreferredCanvasFormat()),\n this.context.configure({\n device: this.device,\n format: this.format,\n alphaMode: \"premultiplied\",\n }),\n this._initPipelines(),\n this._initBuffers(),\n (this._initialized = !0),\n !0)\n : (console.warn(\"Failed to get WebGPU context\"), !1))\n : (console.warn(\"Failed to get WebGPU device\"), !1))\n : (console.warn(\"No WebGPU adapter found\"), !1);\n }\n get initialized() {\n return this._initialized;\n }\n _initPipelines() {\n let e = this.device;\n this.sampler = e.createSampler({\n magFilter: \"linear\",\n minFilter: \"linear\",\n addressModeU: \"clamp-to-edge\",\n addressModeV: \"clamp-to-edge\",\n });\n let t = e.createShaderModule({ code: q }),\n r = e.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n buffer: { type: \"uniform\" },\n },\n { binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: { type: \"filtering\" } },\n { binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: \"float\" } },\n ],\n });\n this.blitPipeline = e.createRenderPipeline({\n layout: e.createPipelineLayout({ bindGroupLayouts: [r] }),\n vertex: {\n module: t,\n entryPoint: \"vertexMain\",\n buffers: [\n {\n arrayStride: 8,\n attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }],\n },\n ],\n },\n fragment: { module: t, entryPoint: \"fragmentMain\", targets: [{ format: \"rgba8unorm\" }] },\n primitive: { topology: \"triangle-strip\" },\n });\n let n = e.createShaderModule({ code: k }),\n i = e.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n buffer: { type: \"uniform\" },\n },\n { binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: { type: \"filtering\" } },\n { binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: \"float\" } },\n ],\n });\n this.blurPipeline = e.createRenderPipeline({\n layout: e.createPipelineLayout({ bindGroupLayouts: [i] }),\n vertex: {\n module: n,\n entryPoint: \"vertexMain\",\n buffers: [\n {\n arrayStride: 8,\n attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }],\n },\n ],\n },\n fragment: { module: n, entryPoint: \"fragmentMain\", targets: [{ format: \"rgba8unorm\" }] },\n primitive: { topology: \"triangle-strip\" },\n });\n let s = e.createShaderModule({ code: W }),\n l = e.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\n buffer: { type: \"uniform\" },\n },\n { binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: { type: \"filtering\" } },\n { binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: \"float\" } },\n { binding: 3, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: \"float\" } },\n ],\n });\n this.glassPipeline = e.createRenderPipeline({\n layout: e.createPipelineLayout({ bindGroupLayouts: [l] }),\n vertex: {\n module: s,\n entryPoint: \"vertexMain\",\n buffers: [\n {\n arrayStride: 8,\n attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }],\n },\n ],\n },\n fragment: {\n module: s,\n entryPoint: \"fragmentMain\",\n targets: [\n {\n format: this.format,\n blend: {\n color: {\n srcFactor: \"src-alpha\",\n dstFactor: \"one-minus-src-alpha\",\n operation: \"add\",\n },\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n },\n },\n ],\n },\n primitive: { topology: \"triangle-strip\" },\n });\n }\n _initBuffers() {\n let e = this.device;\n ((this.quadBuffer = e.createBuffer({\n size: 32,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: !0,\n })),\n new Float32Array(this.quadBuffer.getMappedRange()).set([-1, -1, 1, -1, -1, 1, 1, 1]),\n this.quadBuffer.unmap(),\n (this.panelBuffer = e.createBuffer({\n size: 32,\n usage: GPUBufferUsage.VERTEX,\n mappedAtCreation: !0,\n })),\n new Float32Array(this.panelBuffer.getMappedRange()).set([\n -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5,\n ]),\n this.panelBuffer.unmap(),\n (this.blitUniformBuffer = e.createBuffer({\n size: 16,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n })),\n (this.blurUniformBuffer = e.createBuffer({\n size: 16,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n })),\n (this.glassUniformBuffer = e.createBuffer({\n size: 112,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n })));\n }\n resize(e, t) {\n if (!(this.width === e && this.height === t)) {\n ((this.width = e), (this.height = t));\n for (let r of this.targetCache.values()) this._freeTargetSet(r);\n (this.targetCache.clear(), (this.activeTargets = null));\n }\n }\n uploadAndBlur(e, t, r, n, i, s) {\n if (!this._initialized || !this.device || !this._setActiveSize(n, i)) return;\n let l = this.device,\n a = this.width,\n u = this.height,\n o = this.activeTargets,\n d = document.createElement(\"canvas\");\n ((d.width = a),\n (d.height = u),\n d.getContext(\"2d\").drawImage(e, -t, -r),\n (!this.bgTexture || this.bgTexture.width !== a || this.bgTexture.height !== u) &&\n (this.bgTexture && this.bgTexture.destroy(),\n (this.bgTexture = l.createTexture({\n size: [a, u],\n format: \"rgba8unorm\",\n usage:\n GPUTextureUsage.TEXTURE_BINDING |\n GPUTextureUsage.COPY_DST |\n GPUTextureUsage.RENDER_ATTACHMENT,\n })),\n (this.bgTextureView = this.bgTexture.createView())),\n l.queue.copyExternalImageToTexture(\n { source: d, flipY: !0 },\n { texture: this.bgTexture },\n [a, u],\n ));\n let f = l.createCommandEncoder();\n this._blitPass(f, this.bgTextureView, o.bg.view, a, u, 1, 1, 0, 0);\n let h = o.blurA.w,\n b = o.blurA.h;\n if ((this._blitPass(f, o.bg.view, o.blurA.view, h, b, 1, 1, 0, 0), s > 0)) {\n let g = s * 2.5;\n for (let p = 0; p < L; p++)\n (this._blurPass(f, o.blurA.view, o.blurB.view, h, b, g / h, 0),\n this._blurPass(f, o.blurB.view, o.blurA.view, h, b, 0, g / b));\n }\n l.queue.submit([f.finish()]);\n }\n _blitPass(e, t, r, n, i, s, l, a, u) {\n let o = this.device;\n o.queue.writeBuffer(this.blitUniformBuffer, 0, new Float32Array([s, l, a, u]));\n let d = o.createBindGroup({\n layout: this.blitPipeline.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: { buffer: this.blitUniformBuffer } },\n { binding: 1, resource: this.sampler },\n { binding: 2, resource: t },\n ],\n }),\n c = e.beginRenderPass({\n colorAttachments: [\n {\n view: r,\n loadOp: \"clear\",\n storeOp: \"store\",\n clearValue: { r: 0, g: 0, b: 0, a: 0 },\n },\n ],\n });\n (c.setPipeline(this.blitPipeline),\n c.setBindGroup(0, d),\n c.setVertexBuffer(0, this.quadBuffer),\n c.setViewport(0, 0, n, i, 0, 1),\n c.draw(4),\n c.end());\n }\n _blurPass(e, t, r, n, i, s, l) {\n let a = this.device;\n a.queue.writeBuffer(this.blurUniformBuffer, 0, new Float32Array([s, l, 0, 0]));\n let u = a.createBindGroup({\n layout: this.blurPipeline.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: { buffer: this.blurUniformBuffer } },\n { binding: 1, resource: this.sampler },\n { binding: 2, resource: t },\n ],\n }),\n o = e.beginRenderPass({\n colorAttachments: [\n {\n view: r,\n loadOp: \"clear\",\n storeOp: \"store\",\n clearValue: { r: 0, g: 0, b: 0, a: 0 },\n },\n ],\n });\n (o.setPipeline(this.blurPipeline),\n o.setBindGroup(0, u),\n o.setVertexBuffer(0, this.quadBuffer),\n o.setViewport(0, 0, n, i, 0, 1),\n o.draw(4),\n o.end());\n }\n renderGlassPanel(e, t, r, n) {\n if (!this._initialized || !this.device || !this.context) return;\n let i = this.device,\n s = this.width,\n l = this.height,\n a = this.activeTargets,\n u = new Float32Array([\n s * 0.5,\n l * 0.5,\n t * n,\n r * n,\n s,\n l,\n e.cornerRadius * n,\n T * n,\n e.refraction,\n e.chromAberration,\n e.edgeHighlight,\n e.specular,\n e.fresnel,\n e.distortion,\n e.opacity,\n e.saturation,\n e.tintStrength,\n e.zRadius * n,\n e.brightness,\n e.shadowOpacity,\n e.shadowSpread * n,\n e.shadowOffsetY * n,\n e.bevelMode,\n 0,\n 0,\n 0,\n 0,\n 0,\n ]);\n i.queue.writeBuffer(this.glassUniformBuffer, 0, u);\n let o = i.createBindGroup({\n layout: this.glassPipeline.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: { buffer: this.glassUniformBuffer } },\n { binding: 1, resource: this.sampler },\n { binding: 2, resource: a.bg.view },\n { binding: 3, resource: a.blurA.view },\n ],\n }),\n d = i.createCommandEncoder(),\n c = d.beginRenderPass({\n colorAttachments: [\n {\n view: this.context.getCurrentTexture().createView(),\n loadOp: \"load\",\n storeOp: \"store\",\n },\n ],\n });\n (c.setPipeline(this.glassPipeline),\n c.setBindGroup(0, o),\n c.setVertexBuffer(0, this.panelBuffer),\n c.setViewport(0, 0, s, l, 0, 1),\n c.draw(4),\n c.end(),\n i.queue.submit([d.finish()]));\n }\n clear() {\n if (!this._initialized || !this.device || !this.context) return;\n let e = this.device.createCommandEncoder(),\n t = e.beginRenderPass({\n colorAttachments: [\n {\n view: this.context.getCurrentTexture().createView(),\n loadOp: \"clear\",\n storeOp: \"store\",\n clearValue: { r: 0, g: 0, b: 0, a: 0 },\n },\n ],\n });\n (t.setViewport(0, 0, this.width, this.height, 0, 1),\n t.end(),\n this.device.queue.submit([e.finish()]));\n }\n destroy() {\n for (let e of this.targetCache.values()) this._freeTargetSet(e);\n (this.targetCache.clear(),\n this.bgTexture && this.bgTexture.destroy(),\n this.quadBuffer && this.quadBuffer.destroy(),\n this.panelBuffer && this.panelBuffer.destroy(),\n this.blitUniformBuffer && this.blitUniformBuffer.destroy(),\n this.blurUniformBuffer && this.blurUniformBuffer.destroy(),\n this.glassUniformBuffer && this.glassUniformBuffer.destroy(),\n this.device?.destroy(),\n this.canvas.remove());\n }\n _setActiveSize(e, t) {\n if (e <= 0 || t <= 0) return !1;\n ((this.width = e),\n (this.height = t),\n (this.canvas.width < e || this.canvas.height < t) &&\n ((this.canvas.width = Math.max(this.canvas.width, e)),\n (this.canvas.height = Math.max(this.canvas.height, t)),\n this.context?.configure({\n device: this.device,\n format: this.format,\n alphaMode: \"premultiplied\",\n })));\n let r = `${e}x${t}`,\n n = this.targetCache.get(r);\n return (\n n ||\n ((n = {\n bg: this._makeTarget(e, t),\n blurA: this._makeTarget(e, t),\n blurB: this._makeTarget(e, t),\n }),\n this.targetCache.set(r, n)),\n (this.activeTargets = n),\n !0\n );\n }\n _makeTarget(e, t) {\n let r = this.device.createTexture({\n size: [e, t],\n format: \"rgba8unorm\",\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,\n });\n return { texture: r, view: r.createView(), w: e, h: t };\n }\n _freeTarget(e) {\n e && e.texture.destroy();\n }\n _freeTargetSet(e) {\n (this._freeTarget(e.bg), this._freeTarget(e.blurA), this._freeTarget(e.blurB));\n }\n };\n var R = class {\n canvas;\n ctx;\n renderer;\n sceneCanvas;\n sceneCtx;\n drawElementImage;\n _initPromise;\n _initialized = !1;\n constructor(e) {\n ((this.canvas = e),\n (this.ctx = e.getContext(\"2d\")),\n (this.renderer = new y()),\n (this.sceneCanvas = document.createElement(\"canvas\")),\n (this.sceneCtx = this.sceneCanvas.getContext(\"2d\")));\n let t = this.ctx;\n ((this.drawElementImage = t.drawElementImage?.bind(t) ?? t.drawElement?.bind(t) ?? null),\n (this._initPromise = this._initWebGPU()));\n }\n async _initWebGPU() {\n try {\n return (await this.renderer.init())\n ? ((this._initialized = !0), console.log(\"LiquidGlass: WebGPU renderer initialized\"), !0)\n : (console.error(\"LiquidGlass: WebGPU not available\"), !1);\n } catch (e) {\n return (console.error(\"LiquidGlass: WebGPU init failed\", e), !1);\n }\n }\n get isReady() {\n return this._initialized;\n }\n async waitForInit() {\n return this._initPromise;\n }\n render() {\n let e = this.canvas.width,\n t = this.canvas.height;\n if (e === 0 || t === 0 || !this.drawElementImage || !this._initialized) return;\n this.ctx.clearRect(0, 0, e, t);\n let r = window.devicePixelRatio || 1,\n n = this.canvas.getBoundingClientRect(),\n i = Array.from(this.canvas.children),\n s = Array.from(this.canvas.querySelectorAll(\".liquid-glass\")),\n l = new Set(s);\n i.length === 0 &&\n !this.__lg_warn_empty &&\n (console.warn(\"LiquidGlass: No children found inside the canvas to render.\"),\n (this.__lg_warn_empty = !0));\n for (let a of i)\n if (!l.has(a)) {\n let u = a,\n o = this._getElementPosition(u, n);\n if (o.w <= 0 || o.h <= 0) continue;\n let d = o.x * r,\n c = o.y * r;\n try {\n let f = this.drawElementImage(a, d, c);\n f && (u.style.transform = f.toString());\n } catch (f) {\n a.__lg_error_logged ||\n (console.warn(\n `LiquidGlass: Failed to draw background element ${a.tagName}.${a.className}:`,\n f.message || f,\n ),\n (a.__lg_error_logged = !0));\n }\n }\n for (let a of s)\n try {\n this._renderGlassElement(a, n, r);\n } catch (u) {\n a.__lg_error_logged_glass ||\n (console.error(\n `LiquidGlass: Failed to render glass effect for ${a.tagName}.${a.className}:`,\n u.message || u,\n ),\n (a.__lg_error_logged_glass = !0));\n }\n }\n renderGlassElements() {\n let e = this.canvas.width,\n t = this.canvas.height;\n if (e === 0 || t === 0 || !this.drawElementImage || !this._initialized) return;\n let r = window.devicePixelRatio || 1,\n n = this.canvas.getBoundingClientRect(),\n i = this.canvas.querySelectorAll(\".liquid-glass\");\n for (let s of i) this._renderGlassElement(s, n, r);\n }\n _parseCSSLength(e, t) {\n return !e || e === \"auto\"\n ? NaN\n : ((e = e.trim()),\n e.startsWith(\"calc(\")\n ? this._parseCalc(e, t)\n : e.endsWith(\"%\")\n ? (parseFloat(e) / 100) * t\n : parseFloat(e) || 0);\n }\n _parseCalc(e, t) {\n let r = e.match(/calc\\((.+)\\)/);\n if (!r) return 0;\n let n = r[1].trim(),\n i = n.match(/(.+)\\s*\\+\\s*(.+)/),\n s = n.match(/(.+)\\s*-\\s*(.+)/);\n if (s) {\n let l = this._parseCSSLength(s[1].trim(), t),\n a = this._parseCSSLength(s[2].trim(), t);\n return l - a;\n }\n if (i) {\n let l = this._parseCSSLength(i[1].trim(), t),\n a = this._parseCSSLength(i[2].trim(), t);\n return l + a;\n }\n return this._parseCSSLength(n, t);\n }\n _parseTransform(e, t, r) {\n let n = 0,\n i = 0;\n if (!e || e === \"none\") return { tx: n, ty: i };\n let s = e.match(/translate\\(\\s*([^,)]+)(?:\\s*,\\s*([^)]+))?\\s*\\)/);\n s &&\n ((n = this._parseTranslateValue(s[1], t)),\n (i = s[2] ? this._parseTranslateValue(s[2], r) : 0));\n let l = e.match(/translateX\\(\\s*([^)]+)\\s*\\)/);\n l && (n = this._parseTranslateValue(l[1], t));\n let a = e.match(/translateY\\(\\s*([^)]+)\\s*\\)/);\n a && (i = this._parseTranslateValue(a[1], r));\n let u = e.match(/translate3d\\(\\s*([^,]+)\\s*,\\s*([^,]+)\\s*,\\s*[^)]+\\s*\\)/);\n return (\n u && ((n = this._parseTranslateValue(u[1], t)), (i = this._parseTranslateValue(u[2], r))),\n { tx: n, ty: i }\n );\n }\n _parseTranslateValue(e, t) {\n return ((e = e.trim()), e.endsWith(\"%\") ? (parseFloat(e) / 100) * t : parseFloat(e) || 0);\n }\n _getElementPosition(e, t) {\n let r = getComputedStyle(e),\n n = parseFloat(getComputedStyle(this.canvas).width) || this.canvas.width || 1536,\n i = parseFloat(getComputedStyle(this.canvas).height) || this.canvas.height || 1024,\n s = e.getBoundingClientRect(),\n l = s.width || parseFloat(r.width) || 0,\n a = s.height || parseFloat(r.height) || 0,\n u = 0,\n o = 0,\n d = e.style,\n c = d.left || r.left,\n f = d.right || r.right,\n h = d.top || r.top,\n b = d.bottom || r.bottom,\n g = this._parseCSSLength(c, n),\n p = this._parseCSSLength(f, n),\n v = this._parseCSSLength(h, i),\n S = this._parseCSSLength(b, i),\n P = parseFloat(r.marginLeft) || 0,\n x = parseFloat(r.marginRight) || 0,\n M = parseFloat(r.marginTop) || 0,\n A = parseFloat(r.marginBottom) || 0,\n G = !isNaN(g),\n U = !isNaN(p);\n G && U && g === 0 && p === 0\n ? (u = (n - l) / 2)\n : (G && U) || G\n ? (u = g + P)\n : U && (u = n - l - p - x);\n let B = !isNaN(v),\n C = !isNaN(S);\n B && C && v === 0 && S === 0\n ? (o = (i - a) / 2)\n : (B && C) || B\n ? (o = v + M)\n : C && (o = i - a - S - A);\n let { tx: V, ty: F } = this._parseTransform(r.transform, l, a);\n return ((u += V), (o += F), { x: u, y: o, w: l, h: a });\n }\n _renderGlassElement(e, t, r) {\n if (!this.drawElementImage) return;\n let n = this._getConfigFromCSS(e),\n i = this._getElementPosition(e, t),\n s = i.x,\n l = i.y,\n a = i.w,\n u = i.h,\n o = s * r,\n d = l * r,\n c = a * r,\n f = u * r,\n h = T * r,\n b = o - h,\n g = d - h,\n p = c + h * 2,\n v = f + h * 2;\n this._captureRegion(b, g, p, v);\n let S = Math.round(p),\n P = Math.round(v);\n (this.renderer.clear(),\n this.renderer.uploadAndBlur(this.sceneCanvas, 0, 0, S, P, n.blurAmount),\n this.renderer.renderGlassPanel(n, a, u, r),\n this.ctx.drawImage(this.renderer.canvas, 0, 0, p, v, b, g, p, v));\n try {\n let x = this._drawGlassElementContent(e, o, d);\n x && (e.style.transform = x.toString());\n } catch (x) {\n e.__lg_error_logged ||\n (console.warn(\n `LiquidGlass: Failed to draw glass element ${e.tagName}.${e.className}:`,\n x,\n ),\n (e.__lg_error_logged = !0));\n }\n }\n _drawGlassElementContent(e, t, r) {\n if (!this.drawElementImage) return;\n let n = this._suppressGlassChrome(e);\n try {\n return this.drawElementImage(e, t, r);\n } finally {\n this._restoreInlineStyles(e, n);\n }\n }\n _suppressGlassChrome(e) {\n let t = new Map(),\n r = [\n \"background\",\n \"backgroundColor\",\n \"backgroundImage\",\n \"borderColor\",\n \"boxShadow\",\n \"filter\",\n \"outlineColor\",\n ];\n for (let n of r) t.set(n, e.style[n]);\n return (\n (e.style.background = \"transparent\"),\n (e.style.backgroundColor = \"transparent\"),\n (e.style.backgroundImage = \"none\"),\n (e.style.borderColor = \"transparent\"),\n (e.style.boxShadow = \"none\"),\n (e.style.filter = \"none\"),\n (e.style.outlineColor = \"transparent\"),\n t\n );\n }\n _restoreInlineStyles(e, t) {\n for (let [r, n] of t) e.style[r] = n;\n }\n _captureRegion(e, t, r, n) {\n let i = Math.round(r),\n s = Math.round(n);\n ((this.sceneCanvas.width !== i || this.sceneCanvas.height !== s) &&\n ((this.sceneCanvas.width = i), (this.sceneCanvas.height = s)),\n (this.sceneCtx.fillStyle = \"#ffffff\"),\n this.sceneCtx.fillRect(0, 0, i, s),\n this.sceneCtx.drawImage(this.canvas, e, t, r, n, 0, 0, i, s));\n }\n _getConfigFromCSS(e) {\n let t = getComputedStyle(e),\n r = { ...w };\n for (let [n, i] of Object.entries(_)) {\n let s = t.getPropertyValue(n).trim();\n if (s) {\n let l = parseFloat(s);\n isNaN(l) || (r[i] = l);\n }\n }\n return r;\n }\n destroy() {\n this.renderer.destroy();\n }\n };\n return I(Y);\n})();\n</script>\n <style>\n *,\n *::before,\n *::after {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n body {\n background: #0a0218;\n overflow: hidden;\n font-family: \"Inter\", system-ui, sans-serif;\n }\n #root {\n position: relative;\n width: 1920px;\n height: 1080px;\n overflow: hidden;\n }\n #three-canvas {\n position: absolute;\n top: 0;\n left: 0;\n width: 1920px;\n height: 1080px;\n z-index: 0;\n }\n #glass-canvas {\n position: absolute;\n top: 0;\n left: 0;\n width: 1920px;\n height: 1080px;\n z-index: 1;\n }\n\n /* ── Glass Panels ── */\n .glass-panel {\n position: absolute;\n background: rgba(255, 255, 255, 0.025);\n --lg-blur: 0.42;\n --lg-refraction: 0.82;\n --lg-corner-radius: 28;\n --lg-z-radius: 46;\n --lg-specular: 0.34;\n --lg-fresnel: 1.25;\n --lg-edge-highlight: 0.26;\n --lg-chrom-aberration: 0.08;\n --lg-shadow-opacity: 0;\n --lg-shadow-spread: 0;\n --lg-shadow-offset-y: 0;\n --lg-saturation: 0.38;\n }\n .stat-card {\n width: 220px;\n height: 220px;\n }\n .showcase-card {\n width: 500px;\n height: 320px;\n }\n .pill-chip {\n width: 130px;\n height: 36px;\n --lg-corner-radius: 40;\n }\n\n #glass-stat1 {\n top: 300px;\n left: 200px;\n }\n #glass-stat2 {\n top: 300px;\n left: 460px;\n }\n #glass-stat3 {\n top: 300px;\n left: 720px;\n }\n #glass-showcase {\n top: 380px;\n left: 1100px;\n }\n #glass-pill1 {\n top: 720px;\n left: 300px;\n }\n #glass-pill2 {\n top: 720px;\n left: 460px;\n }\n #glass-pill3 {\n top: 720px;\n left: 620px;\n }\n\n /* ── Text Overlays ── */\n .text-overlay {\n position: absolute;\n z-index: 2;\n pointer-events: none;\n }\n\n /* Stat cards */\n .stat-text {\n width: 220px;\n height: 220px;\n position: absolute;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 10px;\n padding: 22px;\n border-radius: 28px;\n background:\n linear-gradient(\n 150deg,\n rgba(255, 255, 255, 0.28),\n rgba(255, 255, 255, 0.06) 46%,\n rgba(255, 255, 255, 0.16)\n ),\n linear-gradient(180deg, rgba(9, 18, 31, 0.2), rgba(255, 255, 255, 0.04));\n border: 1px solid rgba(255, 255, 255, 0.36);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.5),\n inset 0 -18px 38px rgba(255, 255, 255, 0.08);\n overflow: hidden;\n text-shadow: 0 2px 16px rgba(0, 0, 0, 0.38);\n }\n .stat-text::before,\n .showcase-text::before,\n .pill-text::before {\n content: \"\";\n position: absolute;\n inset: 1px;\n border-radius: inherit;\n pointer-events: none;\n background: linear-gradient(\n 120deg,\n rgba(255, 255, 255, 0.44),\n transparent 28%,\n transparent 66%,\n rgba(255, 255, 255, 0.2)\n );\n opacity: 0.32;\n mix-blend-mode: screen;\n }\n .stat-label {\n position: relative;\n font-size: 14px;\n font-weight: 650;\n color: #fff;\n text-transform: uppercase;\n letter-spacing: 1.5px;\n }\n .stat-value {\n position: relative;\n font-size: 52px;\n font-weight: 700;\n color: #fff;\n font-variant-numeric: tabular-nums;\n line-height: 1;\n }\n .stat-unit {\n position: relative;\n font-size: 24px;\n font-weight: 500;\n color: #fff;\n }\n .mini-meter {\n position: relative;\n width: 140px;\n height: 6px;\n overflow: hidden;\n border-radius: 999px;\n background: rgba(255, 255, 255, 0.28);\n }\n .mini-meter-fill {\n width: 0%;\n height: 100%;\n border-radius: inherit;\n background: linear-gradient(90deg, #06e3fa, #4fdb5e);\n box-shadow: 0 0 12px rgba(79, 219, 94, 0.55);\n }\n .battery-shell {\n position: relative;\n width: 118px;\n height: 40px;\n padding: 4px;\n border: 2px solid rgba(255, 255, 255, 0.66);\n border-radius: 12px;\n }\n .battery-shell::after {\n content: \"\";\n position: absolute;\n top: 12px;\n right: -9px;\n width: 5px;\n height: 14px;\n border-radius: 0 5px 5px 0;\n background: rgba(255, 255, 255, 0.66);\n }\n .battery-fill {\n width: 72%;\n height: 100%;\n border-radius: 8px;\n background: linear-gradient(90deg, #4ade80, #06e3fa);\n box-shadow: 0 0 18px rgba(74, 222, 128, 0.45);\n }\n .steps-ring {\n width: 106px;\n height: 106px;\n display: grid;\n place-items: center;\n border-radius: 50%;\n background: conic-gradient(#a78bfa 0deg, #06e3fa 180deg, rgba(255, 255, 255, 0.18) 180deg);\n }\n .steps-ring-inner {\n width: 78px;\n height: 78px;\n display: grid;\n place-items: center;\n border-radius: 50%;\n background: rgba(7, 10, 18, 0.36);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.22),\n inset 0 -8px 20px rgba(0, 0, 0, 0.14);\n color: #fff;\n font-size: 30px;\n font-weight: 800;\n font-variant-numeric: tabular-nums;\n }\n #text-stat1 {\n top: 300px;\n left: 200px;\n }\n #text-stat2 {\n top: 300px;\n left: 460px;\n }\n #text-stat3 {\n top: 300px;\n left: 720px;\n }\n\n /* Showcase card */\n .showcase-text {\n width: 500px;\n height: 320px;\n position: absolute;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 20px;\n padding: 32px;\n border-radius: 28px;\n background:\n radial-gradient(circle at 18% 12%, rgba(255, 255, 255, 0.38), transparent 24%),\n linear-gradient(\n 135deg,\n rgba(255, 255, 255, 0.24),\n rgba(255, 255, 255, 0.07) 52%,\n rgba(255, 255, 255, 0.18)\n );\n border: 1px solid rgba(255, 255, 255, 0.38);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.5),\n inset 0 -24px 48px rgba(255, 255, 255, 0.08);\n overflow: hidden;\n text-shadow: 0 2px 18px rgba(0, 0, 0, 0.4);\n }\n .showcase-icon {\n position: relative;\n width: 168px;\n height: 52px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .showcase-logo {\n width: 150px;\n height: auto;\n display: block;\n }\n .showcase-title {\n position: relative;\n font-size: 28px;\n font-weight: 700;\n color: #fff;\n text-align: center;\n line-height: 1.2;\n }\n .showcase-desc {\n position: relative;\n font-size: 15px;\n font-weight: 500;\n color: #fff;\n text-align: center;\n line-height: 1.5;\n max-width: 380px;\n }\n .showcase-status {\n position: relative;\n display: flex;\n align-items: center;\n gap: 8px;\n color: #fff;\n font-size: 14px;\n font-weight: 700;\n }\n .showcase-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #4ade80;\n box-shadow: 0 0 14px rgba(74, 222, 128, 0.7);\n }\n .showcase-progress {\n position: relative;\n width: 300px;\n height: 7px;\n overflow: hidden;\n border-radius: 999px;\n background: rgba(255, 255, 255, 0.18);\n }\n .showcase-progress-fill {\n width: 18%;\n height: 100%;\n border-radius: inherit;\n background: linear-gradient(90deg, #06e3fa, #4fdb5e);\n }\n #text-showcase {\n top: 380px;\n left: 1100px;\n }\n\n /* Pill chips */\n .pill-text {\n width: 130px;\n height: 36px;\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n border-radius: 40px;\n background: linear-gradient(130deg, rgba(255, 255, 255, 0.28), rgba(255, 255, 255, 0.1));\n border: 1px solid rgba(255, 255, 255, 0.34);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.48);\n overflow: hidden;\n }\n .pill-dot {\n position: relative;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n }\n .dot-green {\n background: #4ade80;\n }\n .dot-blue {\n background: #60a5fa;\n }\n .dot-violet {\n background: #a78bfa;\n }\n .pill-label {\n position: relative;\n font-size: 13px;\n font-weight: 600;\n color: #fff;\n }\n #text-pill1 {\n top: 720px;\n left: 300px;\n }\n #text-pill2 {\n top: 720px;\n left: 460px;\n }\n #text-pill3 {\n top: 720px;\n left: 620px;\n }\n </style>\n </head>\n <body>\n <div\n id=\"root\"\n data-composition-id=\"liquid-glass-widgets\"\n data-width=\"1920\"\n data-height=\"1080\"\n data-start=\"0\"\n data-duration=\"8\"\n data-root=\"true\"\n >\n <canvas id=\"three-canvas\" width=\"1920\" height=\"1080\"></canvas>\n\n <canvas id=\"glass-canvas\" layoutsubtree width=\"1920\" height=\"1080\">\n <div id=\"glass-stat1\" class=\"glass-panel stat-card liquid-glass\"></div>\n <div id=\"glass-stat2\" class=\"glass-panel stat-card liquid-glass\"></div>\n <div id=\"glass-stat3\" class=\"glass-panel stat-card liquid-glass\"></div>\n <div id=\"glass-showcase\" class=\"glass-panel showcase-card liquid-glass\"></div>\n <div id=\"glass-pill1\" class=\"glass-panel pill-chip liquid-glass\"></div>\n <div id=\"glass-pill2\" class=\"glass-panel pill-chip liquid-glass\"></div>\n <div id=\"glass-pill3\" class=\"glass-panel pill-chip liquid-glass\"></div>\n </canvas>\n\n <!-- Stat cards -->\n <div id=\"text-stat1\" class=\"text-overlay stat-text\">\n <span class=\"stat-label\">Temperature</span>\n <span class=\"stat-value\"\n ><span id=\"temp-value\">21</span><span class=\"stat-unit\">&deg;</span></span\n >\n <div class=\"mini-meter\"><div id=\"temp-meter\" class=\"mini-meter-fill\"></div></div>\n </div>\n <div id=\"text-stat2\" class=\"text-overlay stat-text\">\n <span class=\"stat-label\">Battery</span>\n <div class=\"battery-shell\"><div id=\"battery-fill\" class=\"battery-fill\"></div></div>\n <span class=\"stat-value\"\n ><span id=\"battery-value\">87</span><span class=\"stat-unit\">%</span></span\n >\n </div>\n <div id=\"text-stat3\" class=\"text-overlay stat-text\">\n <span class=\"stat-label\">Steps</span>\n <div id=\"steps-ring\" class=\"steps-ring\">\n <div id=\"steps-value\" class=\"steps-ring-inner\">8.2K</div>\n </div>\n </div>\n\n <!-- Showcase card -->\n <div id=\"text-showcase\" class=\"text-overlay showcase-text\">\n <div class=\"showcase-icon\">\n <img class=\"showcase-logo\" src=\"/public/catalog/assets/f9f942c43b465616.svg\" alt=\"HyperFrames\" />\n </div>\n <div class=\"showcase-title\">Preview pipeline</div>\n <div class=\"showcase-desc\">\n Write HTML, render video. Ship compositions at the speed of code.\n </div>\n <div class=\"showcase-status\">\n <span class=\"showcase-dot\" id=\"showcase-dot\"></span\n ><span id=\"showcase-status\">Encoding frames</span>\n </div>\n <div class=\"showcase-progress\">\n <div id=\"showcase-progress\" class=\"showcase-progress-fill\"></div>\n </div>\n </div>\n\n <!-- Pill chips -->\n <div id=\"text-pill1\" class=\"text-overlay pill-text\">\n <span class=\"pill-dot dot-green\"></span>\n <span class=\"pill-label\">Connected</span>\n </div>\n <div id=\"text-pill2\" class=\"text-overlay pill-text\">\n <span class=\"pill-dot dot-blue\"></span>\n <span class=\"pill-label\">Bluetooth</span>\n </div>\n <div id=\"text-pill3\" class=\"text-overlay pill-text\">\n <span class=\"pill-dot dot-violet\"></span>\n <span class=\"pill-label\">Focus</span>\n </div>\n\n <div\n id=\"driver\"\n class=\"clip\"\n data-start=\"0\"\n data-duration=\"8\"\n data-track-index=\"0\"\n style=\"position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none\"\n ></div>\n </div>\n\n <script>\n var W = 1920,\n H = 1080,\n DURATION = 8;\n\n /* ── Three.js Aurora Shader ─────────────────────────────────────── */\n var vs = \"varying vec2 vUv; void main() { vUv = uv; gl_Position = vec4(position, 1.0); }\";\n var fs = [\n \"precision highp float;\",\n \"varying vec2 vUv;\",\n \"uniform float uTime;\",\n \"vec3 mod289(vec3 x){return x-floor(x*(1.0/289.0))*289.0;}\",\n \"vec4 mod289(vec4 x){return x-floor(x*(1.0/289.0))*289.0;}\",\n \"vec4 permute(vec4 x){return mod289(((x*34.0)+1.0)*x);}\",\n \"vec4 taylorInvSqrt(vec4 r){return 1.79284291400159-0.85373472095314*r;}\",\n \"float snoise(vec3 v){\",\n \" const vec2 C=vec2(1.0/6.0,1.0/3.0);const vec4 D=vec4(0.0,0.5,1.0,2.0);\",\n \" vec3 i=floor(v+dot(v,C.yyy));vec3 x0=v-i+dot(i,C.xxx);\",\n \" vec3 g=step(x0.yzx,x0.xyz);vec3 l=1.0-g;\",\n \" vec3 i1=min(g.xyz,l.zxy);vec3 i2=max(g.xyz,l.zxy);\",\n \" vec3 x1=x0-i1+C.xxx;vec3 x2=x0-i2+C.yyy;vec3 x3=x0-D.yyy;\",\n \" i=mod289(i);\",\n \" vec4 p=permute(permute(permute(i.z+vec4(0.0,i1.z,i2.z,1.0))+i.y+vec4(0.0,i1.y,i2.y,1.0))+i.x+vec4(0.0,i1.x,i2.x,1.0));\",\n \" float n_=0.142857142857;vec3 ns=n_*D.wyz-D.xzx;\",\n \" vec4 j=p-49.0*floor(p*ns.z*ns.z);vec4 x_=floor(j*ns.z);vec4 y_=floor(j-7.0*x_);\",\n \" vec4 x=x_*ns.x+ns.yyyy;vec4 y=y_*ns.x+ns.yyyy;vec4 h=1.0-abs(x)-abs(y);\",\n \" vec4 b0=vec4(x.xy,y.xy);vec4 b1=vec4(x.zw,y.zw);\",\n \" vec4 s0=floor(b0)*2.0+1.0;vec4 s1=floor(b1)*2.0+1.0;\",\n \" vec4 sh=-step(h,vec4(0.0));\",\n \" vec4 a0=b0.xzyw+s0.xzyw*sh.xxyy;vec4 a1=b1.xzyw+s1.xzyw*sh.zzww;\",\n \" vec3 p0=vec3(a0.xy,h.x);vec3 p1=vec3(a0.zw,h.y);vec3 p2=vec3(a1.xy,h.z);vec3 p3=vec3(a1.zw,h.w);\",\n \" vec4 norm=taylorInvSqrt(vec4(dot(p0,p0),dot(p1,p1),dot(p2,p2),dot(p3,p3)));\",\n \" p0*=norm.x;p1*=norm.y;p2*=norm.z;p3*=norm.w;\",\n \" vec4 m=max(0.6-vec4(dot(x0,x0),dot(x1,x1),dot(x2,x2),dot(x3,x3)),0.0);m=m*m;\",\n \" return 42.0*dot(m*m,vec4(dot(p0,x0),dot(p1,x1),dot(p2,x2),dot(p3,x3)));\",\n \"}\",\n \"void main(){\",\n \" vec2 uv=vUv;float ar=1920.0/1080.0;vec2 p=vec2(uv.x*ar,uv.y);float t=uTime*0.06;\",\n \" float wx=snoise(vec3(p*1.4,t*0.5))*0.2;float wy=snoise(vec3(p*1.4+100.0,t*0.5))*0.2;\",\n \" vec2 wp=p+vec2(wx,wy);\",\n \" vec3 base=mix(vec3(0.10,0.02,0.22),vec3(0.04,0.10,0.25),smoothstep(0.0,1.0,uv.x*0.6+uv.y*0.4));\",\n \" float angle=0.65;float ridgeUv=dot(wp,vec2(cos(angle),sin(angle)));\",\n \" float ridge1=sin(ridgeUv*8.0+t*2.0+snoise(vec3(wp*0.8,t))*1.5);\",\n \" float ridge2=sin(ridgeUv*5.5-t*1.4+snoise(vec3(wp*1.2+50.0,t*0.7))*2.0);\",\n \" float ridge3=sin(ridgeUv*12.0+t*3.0+snoise(vec3(wp*0.6+80.0,t*0.4))*1.0);\",\n \" float crease1=pow(abs(ridge1),0.35)*sign(ridge1)*0.5+0.5;\",\n \" float crease2=pow(abs(ridge2),0.4)*sign(ridge2)*0.5+0.5;\",\n \" float crease3=pow(abs(ridge3),0.5)*sign(ridge3)*0.5+0.5;\",\n \" vec3 warm=mix(vec3(0.9,0.4,0.08),vec3(0.95,0.65,0.15),crease1);\",\n \" float warmZone=smoothstep(0.15,0.75,uv.x+uv.y*0.4+snoise(vec3(uv*2.0,t))*0.3);\",\n \" vec3 cool=mix(vec3(0.02,0.4,0.55),vec3(0.25,0.7,0.82),crease2);\",\n \" float coolZone=smoothstep(0.25,0.85,1.2-uv.x+uv.y*0.5+snoise(vec3(uv*2.0+40.0,t*0.8))*0.25);\",\n \" vec3 hot=mix(vec3(0.8,0.1,0.4),vec3(0.6,0.08,0.65),crease3);\",\n \" float hotZone=smoothstep(0.5,0.9,snoise(vec3(uv*2.5+20.0,t*0.6))*0.5+0.5);\",\n \" vec3 col=base;\",\n \" col=mix(col,warm,warmZone*0.75*smoothstep(0.3,0.7,crease1));\",\n \" col=mix(col,cool,coolZone*0.65*smoothstep(0.2,0.65,crease2));\",\n \" col=mix(col,hot,hotZone*0.5*smoothstep(0.35,0.8,crease3));\",\n \" float edgeGlow=pow(1.0-abs(ridge1),6.0)*0.4+pow(1.0-abs(ridge2),5.0)*0.25;\",\n \" col+=edgeGlow*mix(warm,cool,uv.x)*0.8;\",\n \" col*=1.0-pow(abs(ridge1),4.0)*0.15;\",\n \" float vig=1.0-smoothstep(0.5,1.5,length((uv-0.5)*vec2(1.3,1.0)));\",\n \" col*=0.65+vig*0.5;\",\n \" float luma=dot(col,vec3(0.299,0.587,0.114));col=mix(vec3(luma),col,1.5);\",\n \" col=clamp(col,0.0,1.0);col=pow(col,vec3(0.9));\",\n \" gl_FragColor=vec4(col,1.0);\",\n \"}\",\n ].join(\"\\n\");\n\n /* ── Three.js Setup ─────────────────────────────────────────────── */\n var threeCanvas = document.getElementById(\"three-canvas\");\n var renderer = new THREE.WebGLRenderer({ canvas: threeCanvas, alpha: false });\n renderer.setSize(W, H, false);\n renderer.setPixelRatio(1);\n\n var scene = new THREE.Scene();\n var camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);\n var uniforms = { uTime: { value: 0 } };\n var shaderMat = new THREE.ShaderMaterial({\n vertexShader: vs,\n fragmentShader: fs,\n uniforms: uniforms,\n });\n var quad = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), shaderMat);\n scene.add(quad);\n\n /* ── Glass Canvas ───────────────────────────────────────────────── */\n var glassCanvas = document.getElementById(\"glass-canvas\");\n var ctx = glassCanvas.getContext(\"2d\");\n var lg = new LiquidGlass.LiquidGlassCanvas(glassCanvas);\n var lgReady = false;\n\n function renderGlass(time) {\n if (!lgReady) return;\n uniforms.uTime.value = time;\n renderer.render(scene, camera);\n ctx.clearRect(0, 0, W, H);\n ctx.drawImage(threeCanvas, 0, 0, W, H);\n lg.renderGlassElements();\n }\n\n function requestGlassRender(time) {\n if (glassCanvas.requestPaint) {\n glassCanvas.onpaint = function () {\n renderGlass(time);\n };\n glassCanvas.requestPaint();\n return;\n }\n renderGlass(time);\n }\n\n lg.waitForInit().then(function (ok) {\n if (!ok) return;\n lgReady = true;\n requestGlassRender(0);\n });\n\n /* ── GSAP Timeline ──────────────────────────────────────────────── */\n window.__timelines = window.__timelines || {};\n var tl = gsap.timeline({ paused: true });\n\n /* Glass + text element pairs */\n var s1g = document.getElementById(\"glass-stat1\");\n var s2g = document.getElementById(\"glass-stat2\");\n var s3g = document.getElementById(\"glass-stat3\");\n var scg = document.getElementById(\"glass-showcase\");\n var p1g = document.getElementById(\"glass-pill1\");\n var p2g = document.getElementById(\"glass-pill2\");\n var p3g = document.getElementById(\"glass-pill3\");\n var s1t = document.getElementById(\"text-stat1\");\n var s2t = document.getElementById(\"text-stat2\");\n var s3t = document.getElementById(\"text-stat3\");\n var sct = document.getElementById(\"text-showcase\");\n var p1t = document.getElementById(\"text-pill1\");\n var p2t = document.getElementById(\"text-pill2\");\n var p3t = document.getElementById(\"text-pill3\");\n\n var tempValue = document.getElementById(\"temp-value\");\n var batteryValue = document.getElementById(\"battery-value\");\n var stepsValue = document.getElementById(\"steps-value\");\n var stepsRing = document.getElementById(\"steps-ring\");\n var showcaseStatus = document.getElementById(\"showcase-status\");\n var tempCounter = { value: 21 };\n var batteryCounter = { value: 87 };\n var stepsCounter = { value: 8.2 };\n\n // Glass panels (rasterized by the html-in-canvas API) animate top — the API\n // reads sub-pixel getComputedStyle().top, so layout-prop motion does not\n // stutter and the lint rule exempts them. Plain-DOM text overlays DO stutter on\n // layout props, so they animate the transform equivalent (y). y is relative to\n // each text element's CSS resting top (stats 300, showcase 380, pills 720), so the\n // initial seed to visual 1160 is y = 1160 - restingTop.\n var glassPanels = [s1g, s2g, s3g, scg, p1g, p2g, p3g];\n var statText = [s1t, s2t, s3t];\n var showcaseText = sct;\n var pillText = [p1t, p2t, p3t];\n gsap.set(glassPanels, { opacity: 1, top: 1160 });\n gsap.set(statText, { opacity: 1, y: 860 }); // 1160 - 300\n gsap.set(showcaseText, { opacity: 1, y: 780 }); // 1160 - 380\n gsap.set(pillText, { opacity: 1, y: 440 }); // 1160 - 720\n\n tl.to(s1g, { top: 300, duration: 0.46, ease: \"power3.out\" }, 0.12);\n tl.to(s1t, { y: 0, duration: 0.46, ease: \"power3.out\" }, 0.12); // 300 - 300\n tl.to(s2g, { top: 300, duration: 0.46, ease: \"power3.out\" }, 0.24);\n tl.to(s2t, { y: 0, duration: 0.46, ease: \"power3.out\" }, 0.24); // 300 - 300\n tl.to(s3g, { top: 300, duration: 0.46, ease: \"power3.out\" }, 0.36);\n tl.to(s3t, { y: 0, duration: 0.46, ease: \"power3.out\" }, 0.36); // 300 - 300\n tl.to(scg, { top: 380, duration: 0.5, ease: \"power3.out\" }, 0.5);\n tl.to(sct, { y: 0, duration: 0.5, ease: \"power3.out\" }, 0.5); // 380 - 380\n tl.to(p1g, { top: 720, duration: 0.32, ease: \"power3.out\" }, 0.9);\n tl.to(p1t, { y: 0, duration: 0.32, ease: \"power3.out\" }, 0.9); // 720 - 720\n tl.to(p2g, { top: 720, duration: 0.32, ease: \"power3.out\" }, 1.0);\n tl.to(p2t, { y: 0, duration: 0.32, ease: \"power3.out\" }, 1.0); // 720 - 720\n tl.to(p3g, { top: 720, duration: 0.32, ease: \"power3.out\" }, 1.1);\n tl.to(p3t, { y: 0, duration: 0.32, ease: \"power3.out\" }, 1.1); // 720 - 720\n\n tl.to(\"#temp-meter\", { width: \"76%\", duration: 1.7, ease: \"power2.out\" }, 0.9);\n tl.to(\n tempCounter,\n {\n value: 25,\n duration: 2.2,\n ease: \"power2.out\",\n onUpdate: function () {\n tempValue.textContent = Math.round(tempCounter.value);\n },\n },\n 0.9,\n );\n tl.to(\"#battery-fill\", { width: \"91%\", duration: 2.4, ease: \"power2.out\" }, 1.05);\n tl.to(\n batteryCounter,\n {\n value: 91,\n duration: 2.4,\n ease: \"power2.out\",\n onUpdate: function () {\n batteryValue.textContent = Math.round(batteryCounter.value);\n },\n },\n 1.05,\n );\n tl.to(\n stepsCounter,\n {\n value: 9.1,\n duration: 2.6,\n ease: \"power2.out\",\n onUpdate: function () {\n var degrees = Math.round(stepsCounter.value * 31.4);\n stepsValue.textContent = stepsCounter.value.toFixed(1) + \"K\";\n stepsRing.style.background =\n \"conic-gradient(#a78bfa 0deg, #06e3fa \" +\n degrees +\n \"deg, rgba(255, 255, 255, 0.18) \" +\n degrees +\n \"deg)\";\n },\n },\n 1.2,\n );\n tl.to(\"#showcase-progress\", { width: \"92%\", duration: 4.1, ease: \"none\" }, 1.2);\n tl.to(\n \"#showcase-dot\",\n { scale: 1.5, duration: 0.25, ease: \"power2.out\", yoyo: true, repeat: 7 },\n 1.4,\n );\n tl.call(\n function () {\n showcaseStatus.textContent = \"Preview ready\";\n },\n null,\n 5.2,\n );\n tl.to(scg, { top: \"-=10\", duration: 0.2, ease: \"power2.out\", yoyo: true, repeat: 1 }, 5.2);\n tl.to(sct, { y: \"-=10\", duration: 0.2, ease: \"power2.out\", yoyo: true, repeat: 1 }, 5.2);\n tl.to(\n \".pill-dot\",\n { scale: 1.55, duration: 0.2, ease: \"power2.out\", stagger: 0.12, yoyo: true, repeat: 3 },\n 2.2,\n );\n\n tl.to(\n [s1g, s2g, s3g],\n { top: \"-=12\", duration: 0.2, ease: \"power2.out\", yoyo: true, repeat: 1 },\n 5.7,\n );\n tl.to(\n [s1t, s2t, s3t],\n { y: \"-=12\", duration: 0.2, ease: \"power2.out\", yoyo: true, repeat: 1 },\n 5.7,\n );\n tl.to(\n [s1g, s2g, s3g, scg, p1g, p2g, p3g],\n { top: \"+=760\", duration: 0.42, ease: \"power2.in\" },\n 6.74,\n );\n tl.to(\n [s1t, s2t, s3t, sct, p1t, p2t, p3t],\n { y: \"+=760\", duration: 0.42, ease: \"power2.in\" },\n 6.74,\n );\n\n /* Duration driver */\n tl.to({ v: 0 }, { v: 1, duration: DURATION, ease: \"none\" }, 0);\n\n tl.eventCallback(\"onUpdate\", function () {\n requestGlassRender(tl.time());\n });\n\n window.__timelines[\"liquid-glass-widgets\"] = tl;\n </script>\n </body>\n</html>\n"}