vireglass 2.2.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/{adapters-DugC6Qri.d.cts → adapters-BOPIRMnL.d.cts} +3 -1
- package/dist/{adapters-BfeAopGO.d.ts → adapters-B_amRBqc.d.ts} +3 -1
- package/dist/{chunk-2XJJO7SC.js → chunk-UDPJLNFW.js} +25 -5
- package/dist/chunk-UDPJLNFW.js.map +1 -0
- package/dist/{chunk-H5QTBF67.js → chunk-V47YU75P.js} +2 -2
- package/dist/{chunk-H5QTBF67.js.map → chunk-V47YU75P.js.map} +1 -1
- package/dist/dom.cjs.map +1 -1
- package/dist/dom.d.cts +1 -1
- package/dist/dom.d.ts +1 -1
- package/dist/dom.js +1 -1
- package/dist/dom.js.map +1 -1
- package/dist/index.cjs +22 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -4
- package/dist/index.d.ts +13 -4
- package/dist/index.js +2 -2
- package/dist/web/index.cjs +282 -152
- package/dist/web/index.cjs.map +1 -1
- package/dist/web/index.d.cts +89 -3
- package/dist/web/index.d.ts +89 -3
- package/dist/web/index.js +255 -154
- package/dist/web/index.js.map +1 -1
- package/package.json +4 -2
- package/src/adapters.ts +3 -1
- package/src/dom/index.ts +6 -5
- package/src/targets/glsl.ts +31 -2
- package/src/web/gl.ts +57 -4
- package/src/web/gpu-timer.ts +111 -0
- package/src/web/index.ts +1 -0
- package/src/web/renderer.ts +305 -218
- package/dist/chunk-2XJJO7SC.js.map +0 -1
package/dist/web/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/web/gl.ts","../../src/web/probe.ts","../../src/web/renderer.ts"],"names":["slot"],"mappings":"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","file":"index.js","sourcesContent":["// Low-level GL helpers for the pipeline: program compilation, textures, FBOs, the fullscreen\n// triangle. Knows nothing about VireGlass — a reusable layer on top of WebGL2.\n\n/** The same trick as in `scripts/check-glsl.mjs`: three vertices with no buffer, indexed by\n * `gl_VertexID`. One vertex shader works for EVERY pass of the pipeline, because each fragment\n * shader pulls its own coordinate from `gl_FragCoord`. */\nexport const FULLSCREEN_TRIANGLE_VERTEX_SOURCE = `#version 300 es\nconst vec2 VG_POS[3] = vec2[3](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));\nvoid main() {\n gl_Position = vec4(VG_POS[gl_VertexID], 0.0, 1.0);\n}\n`;\n\nexport function compileShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader {\n const shader = gl.createShader(type);\n if (!shader) throw new Error('vireglass/web: gl.createShader returned null');\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const log = gl.getShaderInfoLog(shader) ?? '(no log)';\n gl.deleteShader(shader);\n throw new Error(`vireglass/web: shader failed to compile:\\n${log}`);\n }\n return shader;\n}\n\nexport function createProgram(\n gl: WebGL2RenderingContext,\n vertexSource: string,\n fragmentSource: string,\n): WebGLProgram {\n const vertex = compileShader(gl, gl.VERTEX_SHADER, vertexSource);\n const fragment = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSource);\n const program = gl.createProgram();\n if (!program) throw new Error('vireglass/web: gl.createProgram returned null');\n gl.attachShader(program, vertex);\n gl.attachShader(program, fragment);\n gl.linkProgram(program);\n gl.deleteShader(vertex);\n gl.deleteShader(fragment);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n const log = gl.getProgramInfoLog(program) ?? '(no log)';\n gl.deleteProgram(program);\n throw new Error(`vireglass/web: program failed to link:\\n${log}`);\n }\n return program;\n}\n\n/** Draws the fullscreen triangle with the current program. No attributes — the vertices are\n * baked into the shader, so even a VAO isn't needed. */\nexport function drawFullscreenTriangle(gl: WebGL2RenderingContext): void {\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n}\n\nexport type TextureOptions = {\n width: number;\n height: number;\n /** RGBA8 by default; the probe needs float when it needs more than 8 bits of precision. */\n internalFormat?: number;\n format?: number;\n type?: number;\n};\n\n/**\n * content/probe texture: LINEAR on MIN and MAG, no mipmaps, CLAMP_TO_EDGE. Skia's `.eval` is\n * bilinear by default — NEAREST would break the disc gather into pixel-stepped bands (spec §4).\n */\nexport function createTexture(gl: WebGL2RenderingContext, options: TextureOptions): WebGLTexture {\n const texture = gl.createTexture();\n if (!texture) throw new Error('vireglass/web: gl.createTexture returned null');\n const internalFormat = options.internalFormat ?? gl.RGBA8;\n const format = options.format ?? gl.RGBA;\n const type = options.type ?? gl.UNSIGNED_BYTE;\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n internalFormat,\n options.width,\n options.height,\n 0,\n format,\n type,\n null,\n );\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.bindTexture(gl.TEXTURE_2D, null);\n return texture;\n}\n\nexport function createFramebuffer(gl: WebGL2RenderingContext, texture: WebGLTexture): WebGLFramebuffer {\n const fbo = gl.createFramebuffer();\n if (!fbo) throw new Error('vireglass/web: gl.createFramebuffer returned null');\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);\n const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n if (status !== gl.FRAMEBUFFER_COMPLETE) {\n throw new Error(`vireglass/web: FBO incomplete, status ${status}`);\n }\n return fbo;\n}\n\n/** The one texture unit any pipeline pass needs here — a bind with no extra slot bookkeeping. */\nexport function bindTextureAt(\n gl: WebGL2RenderingContext,\n unit: number,\n texture: WebGLTexture,\n program: WebGLProgram,\n uniformName: string,\n): void {\n gl.activeTexture(gl.TEXTURE0 + unit);\n gl.bindTexture(gl.TEXTURE_2D, texture);\n const loc = gl.getUniformLocation(program, uniformName);\n gl.uniform1i(loc, unit);\n}\n","// Backdrop lightness probe under the lens — the web counterpart to the native capture in\n// ImageReader (`GlassLensView.kt`); see the web-core design spec and its Phase 3 plan.\n//\n// Downsampling the scene into a 48×96 grid runs as a GL pass (sampling `content` in the\n// downsample program, see `renderer.ts`), while READING the result happens here, through a PBO\n// with `fenceSync`: a synchronous `readPixels` stalls the pipeline, and a naive port stutters\n// while dragging sliders.\n//\n// Lagging by a frame or two isn't a bug, it's part of the contract (per the Phase 3 plan): we\n// read whatever the GPU already finished by the previous frame, rather than waiting on the\n// current one.\n\nimport { bindTextureAt, createFramebuffer, createProgram, drawFullscreenTriangle } from './gl';\n\nexport const PROBE_GRID_WIDTH = 48;\nexport const PROBE_GRID_HEIGHT = 96;\n\n/** Stats for the lens rectangle from a single probe sample. `null` until the first ready frame\n * has come in — the shader falls back to `u_probeLuma = -1` in that case (see `lens-shader.ts`). */\nexport type ProbeStats = {\n luma: number;\n busy: number;\n lo: number;\n hi: number;\n slopeX: number;\n slopeY: number;\n r: number;\n g: number;\n b: number;\n};\n\nconst DOWNSAMPLE_FRAGMENT_SOURCE = `#version 300 es\nprecision highp float;\nout vec4 fragColor;\nuniform sampler2D u_content;\nuniform vec2 u_contentSize;\nuniform vec2 u_gridSize;\n\n// Cell → content UV mapping. Does NOT correspond to the canvas's visible top/bottom — this is an\n// internal pass, its buffer is never displayed, only read back on the CPU with the same formula\n// (see rectStats below). It doesn't need to match the blit pass's orientation.\nvoid main() {\n vec2 uv = gl_FragCoord.xy / u_gridSize;\n vec3 sum = vec3(0.0);\n const int N = 5;\n vec2 block = u_contentSize / u_gridSize;\n vec2 origin = uv * u_contentSize;\n for (int y = 0; y < N; y++) {\n for (int x = 0; x < N; x++) {\n vec2 p = origin + (vec2(float(x), float(y)) + 0.5) * (block / float(N));\n sum += texture(u_content, p / u_contentSize).rgb;\n }\n }\n fragColor = vec4(sum / float(N * N), 1.0);\n}\n`;\n\ntype PboSlot = {\n buffer: WebGLBuffer;\n sync: WebGLSync | null;\n pending: boolean;\n};\n\nexport type ProbeRect = { centerX: number; centerY: number; halfWidth: number; halfHeight: number };\n\nexport type Probe = {\n /** Renders a downsample of the current `contentTexture` into its own FBO and advances the PBO\n * read pipeline. Returns stats for the lens rectangle — lagging by a frame or two, or `null`\n * until a reader is ready. */\n sample(\n contentTexture: WebGLTexture,\n contentWidth: number,\n contentHeight: number,\n rect: ProbeRect,\n ): ProbeStats | null;\n /** Stats for another rectangle from the ALREADY-captured grid — no new pass, no new read. */\n statsFor(contentWidth: number, contentHeight: number, rect: ProbeRect): ProbeStats | null;\n destroy(): void;\n};\n\n/** RGBA32F gives the probe sub-pixel averaging precision (spec §5: \"where the web has the edge\")\n * — without it, the sum of 25 eight-bit samples per cell gets requantized back to 8 bits, and a\n * near-black gradient slice bands right at this step. Without `EXT_color_buffer_float` we fall\n * back to RGBA8 — renders everywhere, just coarser. */\nfunction pickDownsampleFormat(\n gl: WebGL2RenderingContext,\n): { internalFormat: number; type: number; floatPrecision: boolean } {\n const hasFloat = gl.getExtension('EXT_color_buffer_float') !== null;\n return hasFloat\n ? { internalFormat: gl.RGBA32F, type: gl.FLOAT, floatPrecision: true }\n : { internalFormat: gl.RGBA8, type: gl.UNSIGNED_BYTE, floatPrecision: false };\n}\n\nfunction luma(r: number, g: number, b: number): number {\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/**\n * Rectangle stats from the 48×96 buffer. Buffer row `r` is `(r+0.5)/H` by the same formula as in\n * `DOWNSAMPLE_FRAGMENT_SOURCE`; here that same formula is inverted, so the buffer's orientation\n * (up/down) doesn't matter — only symmetry between reading and writing does.\n */\ntype DownsampleBuffer = Float32Array | Uint8Array;\n\nfunction rectStats(\n buffer: DownsampleBuffer,\n floatPrecision: boolean,\n gridW: number,\n gridH: number,\n contentWidth: number,\n contentHeight: number,\n rect: ProbeRect,\n): ProbeStats | null {\n const x0 = rect.centerX - rect.halfWidth;\n const x1 = rect.centerX + rect.halfWidth;\n const y0 = rect.centerY - rect.halfHeight;\n const y1 = rect.centerY + rect.halfHeight;\n\n const lumas: number[] = [];\n const nx: number[] = [];\n const ny: number[] = [];\n let sr = 0;\n let sg = 0;\n let sb = 0;\n\n const norm = floatPrecision ? 1 : 255;\n for (let row = 0; row < gridH; row++) {\n const cy = ((row + 0.5) / gridH) * contentHeight;\n if (cy < y0 || cy > y1) continue;\n for (let col = 0; col < gridW; col++) {\n const cx = ((col + 0.5) / gridW) * contentWidth;\n if (cx < x0 || cx > x1) continue;\n const i = (row * gridW + col) * 4;\n const r = buffer[i] / norm;\n const g = buffer[i + 1] / norm;\n const b = buffer[i + 2] / norm;\n lumas.push(luma(r, g, b));\n nx.push((cx - rect.centerX) / Math.max(rect.halfWidth, 1));\n ny.push((cy - rect.centerY) / Math.max(rect.halfHeight, 1));\n sr += r;\n sg += g;\n sb += b;\n }\n }\n const n = lumas.length;\n if (n === 0) return null;\n\n let mean = 0;\n for (const v of lumas) mean += v;\n mean /= n;\n\n let busy = 0;\n for (const v of lumas) busy += Math.abs(v - mean);\n busy = (busy / n) * 2;\n\n const sorted = [...lumas].sort((a, b) => a - b);\n const percentile = (p: number) => {\n const idx = p * (n - 1);\n const lo = Math.floor(idx);\n const hi = Math.ceil(idx);\n return sorted[lo] + (sorted[hi] - sorted[lo]) * (idx - lo);\n };\n\n const slope = (xs: number[]) => {\n let mx = 0;\n for (const v of xs) mx += v;\n mx /= n;\n let sxx = 0;\n let sxl = 0;\n for (let i = 0; i < n; i++) {\n const dx = xs[i] - mx;\n sxx += dx * dx;\n sxl += dx * (lumas[i] - mean);\n }\n return sxx > 1e-6 ? sxl / sxx : 0;\n };\n\n return {\n luma: mean,\n busy: Math.min(busy, 1),\n lo: percentile(0.1),\n hi: percentile(0.9),\n slopeX: slope(nx),\n slopeY: slope(ny),\n r: sr / n,\n g: sg / n,\n b: sb / n,\n };\n}\n\nexport function createProbe(gl: WebGL2RenderingContext, vertexSource: string): Probe {\n const program = createProgram(gl, vertexSource, DOWNSAMPLE_FRAGMENT_SOURCE);\n const format = pickDownsampleFormat(gl);\n\n const texture = gl.createTexture();\n if (!texture) throw new Error('vireglass/web/probe: gl.createTexture returned null');\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n format.internalFormat,\n PROBE_GRID_WIDTH,\n PROBE_GRID_HEIGHT,\n 0,\n gl.RGBA,\n format.type,\n null,\n );\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.bindTexture(gl.TEXTURE_2D, null);\n const fbo = createFramebuffer(gl, texture);\n\n const byteSize = PROBE_GRID_WIDTH * PROBE_GRID_HEIGHT * 4 * (format.floatPrecision ? 4 : 1);\n const slots: PboSlot[] = [0, 1].map(() => {\n const buffer = gl.createBuffer();\n if (!buffer) throw new Error('vireglass/web/probe: gl.createBuffer returned null');\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buffer);\n gl.bufferData(gl.PIXEL_PACK_BUFFER, byteSize, gl.STREAM_READ);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);\n return { buffer, sync: null, pending: false };\n });\n let cursor = 0;\n let latestRaw: DownsampleBuffer | null = null;\n\n const contentLoc = gl.getUniformLocation(program, 'u_content');\n const contentSizeLoc = gl.getUniformLocation(program, 'u_contentSize');\n const gridSizeLoc = gl.getUniformLocation(program, 'u_gridSize');\n\n function pollReady(slot: PboSlot): void {\n if (!slot.pending || !slot.sync) return;\n // The flag flushes the command queue, otherwise a fence placed after readPixels might never\n // fire at all. The wait itself is zero. WAIT_FAILED isn't \"ready\": without a separate branch\n // for it, execution fell through and read garbage out of the PBO.\n const status = gl.clientWaitSync(slot.sync, gl.SYNC_FLUSH_COMMANDS_BIT, 0);\n if (status === gl.TIMEOUT_EXPIRED || status === gl.WAIT_FAILED) return;\n gl.deleteSync(slot.sync);\n slot.sync = null;\n slot.pending = false;\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, slot.buffer);\n const out: DownsampleBuffer = format.floatPrecision\n ? new Float32Array(PROBE_GRID_WIDTH * PROBE_GRID_HEIGHT * 4)\n : new Uint8Array(PROBE_GRID_WIDTH * PROBE_GRID_HEIGHT * 4);\n gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, out);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);\n latestRaw = out;\n }\n\n function sample(\n contentTexture: WebGLTexture,\n contentWidth: number,\n contentHeight: number,\n rect: ProbeRect,\n ): ProbeStats | null {\n // Collect finished reads from PAST frames before requesting a new one.\n for (const slot of slots) pollReady(slot);\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n gl.viewport(0, 0, PROBE_GRID_WIDTH, PROBE_GRID_HEIGHT);\n gl.useProgram(program);\n bindTextureAt(gl, 0, contentTexture, program, 'u_content');\n gl.uniform1i(contentLoc, 0);\n gl.uniform2f(contentSizeLoc, contentWidth, contentHeight);\n gl.uniform2f(gridSizeLoc, PROBE_GRID_WIDTH, PROBE_GRID_HEIGHT);\n gl.disable(gl.BLEND);\n drawFullscreenTriangle(gl);\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\n const slot = slots[cursor];\n cursor = (cursor + 1) % slots.length;\n if (!slot.pending) {\n gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, slot.buffer);\n gl.readPixels(0, 0, PROBE_GRID_WIDTH, PROBE_GRID_HEIGHT, gl.RGBA, format.type, 0);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);\n gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);\n slot.sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);\n slot.pending = true;\n }\n\n return statsFor(contentWidth, contentHeight, rect);\n }\n\n // The downsample is one per frame, but a frame can have many elements: each needs stats for\n // ITS OWN rectangle out of the same grid, not its own pass and its own PBO read.\n function statsFor(contentWidth: number, contentHeight: number, rect: ProbeRect): ProbeStats | null {\n if (!latestRaw) return null;\n return rectStats(\n latestRaw,\n format.floatPrecision,\n PROBE_GRID_WIDTH,\n PROBE_GRID_HEIGHT,\n contentWidth,\n contentHeight,\n rect,\n );\n }\n\n function destroy(): void {\n for (const slot of slots) {\n if (slot.sync) gl.deleteSync(slot.sync);\n gl.deleteBuffer(slot.buffer);\n }\n gl.deleteFramebuffer(fbo);\n gl.deleteTexture(texture);\n gl.deleteProgram(program);\n }\n\n return { sample, statsFor, destroy };\n}\n","// The web lab's WebGL2 pipeline (per the Phase 3 plan; web-core spec §5). Four passes, and the\n// ordering and layer split deliberately mirror Android — the lens and the surface are NOT\n// collapsed into one pass, otherwise the lab stops predicting the phone (there they're two\n// separate layers):\n//\n// 1. scene backdrop — rasterized into an offscreen 2D canvas (text and cover art are\n// easier there than in GL) and uploaded into the `content`\n// texture. This texture plays the role of the spec's FBO(scene):\n// later passes only SAMPLE it, never redraw it.\n// 2. blit backdrop to screen — `content` is drawn as the backing; without it the screen would\n// show only the element, and the material is compared against\n// exactly what's around it.\n// 3. downsample (`probe.ts`) — stats for the lens rectangle, see there.\n// 4. lens (`toGLSL(LENS_SHADER)`) — samples `content`, draws over the backdrop.\n// 5. surface (`toGLSL(SURFACE_SHADER)`) — bevel and highlight over the lens.\n//\n// UNITS. Everything is device-px, one coordinate space for the whole canvas (web-core spec\n// §4.2): `toLensProps` already multiplies by `density`; `toSurfaceUniforms` doesn't and\n// shouldn't (its contract is shared with Android), so its result gets run through\n// `toDeviceSurfaceUniforms`.\n//\n// SHARED CENTER. On Android the lens and the surface live in THEIR OWN local spaces (different\n// `lensPadDp`/`surfacePadDp` margins), and concentricity is a convention the component\n// maintains. Here both shaders get screen coordinates directly (`gl_FragCoord`), so the only way\n// to align them is to pass the exact SAME `u_center` in canvas pixels to both: the lens gets it\n// as-is (a native uniform), the surface gets it substituted in place of the adapter's own value\n// (which is only meaningful in its own local canvas, which doesn't exist here).\nimport {\n DYNAMIC_UNIFORMS,\n ICON_UNIFORMS,\n OVERLAY_UNIFORMS,\n toLensProps,\n toDeviceSurfaceUniforms,\n toSurfaceUniforms,\n type VireGlassAccent,\n type VireGlassMorph,\n type VireGlassTouch,\n} from '../adapters';\nimport { lensPadDp, shadowOpacity, surfacePadDp, type VireGlassGeometry } from '../geometry';\nimport { LENS_SHADER } from '../lens-shader';\nimport type { VireGlassDebugMode, VireGlassOptics } from '../material';\nimport { SURFACE_SHADER } from '../surface-shader';\nimport { toGLSL } from '../targets/glsl';\nimport {\n bindTextureAt,\n createProgram,\n createTexture,\n drawFullscreenTriangle,\n FULLSCREEN_TRIANGLE_VERTEX_SOURCE,\n} from './gl';\nimport { createProbe, type ProbeStats } from './probe';\n\n/** The scene draws itself with an offset: the lenses in the frame stay put while the canvas\n * underneath them slides — only this way can you actually see what refraction does to whatever\n * passes under the element. Offset in device-px. */\nexport type VireGlassSceneDrawer = (\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n offsetX: number,\n offsetY: number,\n /** Pixels per dp — the same value used for elements. The canvas and the glass must live at the\n * same scale: as a fraction of canvas width, a cell on desktop came out five times larger than\n * on a phone, and an element of the same size looked completely different on the lab bench\n * than on a device. */\n density: number,\n) => void;\n\n/** One glass element in the frame. Each has its own material — that's how they're compared side by side. */\nexport type VireGlassPiece = {\n optics: VireGlassOptics;\n geometry: VireGlassGeometry;\n /** Element center in CANVAS PIXELS (device-px). Shared between the lens and the surface. */\n centerX: number;\n centerY: number;\n morph?: VireGlassMorph;\n /** Third shape of the same body: breaking the element into pieces uses two bridges. */\n morph2?: VireGlassMorph;\n /** Local finger response: touch point, drag, press, wave. */\n touch?: VireGlassTouch;\n /** Press response, 0…1 — the highlight blooms, the body thickens slightly. */\n press?: number;\n /** Element under the finger, 0…1 — a stronger highlight and rim light. */\n active?: number;\n /** Played fraction, 0…1: an active state expressed as a field. Omitted means no progress. */\n progress?: number;\n /** Whether to draw the icon from the frame's shared mask on this element (see `iconMask` in the frame options). */\n icon?: boolean;\n /** Whether to draw the frame's colored layer on this element (see `colorLayer`). */\n overlay?: boolean;\n /** Icon color at rest and in the active state, RGBA 0…1. */\n inkIdle?: readonly number[];\n inkActive?: readonly number[];\n /** Key light direction in screen space; defaults to the light at rest. */\n light?: readonly [number, number];\n /** 0…1: the element appearing as the lens builds up (M 2:55). */\n appear?: number;\n /** 0 — the element sinks in under the finger, 1 — it rises into glass (reference §5). */\n lift?: number;\n /** Tint for the primary action — colored glass, not a fill. */\n accent?: VireGlassAccent;\n};\n\nexport type VireGlassRenderOptions = {\n /** `devicePixelRatio` — passed as an argument rather than read globally, so the renderer stays\n * testable and isn't tied to a specific window. */\n density: number;\n debug: VireGlassDebugMode;\n pieces: readonly VireGlassPiece[];\n scene: VireGlassSceneDrawer;\n /** Canvas offset under stationary elements, device-px. */\n offsetX?: number;\n offsetY?: number;\n /**\n * Ink mask the size of the canvas, screen coordinates, read from the GREEN channel. White on\n * BLACK: antialiasing has to live in color, not alpha, otherwise green holds at one all the way\n * to the edge inside a stroke and the icon's edges tear.\n *\n * The mask does NOT carry and must not carry a calm backing under the ink: that's a property of\n * the material itself (`legibility`), the same across the whole element. While the app used to\n * supply that backing, one element had it and another didn't, with nothing to explain the\n * difference.\n */\n iconMask?: TexImageSource | null;\n /**\n * App-colored layer the size of the canvas, screen coordinates: cover art, a thumbnail —\n * anything the app puts ON the glass in color. Separate from the ink mask, because that one\n * carries a single channel colored by polarity, while this one has its own color.\n *\n * Drawn INSIDE the material, at the same coordinate as the ink: only this way does the\n * surface's deformation carry them together. As a separate layer on top of the glass, text used\n * to shake on press while the cover art stayed put.\n */\n colorLayer?: TexImageSource | null;\n};\n\nexport type VireGlassRenderResult = {\n /** One backdrop sample per element, in the same order as `pieces`. */\n probes: readonly (ProbeStats | null)[];\n};\n\nexport type VireGlassRenderer = {\n resize(widthPx: number, heightPx: number): void;\n render(options: VireGlassRenderOptions): VireGlassRenderResult;\n destroy(): void;\n};\n\nconst BLIT_FRAGMENT_SOURCE = `#version 300 es\nprecision highp float;\nout vec4 fragColor;\nuniform sampler2D u_content;\nuniform vec2 u_resolution;\nvoid main() {\n // The same Y flip the transpiler does for the lens/surface (targets/glsl.ts): content is\n // uploaded from the 2D canvas WITHOUT flipping, so its V=0 is the scene's top row. This keeps\n // the same order here, otherwise the backdrop and what the lens refracts through it drift\n // apart vertically.\n vec2 uv = gl_FragCoord.xy / u_resolution;\n uv.y = 1.0 - uv.y;\n fragColor = texture(u_content, uv);\n}\n`;\n\ntype UniformValue = number | readonly number[];\n\nfunction locationCache(gl: WebGL2RenderingContext, program: WebGLProgram) {\n const cache = new Map<string, WebGLUniformLocation | null>();\n return (name: string): WebGLUniformLocation | null => {\n let loc = cache.get(name);\n if (loc === undefined) {\n loc = gl.getUniformLocation(program, name);\n cache.set(name, loc);\n }\n return loc;\n };\n}\n\nfunction setUniform(\n gl: WebGL2RenderingContext,\n loc: WebGLUniformLocation | null,\n value: UniformValue,\n): void {\n if (!loc) return;\n if (typeof value === 'number') {\n gl.uniform1f(loc, value);\n return;\n }\n switch (value.length) {\n case 1:\n gl.uniform1f(loc, value[0]);\n break;\n case 2:\n gl.uniform2f(loc, value[0], value[1]);\n break;\n case 3:\n gl.uniform3f(loc, value[0], value[1], value[2]);\n break;\n case 4:\n gl.uniform4f(loc, value[0], value[1], value[2], value[3]);\n break;\n default:\n throw new Error(`vireglass/web: unsupported uniform size (${value.length})`);\n }\n}\n\n/** The material arrives as ONE channel (web-core spec §4, \"Uniform contract\"): name/size/value\n * as three parallel arrays — exactly the layout that used to get lost with Android Props. */\nfunction applyChannel(\n gl: WebGL2RenderingContext,\n get: (name: string) => WebGLUniformLocation | null,\n names: readonly string[],\n sizes: readonly number[],\n values: readonly number[],\n): void {\n let cursor = 0;\n for (let i = 0; i < names.length; i += 1) {\n const size = sizes[i];\n setUniform(gl, get(names[i]), values.slice(cursor, cursor + size));\n cursor += size;\n }\n}\n\nfunction applyObject(\n gl: WebGL2RenderingContext,\n get: (name: string) => WebGLUniformLocation | null,\n values: Record<string, UniformValue>,\n): void {\n for (const name of Object.keys(values)) setUniform(gl, get(name), values[name]);\n}\n\nexport function createVireGlassRenderer(canvas: HTMLCanvasElement): VireGlassRenderer {\n const context = canvas.getContext('webgl2', {\n preserveDrawingBuffer: true,\n alpha: false,\n antialias: false,\n });\n if (!context) throw new Error('vireglass/web: WebGL2 unavailable');\n // Explicit non-nullable typing — otherwise the `!context` narrowing doesn't survive the\n // closures of the nested `function resize/render/destroy` below, and tsc goes back to treating\n // `gl` as `WebGL2RenderingContext | null`.\n const gl: WebGL2RenderingContext = context;\n\n const blitProgram = createProgram(gl, FULLSCREEN_TRIANGLE_VERTEX_SOURCE, BLIT_FRAGMENT_SOURCE);\n const lensProgram = createProgram(gl, FULLSCREEN_TRIANGLE_VERTEX_SOURCE, toGLSL(LENS_SHADER));\n const surfaceProgram = createProgram(\n gl,\n FULLSCREEN_TRIANGLE_VERTEX_SOURCE,\n toGLSL(SURFACE_SHADER),\n );\n const probe = createProbe(gl, FULLSCREEN_TRIANGLE_VERTEX_SOURCE);\n\n const blitLoc = locationCache(gl, blitProgram);\n const lensLoc = locationCache(gl, lensProgram);\n const surfaceLoc = locationCache(gl, surfaceProgram);\n\n let width = canvas.width;\n let height = canvas.height;\n\n let sceneCanvas = document.createElement('canvas');\n let sceneCtx = sceneCanvas.getContext('2d');\n if (!sceneCtx) throw new Error('vireglass/web: scene 2D context unavailable');\n\n // Smoothed backdrop estimate per element: keyed by its position in the pieces list.\n const settled = new Map<number, ProbeStats>();\n /** Fraction of the new sample per frame. Same magnitude as SETTLE on Android. */\n const SETTLE = 0.12;\n\n function settleStats(index: number, fresh: ProbeStats): ProbeStats {\n const prev = settled.get(index);\n if (!prev) {\n settled.set(index, fresh);\n return fresh;\n }\n const mix = (a: number, b: number) => a + (b - a) * SETTLE;\n const next: ProbeStats = {\n luma: mix(prev.luma, fresh.luma),\n busy: mix(prev.busy, fresh.busy),\n lo: mix(prev.lo, fresh.lo),\n hi: mix(prev.hi, fresh.hi),\n slopeX: mix(prev.slopeX, fresh.slopeX),\n slopeY: mix(prev.slopeY, fresh.slopeY),\n r: mix(prev.r, fresh.r),\n g: mix(prev.g, fresh.g),\n b: mix(prev.b, fresh.b),\n };\n settled.set(index, next);\n return next;\n }\n\n let contentTexture = createTexture(gl, {\n width: Math.max(width, 1),\n height: Math.max(height, 1),\n });\n\n // The icon mask is ONE per frame, the size of the canvas. The shader samples it at the pixel's\n // screen coordinate (`u_center + p` is exactly `xy`), so each element's icon is simply drawn\n // into the mask at its own spot: no separate texture per button is needed here.\n const iconTexture = createTexture(gl, { width: 1, height: 1 });\n const colorTexture = createTexture(gl, { width: 1, height: 1 });\n gl.bindTexture(gl.TEXTURE_2D, iconTexture);\n gl.texSubImage2D(\n gl.TEXTURE_2D,\n 0,\n 0,\n 0,\n 1,\n 1,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n new Uint8Array([0, 0, 0, 0]),\n );\n gl.bindTexture(gl.TEXTURE_2D, null);\n\n function resize(widthPx: number, heightPx: number): void {\n width = Math.max(1, Math.round(widthPx));\n height = Math.max(1, Math.round(heightPx));\n canvas.width = width;\n canvas.height = height;\n gl.viewport(0, 0, width, height);\n\n sceneCanvas = document.createElement('canvas');\n sceneCanvas.width = width;\n sceneCanvas.height = height;\n sceneCtx = sceneCanvas.getContext('2d');\n if (!sceneCtx) throw new Error('vireglass/web: scene 2D context unavailable');\n\n gl.deleteTexture(contentTexture);\n contentTexture = createTexture(gl, { width, height });\n }\n\n function render(options: VireGlassRenderOptions): VireGlassRenderResult {\n if (!sceneCtx) throw new Error('vireglass/web: renderer not initialized (resize was never called)');\n\n // 1. Scene backdrop: a 2D canvas is easier for text and \"cover art\" (task, item 3), and the\n // texture itself plays the role of the plan's FBO(scene) — everything after this only reads\n // it.\n sceneCtx.clearRect(0, 0, width, height);\n options.scene(sceneCtx, width, height, options.offsetX ?? 0, options.offsetY ?? 0, options.density);\n gl.bindTexture(gl.TEXTURE_2D, contentTexture);\n gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, sceneCanvas);\n gl.bindTexture(gl.TEXTURE_2D, null);\n\n if (options.colorLayer) {\n gl.bindTexture(gl.TEXTURE_2D, colorTexture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, options.colorLayer);\n }\n if (options.iconMask) {\n gl.bindTexture(gl.TEXTURE_2D, iconTexture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, options.iconMask);\n gl.bindTexture(gl.TEXTURE_2D, null);\n }\n\n // 2. Backdrop to screen — the backing the element is seen against.\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n gl.viewport(0, 0, width, height);\n gl.disable(gl.BLEND);\n gl.disable(gl.SCISSOR_TEST);\n gl.useProgram(blitProgram);\n bindTextureAt(gl, 0, contentTexture, blitProgram, 'u_content');\n setUniform(gl, blitLoc('u_resolution'), [width, height]);\n drawFullscreenTriangle(gl);\n\n const probes: (ProbeStats | null)[] = [];\n\n for (let index = 0; index < options.pieces.length; index += 1) {\n const piece = options.pieces[index];\n\n // 3. Downsample + stats for the rectangle of VISIBLE glass (no lens/surface margins — the\n // same `glassWidth`/`glassHeight` that go into toLensProps). Only the first element\n // captures the grid: it's shared for the frame, the rest just need their own rectangle out\n // of it.\n const halfWidth = (piece.geometry.width * options.density) / 2;\n const halfHeight = (piece.geometry.height * options.density) / 2;\n const rect = {\n centerX: piece.centerX,\n centerY: piece.centerY,\n halfWidth,\n halfHeight,\n };\n const fresh =\n index === 0\n ? probe.sample(contentTexture, width, height, rect)\n : probe.statsFor(width, height, rect);\n // The backdrop estimate eases toward the new value instead of jumping to it. On Android\n // the native view does this (`GlassLensView.kt`, a per-frame SETTLE); nobody did it on the\n // web: under a moving canvas, body density used to jerk with the instantaneous sample, and\n // on screen that read as lighting artifacts.\n const stats = fresh ? settleStats(index, fresh) : null;\n probes.push(stats);\n // Restore the viewport and the content texture binding — the probe pass reuses TEXTURE0\n // and its own FBO, unbinds them itself, but does change the viewport.\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n gl.viewport(0, 0, width, height);\n\n gl.enable(gl.BLEND);\n // Premultiplied-over: both the lens and the surface emit premultiplied alpha (see `return\n // half4(half3(...) * alpha, alpha)` in both shaders).\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n\n // Both passes draw a fullscreen triangle, but the element covers only a small part of the\n // frame: without scissoring, a row of samples multiplies cost by the number of elements (on\n // a headless software renderer this pushed a frame into seconds). Margin is added on both\n // sides — the shadow, bevel and light gathering all reach past the element's own bounds.\n // The morph drop travels past the element's bounds — its travel is part of the margin,\n // otherwise scissoring would cut off the tail right where it matters.\n const reachOf = (m?: VireGlassMorph) =>\n m ? Math.hypot(m.offsetX, m.offsetY) + Math.max(m.width, m.height) / 2 + m.smoothing : 0;\n const morphReach = Math.max(reachOf(piece.morph), reachOf(piece.morph2));\n // Field deformation pushes the element's edge past its own bounds — drag, wave amplitude\n // and growth on press. Without this term, scissoring cuts off exactly the part being\n // dragged toward.\n const touchReach = piece.touch\n ? Math.hypot(piece.touch.pullX, piece.touch.pullY) +\n piece.touch.waveAmp * 2 +\n Math.max(piece.geometry.width, piece.geometry.height) * 0.05 * piece.touch.press\n : 0;\n const padPx =\n (lensPadDp(piece.geometry, piece.optics) + surfacePadDp(piece.geometry, 0) + morphReach + touchReach) *\n options.density;\n const left = Math.max(0, Math.floor(piece.centerX - halfWidth - padPx));\n const right = Math.min(width, Math.ceil(piece.centerX + halfWidth + padPx));\n const top = Math.max(0, Math.floor(height - (piece.centerY + halfHeight + padPx)));\n const bottom = Math.min(height, Math.ceil(height - (piece.centerY - halfHeight - padPx)));\n gl.enable(gl.SCISSOR_TEST);\n gl.scissor(left, top, Math.max(0, right - left), Math.max(0, bottom - top));\n\n // 4. Lens.\n gl.useProgram(lensProgram);\n bindTextureAt(gl, 0, contentTexture, lensProgram, 'content');\n setUniform(gl, lensLoc('u_contentSize'), [width, height]);\n setUniform(gl, lensLoc('u_resolution'), [width, height]);\n setUniform(gl, lensLoc('u_center'), [piece.centerX, piece.centerY]);\n // There's no local-view margin here (one shared coordinate space) — on Android `u_reach`\n // capped adaptive-blur gathering at the edge of the lens view's PADDING; there's no such\n // boundary here, so the value is chosen deliberately larger than any real gather radius, so\n // the `reach - length(p)` condition never triggers before `u_contentMin/Max` does.\n setUniform(gl, lensLoc('u_reach'), Math.max(width, height));\n setUniform(gl, lensLoc('u_contentMin'), [1, 1]);\n setUniform(gl, lensLoc('u_contentMax'), [width - 1, height - 1]);\n if (stats) {\n setUniform(gl, lensLoc('u_probeLuma'), stats.luma);\n setUniform(gl, lensLoc('u_probeBusy'), stats.busy);\n setUniform(gl, lensLoc('u_probeRange'), [stats.lo, stats.hi]);\n setUniform(gl, lensLoc('u_probeSlope'), [stats.slopeX, stats.slopeY]);\n setUniform(gl, lensLoc('u_probe'), [stats.r, stats.g, stats.b]);\n } else {\n // The probe hasn't reported yet (the first frame or two) — the -1 sentinel keeps the\n // shader on its own point samples (see the comment in `lens-shader.ts`).\n setUniform(gl, lensLoc('u_probeLuma'), -1);\n }\n const lens = toLensProps(piece.optics, piece.geometry, options.density, {\n debug: options.debug,\n morph: piece.morph,\n morph2: piece.morph2,\n touch: piece.touch,\n progress: piece.progress,\n light: piece.light,\n appear: piece.appear,\n accent: piece.accent,\n });\n applyChannel(gl, lensLoc, lens.uniformNames, lens.uniformSizes, lens.uniformValues);\n drawFullscreenTriangle(gl);\n\n // 5. Surface — shares its center with the lens (see the comment at the top of this file).\n // `toSurfaceUniforms`'s contract is dp, shared with Android; the core converts it to pixels.\n gl.useProgram(surfaceProgram);\n const rawSurface = toSurfaceUniforms(piece.optics, piece.geometry, {\n debug: options.debug,\n morph: piece.morph,\n morph2: piece.morph2,\n bodyInLens: true,\n touch: piece.touch,\n progress: piece.progress,\n // The shadow is denser over text, weaker over a flat backdrop (M 11:47). The rule lives\n // in the core: while it lived here, Android didn't have it at all.\n shadow: stats ? shadowOpacity(stats.busy) : 1,\n // The probe has already computed the ambient color — the shadow gets it for free. Taken\n // as-is: `settleStats` has already smoothed it, and rounding would bring back exactly the\n // steps the smoothing was written to remove.\n ambient: stats ? ([stats.r, stats.g, stats.b] as const) : undefined,\n appear: piece.appear,\n lift: piece.lift,\n });\n // The dp → device pixel conversion lives in the core (`toDeviceSurfaceUniforms`): one list\n // of lengths for every field, so a new field can't be forgotten here by oversight.\n applyObject(gl, surfaceLoc, {\n ...toDeviceSurfaceUniforms(rawSurface, options.density),\n u_center: [piece.centerX, piece.centerY],\n });\n // What's worklet dynamics on Android (press, active, tilt) arrives here as fields on the element.\n setUniform(gl, surfaceLoc(DYNAMIC_UNIFORMS[0]), piece.press ?? 0);\n setUniform(gl, surfaceLoc(DYNAMIC_UNIFORMS[1]), piece.active ?? 0);\n const hasIcon = Boolean(piece.icon && options.iconMask);\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[0]), hasIcon ? 1 : 0);\n // Scale 1: the coordinate is already in screen space, the sampler itself normalizes by size.\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[1]), 1);\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[2]), piece.inkIdle ?? [1, 1, 1, 1]);\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[3]), piece.inkActive ?? [1, 1, 1, 1]);\n bindTextureAt(gl, 1, iconTexture, surfaceProgram, 'u_icon');\n setUniform(gl, surfaceLoc('u_iconSize'), hasIcon ? [width, height] : [1, 1]);\n const hasColor = Boolean(piece.overlay && options.colorLayer);\n setUniform(gl, surfaceLoc(OVERLAY_UNIFORMS[0]), hasColor ? 1 : 0);\n bindTextureAt(gl, 2, colorTexture, surfaceProgram, 'u_overlay');\n setUniform(gl, surfaceLoc('u_overlaySize'), hasColor ? [width, height] : [1, 1]);\n setUniform(gl, surfaceLoc('u_resolution'), [width, height]);\n drawFullscreenTriangle(gl);\n }\n gl.disable(gl.SCISSOR_TEST);\n\n return { probes };\n }\n\n function destroy(): void {\n probe.destroy();\n gl.deleteProgram(blitProgram);\n gl.deleteProgram(lensProgram);\n gl.deleteProgram(surfaceProgram);\n gl.deleteTexture(contentTexture);\n gl.deleteTexture(iconTexture);\n gl.deleteTexture(colorTexture);\n }\n\n return { resize, render, destroy };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/web/gl.ts","../../src/web/gpu-timer.ts","../../src/web/probe.ts","../../src/web/renderer.ts"],"names":["slot"],"mappings":"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","file":"index.js","sourcesContent":["// Low-level GL helpers for the pipeline: program compilation, textures, FBOs, the fullscreen\n// triangle. Knows nothing about VireGlass — a reusable layer on top of WebGL2.\n\n/** The same trick as in `scripts/check-glsl.mjs`: three vertices with no buffer, indexed by\n * `gl_VertexID`. One vertex shader works for EVERY pass of the pipeline, because each fragment\n * shader pulls its own coordinate from `gl_FragCoord`. */\nexport const FULLSCREEN_TRIANGLE_VERTEX_SOURCE = `#version 300 es\nconst vec2 VG_POS[3] = vec2[3](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));\nvoid main() {\n gl_Position = vec4(VG_POS[gl_VertexID], 0.0, 1.0);\n}\n`;\n\nexport function compileShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader {\n const shader = gl.createShader(type);\n if (!shader) throw new Error('vireglass/web: gl.createShader returned null');\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const log = gl.getShaderInfoLog(shader) ?? '(no log)';\n gl.deleteShader(shader);\n throw new Error(`vireglass/web: shader failed to compile:\\n${log}`);\n }\n return shader;\n}\n\nexport function createProgram(\n gl: WebGL2RenderingContext,\n vertexSource: string,\n fragmentSource: string,\n): WebGLProgram {\n const vertex = compileShader(gl, gl.VERTEX_SHADER, vertexSource);\n const fragment = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSource);\n const program = gl.createProgram();\n if (!program) throw new Error('vireglass/web: gl.createProgram returned null');\n gl.attachShader(program, vertex);\n gl.attachShader(program, fragment);\n gl.linkProgram(program);\n gl.deleteShader(vertex);\n gl.deleteShader(fragment);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n const log = gl.getProgramInfoLog(program) ?? '(no log)';\n gl.deleteProgram(program);\n throw new Error(`vireglass/web: program failed to link:\\n${log}`);\n }\n return program;\n}\n\n/** Draws the fullscreen triangle with the current program. No attributes — the vertices are\n * baked into the shader, so even a VAO isn't needed. */\nexport function drawFullscreenTriangle(gl: WebGL2RenderingContext): void {\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n}\n\nexport type TextureOptions = {\n width: number;\n height: number;\n /** RGBA8 by default; the probe needs float when it needs more than 8 bits of precision. */\n internalFormat?: number;\n format?: number;\n type?: number;\n /** CLAMP_TO_EDGE by default. A simulation with a periodic domain (a tiling pattern, a torus)\n * wants REPEAT on its own textures instead — applied to both S and T, there's no case here\n * that wants them to differ. */\n wrap?: number;\n};\n\n/**\n * General-purpose texture allocator: LINEAR on MIN and MAG, no mipmaps, CLAMP_TO_EDGE by default.\n * Used throughout `web/` for `contentTexture` and the probe's downsample buffer, and public so a\n * `VireGlassBackdropPass` can build its own textures the same way. LINEAR rather than NEAREST\n * because Skia's `.eval` is bilinear by default — NEAREST would break the disc gather into\n * pixel-stepped bands (spec §4); a pass with different needs overrides `internalFormat`/`format`/\n * `type`/`wrap` directly.\n */\nexport function createTexture(gl: WebGL2RenderingContext, options: TextureOptions): WebGLTexture {\n const texture = gl.createTexture();\n if (!texture) throw new Error('vireglass/web: gl.createTexture returned null');\n const internalFormat = options.internalFormat ?? gl.RGBA8;\n const format = options.format ?? gl.RGBA;\n const type = options.type ?? gl.UNSIGNED_BYTE;\n const wrap = options.wrap ?? gl.CLAMP_TO_EDGE;\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n internalFormat,\n options.width,\n options.height,\n 0,\n format,\n type,\n null,\n );\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrap);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrap);\n gl.bindTexture(gl.TEXTURE_2D, null);\n return texture;\n}\n\nexport type UniformValue = number | readonly number[];\n\n/** One cache per program: `getUniformLocation` is a name lookup, and every piece re-sets every\n * uniform every frame. */\nexport function locationCache(gl: WebGL2RenderingContext, program: WebGLProgram) {\n const cache = new Map<string, WebGLUniformLocation | null>();\n return (name: string): WebGLUniformLocation | null => {\n let loc = cache.get(name);\n if (loc === undefined) {\n loc = gl.getUniformLocation(program, name);\n cache.set(name, loc);\n }\n return loc;\n };\n}\n\nexport function setUniform(\n gl: WebGL2RenderingContext,\n loc: WebGLUniformLocation | null,\n value: UniformValue,\n): void {\n if (!loc) return;\n if (typeof value === 'number') {\n gl.uniform1f(loc, value);\n return;\n }\n switch (value.length) {\n case 1:\n gl.uniform1f(loc, value[0]);\n break;\n case 2:\n gl.uniform2f(loc, value[0], value[1]);\n break;\n case 3:\n gl.uniform3f(loc, value[0], value[1], value[2]);\n break;\n case 4:\n gl.uniform4f(loc, value[0], value[1], value[2], value[3]);\n break;\n default:\n throw new Error(`vireglass/web: unsupported uniform size (${value.length})`);\n }\n}\n\nexport function createFramebuffer(gl: WebGL2RenderingContext, texture: WebGLTexture): WebGLFramebuffer {\n const fbo = gl.createFramebuffer();\n if (!fbo) throw new Error('vireglass/web: gl.createFramebuffer returned null');\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);\n const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n if (status !== gl.FRAMEBUFFER_COMPLETE) {\n throw new Error(`vireglass/web: FBO incomplete, status ${status}`);\n }\n return fbo;\n}\n\n/** The one texture unit any pipeline pass needs here — a bind with no extra slot bookkeeping. */\nexport function bindTextureAt(\n gl: WebGL2RenderingContext,\n unit: number,\n texture: WebGLTexture,\n program: WebGLProgram,\n uniformName: string,\n): void {\n gl.activeTexture(gl.TEXTURE0 + unit);\n gl.bindTexture(gl.TEXTURE_2D, texture);\n const loc = gl.getUniformLocation(program, uniformName);\n gl.uniform1i(loc, unit);\n}\n","// GPU timing for `VireGlassRenderer.getLastGpuMs()`, isolated from the renderer so it can be\n// unit-tested against a fake: `EXT_disjoint_timer_query_webgl2` is unavailable in the headless\n// Chromium the shader gates run in, so nothing in this repository otherwise exercises the ring\n// logic at all.\n\n/** The two tokens the extension adds; everything else the timer needs is core WebGL2. */\nexport type GpuTimerExtension = {\n readonly TIME_ELAPSED_EXT: number;\n readonly GPU_DISJOINT_EXT: number;\n};\n\n/** The slice of WebGL2 this module needs, kept narrow so a test can fake it without a real GL\n * context. A `WebGL2RenderingContext` satisfies this structurally — no cast needed at the call\n * site in `renderer.ts`. */\nexport type GpuTimerContext = {\n readonly QUERY_RESULT_AVAILABLE: number;\n readonly QUERY_RESULT: number;\n getExtension(name: string): unknown;\n createQuery(): WebGLQuery | null;\n deleteQuery(query: WebGLQuery): void;\n beginQuery(target: number, query: WebGLQuery): void;\n endQuery(target: number): void;\n getQueryParameter(query: WebGLQuery, pname: number): unknown;\n getParameter(pname: number): unknown;\n};\n\n/** Queries in flight at once. `EXT_disjoint_timer_query_webgl2` results arrive asynchronously,\n * often a few frames late, so one query per frame would mean starting a new query before the\n * previous one's result is back — undefined by spec. */\nexport const GPU_TIMER_RING_SIZE = 3;\n\ntype TimerSlot = { query: WebGLQuery; pending: boolean };\n\nexport type GpuTimer = {\n /** Runs `fn` as one timed sample. Always calls the matching `endQuery` even if `fn` throws, so\n * a frame that fails partway through (a broken backdrop pass, a validation error) never leaves\n * a query open for the next call to trip over. */\n time<T>(fn: () => T): T;\n /** `null` without the extension or while the ring hasn't produced a non-disjoint result yet. */\n getLastMs(): number | null;\n destroy(): void;\n};\n\n/** Missing the extension (most headless/CI setups, and every browser but Chromium-family in\n * practice) degrades every method here to a no-op / `null` — never an error. */\nexport function createGpuTimer(gl: GpuTimerContext): GpuTimer {\n const ext = gl.getExtension('EXT_disjoint_timer_query_webgl2') as GpuTimerExtension | null;\n const slots: TimerSlot[] = ext\n ? Array.from({ length: GPU_TIMER_RING_SIZE }, () => ({\n query: gl.createQuery() as WebGLQuery,\n pending: false,\n }))\n : [];\n let cursor = 0;\n let active: TimerSlot | null = null;\n let lastMs: number | null = null;\n\n function poll(): void {\n if (!ext) return;\n for (const slot of slots) {\n if (!slot.pending) continue;\n if (!gl.getQueryParameter(slot.query, gl.QUERY_RESULT_AVAILABLE)) continue;\n slot.pending = false;\n // A disjoint event (e.g. the GPU clock changed) invalidates every query since the last\n // check — the sample is discarded, not reported as zero or stale.\n if (gl.getParameter(ext.GPU_DISJOINT_EXT)) continue;\n const ns = gl.getQueryParameter(slot.query, gl.QUERY_RESULT) as number;\n lastMs = ns / 1e6;\n }\n }\n\n function begin(): void {\n active = null;\n if (!ext || slots.length === 0) return;\n poll();\n const slot = slots[cursor];\n // The ring hasn't caught up (this slot's previous result isn't back yet) — skip timing this\n // frame rather than reuse a query that's still in flight.\n if (slot.pending) return;\n gl.beginQuery(ext.TIME_ELAPSED_EXT, slot.query);\n active = slot;\n }\n\n function end(): void {\n if (!ext || !active) return;\n gl.endQuery(ext.TIME_ELAPSED_EXT);\n active.pending = true;\n cursor = (cursor + 1) % slots.length;\n active = null;\n }\n\n function time<T>(fn: () => T): T {\n begin();\n try {\n return fn();\n } finally {\n end();\n }\n }\n\n function getLastMs(): number | null {\n poll();\n return lastMs;\n }\n\n function destroy(): void {\n for (const slot of slots) gl.deleteQuery(slot.query);\n }\n\n return { time, getLastMs, destroy };\n}\n","// Backdrop lightness probe under the lens — the web counterpart to the native capture in\n// ImageReader (`GlassLensView.kt`); see the web-core design spec and its Phase 3 plan.\n//\n// Downsampling the scene into a 48×96 grid runs as a GL pass (sampling `content` in the\n// downsample program, see `renderer.ts`), while READING the result happens here, through a PBO\n// with `fenceSync`: a synchronous `readPixels` stalls the pipeline, and a naive port stutters\n// while dragging sliders.\n//\n// Lagging by a frame or two isn't a bug, it's part of the contract (per the Phase 3 plan): we\n// read whatever the GPU already finished by the previous frame, rather than waiting on the\n// current one.\n\nimport { bindTextureAt, createFramebuffer, createProgram, drawFullscreenTriangle } from './gl';\n\nexport const PROBE_GRID_WIDTH = 48;\nexport const PROBE_GRID_HEIGHT = 96;\n\n/** Stats for the lens rectangle from a single probe sample. `null` until the first ready frame\n * has come in — the shader falls back to `u_probeLuma = -1` in that case (see `lens-shader.ts`). */\nexport type ProbeStats = {\n luma: number;\n busy: number;\n lo: number;\n hi: number;\n slopeX: number;\n slopeY: number;\n r: number;\n g: number;\n b: number;\n};\n\nconst DOWNSAMPLE_FRAGMENT_SOURCE = `#version 300 es\nprecision highp float;\nout vec4 fragColor;\nuniform sampler2D u_content;\nuniform vec2 u_contentSize;\nuniform vec2 u_gridSize;\n\n// Cell → content UV mapping. Does NOT correspond to the canvas's visible top/bottom — this is an\n// internal pass, its buffer is never displayed, only read back on the CPU with the same formula\n// (see rectStats below). It doesn't need to match the blit pass's orientation.\nvoid main() {\n vec2 uv = gl_FragCoord.xy / u_gridSize;\n vec3 sum = vec3(0.0);\n const int N = 5;\n vec2 block = u_contentSize / u_gridSize;\n vec2 origin = uv * u_contentSize;\n for (int y = 0; y < N; y++) {\n for (int x = 0; x < N; x++) {\n vec2 p = origin + (vec2(float(x), float(y)) + 0.5) * (block / float(N));\n sum += texture(u_content, p / u_contentSize).rgb;\n }\n }\n fragColor = vec4(sum / float(N * N), 1.0);\n}\n`;\n\ntype PboSlot = {\n buffer: WebGLBuffer;\n sync: WebGLSync | null;\n pending: boolean;\n};\n\nexport type ProbeRect = { centerX: number; centerY: number; halfWidth: number; halfHeight: number };\n\nexport type Probe = {\n /** Renders a downsample of the current `contentTexture` into its own FBO and advances the PBO\n * read pipeline. Returns stats for the lens rectangle — lagging by a frame or two, or `null`\n * until a reader is ready. */\n sample(\n contentTexture: WebGLTexture,\n contentWidth: number,\n contentHeight: number,\n rect: ProbeRect,\n ): ProbeStats | null;\n /** Stats for another rectangle from the ALREADY-captured grid — no new pass, no new read. */\n statsFor(contentWidth: number, contentHeight: number, rect: ProbeRect): ProbeStats | null;\n destroy(): void;\n};\n\n/** RGBA32F gives the probe sub-pixel averaging precision (spec §5: \"where the web has the edge\")\n * — without it, the sum of 25 eight-bit samples per cell gets requantized back to 8 bits, and a\n * near-black gradient slice bands right at this step. Without `EXT_color_buffer_float` we fall\n * back to RGBA8 — renders everywhere, just coarser. */\nfunction pickDownsampleFormat(\n gl: WebGL2RenderingContext,\n): { internalFormat: number; type: number; floatPrecision: boolean } {\n const hasFloat = gl.getExtension('EXT_color_buffer_float') !== null;\n return hasFloat\n ? { internalFormat: gl.RGBA32F, type: gl.FLOAT, floatPrecision: true }\n : { internalFormat: gl.RGBA8, type: gl.UNSIGNED_BYTE, floatPrecision: false };\n}\n\nfunction luma(r: number, g: number, b: number): number {\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/**\n * Rectangle stats from the 48×96 buffer. Buffer row `r` is `(r+0.5)/H` by the same formula as in\n * `DOWNSAMPLE_FRAGMENT_SOURCE`; here that same formula is inverted, so the buffer's orientation\n * (up/down) doesn't matter — only symmetry between reading and writing does.\n */\ntype DownsampleBuffer = Float32Array | Uint8Array;\n\nfunction rectStats(\n buffer: DownsampleBuffer,\n floatPrecision: boolean,\n gridW: number,\n gridH: number,\n contentWidth: number,\n contentHeight: number,\n rect: ProbeRect,\n): ProbeStats | null {\n const x0 = rect.centerX - rect.halfWidth;\n const x1 = rect.centerX + rect.halfWidth;\n const y0 = rect.centerY - rect.halfHeight;\n const y1 = rect.centerY + rect.halfHeight;\n\n const lumas: number[] = [];\n const nx: number[] = [];\n const ny: number[] = [];\n let sr = 0;\n let sg = 0;\n let sb = 0;\n\n const norm = floatPrecision ? 1 : 255;\n for (let row = 0; row < gridH; row++) {\n const cy = ((row + 0.5) / gridH) * contentHeight;\n if (cy < y0 || cy > y1) continue;\n for (let col = 0; col < gridW; col++) {\n const cx = ((col + 0.5) / gridW) * contentWidth;\n if (cx < x0 || cx > x1) continue;\n const i = (row * gridW + col) * 4;\n const r = buffer[i] / norm;\n const g = buffer[i + 1] / norm;\n const b = buffer[i + 2] / norm;\n lumas.push(luma(r, g, b));\n nx.push((cx - rect.centerX) / Math.max(rect.halfWidth, 1));\n ny.push((cy - rect.centerY) / Math.max(rect.halfHeight, 1));\n sr += r;\n sg += g;\n sb += b;\n }\n }\n const n = lumas.length;\n if (n === 0) return null;\n\n let mean = 0;\n for (const v of lumas) mean += v;\n mean /= n;\n\n let busy = 0;\n for (const v of lumas) busy += Math.abs(v - mean);\n busy = (busy / n) * 2;\n\n const sorted = [...lumas].sort((a, b) => a - b);\n const percentile = (p: number) => {\n const idx = p * (n - 1);\n const lo = Math.floor(idx);\n const hi = Math.ceil(idx);\n return sorted[lo] + (sorted[hi] - sorted[lo]) * (idx - lo);\n };\n\n const slope = (xs: number[]) => {\n let mx = 0;\n for (const v of xs) mx += v;\n mx /= n;\n let sxx = 0;\n let sxl = 0;\n for (let i = 0; i < n; i++) {\n const dx = xs[i] - mx;\n sxx += dx * dx;\n sxl += dx * (lumas[i] - mean);\n }\n return sxx > 1e-6 ? sxl / sxx : 0;\n };\n\n return {\n luma: mean,\n busy: Math.min(busy, 1),\n lo: percentile(0.1),\n hi: percentile(0.9),\n slopeX: slope(nx),\n slopeY: slope(ny),\n r: sr / n,\n g: sg / n,\n b: sb / n,\n };\n}\n\nexport function createProbe(gl: WebGL2RenderingContext, vertexSource: string): Probe {\n const program = createProgram(gl, vertexSource, DOWNSAMPLE_FRAGMENT_SOURCE);\n const format = pickDownsampleFormat(gl);\n\n const texture = gl.createTexture();\n if (!texture) throw new Error('vireglass/web/probe: gl.createTexture returned null');\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n format.internalFormat,\n PROBE_GRID_WIDTH,\n PROBE_GRID_HEIGHT,\n 0,\n gl.RGBA,\n format.type,\n null,\n );\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.bindTexture(gl.TEXTURE_2D, null);\n const fbo = createFramebuffer(gl, texture);\n\n const byteSize = PROBE_GRID_WIDTH * PROBE_GRID_HEIGHT * 4 * (format.floatPrecision ? 4 : 1);\n const slots: PboSlot[] = [0, 1].map(() => {\n const buffer = gl.createBuffer();\n if (!buffer) throw new Error('vireglass/web/probe: gl.createBuffer returned null');\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buffer);\n gl.bufferData(gl.PIXEL_PACK_BUFFER, byteSize, gl.STREAM_READ);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);\n return { buffer, sync: null, pending: false };\n });\n let cursor = 0;\n let latestRaw: DownsampleBuffer | null = null;\n\n const contentLoc = gl.getUniformLocation(program, 'u_content');\n const contentSizeLoc = gl.getUniformLocation(program, 'u_contentSize');\n const gridSizeLoc = gl.getUniformLocation(program, 'u_gridSize');\n\n function pollReady(slot: PboSlot): void {\n if (!slot.pending || !slot.sync) return;\n // The flag flushes the command queue, otherwise a fence placed after readPixels might never\n // fire at all. The wait itself is zero. WAIT_FAILED isn't \"ready\": without a separate branch\n // for it, execution fell through and read garbage out of the PBO.\n const status = gl.clientWaitSync(slot.sync, gl.SYNC_FLUSH_COMMANDS_BIT, 0);\n if (status === gl.TIMEOUT_EXPIRED || status === gl.WAIT_FAILED) return;\n gl.deleteSync(slot.sync);\n slot.sync = null;\n slot.pending = false;\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, slot.buffer);\n const out: DownsampleBuffer = format.floatPrecision\n ? new Float32Array(PROBE_GRID_WIDTH * PROBE_GRID_HEIGHT * 4)\n : new Uint8Array(PROBE_GRID_WIDTH * PROBE_GRID_HEIGHT * 4);\n gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, out);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);\n latestRaw = out;\n }\n\n function sample(\n contentTexture: WebGLTexture,\n contentWidth: number,\n contentHeight: number,\n rect: ProbeRect,\n ): ProbeStats | null {\n // Collect finished reads from PAST frames before requesting a new one.\n for (const slot of slots) pollReady(slot);\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n gl.viewport(0, 0, PROBE_GRID_WIDTH, PROBE_GRID_HEIGHT);\n gl.useProgram(program);\n bindTextureAt(gl, 0, contentTexture, program, 'u_content');\n gl.uniform1i(contentLoc, 0);\n gl.uniform2f(contentSizeLoc, contentWidth, contentHeight);\n gl.uniform2f(gridSizeLoc, PROBE_GRID_WIDTH, PROBE_GRID_HEIGHT);\n gl.disable(gl.BLEND);\n drawFullscreenTriangle(gl);\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\n const slot = slots[cursor];\n cursor = (cursor + 1) % slots.length;\n if (!slot.pending) {\n gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, slot.buffer);\n gl.readPixels(0, 0, PROBE_GRID_WIDTH, PROBE_GRID_HEIGHT, gl.RGBA, format.type, 0);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);\n gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);\n slot.sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);\n slot.pending = true;\n }\n\n return statsFor(contentWidth, contentHeight, rect);\n }\n\n // The downsample is one per frame, but a frame can have many elements: each needs stats for\n // ITS OWN rectangle out of the same grid, not its own pass and its own PBO read.\n function statsFor(contentWidth: number, contentHeight: number, rect: ProbeRect): ProbeStats | null {\n if (!latestRaw) return null;\n return rectStats(\n latestRaw,\n format.floatPrecision,\n PROBE_GRID_WIDTH,\n PROBE_GRID_HEIGHT,\n contentWidth,\n contentHeight,\n rect,\n );\n }\n\n function destroy(): void {\n for (const slot of slots) {\n if (slot.sync) gl.deleteSync(slot.sync);\n gl.deleteBuffer(slot.buffer);\n }\n gl.deleteFramebuffer(fbo);\n gl.deleteTexture(texture);\n gl.deleteProgram(program);\n }\n\n return { sample, statsFor, destroy };\n}\n","// The web lab's WebGL2 pipeline (per the Phase 3 plan; web-core spec §5). Four passes, and the\n// ordering and layer split deliberately mirror Android — the lens and the surface are NOT\n// collapsed into one pass, otherwise the lab stops predicting the phone (there they're two\n// separate layers):\n//\n// 1. backdrop — fills the `content` texture one of two ways: `scene` rasterizes\n// into an offscreen 2D canvas (text and cover art are easier there\n// than in GL) and uploads it via `texSubImage2D`; `backdrop` draws\n// straight into `content` with its own GPU pass instead, no canvas,\n// no readback (see `VireGlassBackdropPass`). Either way the texture\n// plays the role of the spec's FBO(scene): later passes only SAMPLE\n// it, never redraw it.\n// 2. blit backdrop to screen — `content` is drawn as the backing; without it the screen would\n// show only the element, and the material is compared against\n// exactly what's around it.\n// 3. downsample (`probe.ts`) — stats for the lens rectangle, see there.\n// 4. lens (`toGLSL(LENS_SHADER)`) — samples `content`, draws over the backdrop.\n// 5. surface (`toGLSL(SURFACE_SHADER)`) — bevel and highlight over the lens.\n//\n// UNITS. Everything is device-px, one coordinate space for the whole canvas (web-core spec\n// §4.2): `toLensProps` already multiplies by `density`; `toSurfaceUniforms` doesn't and\n// shouldn't (its contract is shared with Android), so its result gets run through\n// `toDeviceSurfaceUniforms`.\n//\n// SHARED CENTER. On Android the lens and the surface live in THEIR OWN local spaces (different\n// `lensPadDp`/`surfacePadDp` margins), and concentricity is a convention the component\n// maintains. Here both shaders get screen coordinates directly (`gl_FragCoord`), so the only way\n// to align them is to pass the exact SAME `u_center` in canvas pixels to both: the lens gets it\n// as-is (a native uniform), the surface gets it substituted in place of the adapter's own value\n// (which is only meaningful in its own local canvas, which doesn't exist here).\nimport {\n DYNAMIC_UNIFORMS,\n ICON_UNIFORMS,\n OVERLAY_UNIFORMS,\n toLensProps,\n toDeviceSurfaceUniforms,\n toSurfaceUniforms,\n type VireGlassAccent,\n type VireGlassMorph,\n type VireGlassTouch,\n} from '../adapters';\nimport { lensPadDp, shadowOpacity, surfacePadDp, type VireGlassGeometry } from '../geometry';\nimport { LENS_SHADER } from '../lens-shader';\nimport type { VireGlassDebugMode, VireGlassOptics } from '../material';\nimport { SURFACE_SHADER } from '../surface-shader';\nimport { toGLSL } from '../targets/glsl';\nimport {\n bindTextureAt,\n createFramebuffer,\n createProgram,\n createTexture,\n drawFullscreenTriangle,\n FULLSCREEN_TRIANGLE_VERTEX_SOURCE,\n locationCache,\n setUniform,\n type UniformValue,\n} from './gl';\nimport { createGpuTimer } from './gpu-timer';\nimport { createProbe, type ProbeStats } from './probe';\n\n/** The scene draws itself with an offset: the lenses in the frame stay put while the canvas\n * underneath them slides — only this way can you actually see what refraction does to whatever\n * passes under the element. Offset in device-px. */\nexport type VireGlassSceneDrawer = (\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n offsetX: number,\n offsetY: number,\n /** Pixels per dp — the same value used for elements. The canvas and the glass must live at the\n * same scale: as a fraction of canvas width, a cell on desktop came out five times larger than\n * on a phone, and an element of the same size looked completely different on the lab bench\n * than on a device. */\n density: number,\n) => void;\n\n/** The target a `VireGlassBackdropPass` must finish its frame in — the FBO wraps `contentTexture`\n * itself, so drawing into it needs no readback: the very texture the lens samples gets the pixels\n * directly. */\nexport type VireGlassBackdropTarget = {\n /** Owned by the renderer — the FBO wrapping `contentTexture` itself, recreated on `resize` and\n * freed in `destroy`. The pass must not delete it, and must not hold onto it past the call:\n * the object may be gone or pointing at a different texture by the next `render()`. */\n framebuffer: WebGLFramebuffer;\n width: number;\n height: number;\n};\n\n/**\n * Alternative to `scene`: draws the backdrop with a GPU pass, in this same WebGL2 context, straight\n * into the texture the lens samples — no offscreen 2D canvas, no `texSubImage2D` readback. The\n * renderer doesn't know or care what's drawn; a fluid sim, a video frame, anything that ends up as\n * pixels.\n *\n * ORIENTATION CONTRACT. `contentTexture` carries the same layout the `scene` path has always\n * produced: uploaded from a 2D canvas without a Y flip, so texel row 0 (`v≈0`) is the scene's TOP\n * row (see `BLIT_FRAGMENT_SOURCE` below) — and that row sits at `gl_FragCoord.y = 0` in this FBO,\n * the window-coordinate BOTTOM, not the top. A pass that copies an ordinary top-row-first image\n * (one loaded the normal way, via `texImage2D` from a canvas or an `<img>`) straight across with\n * `texture(src, gl_FragCoord.xy / vec2(target.width, target.height))` reproduces it correctly,\n * with no flip of its own. A pass that instead treats INCREASING y as its own \"up\" — the natural\n * convention for a physical simulation — must flip before this final write, or its top ends up\n * stored as the scene's bottom and appears upside down once the lens samples it.\n *\n * The pass may render through as many of its own FBOs first as it likes (a multi-step simulation)\n * and leave the GL context in whatever state suits it; it must finish by drawing into\n * `target.framebuffer` at `viewport(0, 0, target.width, target.height)`. The renderer puts back\n * every piece of state its own remaining steps depend on right after — framebuffer, viewport,\n * blend, scissor, depth/stencil/cull, the vertex array binding, the active texture unit, and the\n * `UNPACK_*` pixel-store flags used to upload `iconMask`/`colorLayer` — so the pass is free to\n * change any of it without arranging its own cleanup.\n */\nexport type VireGlassBackdropPass = (\n gl: WebGL2RenderingContext,\n target: VireGlassBackdropTarget,\n) => void;\n\n/** One glass element in the frame. Each has its own material — that's how they're compared side by side. */\nexport type VireGlassPiece = {\n optics: VireGlassOptics;\n geometry: VireGlassGeometry;\n /** Element center in CANVAS PIXELS (device-px). Shared between the lens and the surface. */\n centerX: number;\n centerY: number;\n morph?: VireGlassMorph;\n /** Third shape of the same body: breaking the element into pieces uses two bridges. */\n morph2?: VireGlassMorph;\n /** Local finger response: touch point, drag, press, wave. */\n touch?: VireGlassTouch;\n /** Press response, 0…1 — the highlight blooms, the body thickens slightly. */\n press?: number;\n /** Element under the finger, 0…1 — a stronger highlight and rim light. */\n active?: number;\n /** Played fraction, 0…1: an active state expressed as a field. Omitted means no progress. */\n progress?: number;\n /** Whether to draw the icon from the frame's shared mask on this element (see `iconMask` in the frame options). */\n icon?: boolean;\n /** Whether to draw the frame's colored layer on this element (see `colorLayer`). */\n overlay?: boolean;\n /** Icon color at rest and in the active state, RGBA 0…1. */\n inkIdle?: readonly number[];\n inkActive?: readonly number[];\n /** Key light direction in screen space; defaults to the light at rest. */\n light?: readonly [number, number];\n /** 0…1: the element appearing as the lens builds up (M 2:55). */\n appear?: number;\n /** 0 — the element sinks in under the finger, 1 — it rises into glass (reference §5). */\n lift?: number;\n /** Tint for the primary action — colored glass, not a fill. */\n accent?: VireGlassAccent;\n};\n\nexport type VireGlassRenderOptions = {\n /** `devicePixelRatio` — passed as an argument rather than read globally, so the renderer stays\n * testable and isn't tied to a specific window. */\n density: number;\n debug: VireGlassDebugMode;\n pieces: readonly VireGlassPiece[];\n /** CPU-side backdrop: draws into an offscreen 2D canvas, uploaded via `texSubImage2D`. Exactly\n * one of `scene`/`backdrop` is required — `render()` throws if both or neither are given — see\n * `backdrop` for the GPU alternative. */\n scene?: VireGlassSceneDrawer;\n /** GPU-side backdrop: draws straight into the texture the lens samples, in this context, no\n * readback. Exactly one of `scene`/`backdrop` is required — see `VireGlassBackdropPass` for the\n * orientation contract it must honor. */\n backdrop?: VireGlassBackdropPass | null;\n /** Canvas offset under stationary elements, device-px. */\n offsetX?: number;\n offsetY?: number;\n /**\n * Ink mask the size of the canvas, screen coordinates, read from the GREEN channel. White on\n * BLACK: antialiasing has to live in color, not alpha, otherwise green holds at one all the way\n * to the edge inside a stroke and the icon's edges tear.\n *\n * The mask does NOT carry and must not carry a calm backing under the ink: that's a property of\n * the material itself (`legibility`), the same across the whole element. While the app used to\n * supply that backing, one element had it and another didn't, with nothing to explain the\n * difference.\n */\n iconMask?: TexImageSource | null;\n /**\n * App-colored layer the size of the canvas, screen coordinates: cover art, a thumbnail —\n * anything the app puts ON the glass in color. Separate from the ink mask, because that one\n * carries a single channel colored by polarity, while this one has its own color.\n *\n * Drawn INSIDE the material, at the same coordinate as the ink: only this way does the\n * surface's deformation carry them together. As a separate layer on top of the glass, text used\n * to shake on press while the cover art stayed put.\n */\n colorLayer?: TexImageSource | null;\n};\n\nexport type VireGlassRenderResult = {\n /** One backdrop sample per element, in the same order as `pieces`. */\n probes: readonly (ProbeStats | null)[];\n};\n\nexport type VireGlassRenderer = {\n resize(widthPx: number, heightPx: number): void;\n render(options: VireGlassRenderOptions): VireGlassRenderResult;\n /** GPU time of the last `render()` call, milliseconds, via\n * `EXT_disjoint_timer_query_webgl2`. `null` when the extension is unavailable or the sample\n * came back disjoint — never an error either way. */\n getLastGpuMs(): number | null;\n destroy(): void;\n};\n\nconst BLIT_FRAGMENT_SOURCE = `#version 300 es\nprecision highp float;\nout vec4 fragColor;\nuniform sampler2D u_content;\nuniform vec2 u_resolution;\nvoid main() {\n // The same Y flip the transpiler does for the lens/surface (targets/glsl.ts): content is\n // uploaded from the 2D canvas WITHOUT flipping, so its V=0 is the scene's top row. This keeps\n // the same order here, otherwise the backdrop and what the lens refracts through it drift\n // apart vertically.\n vec2 uv = gl_FragCoord.xy / u_resolution;\n uv.y = 1.0 - uv.y;\n fragColor = texture(u_content, uv);\n}\n`;\n\n/** The material arrives as ONE channel (web-core spec §4, \"Uniform contract\"): name/size/value\n * as three parallel arrays — exactly the layout that used to get lost with Android Props. */\nfunction applyChannel(\n gl: WebGL2RenderingContext,\n get: (name: string) => WebGLUniformLocation | null,\n names: readonly string[],\n sizes: readonly number[],\n values: readonly number[],\n): void {\n let cursor = 0;\n for (let i = 0; i < names.length; i += 1) {\n const size = sizes[i];\n setUniform(gl, get(names[i]), values.slice(cursor, cursor + size));\n cursor += size;\n }\n}\n\nfunction applyObject(\n gl: WebGL2RenderingContext,\n get: (name: string) => WebGLUniformLocation | null,\n values: Record<string, UniformValue>,\n): void {\n for (const name of Object.keys(values)) setUniform(gl, get(name), values[name]);\n}\n\nexport function createVireGlassRenderer(canvas: HTMLCanvasElement): VireGlassRenderer {\n const context = canvas.getContext('webgl2', {\n preserveDrawingBuffer: true,\n alpha: false,\n antialias: false,\n });\n if (!context) throw new Error('vireglass/web: WebGL2 unavailable');\n // Explicit non-nullable typing — otherwise the `!context` narrowing doesn't survive the\n // closures of the nested `function resize/render/destroy` below, and tsc goes back to treating\n // `gl` as `WebGL2RenderingContext | null`.\n const gl: WebGL2RenderingContext = context;\n\n const blitProgram = createProgram(gl, FULLSCREEN_TRIANGLE_VERTEX_SOURCE, BLIT_FRAGMENT_SOURCE);\n const lensProgram = createProgram(gl, FULLSCREEN_TRIANGLE_VERTEX_SOURCE, toGLSL(LENS_SHADER));\n const surfaceProgram = createProgram(\n gl,\n FULLSCREEN_TRIANGLE_VERTEX_SOURCE,\n toGLSL(SURFACE_SHADER),\n );\n const probe = createProbe(gl, FULLSCREEN_TRIANGLE_VERTEX_SOURCE);\n\n const blitLoc = locationCache(gl, blitProgram);\n const lensLoc = locationCache(gl, lensProgram);\n const surfaceLoc = locationCache(gl, surfaceProgram);\n\n let width = canvas.width;\n let height = canvas.height;\n\n let sceneCanvas = document.createElement('canvas');\n let sceneCtx = sceneCanvas.getContext('2d');\n if (!sceneCtx) throw new Error('vireglass/web: scene 2D context unavailable');\n\n // Smoothed backdrop estimate per element: keyed by its position in the pieces list.\n const settled = new Map<number, ProbeStats>();\n /** Fraction of the new sample per frame. Same magnitude as SETTLE on Android. */\n const SETTLE = 0.12;\n\n function settleStats(index: number, fresh: ProbeStats): ProbeStats {\n const prev = settled.get(index);\n if (!prev) {\n settled.set(index, fresh);\n return fresh;\n }\n const mix = (a: number, b: number) => a + (b - a) * SETTLE;\n const next: ProbeStats = {\n luma: mix(prev.luma, fresh.luma),\n busy: mix(prev.busy, fresh.busy),\n lo: mix(prev.lo, fresh.lo),\n hi: mix(prev.hi, fresh.hi),\n slopeX: mix(prev.slopeX, fresh.slopeX),\n slopeY: mix(prev.slopeY, fresh.slopeY),\n r: mix(prev.r, fresh.r),\n g: mix(prev.g, fresh.g),\n b: mix(prev.b, fresh.b),\n };\n settled.set(index, next);\n return next;\n }\n\n let contentTexture = createTexture(gl, {\n width: Math.max(width, 1),\n height: Math.max(height, 1),\n });\n\n // FBO for the `backdrop` path, wrapping `contentTexture` itself — lazy, so a `scene`-only\n // caller never pays for it. Stale after `resize` (it points at a texture that's about to be\n // deleted); dropped there and rebuilt against the new one on next use.\n let backdropFbo: WebGLFramebuffer | null = null;\n function ensureBackdropFbo(): WebGLFramebuffer {\n if (!backdropFbo) backdropFbo = createFramebuffer(gl, contentTexture);\n return backdropFbo;\n }\n\n // GPU timing for `getLastGpuMs()` — the ring buffer and disjoint handling live in\n // `gpu-timer.ts`, isolated so they can be unit-tested against a fake (this extension is\n // unavailable in the headless Chromium the shader gates run in).\n const gpuTimer = createGpuTimer(gl);\n\n // The icon mask is ONE per frame, the size of the canvas. The shader samples it at the pixel's\n // screen coordinate (`u_center + p` is exactly `xy`), so each element's icon is simply drawn\n // into the mask at its own spot: no separate texture per button is needed here.\n const iconTexture = createTexture(gl, { width: 1, height: 1 });\n const colorTexture = createTexture(gl, { width: 1, height: 1 });\n gl.bindTexture(gl.TEXTURE_2D, iconTexture);\n gl.texSubImage2D(\n gl.TEXTURE_2D,\n 0,\n 0,\n 0,\n 1,\n 1,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n new Uint8Array([0, 0, 0, 0]),\n );\n gl.bindTexture(gl.TEXTURE_2D, null);\n\n function resize(widthPx: number, heightPx: number): void {\n width = Math.max(1, Math.round(widthPx));\n height = Math.max(1, Math.round(heightPx));\n canvas.width = width;\n canvas.height = height;\n gl.viewport(0, 0, width, height);\n\n sceneCanvas = document.createElement('canvas');\n sceneCanvas.width = width;\n sceneCanvas.height = height;\n sceneCtx = sceneCanvas.getContext('2d');\n if (!sceneCtx) throw new Error('vireglass/web: scene 2D context unavailable');\n\n gl.deleteTexture(contentTexture);\n contentTexture = createTexture(gl, { width, height });\n\n if (backdropFbo) {\n gl.deleteFramebuffer(backdropFbo);\n backdropFbo = null;\n }\n }\n\n function render(options: VireGlassRenderOptions): VireGlassRenderResult {\n if (!sceneCtx) throw new Error('vireglass/web: renderer not initialized (resize was never called)');\n // Narrowed once, before the timed section: a `let` read from inside the closure below would\n // widen back to `| null`, since TS cannot see that nothing reassigns it in between.\n const ctx = sceneCtx;\n\n // Validated BEFORE the GPU timer starts, not inside it: a bad call here has to throw cleanly\n // with no query left open, which an error thrown mid-timing would risk.\n if (options.backdrop && options.scene) {\n throw new Error(\n 'vireglass/web: render() needs exactly one of options.scene or options.backdrop, not both',\n );\n }\n if (!options.backdrop && !options.scene) {\n throw new Error('vireglass/web: render() needs either options.scene or options.backdrop');\n }\n\n // The rest of the frame, including a caller-supplied `backdrop` pass that may itself throw\n // (a shader typo, a bad uniform), runs inside `time`'s own try/finally — `endQuery` always\n // pairs with `beginQuery` no matter how this exits.\n return gpuTimer.time((): VireGlassRenderResult => {\n // 1. Backdrop. Exactly one of two paths fills `contentTexture` — everything after this only\n // SAMPLES it, never redraws it.\n if (options.backdrop) {\n // GPU pass, straight into `contentTexture` via its own FBO: no 2D canvas, no readback. See\n // `VireGlassBackdropPass` for the orientation contract the pass has to honor.\n const fbo = ensureBackdropFbo();\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n gl.viewport(0, 0, width, height);\n options.backdrop(gl, { framebuffer: fbo, width, height });\n // The pass is free to leave the context in ANY state (per its own JSDoc) — put back\n // everything the rest of this render depends on, not just the obvious framebuffer/\n // viewport pair: a pass that enables depth/stencil/face culling, binds its own VAO, or\n // changes the unpack flags used to upload `iconMask`/`colorLayer` just below would\n // otherwise corrupt a step it never touched directly.\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n gl.viewport(0, 0, width, height);\n gl.disable(gl.BLEND);\n gl.disable(gl.SCISSOR_TEST);\n gl.disable(gl.DEPTH_TEST);\n gl.disable(gl.CULL_FACE);\n gl.disable(gl.STENCIL_TEST);\n gl.colorMask(true, true, true, true);\n gl.depthMask(true);\n gl.bindVertexArray(null);\n gl.activeTexture(gl.TEXTURE0);\n gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);\n gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);\n gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.BROWSER_DEFAULT_WEBGL);\n } else {\n // CPU-side: a 2D canvas is easier for text and \"cover art\" (task, item 3), and the texture\n // itself plays the role of the plan's FBO(scene).\n ctx.clearRect(0, 0, width, height);\n options.scene?.(ctx, width, height, options.offsetX ?? 0, options.offsetY ?? 0, options.density);\n gl.bindTexture(gl.TEXTURE_2D, contentTexture);\n gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, sceneCanvas);\n gl.bindTexture(gl.TEXTURE_2D, null);\n }\n\n if (options.colorLayer) {\n gl.bindTexture(gl.TEXTURE_2D, colorTexture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, options.colorLayer);\n }\n if (options.iconMask) {\n gl.bindTexture(gl.TEXTURE_2D, iconTexture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, options.iconMask);\n gl.bindTexture(gl.TEXTURE_2D, null);\n }\n\n // 2. Backdrop to screen — the backing the element is seen against.\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n gl.viewport(0, 0, width, height);\n gl.disable(gl.BLEND);\n gl.disable(gl.SCISSOR_TEST);\n gl.useProgram(blitProgram);\n bindTextureAt(gl, 0, contentTexture, blitProgram, 'u_content');\n setUniform(gl, blitLoc('u_resolution'), [width, height]);\n drawFullscreenTriangle(gl);\n\n const probes: (ProbeStats | null)[] = [];\n\n for (let index = 0; index < options.pieces.length; index += 1) {\n const piece = options.pieces[index];\n\n // 3. Downsample + stats for the rectangle of VISIBLE glass (no lens/surface margins — the\n // same `glassWidth`/`glassHeight` that go into toLensProps). Only the first element\n // captures the grid: it's shared for the frame, the rest just need their own rectangle out\n // of it.\n const halfWidth = (piece.geometry.width * options.density) / 2;\n const halfHeight = (piece.geometry.height * options.density) / 2;\n const rect = {\n centerX: piece.centerX,\n centerY: piece.centerY,\n halfWidth,\n halfHeight,\n };\n const fresh =\n index === 0\n ? probe.sample(contentTexture, width, height, rect)\n : probe.statsFor(width, height, rect);\n // The backdrop estimate eases toward the new value instead of jumping to it. On Android\n // the native view does this (`GlassLensView.kt`, a per-frame SETTLE); nobody did it on the\n // web: under a moving canvas, body density used to jerk with the instantaneous sample, and\n // on screen that read as lighting artifacts.\n const stats = fresh ? settleStats(index, fresh) : null;\n probes.push(stats);\n // Restore the viewport and the content texture binding — the probe pass reuses TEXTURE0\n // and its own FBO, unbinds them itself, but does change the viewport.\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n gl.viewport(0, 0, width, height);\n\n gl.enable(gl.BLEND);\n // Premultiplied-over: both the lens and the surface emit premultiplied alpha (see `return\n // half4(half3(...) * alpha, alpha)` in both shaders).\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n\n // Both passes draw a fullscreen triangle, but the element covers only a small part of the\n // frame: without scissoring, a row of samples multiplies cost by the number of elements (on\n // a headless software renderer this pushed a frame into seconds). Margin is added on both\n // sides — the shadow, bevel and light gathering all reach past the element's own bounds.\n // The morph drop travels past the element's bounds — its travel is part of the margin,\n // otherwise scissoring would cut off the tail right where it matters.\n const reachOf = (m?: VireGlassMorph) =>\n m ? Math.hypot(m.offsetX, m.offsetY) + Math.max(m.width, m.height) / 2 + m.smoothing : 0;\n const morphReach = Math.max(reachOf(piece.morph), reachOf(piece.morph2));\n // Field deformation pushes the element's edge past its own bounds — drag, wave amplitude\n // and growth on press. Without this term, scissoring cuts off exactly the part being\n // dragged toward.\n const touchReach = piece.touch\n ? Math.hypot(piece.touch.pullX, piece.touch.pullY) +\n piece.touch.waveAmp * 2 +\n Math.max(piece.geometry.width, piece.geometry.height) * 0.05 * piece.touch.press\n : 0;\n const padPx =\n (lensPadDp(piece.geometry, piece.optics) + surfacePadDp(piece.geometry, 0) + morphReach + touchReach) *\n options.density;\n const left = Math.max(0, Math.floor(piece.centerX - halfWidth - padPx));\n const right = Math.min(width, Math.ceil(piece.centerX + halfWidth + padPx));\n const top = Math.max(0, Math.floor(height - (piece.centerY + halfHeight + padPx)));\n const bottom = Math.min(height, Math.ceil(height - (piece.centerY - halfHeight - padPx)));\n gl.enable(gl.SCISSOR_TEST);\n gl.scissor(left, top, Math.max(0, right - left), Math.max(0, bottom - top));\n\n // 4. Lens.\n gl.useProgram(lensProgram);\n bindTextureAt(gl, 0, contentTexture, lensProgram, 'content');\n setUniform(gl, lensLoc('u_contentSize'), [width, height]);\n setUniform(gl, lensLoc('u_resolution'), [width, height]);\n setUniform(gl, lensLoc('u_center'), [piece.centerX, piece.centerY]);\n // There's no local-view margin here (one shared coordinate space) — on Android `u_reach`\n // capped adaptive-blur gathering at the edge of the lens view's PADDING; there's no such\n // boundary here, so the value is chosen deliberately larger than any real gather radius, so\n // the `reach - length(p)` condition never triggers before `u_contentMin/Max` does.\n setUniform(gl, lensLoc('u_reach'), Math.max(width, height));\n setUniform(gl, lensLoc('u_contentMin'), [1, 1]);\n setUniform(gl, lensLoc('u_contentMax'), [width - 1, height - 1]);\n if (stats) {\n setUniform(gl, lensLoc('u_probeLuma'), stats.luma);\n setUniform(gl, lensLoc('u_probeBusy'), stats.busy);\n setUniform(gl, lensLoc('u_probeRange'), [stats.lo, stats.hi]);\n setUniform(gl, lensLoc('u_probeSlope'), [stats.slopeX, stats.slopeY]);\n setUniform(gl, lensLoc('u_probe'), [stats.r, stats.g, stats.b]);\n } else {\n // The probe hasn't reported yet (the first frame or two) — the -1 sentinel keeps the\n // shader on its own point samples (see the comment in `lens-shader.ts`).\n setUniform(gl, lensLoc('u_probeLuma'), -1);\n }\n const lens = toLensProps(piece.optics, piece.geometry, options.density, {\n debug: options.debug,\n morph: piece.morph,\n morph2: piece.morph2,\n touch: piece.touch,\n progress: piece.progress,\n light: piece.light,\n appear: piece.appear,\n accent: piece.accent,\n });\n applyChannel(gl, lensLoc, lens.uniformNames, lens.uniformSizes, lens.uniformValues);\n drawFullscreenTriangle(gl);\n\n // 5. Surface — shares its center with the lens (see the comment at the top of this file).\n // `toSurfaceUniforms`'s contract is dp, shared with Android; the core converts it to pixels.\n gl.useProgram(surfaceProgram);\n const rawSurface = toSurfaceUniforms(piece.optics, piece.geometry, {\n debug: options.debug,\n morph: piece.morph,\n morph2: piece.morph2,\n bodyInLens: true,\n touch: piece.touch,\n progress: piece.progress,\n // The shadow is denser over text, weaker over a flat backdrop (M 11:47). The rule lives\n // in the core: while it lived here, Android didn't have it at all.\n shadow: stats ? shadowOpacity(stats.busy) : 1,\n // The probe has already computed the ambient color — the shadow gets it for free. Taken\n // as-is: `settleStats` has already smoothed it, and rounding would bring back exactly the\n // steps the smoothing was written to remove.\n ambient: stats ? ([stats.r, stats.g, stats.b] as const) : undefined,\n appear: piece.appear,\n lift: piece.lift,\n });\n // The dp → device pixel conversion lives in the core (`toDeviceSurfaceUniforms`): one list\n // of lengths for every field, so a new field can't be forgotten here by oversight.\n applyObject(gl, surfaceLoc, {\n ...toDeviceSurfaceUniforms(rawSurface, options.density),\n u_center: [piece.centerX, piece.centerY],\n });\n // What's worklet dynamics on Android (press, active, tilt) arrives here as fields on the element.\n setUniform(gl, surfaceLoc(DYNAMIC_UNIFORMS[0]), piece.press ?? 0);\n setUniform(gl, surfaceLoc(DYNAMIC_UNIFORMS[1]), piece.active ?? 0);\n const hasIcon = Boolean(piece.icon && options.iconMask);\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[0]), hasIcon ? 1 : 0);\n // Scale 1: the coordinate is already in screen space, the sampler itself normalizes by size.\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[1]), 1);\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[2]), piece.inkIdle ?? [1, 1, 1, 1]);\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[3]), piece.inkActive ?? [1, 1, 1, 1]);\n bindTextureAt(gl, 1, iconTexture, surfaceProgram, 'u_icon');\n setUniform(gl, surfaceLoc('u_iconSize'), hasIcon ? [width, height] : [1, 1]);\n const hasColor = Boolean(piece.overlay && options.colorLayer);\n setUniform(gl, surfaceLoc(OVERLAY_UNIFORMS[0]), hasColor ? 1 : 0);\n bindTextureAt(gl, 2, colorTexture, surfaceProgram, 'u_overlay');\n setUniform(gl, surfaceLoc('u_overlaySize'), hasColor ? [width, height] : [1, 1]);\n setUniform(gl, surfaceLoc('u_resolution'), [width, height]);\n drawFullscreenTriangle(gl);\n }\n gl.disable(gl.SCISSOR_TEST);\n\n return { probes };\n });\n }\n\n function destroy(): void {\n probe.destroy();\n gl.deleteProgram(blitProgram);\n gl.deleteProgram(lensProgram);\n gl.deleteProgram(surfaceProgram);\n gl.deleteTexture(contentTexture);\n gl.deleteTexture(iconTexture);\n gl.deleteTexture(colorTexture);\n if (backdropFbo) gl.deleteFramebuffer(backdropFbo);\n gpuTimer.destroy();\n }\n\n return { resize, render, getLastGpuMs: gpuTimer.getLastMs, destroy };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vireglass",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "A physically-derived liquid glass material for interfaces. One material model, three render targets: WebGL2, live DOM, and Android AGSL.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Danil Kotlaev",
|
|
@@ -89,13 +89,15 @@
|
|
|
89
89
|
"test:watch": "vitest",
|
|
90
90
|
"check:glsl": "tsx scripts/check-glsl.mjs",
|
|
91
91
|
"check:optics": "tsx scripts/check-optics.mjs",
|
|
92
|
+
"check:backdrop": "tsx scripts/check-backdrop.mjs",
|
|
92
93
|
"check:law": "node scripts/check-law.mjs",
|
|
93
94
|
"check:dom": "node scripts/check-dom.mjs",
|
|
94
95
|
"measure:dom": "node scripts/measure-dom.mjs",
|
|
95
96
|
"prepare": "tsup",
|
|
96
97
|
"check:package": "node scripts/check-package.mjs",
|
|
97
98
|
"check:readme": "node scripts/check-readme.mjs",
|
|
98
|
-
"check:agsl": "tsx scripts/check-agsl.mjs"
|
|
99
|
+
"check:agsl": "tsx scripts/check-agsl.mjs",
|
|
100
|
+
"check:english": "node scripts/check-english.mjs"
|
|
99
101
|
},
|
|
100
102
|
"peerDependencies": {
|
|
101
103
|
"@shopify/react-native-skia": ">=2.0.0",
|
package/src/adapters.ts
CHANGED
|
@@ -13,7 +13,9 @@ import { LENS_SHADER } from './lens-shader';
|
|
|
13
13
|
import { neckToBridge } from './sdf';
|
|
14
14
|
import { debugIndex, type VireGlassDebugMode, type VireGlassOptics } from './material';
|
|
15
15
|
|
|
16
|
-
/**
|
|
16
|
+
/** A second shape joined to the element by a smooth union: the geometry that merges and growth
|
|
17
|
+
* transitions are built on (a capsule drawn into a drop, then grown into its menu). Offsets from
|
|
18
|
+
* the element's centre and sizes in dp. */
|
|
17
19
|
export type VireGlassMorph = {
|
|
18
20
|
offsetX: number;
|
|
19
21
|
offsetY: number;
|
package/src/dom/index.ts
CHANGED
|
@@ -188,8 +188,9 @@ function buildFilterElement(
|
|
|
188
188
|
pass.setAttribute('xChannelSelector', 'R');
|
|
189
189
|
pass.setAttribute('yChannelSelector', 'G');
|
|
190
190
|
pass.setAttribute('result', `${name}raw`);
|
|
191
|
-
//
|
|
192
|
-
//
|
|
191
|
+
// Each channel displaces by its own share of the base scale. The share is stored on the
|
|
192
|
+
// element itself: under a press the scale is recomputed every frame, with nowhere else to
|
|
193
|
+
// recover the shares from.
|
|
193
194
|
pass.setAttribute('data-vireglass-ratio', String(scale > 0 ? chScale / scale : 1));
|
|
194
195
|
const only = document.createElementNS(SVG_NS, 'feColorMatrix');
|
|
195
196
|
only.setAttribute('in', `${name}raw`);
|
|
@@ -580,9 +581,9 @@ export function attachGlass(el: HTMLElement, opts: AttachGlassOptions = {}): Gla
|
|
|
580
581
|
if (filterEl) {
|
|
581
582
|
const feImage = filterEl.querySelector('feImage');
|
|
582
583
|
feImage?.setAttribute('href', map.url);
|
|
583
|
-
//
|
|
584
|
-
//
|
|
585
|
-
//
|
|
584
|
+
// EVERY pass, not the first. With dispersion there are three at different scales, and
|
|
585
|
+
// querySelector returned only red: under a finger it got the undispersed scale while green
|
|
586
|
+
// and blue kept their attach-time values, and the coloured rim stopped following the finger.
|
|
586
587
|
for (const pass of filterEl.querySelectorAll('feDisplacementMap')) {
|
|
587
588
|
const ratio = Number(pass.getAttribute('data-vireglass-ratio') ?? 1);
|
|
588
589
|
pass.setAttribute('scale', String(map.scale * (Number.isFinite(ratio) ? ratio : 1)));
|
package/src/targets/glsl.ts
CHANGED
|
@@ -67,11 +67,36 @@ export function convertEvalCalls(src: string): string {
|
|
|
67
67
|
return out;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/** Comments are prose, and the rewrites here are regexes over raw text: a comment mentioning
|
|
71
|
+
* "return" became one, and a brace in a comment ended the entry point early. Newlines inside
|
|
72
|
+
* block comments survive, so a compile error still points at the source line. */
|
|
73
|
+
export function stripComments(src: string): string {
|
|
74
|
+
let out = '';
|
|
75
|
+
let i = 0;
|
|
76
|
+
while (i < src.length) {
|
|
77
|
+
if (src.startsWith('//', i)) {
|
|
78
|
+
const end = src.indexOf('\n', i);
|
|
79
|
+
i = end < 0 ? src.length : end;
|
|
80
|
+
} else if (src.startsWith('/*', i)) {
|
|
81
|
+
const end = src.indexOf('*/', i + 2);
|
|
82
|
+
if (end < 0) throw new Error('vireglass/targets/glsl: unterminated block comment');
|
|
83
|
+
const stop = end + 2;
|
|
84
|
+
out += src.slice(i, stop).replace(/[^\n]/g, '');
|
|
85
|
+
i = stop;
|
|
86
|
+
} else {
|
|
87
|
+
out += src[i];
|
|
88
|
+
i += 1;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
|
|
70
94
|
/**
|
|
71
95
|
* Early `return <expression>;` inside `main` → `fragColor = <expression>; return;`. Takes ONLY
|
|
72
96
|
* the body of main (see `convertEntryPoint`) — ordinary `return`s in helper functions live
|
|
73
97
|
* outside this text and are untouched. Expressions never contain a `;` of their own (shaders have
|
|
74
|
-
* none — the only `;` lives inside `for(...)`, which isn't a return), so `[^;]+` is safe
|
|
98
|
+
* none — the only `;` lives inside `for(...)`, which isn't a return), so `[^;]+` is safe once
|
|
99
|
+
* comments are gone (`stripComments`).
|
|
75
100
|
*/
|
|
76
101
|
export function convertReturns(mainBody: string): string {
|
|
77
102
|
return mainBody.replace(/\breturn\s+([^;]+);/g, 'fragColor = $1; return;');
|
|
@@ -85,6 +110,10 @@ const ENTRY_RE = /half4\s+main\s*\(\s*float2\s+(\w+)\s*\)\s*\{/;
|
|
|
85
110
|
* origin, y up. The flip via `u_resolution.y - gl_FragCoord.y` restores the original convention
|
|
86
111
|
* (both coordinate systems center the pixel at `+0.5`, so no X shift or constant is needed).
|
|
87
112
|
* `out vec4 fragColor` and `uniform vec2 u_resolution` are declared in the prologue (`addPrologue`).
|
|
113
|
+
*
|
|
114
|
+
* `xy` and `.eval()` are flipped together — but only inside a shader THIS function translates. A
|
|
115
|
+
* `VireGlassBackdropPass` (`web/renderer.ts`) that reads its own previous frame from an FBO is raw
|
|
116
|
+
* `gl_FragCoord`, unflipped; reusing AGSL-style helpers there needs an explicit flip of its own.
|
|
88
117
|
*/
|
|
89
118
|
export function convertEntryPoint(src: string): string {
|
|
90
119
|
const match = ENTRY_RE.exec(src);
|
|
@@ -129,7 +158,7 @@ export function addPrologue(src: string): string {
|
|
|
129
158
|
* literal AGSL signature BEFORE type conversion, otherwise `half4 main(float2 xy)` can't be
|
|
130
159
|
* found. */
|
|
131
160
|
export function toGLSL(shaderSource: string): string {
|
|
132
|
-
let out = shaderSource;
|
|
161
|
+
let out = stripComments(shaderSource);
|
|
133
162
|
out = convertEntryPoint(out);
|
|
134
163
|
out = convertShaderUniforms(out);
|
|
135
164
|
out = convertEvalCalls(out);
|
package/src/web/gl.ts
CHANGED
|
@@ -59,11 +59,19 @@ export type TextureOptions = {
|
|
|
59
59
|
internalFormat?: number;
|
|
60
60
|
format?: number;
|
|
61
61
|
type?: number;
|
|
62
|
+
/** CLAMP_TO_EDGE by default. A simulation with a periodic domain (a tiling pattern, a torus)
|
|
63
|
+
* wants REPEAT on its own textures instead — applied to both S and T, there's no case here
|
|
64
|
+
* that wants them to differ. */
|
|
65
|
+
wrap?: number;
|
|
62
66
|
};
|
|
63
67
|
|
|
64
68
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
69
|
+
* General-purpose texture allocator: LINEAR on MIN and MAG, no mipmaps, CLAMP_TO_EDGE by default.
|
|
70
|
+
* Used throughout `web/` for `contentTexture` and the probe's downsample buffer, and public so a
|
|
71
|
+
* `VireGlassBackdropPass` can build its own textures the same way. LINEAR rather than NEAREST
|
|
72
|
+
* because Skia's `.eval` is bilinear by default — NEAREST would break the disc gather into
|
|
73
|
+
* pixel-stepped bands (spec §4); a pass with different needs overrides `internalFormat`/`format`/
|
|
74
|
+
* `type`/`wrap` directly.
|
|
67
75
|
*/
|
|
68
76
|
export function createTexture(gl: WebGL2RenderingContext, options: TextureOptions): WebGLTexture {
|
|
69
77
|
const texture = gl.createTexture();
|
|
@@ -71,6 +79,7 @@ export function createTexture(gl: WebGL2RenderingContext, options: TextureOption
|
|
|
71
79
|
const internalFormat = options.internalFormat ?? gl.RGBA8;
|
|
72
80
|
const format = options.format ?? gl.RGBA;
|
|
73
81
|
const type = options.type ?? gl.UNSIGNED_BYTE;
|
|
82
|
+
const wrap = options.wrap ?? gl.CLAMP_TO_EDGE;
|
|
74
83
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
75
84
|
gl.texImage2D(
|
|
76
85
|
gl.TEXTURE_2D,
|
|
@@ -85,12 +94,56 @@ export function createTexture(gl: WebGL2RenderingContext, options: TextureOption
|
|
|
85
94
|
);
|
|
86
95
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
87
96
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
88
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S,
|
|
89
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T,
|
|
97
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrap);
|
|
98
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrap);
|
|
90
99
|
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
91
100
|
return texture;
|
|
92
101
|
}
|
|
93
102
|
|
|
103
|
+
export type UniformValue = number | readonly number[];
|
|
104
|
+
|
|
105
|
+
/** One cache per program: `getUniformLocation` is a name lookup, and every piece re-sets every
|
|
106
|
+
* uniform every frame. */
|
|
107
|
+
export function locationCache(gl: WebGL2RenderingContext, program: WebGLProgram) {
|
|
108
|
+
const cache = new Map<string, WebGLUniformLocation | null>();
|
|
109
|
+
return (name: string): WebGLUniformLocation | null => {
|
|
110
|
+
let loc = cache.get(name);
|
|
111
|
+
if (loc === undefined) {
|
|
112
|
+
loc = gl.getUniformLocation(program, name);
|
|
113
|
+
cache.set(name, loc);
|
|
114
|
+
}
|
|
115
|
+
return loc;
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function setUniform(
|
|
120
|
+
gl: WebGL2RenderingContext,
|
|
121
|
+
loc: WebGLUniformLocation | null,
|
|
122
|
+
value: UniformValue,
|
|
123
|
+
): void {
|
|
124
|
+
if (!loc) return;
|
|
125
|
+
if (typeof value === 'number') {
|
|
126
|
+
gl.uniform1f(loc, value);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
switch (value.length) {
|
|
130
|
+
case 1:
|
|
131
|
+
gl.uniform1f(loc, value[0]);
|
|
132
|
+
break;
|
|
133
|
+
case 2:
|
|
134
|
+
gl.uniform2f(loc, value[0], value[1]);
|
|
135
|
+
break;
|
|
136
|
+
case 3:
|
|
137
|
+
gl.uniform3f(loc, value[0], value[1], value[2]);
|
|
138
|
+
break;
|
|
139
|
+
case 4:
|
|
140
|
+
gl.uniform4f(loc, value[0], value[1], value[2], value[3]);
|
|
141
|
+
break;
|
|
142
|
+
default:
|
|
143
|
+
throw new Error(`vireglass/web: unsupported uniform size (${value.length})`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
94
147
|
export function createFramebuffer(gl: WebGL2RenderingContext, texture: WebGLTexture): WebGLFramebuffer {
|
|
95
148
|
const fbo = gl.createFramebuffer();
|
|
96
149
|
if (!fbo) throw new Error('vireglass/web: gl.createFramebuffer returned null');
|