The Comonad.Readertypes, (co)monads, substructural logic

Quine: Shader Toys

On this page
  1. Dodecahedron
  2. Generators Redux
  3. From OpenGL to the browser
  4. Sources

Quine existed primarily to test the then-new gl package, the raw OpenGL bindings for Haskell (source on GitHub). It doubled as a graphics playground. Its README puts it simply:

This is just me waxing nostalgic and throwing together some code for playing with graphics.

These two shader toys now run here. Choose a shader, pause it, or move through time. Generators also lets you look around by dragging the image or using the arrow keys.

This example needs WebGL 2. The complete shader sources are linked below.
0.0 s

Generators: drag to look around, or focus the image and use the arrow keys. Home resets the view.

Loading the shader…

Quine’s dodecahedron example: twenty triangular frames, ray-marched with shadows and ambient occlusion. Browser shader · Original shader

Dodecahedron

Twenty triangular frames form an interlocking compound. The shader combines distance estimates for triangular prisms, marches a ray through the resulting field, and shades the surface with two lights, shadows, and ambient occlusion. The camera circles it as time advances.

The example first appeared in Quine on 28 October 2014. Its source credits this Shadertoy as the starting point.

Generators Redux

A camera follows a reflective ball through a repeating fractal structure. This is Generators Redux by Kali, reworked by eiffie for speed and ANGLE compatibility, then included in Quine on 8 November 2014.

The shader keeps its original Shadertoy attribution and CC BY-NC-SA 3.0 license. The browser adaptation of this shader is distributed under the same license.

From OpenGL to the browser

This is a new browser companion to the historical repository, built in September 2026. The date in the archive marks the first of these shader examples in Quine, rather than the date of this page.

The two fragment shaders run directly on the GPU through WebGL 2. Their distance fields, ray marching, shading, and camera paths are retained. The port changes the desktop GLSL header to GLSL ES, supplies the uniforms from the browser, moves a time-dependent global initializer into the fragment entry point, and renames a function that overlaps the browser shader language’s built-in texture function.

The surrounding Haskell/SDL application is preserved as source. This companion replaces its window and rendering loop with a small browser host; it does not compile the Haskell application to WebAssembly.

“Detail” changes the rendering resolution. The demo limits its frame rate to 30 frames per second, pauses while off screen or in a hidden tab, and starts paused when reduced motion is requested.

Sources