About this simulation
Neon Tunnel renders an endless corridor of light entirely inside a single GLSL fragment shader running on the GPU. There is no 3-D geometry — just a full-screen quad whose every pixel is coloured by a polar tunnel mapping formula: the pixel's angle and inverse-radius define a 2-D tunnel space, and a depth coordinate t = 1/r + time × speed drives the illusion of forward flight. Periodic ring and stripe patterns layered on that space, combined with a cosine colour palette, produce the pulsing neon grid you see. This is pure generative art: entirely procedural, no textures, no meshes.
🔬 What it shows
The simulation demonstrates polar-coordinate tunnel mapping — a classic fragment-shader technique. Each frame, the shader converts screen-space UV coordinates to polar form, applies the t = 1/r depth transform to create a perspective-correct vanishing point, then draws rings (periodic in t) and radial stripes (periodic in angle) to form the neon grid. A centre-glow bloom and a rim vignette add spatial depth without any actual 3-D rendering.
🎮 How to use
Use Flight speed to control how fast you fly through the tunnel (0.1 – 4.0). Twist amount spirals the corridor walls — try values above 1.5 for a corkscrew effect. Ring density sets how many neon stripes divide the tunnel circumference (2 – 24). Colour cycle speed changes how fast the cosine palette rotates through hues. Switch between the three palettes (Neon Pink-Cyan, Green Matrix, Sunset) and hit Boost for a 2.5× speed surge that lasts 1.2 seconds.
💡 Did you know?
The cosine colour palette formula — colour = a + b·cos(2π(c·t + d)) — was popularised by Inigo Quilez and can represent virtually any smooth colour gradient with just four 3-component vectors. By slowly advancing the palette's phase with time (the Colour cycle speed slider), the entire tunnel shifts through spectrum continuously, a technique widely used in demoscene productions and live-coding visuals.
Frequently asked questions
How does polar tunnel mapping actually create the illusion of 3-D depth?
The trick is the inverse-radius transform: t = 1/r maps the screen so that values near the centre (small r) produce very large t, simulating great depth, while values near the edge (large r) produce small t, simulating the near wall. Advancing t uniformly with time makes all depth layers scroll toward the viewer simultaneously, creating a convincing forward-flight perspective — all without a camera, matrices, or geometry of any kind.
What is a cosine colour palette and why does it look so smooth?
A cosine palette generates colour by evaluating a + b · cos(2π(c · t + d)) per colour channel, where a, b, c, d are vec3 constants. Because cosine is continuous and bounded between −1 and 1, the result is always a smooth, cyclic colour curve with no abrupt jumps. The three built-in palettes differ only in their four constant vectors: Neon Pink-Cyan uses equal amplitudes for a psychedelic rainbow, Green Matrix biases amplitude toward green, and Sunset skews toward warm reds and oranges.
What does the Twist slider actually change in the shader?
Twist adds a depth-dependent rotation to the polar angle: a = angle + t × twist. Because t grows as you approach the centre, deeper parts of the tunnel are rotated more than shallower parts, making the grid lines spiral rather than run straight. At twist = 0 the stripes are perfectly radial; at twist ≈ 1.5 they form a gentle helix; beyond 2.5 the corridor becomes a tight corkscrew that can be quite disorienting at high speed.
Why is there a brief speed burst when I click Boost?
The Boost button temporarily sets the flight speed to 2.5 × its current slider value (capped at 10) for exactly 1.2 seconds, then restores the original speed. It is a simple setTimeout in the JavaScript control layer — the shader uniform uSpeed is written directly each frame, so there is no easing or interpolation; the surge and release are instant. If you want a sustained high speed, just drag the Flight speed slider up instead.
Does this simulation use WebGL, Three.js, or raw canvas?
It uses Three.js as a thin WebGL wrapper. Three.js handles context creation, a fullscreen PlaneGeometry quad, and the ShaderMaterial that hosts the custom GLSL vertex and fragment shaders. The vertex shader is trivial (it just passes through clip-space positions); all the visual logic lives in the fragment shader. No Three.js geometry, lights, or post-processing passes are involved — Three.js is used purely for convenience to manage the WebGL canvas and uniforms.