mirrorpool

mirrorpool · sources

MIRRORPOOL — a WebGL2 VIDEO source rendering a hemisphere pool of liquid inside a box, viewed by a full-PTZ camera you fly around within it. TWO video inputs feed the optics: POOL is surface-mapped to the INSIDE of the hemisphere (the underwater view you see refracted through the water, with Beer-Lambert depth absorption + chromatic dispersion) and SCENE is the surroundings, reflected off the surface as an overhead backdrop (projected to the box ceiling so a camera pan slides a RECOGNISABLE reflection, not a lat-long smear). A single REAL height field drives all the optics — not a flat normal-map fake: WIND raises a set of 4 directional swell waves whose amplitude grows with wavelength (dispersion omega=sqrt(g*k), so bigger crests are genuinely TALLER and travel FASTER), and RAIN runs a seeded Poisson scheduler spawning raindrop impacts that punch one-shot dimples which expand into propagating rings — sparse shallow drizzle up to a dense deep downpour. The surface NORMAL reconstructed from that height field (by finite differences, one consistent sign convention shared by the sim + swell so they never cancel) drives a physically-based Schlick FRESNEL split (water F0=0.02, eta=1/1.33). In the default REFRACT mode (MODE=0) you see the reflected scene layered over the refracted, caustic-lit pool beneath; sweep MODE toward MIRROR (1) and the surface becomes a near-full mirror of the sky/scene that the ripple normals shatter and distort — one continuous CV-friendly scalar, no branch. BRIGHT is a virtual sun scaling overall scene light uniformly (no sun disc drawn yet). The camera is a repositionable ORBIT + FREE-LOOK rig surfaced as the card's TWO X-Y pads: pad 1 POSITIONS the eye on a sphere around the pool (Orbit = azimuth around it, Elev = elevation from straight overhead down BELOW the water surface, plus a Dist dial), and pad 2 is the free-LOOK offset (Look X = yaw, Look Y = pitch) off the default aim-at-centre so the view can point any direction; Zoom sets a 70..20 degree FOV. Dropping the elevation below the surface flips the render into an underwater Snell-window path (a bright refracted cone of the sky/scene overhead, ringed by total-internal-reflection of the pool interior). Every control has a matching CV input (port id == param id + `_cv`), so patch an LFO into orbit_az_cv for a slow orbit, noise into rain_cv to gust the storm, or an envelope into surface_mode_cv to melt between a clear pool and a hard mirror. The rain wave sim runs as a float ping-pong wave-equation FBO when the GPU exposes renderable float targets, and falls back to an analytic expanding-ring model in the render shader when it does not (isFloat=false, e.g. some SwiftShader configs) so rain is never a dead field. Rendered at half engine resolution and LINEAR-upscaled (the mandelbulb perf discipline). With nothing patched it still renders a live procedural sky + rippling water, so it doubles as a standalone generative source. All ports live on the yellow drill-down PATCH PANEL (no raw side jacks). The pure physics (Fresnel / swell gradients / normal reconstruction / Poisson rain / orbit + free-look camera) is unit-tested in $lib/video/mirrorpool-core (the exact CPU mirror of the shader).

mirrorpool renders a hemisphere pool of liquid sitting in a box, viewed by a repositionable ORBIT camera you fly around the pool. Two video inputs feed the optics: POOL is surface-mapped to the INSIDE of the hemisphere (the underwater view you see refracted through the water) and SCENE is the surroundings, reflected off the surface as an overhead backdrop. A single real height field drives everything: WIND raises a set of directional swell waves (bigger waves are genuinely taller and travel faster — dispersion, not a flat normal-map trick) and RAIN spawns raindrop impacts that punch one-shot dimples which expand into propagating rings, denser and deeper from drizzle up to a downpour. The surface normal reconstructed from that height field drives a physically-based Fresnel split: in the default REFRACT mode you see the reflected scene layered over the refracted, caustic-lit, colour-absorbed pool beneath; sweep MODE toward MIRROR and the surface becomes a near-full mirror of the sky/scene that the ripples shatter and distort. BRIGHT is a virtual sun that scales overall scene light (no sun disc is drawn yet). The camera is the card's TWO X-Y pads: pad 1 POSITIONS the eye on a sphere around the pool (Orbit = azimuth around it, Elev = elevation from straight overhead down BELOW the surface for an underwater Snell's-window view) with a Dist dial for how far out it sits; pad 2 is the free-LOOK (Look X = yaw, Look Y = pitch) that swings the view off the default aim-at-centre so you can look any direction, and Zoom sets the field of view. Every control has a matching CV input, so patch an LFO into orbit_az_cv for a slow orbit, a noise source into rain_cv to gust the storm, or an envelope into surface_mode_cv to melt between a clear refractive pool and a hard mirror. With nothing patched it still renders a live procedural sky + water, so it works as a standalone generative source.

the faceplate

mirrorpoolpoolvideoscenevideowind_speed_cvcvwind_dir_cvcvrain_cvcvbrightness_cvcvsurface_mode_cvcvorbit_az_cvcvorbit_el_cvcvorbit_dist_cvcvlook_yaw_cvcvlook_pitch_cvcvzoom_cvcvvideo_outvideoaudiocvgatepitch
13 inputs · 1 outputs · 12 params

inputs

idcablewhat it does
poolvideoThe underwater view, surface-mapped to the inside of the hemisphere bowl. Sampled along the refracted ray (with Beer-Lambert depth absorption + chromatic dispersion), so it appears distorted beneath the rippling surface. Unpatched, the pool floor falls back to a murky tinted shade.
RGB video stream
scenevideoThe surroundings, reflected on the water surface as an overhead backdrop. Sampled along the reflected ray so a camera pan slides a recognisable image and the ripples break it. Unpatched, the reflection falls back to the ambient virtual-sun sky.
RGB video stream
wind_speed_cvcvModulates Wind: linear CV sweeps the swell amplitude/steepness over 0..1 — higher CV builds bigger, faster waves (taller ripples refract and reflect more).
control voltage (CV); modulates wind_speed (additive offset — ±1 CV sweeps the full range, centered on the knob)
wind_dir_cvcvModulates Dir: linear CV sweeps the wind/swell propagation direction over -pi..pi, rotating which way the wave crests travel.
control voltage (CV); modulates wind_dir (additive offset — ±1 CV sweeps the full range, centered on the knob)
rain_cvcvModulates Rain: linear CV sweeps the storm intensity over 0..1 — 0 is still, rising through drizzle and rainy to a dense downpour of expanding-ring impacts.
control voltage (CV); modulates rain (additive offset — ±1 CV sweeps the full range, centered on the knob)
brightness_cvcvModulates Bright (the virtual sun): linear CV sweeps overall scene brightness over 0..2. Higher CV brightens the reflection, caustics and glitter together (no sun disc is drawn).
control voltage (CV); modulates brightness (additive offset — ±1 CV sweeps the full range, centered on the knob)
surface_mode_cvcvModulates Mode: linear CV blends continuously from Refract (0) to Mirror (1) by raising the surface reflectivity, so an envelope can melt a clear pool into a hard mirror.
control voltage (CV); modulates surface_mode (additive offset — ±1 CV sweeps the full range, centered on the knob)
orbit_az_cvcvModulates Orbit (pad 1 X): linear CV sweeps the camera azimuth over -pi..pi, orbiting the eye around the pool. Patch a slow LFO here for a continuous orbit.
control voltage (CV); modulates orbit_az (additive offset — ±1 CV sweeps the full range, centered on the knob)
orbit_el_cvcvModulates Elev (pad 1 Y): linear CV sweeps the camera elevation over -1.45..1.45 rad; positive lifts the eye toward straight overhead, negative drops it BELOW the surface into the underwater view.
control voltage (CV); modulates orbit_el (additive offset — ±1 CV sweeps the full range, centered on the knob)
orbit_dist_cvcvModulates Dist: linear CV sweeps the camera distance from the pool centre over 0.4..5 world units — a dolly in/out.
control voltage (CV); modulates orbit_dist (additive offset — ±1 CV sweeps the full range, centered on the knob)
look_yaw_cvcvModulates Look X (pad 2 X): linear CV sweeps the free-look yaw over -pi..pi, swinging the view left/right off the default aim-at-centre.
control voltage (CV); modulates look_yaw (additive offset — ±1 CV sweeps the full range, centered on the knob)
look_pitch_cvcvModulates Look Y (pad 2 Y): linear CV sweeps the free-look pitch over -1.45..1.45 rad, tilting the view up/down off the aim-at-centre.
control voltage (CV); modulates look_pitch (additive offset — ±1 CV sweeps the full range, centered on the knob)
zoom_cvcvModulates Zoom: linear CV narrows the field of view from 70 degrees (0) to 20 degrees (1), zooming the camera in.
control voltage (CV); modulates zoom (additive offset — ±1 CV sweeps the full range, centered on the knob)

outputs

idcablewhat it does
video_outvideoThe rendered pool scene from the orbit/free-look camera (rendered at half engine resolution and LINEAR-upscaled). Always live: even with no inputs patched it shows a procedural sky + rippling water, so it doubles as a standalone generative source.
RGB video stream

params

idlabelrangedefaultcurve
wind_speedWind0..1linear
wind_dirDir?..?linear
rainRain0..1linear
brightnessBright0..2linear
surface_modeMode0..1linear
orbit_azOrbit?..?linear
orbit_elElev-1.45..1.45linear
orbit_distDist0.4..5linear
look_yawLook X?..?linear
look_pitchLook Y-1.45..1.45linear
zoomZoom0..1linear
freezeFreeze0..1linear

controls

controlwhat it does
BrightBright (0..2, default 1): the virtual-sun scene brightness. Scales the whole render (reflection, caustics, glitter and sky) uniformly. No sun disc is drawn yet.
FreezeFreeze (0/1, default 0): a hidden determinism toggle with NO control anywhere - not on the card, not on the faceplate, not on the patch surface. At 0.5 or above the draw step is a no-op, so every surface holds its last frame instead of going black. It exists because pinning the clock is not enough here: the height field is a ping-pong wave simulation that integrates once per draw, and the rain scheduler spawns new impacts from a frame counter, so two captures of the same settings are never the same pixels however the time seam is set. The visual-regression harness writes it before comparing a screenshot; nothing else ever does.
Look YLook Y (-1.45..1.45 rad, default 0): free-LOOK pitch — the Y axis of look pad 2. 0 aims at the centre; positive tilts the view up, negative down, off the aim-at-centre. Clamped to about +/-83 degrees.
Look XLook X (-pi..pi, default 0): free-LOOK yaw — the X axis of look pad 2. 0 aims straight at the pool centre so the pool is always framed at rest; sweeping it swings the view left/right so the camera can look away from the pool.
OrbitOrbit (-pi..pi, default 0): camera AZIMUTH around the pool — the X axis of position pad 1. 0 places the eye in front (on +z) aiming toward -z; sweeping it orbits the eye all the way around the pool.
DistDist (0.4..5, default 2.6): how far the eye sits from the pool centre (world units, the pool radius being 1). Small values dive in close (or inside the water); large values pull back for a wide framing.
ElevElev (-1.45..1.45 rad, default 0.55): camera ELEVATION — the Y axis of position pad 1. Positive raises the eye toward a straight-overhead bird's-eye; 0 is level with the rim; NEGATIVE drops the eye BELOW the water surface for an underwater looking-up (Snell's-window) view. Clamped to about +/-83 degrees to dodge the vertical gimbal.
RainRain (0..1, default 0.2): storm intensity from still to downpour. Drives a seeded Poisson scheduler that spawns raindrop impacts — sparse shallow dimples at drizzle, dense deep craters at downpour — each expanding into a propagating ring.
ModeMode (0..1, default 0): the continuous Refract -> Mirror blend. 0 = Fresnel refract/reflect (scene over the refracted pool); 1 = a near-full mirror of the sky/scene broken by the ripple normals.
DirDir (-pi..pi, default 0): the direction the swell crests propagate.
WindWind (0..1, default 0.3): the directional swell strength. 0 is a glassy pool; raising it builds a set of 4 dispersive waves whose amplitude grows with wavelength, so bigger, faster crests that tilt the surface normals and break the reflection.
ZoomZoom (0..1, default 0.5): maps to a 70..20 degree vertical field of view; higher zooms the camera in.

source

mirrorpool.ts on GitHub.

Generated from packages/web/src/lib/{audio,video}/module-registry.ts · repo