Note on the filename: This file is named
migration_repl.mdas requested. The subject is regl — the WebGL helper library used underjs/webgl/, not a language “REPL”.
This document describes exactly what must change, which Matrix modes and effects are impacted, and a practical order of work to replace regl with first-party WebGL (raw WebGLRenderingContext) or another dependency that satisfies DEPENDENCY_POLICY.md. The unused twgl package has been removed from the repo.
regl is effectively unmaintained (last meaningful releases years ago). Staying on it risks:
- No fixes for new browser regressions or WebGL quirks.
- Security / supply-chain policy blocks in some orgs.
- Harder onboarding: fewer examples match current APIs.
The cost is you own the full WebGL layer that regl currently abstracts.
In js/webgl/main.js and passes, regl provides:
| Concern | regl usage today | After removal |
|---|---|---|
| Context + extensions | createREGL({ canvas, extensions, optionalExtensions }) |
canvas.getContext("webgl") or "webgl2" + manual getExtension / feature detection |
| Programs | regl({ vert, frag, uniforms, attributes, framebuffer, ... }) |
createProgram, attachShader, linkProgram, useProgram, getUniformLocation, vertexAttribPointer, etc. |
| Textures | regl.texture(...), subimage updates |
createTexture, texImage2D / texSubImage2D, format/type rules |
| Framebuffers | regl.framebuffer({ color: [...] }) |
createFramebuffer, framebufferTexture2D, completeness checks |
| Draw loop | regl.frame(callback), regl.now() |
requestAnimationFrame, performance.now() |
| State | Blending, depth, viewport inside regl({ ... }) |
Explicit gl.enable / blendFunc / viewport / VAOs if you adopt them |
| Context loss | regl helps with some lifecycle patterns | Listen for webglcontextlost / webglcontextrestored and rebuild resources |
Important: Shaders stay GLSL ES 1.00 if you keep WebGL 1. Moving to WebGL 2 implies GLSL ES 3.00 (#version 300 es) — a separate, larger shader port (every .glsl under shaders/glsl/ used by WebGL).
- Keep existing
shaders/glsl/*.glslas GLSL ES 1.00. - Replace regl calls with hand-written passes (or a new maintained helper library that passes the dependency policy — do not reintroduce unmaintained vendors “just for buffers”).
- Pros: Less shader churn. Cons: Most typing; framebuffer/half-float edge cases are yours.
getContext("webgl2"), rewrite shaders to#version 300 es, replacetexture2D→texture, varyings →in/out, etc.- Pros: Better features (multiple render targets, cleaner integer paths). Cons: Largest change set; retest every mode/effect.
- Still a full API migration from regl’s declarative style to that library’s model.
- Pros: Community maintenance. Cons: New dependency, learning curve, same pass-by-pass port.
Recommendation for this repo: Option A first (drop regl, keep WebGL1 + current GLSL), then optionally a follow-up project to WebGL2.
| Area | Reason |
|---|---|
js/webgpu/ |
Separate renderer; no regl. |
js/main.js URL routing, mode manager, gallery UI |
Still runs; only the rain WebGL module import path changes if you rename entry files. |
js/config.js versions / effects list |
Data only; unchanged unless you add renderer flags. |
| PWA shell | index.html, service-worker.js, manifest — unchanged except stop shipping lib/regl.min.js and update STATIC_ASSETS. |
npm postinstall |
Edit scripts/vendor-webgl-deps.mjs and package.json to drop regl. |
Any URL or default that ends up on renderer=webgl (default) or renderer=regl (legacy alias → webgl in parseRenderer) runs js/webgl/main.js. So every Matrix version in js/config.js versions (including aliases) is affected when that session uses WebGL.
These are the object keys defined in export const versions { ... }:
classicmegacityneomatrixologyoperatornightmareparadiseresurrectionstrinitymorpheusbugspalimpsesttwilightholoplay3d(URL:version=3d— key is the string3din code)mathcodealphabet
Assigned after the object literal:
| URL / key | Resolves to |
|---|---|
throwback |
operator |
updated |
resurrections |
1999 |
operator |
2003 |
classic |
2021 |
resurrections |
None of these change behavior for migration planning — they all still execute the WebGL pipeline when WebGL is selected.
holoplay: Forces WebGL (Looking Glass quilt path inmakeQuiltPass+lkgHelper). Highest integration risk; test hardware or LKG stubs last. Product and vendor context: HOLOPLAY.md.trinity/morpheus/bugs/holoplay/3d:volumetric: true— extra load on rain vertex shader and camera uniforms; regression-test carefully.nightmare/paradise/operator: Ripples / polar / box effects — stressesrainPass.effect.frag.glsland uniforms.
EXCLUDED_VERSIONS only contains excludeME (not a user-facing mode).
From getAvailableEffects() and js/effects.js WebGL mapping (createEffectsMapping("webgl", ...)):
| Effect | WebGL pass module | regl today |
|---|---|---|
none |
No extra pass (debug-style rain output) | rain + bloom + quilt only |
plain, palette |
palettePass.js |
yes |
customStripes, stripes, rainbow, spectrum |
stripePass.js |
yes |
image |
imagePass.js |
yes |
mirror |
mirrorPass.js (+ camera texture) |
yes |
gallery |
Not in WebGL pipeline — main.js short-circuits to gallery |
unaffected by regl removal in the rain path |
Pipeline order (from js/webgl/main.js):
makeRain → makeBloomPass → effect pass (palette / stripe / image / mirror) → makeQuiltPass → fullscreen blit to canvas.
Every stage that calls regl({...}) must be rewritten.
| File | Role |
|---|---|
js/webgl/main.js |
loadJS("lib/regl.min.js"), createREGL, regl.frame, regl.texture, pipeline glue |
js/webgl/utils.js |
makePassTexture, makePassFBO, makeDoubleBuffer, loadImage, loadText, makeFullScreenQuad, helpers used by all passes |
js/webgl/rainPass.js |
Largest: many regl({}) programs, FBOs, draw order |
js/webgl/bloomPass.js |
Multi-stage FBO + regl draws |
js/webgl/palettePass.js |
Fullscreen quad pass |
js/webgl/stripePass.js |
Fullscreen quad pass |
js/webgl/imagePass.js |
Fullscreen quad + texture |
js/webgl/mirrorPass.js |
Fullscreen + camera sampling |
js/webgl/quiltPass.js |
Holoplay quilt composite |
package.json |
Remove regl dependency |
scripts/vendor-webgl-deps.mjs |
Stop copying regl to lib/ |
service-worker.js |
Remove lib/regl.min.js from STATIC_ASSETS when file deleted |
tests/regression/matrix-full.spec.js |
Still valid; must pass after migration (WebGL-only matrix; skips experimental renderer presets). |
tests/regression/matrix-experimental-renderers.spec.js |
three-rain / p5-rain URLs; must pass if those paths change. |
README.md / RENDERING.md / .github/copilot-instructions.md |
Update wording from “regl” to new stack |
Optional: js/webgl/lkgHelper.js — may stay JS-only; verify it does not assume regl types.
- Run
npm testandnpm run test:regressiononmaster; save logs as baseline. - Freeze shader behavior: no GLSL edits in phase 1 if using WebGL 1 strategy.
- Add
js/webgl/glContext.js(name arbitrary): createsWebGLRenderingContext, requests extensions matching current list inmain.js:OES_texture_half_float,OES_texture_half_float_linear,OES_standard_derivatives,EXT_color_buffer_half_float, optionalWEBGL_color_buffer_float.
- Implement minimal helpers:
createProgram(gl, vertSrc, fragSrc),createTexture,createFramebufferColor,setViewportToCanvas. - Port
makeFullScreenQuadinutils.jsto raw GL first (one program, one VBO) — used everywhere.
Order: palettePass → stripePass → imagePass → mirrorPass → bloomPass (bloom depends on ping-pong textures like rain; may swap order with rain if easier to keep regl until bloom done — but end state is zero regl).
Each pass: preserve inputs/outputs (texture handles) so main.js pipeline shape stays { outputs: { primary }, ready, setSize, execute }.
- Replace FBO/texture creation (
makePassFBO,makeDoubleBuffer) with GL equivalents; verify half-float attachment completeness (checkFramebufferStatus). - Replace each
regl({})with aWebGLProgram+ draw call; keep static shader strings (already required after prior fixes). - Reinstall
installWebGLShaderDebugHooks(or equivalent) on the sameglyou own.
- Port
quiltPass.jslast; validate againstuseHoloplay/configfromholoplayversion. Read HOLOPLAY.md for howlkgHelperand the vendoredholoplay-coreclient fit in (regl migration does not replace that file unless you deliberately change LKG integration). - If no hardware: use mock framebuffer sizes and assert shader compile only (
lkgHelperrecorded device path).
- Replace
regl.framewithrequestAnimationFrameloop calling the sameticklogic (shouldRender,setSize,execute, blit). - Remove
loadJS("lib/regl.min.js").
- Delete
lib/regl.min.js; remove fromSTATIC_ASSETS. package.json/ lockfile /vendor-webgl-deps.mjs.- Update all docs that say “regl”.
- Half-float rain + compute FBOs: Without
EXT_color_buffer_half_float, many GPUs fail silently or produce black frames — match current extension list. - MSDF
fwidth: RequiresOES_standard_derivativeson WebGL1 (already documented in shaders). - Uniform precision: Shared
floatuniforms between vert/frag must use matching explicit precision (seerainPass.*.glslandSHADER_GUIDE.md). - SwiftShader / software GL: Keep Playwright expectations — some tests may skip WebGPU; WebGL should still link.
After migration, at minimum:
npm test(smoke + unit).npm run test:regression— iteratesgetAvailableModes()×getAvailableEffects()withrenderer=webgl(seetests/regression/matrix-full.spec.js).
That run covers every version key returned by getAvailableModes() (all keys on versions except excludeME) × every effect including gallery (gallery path uses different bootstrap but still must not regress).
Manually spot-check:
version=holoplay&renderer=webgl(or default) with LKG if available.effect=mirror&camera=true(camera texture upload path).effect=imagewith remoteurl=(CORS) and localassets/sand.png.
- Keep migration on a long-lived branch until
test:regressionis green in CI. - Tag pre-migration commit (e.g.
before-regl-removal) for bisect.
| If incomplete… | Symptom |
|---|---|
| rainPass only | Black / static screen; no rain |
| bloomPass | Rain visible but no glow / wrong exposure |
| effect pass | Rain + bloom OK but wrong colors / stripes / image / mirror |
| quiltPass | Holoplay mode broken; standard modes may still work |
| extensions | Intermittent black FBOs, link errors, or NaN tiles |
| blit to canvas | GPU works but canvas stays cleared |
End of migration guide. Filename migration_repl.md is intentional; content applies to regl removal.