A real-time, WebGL image-warping visualiser - a browser port of the classic Drempels / Geiss warp.
npm install
npm run devOpen the printed local URL, then drop image files onto the window to warp them. Until you do, a procedural plasma texture plays as a fallback.
Each frame the CPU computes a coarse grid (UV_CELLS_X × UV_CELLS_Y) of texture coordinates by blending seven independent warp modes - swirl, tunnel, zoom, rotation, and more - weighted by slowly cycling sinusoids.
That grid is uploaded to the GPU, where a fragment shader samples the source image through it using bicubic (Catmull-Rom) interpolation for a smooth, seam-free warp. A second pass blends each frame with the previous one to produce motion-blur trails.
computeWarpGrid (CPU) ──► warp grid texture ──► warp pass (GPU) ──► blit to canvas
▲
previous frame (motion blur)
The control panel appears when you move the pointer over the window. Touch devices never hover, so there the ☰ button in the top-right reveals it.
| Control | Effect |
|---|---|
| Motion blur | Strength of the frame-to-frame trails |
| Warp amount | Displacement strength of the primary warp |
| Zoom | Overall zoom in/out |
| Speed | Animation speed |
| Tex interval | Seconds between automatic texture crossfades |
| Scroll wheel | Zoom in / out |
| Drag-and-drop | Drop image files to load and warp them |
| Key | Action |
|---|---|
Space |
Crossfade to the next texture |
P |
Pause / resume |
F |
Toggle fullscreen |
↑ / ↓ |
Increase / decrease motion blur |
+ / - |
Zoom in / out |
Default parameters live in src/config.yaml and are loaded at build time. Edit values there - grid resolution, texture size, crossfade timing,
initial warp settings - and the dev server hot-reloads them.
Every value is range-checked as it loads, so a typo fails at startup with the
offending key named rather than propagating through the warp field as NaN.
src/
main.ts Entry point: resolves DOM elements, reports startup failure
config.yaml Tunable defaults
engine/ Rendering engine — no dependency on app code or config
renderer.ts Two-pass WebGL renderer (warp + blit, ping-pong FBOs)
warp.ts CPU warp-grid computation (7 blended modes)
webgl-utils.ts Low-level WebGL helpers
shaders/ GLSL shaders (both passes share fullscreen.vert)
app/ App-specific glue
app.ts Assembles the engine and UI, owns the frame loop
config.ts Validated, typed accessors over config.yaml
state.ts Live state shared by the UI and the frame loop
warp-animator.ts Warp grid plus the morph between random warp states
texture-manager.ts Image loading and pixel-slot management
crossfade.ts Texture crossfade state machine
ui.ts DOM controls, keyboard, drag-and-drop
scripts/
release.mjs Packages dist/ into a versioned zip
The engine takes its grid and texture dimensions as parameters, so it can be
reused at any size and tested without loading config.yaml.
| Command | Description |
|---|---|
npm run dev |
Start the Vite dev server |
npm run build |
Type-check and build for production |
npm run preview |
Preview the production build |
npm run typecheck |
Type-check src, tests and configs |
npm run lint |
Run ESLint |
npm run format |
Format with Prettier |
npm run format:check |
Check formatting without writing |
npm test |
Run the unit tests (Vitest) |
npm run test:watch |
Run tests in watch mode |
npm run coverage |
Run tests with a coverage report |
npm run release |
Build and zip a versioned release |
npm run release produces a production build and packages it into a versioned,
self-contained zip:
releases/glemples-<version>.zip
The version is read from package.json. The archive contains the built page at
its root (index.html plus assets), so it can be unzipped and served — or
opened directly — as a standalone release.
A browser with WebGL and the OES_texture_float extension (all current
desktop and mobile browsers qualify).
GLemples is a WebGL port of Drempels by Ryan Geiss. See CREDITS.md for full attribution.
Licensed under the GNU General Public License v3.0 or later (GPL-3.0-or-later). See LICENSE for the full text.
Source files carry an SPDX short-form identifier
(SPDX-License-Identifier: GPL-3.0-or-later) rather than the full notice.