Python / MySQL / AI Pipelines
Hypnotic Spirals in Three.js: Mathematical Topology, Perceptual Neuroscience, and Advanced GPU Rendering
Report summary
The generation of hypnotic spirals within interactive, real-time three-dimensional environments represents a profound convergence of mathematical topology, neurobiological visual processing, and high-performance computer graphics. Within the context of Three.js—the premier JavaScript library for web
Key topics
- Python / MySQL / AI Pipelines
- Python
- MySQL
- AI Pipelines
- AI
- .NET
- Angular
- Runtime
- Physics
Research provenance
For citation, use the report title and canonical URL. Archival presence does not establish authorship or promote report statements into portfolio evidence.
This page renders the archived Markdown as safe, formatted HTML. It is background research and does not become a portfolio claim without evidence review.
Full report
On this page
Introduction to the Intersection of Geometry and Perception
The generation of hypnotic spirals within interactive, real-time three-dimensional environments represents a profound convergence of mathematical topology, neurobiological visual processing, and high-performance computer graphics. Within the context of Three.js—the premier JavaScript library for web-based 3D rendering—engineering these spiraling phenomena necessitates a highly layered understanding of both hardware-accelerated rendering pipelines and the perceptual psychology of the mammalian visual cortex. Historically, real-time web graphics relied entirely on explicit CPU-side geometry generation, mapping discrete vertices to represent curved surfaces in a strictly linear pipeline1. However, the continuous evolution of WebGL fragment shaders, and the subsequent architectural revolution brought about by WebGPU and the Three.js Shading Language (TSL), have shifted the paradigm toward procedural, GPU-driven execution4.
A truly "hypnotic" spiral is far more than a rotating texture mapped onto a primitive plane; it is a meticulously constructed optical stimulus designed to engage specific motion-processing centers in the brain, inducing targeted neurological responses7. Achieving this profound psychological effect necessitates precise manipulation of logarithmic geometry, analytical anti-aliasing to prevent artifact disruption, and advanced color theory utilizing cosine-based procedural palettes8. Furthermore, the modern rendering ecosystem demands that such visual complexity is achieved at optimal frame rates, leveraging advanced techniques such as raymarching, Signed Distance Functions (SDFs), and compute shaders for volumetric or particle-based manifestations10. The following analysis delineates the comprehensive pipeline for engineering these immersive stimuli, transitioning from theoretical mathematics and neurological mechanisms to concrete, high-performance architectural implementations within the Three.js ecosystem.
The Mathematical Topology of the Logarithmic Spiral
To engineer a spiral that reliably induces a hypnotic effect, one must first establish the underlying mathematical framework. While Archimedean spirals expand at a constant linear rate (where the distance between successive turns remains uniform), the canonical hypnotic spiral is modeled almost exclusively on the logarithmic spiral, also known as the equiangular spiral, the growth spiral, or the spira mirabilis13. First described by Albrecht Dürer in 1525, mathematically formalized by René Descartes in 1638, and later extensively studied by Jacob Bernoulli, the logarithmic spiral exhibits inherent properties of scale-invariance and self-similarity that are absolutely vital for continuous, seamless animation14.
In a two-dimensional polar coordinate system, the position of any point on the spiral is defined by its radial distance [Figure omitted from source export] from the origin and its angular position [Figure omitted from source export]. The general polar equation for a logarithmic spiral is expressed as:
[Figure omitted from source export]
In this standard formulation, [Figure omitted from source export] represents a positive constant corresponding to the initial radius (the scale of the spiral when [Figure omitted from source export]), and [Figure omitted from source export] is a non-zero constant that dictates the rate of outward expansion17. The constant [Figure omitted from source export] is Euler's number (approximately 2.71828). When [Figure omitted from source export], the spiral expands as [Figure omitted from source export] increases, and when [Figure omitted from source export], it contracts17. The unique, defining geometric characteristic of the logarithmic spiral is its equiangular property: any straight line (radial ray) originating from the central pole intersects the curve of the spiral at a strictly constant angle [Figure omitted from source export], which is known as the pitch angle13. The mathematical relationship between the expansion rate [Figure omitted from source export] and the constant pitch angle [Figure omitted from source export] is given by the trigonometric identity:
[Figure omitted from source export]
Because the spiral is self-similar, scaling the spiral uniformly around its origin by a factor produces a curve that is geometrically and visually congruent to a simple rotation of the original curve15. This specific topological property is the fundamental engine for generating hypnotic animations in WebGL and Three.js: a continuous zooming or scaling transformation can be perfectly masked by, or equated to, a continuous rotational transformation. Furthermore, the arc length [Figure omitted from source export] of the logarithmic spiral from the origin to a given point at radius [Figure omitted from source export] is perfectly finite and can be calculated elegantly as [Figure omitted from source export]16. When projecting these coordinates into a fragment shader, the conversion from standard Cartesian UV coordinates [Figure omitted from source export] to polar coordinates [Figure omitted from source export] allows the geometry to be evaluated in a transformed domain where radial depth and angular rotation are completely decoupled.
Perceptual Psychology and the Neuroscience of Illusory Motion
The psychological efficacy of a hypnotic spiral relies fundamentally on exploiting the highly specialized biological architecture of the human visual system. Illusory perception—where the subjective visual experience diverges significantly from physical reality—persists even when the observer possesses conscious, intellectual awareness of the physical properties of the stimulus on the screen7. This persistence clearly indicates that these optical effects are hardwired into low-level and mid-level visual processing networks within the brain, bypassing higher-order cognitive correction mechanisms7.
Cortical Magnification and Spatial Frequency
The primary visual cortex (V1), located in the occipital lobe, maps the visual field with a significant spatial bias known as cortical magnification20. Neurons responsible for processing stimuli in the fovea (the very center of the retina, responsible for high-acuity vision) vastly outnumber those dedicated to the peripheral visual field20. A logarithmic spiral intrinsically and mathematically mirrors this biological weighting20. Its structural density is highest at the center singularity and gradually expands outward exponentially. This exact geometric progression ensures that the spatial frequency of the stimulus remains roughly proportional to the increasing receptive field sizes of retinal ganglion cells and V1 neurons across the eccentricity of the visual field20. Consequently, a logarithmic spiral creates a uniform level of neural stimulation across the entire topology of the primary visual cortex, maximizing the overall cognitive load and contributing significantly to the "mesmerizing" or immersive quality of the animation20.
The Visual Motion Area (MT/V5) and the Motion Aftereffect
The illusion of continuous inward or outward motion generated by an animated spiral strongly stimulates the middle temporal visual area of the cerebral cortex, commonly referred to as area MT or V524. Area V5/MT contains exceptionally high concentrations of direction-specific, motion-responsive neurons24. When a user observes a rotating hypnotic spiral, the continuous motion in a specific direction (e.g., expanding outward) causes selective adaptation in the sub-population of MT neurons tuned to that specific directional vector24.
Prolonged exposure (typically 20 to 60 seconds) forces these specific neurons to experience a reduction in responsiveness—a mechanism identified as contrast gain reduction—due to sustained, fatiguing firing rates24. If the spiral suddenly stops rotating, or if the user averts their gaze to a stationary object, the opposing, unadapted neurons in area MT dominate the competitive neural interaction24. This imbalance generates a powerful sensory-contingent illusory percept known as the Motion Aftereffect (MAE), occasionally referred to as the waterfall illusion24.
Functional magnetic resonance imaging (fMRI) studies, utilizing Blood-Oxygen-Level-Dependent (BOLD) contrast imaging, have demonstrated a clear, persistent, and measurable increase in metabolic activity in human area MT when subjects perceive this illusory motion on a physically stationary stimulus25. The time course of the neural signal decay in these fMRI studies mirrors the psychological duration of the aftereffect reported by subjects, confirming that the hypnotic aftereffect is a physical, lower-level neurological phenomenon rather than a higher-level cognitive misinterpretation24.
Static Orientation Illusions: The Fraser Spiral
Beyond motion-induced illusions, static geometric configurations can also induce spiral perceptions. The Fraser spiral illusion (often referred to as the "twisted cord" illusion), first described by Sir James Fraser in 1908, leverages high-contrast spatial frequencies to deceive the visual cortex into perceiving continuous spiral trajectories where only discrete concentric circles actually exist31. By integrating regular concentric line patterns with misaligned, alternating light and dark segments (cords), the brain's orientation-selective receptive fields—specifically simple cells in area V1—incorrectly integrate local, tilted tangent vectors into a global spiral percept31.
| Illusion Classification | Primary Neurological Mechanism | Visual Manifestation in 3D Graphics |
|---|---|---|
| Motion Aftereffect (MAE) | MT/V5 neuron selective adaptation and contrast gain reduction. | Perception of radial expansion or contraction on stationary objects after viewing a moving spiral. |
| Cortical Magnification | Inverse relationship between V1 receptive field size and foveal eccentricity. | Scale-invariant logarithmic spirals maintain constant neural stimulation density across the visual field. |
| Fraser Spiral Illusion | Local orientation misinterpretation and false vector integration in V1 simple cells. | Concentric toroidal geometry patterned with twisted contrast textures appearing as a continuous spiral path. |
| McCollough Effect | Orientation-contingent color adaptation in the visual cortex. | Phantom colored afterimages appearing on monochromatic, orthogonal grid lines after prolonged exposure. |
Understanding these neurological pathways dictates strict rendering requirements. High dynamic contrast, mathematically pure gradients, and precise anti-aliasing are absolutely non-negotiable. High-frequency rendering artifacts, such as jagged pixelation or texture aliasing, provide static spatial cues to the visual system. The brain immediately uses these unintended static cues to anchor its perception, breaking the illusion of continuous motion and neutralizing the V5/MT adaptation9.
Explicit CPU-Side Geometry Generation in Three.js
Before transitioning to the advanced mathematics of GPU-accelerated shaders, it is necessary to examine how spirals can be modeled as explicit, discrete 3D geometry using the CPU-side abstractions provided by Three.js. This explicit topological approach is optimal for creating physical spiral structures within a scene, such as winding staircases, twisted physical tunnels, dynamic rollercoasters, or sculpted meshes that interact with physics engines.
The architectural foundation of explicit procedural geometry in Three.js is the THREE.Curve base class. To generate a 3D spiral algorithmically, developers must extend this base class and override the getPoint(t, optionalTarget) method34. The parameter t represents the normalized interpolation distance along the parametric curve, ranging linearly from [Figure omitted from source export] to [Figure omitted from source export]. The method's responsibility is to compute the exact Cartesian coordinates [Figure omitted from source export] for that specific segment of the curve.
A typical implementation of a three-dimensional spiral curve scales the [Figure omitted from source export] and [Figure omitted from source export] axes with trigonometric functions to create rotation, while advancing the [Figure omitted from source export] axis linearly to create depth or height:
JavaScript
import \* as THREE from 'three';
class CustomLogarithmicSpiralCurve extends THREE.Curve { constructor(scale \= 1, revolutions \= 10, growthRate \= 0.2) { super(); this.scale \= scale; this.revolutions \= revolutions; this.growthRate \= growthRate; } getPoint(t, optionalTarget \= new THREE.Vector3()) { // Map normalized t to an angular domain const angle \= t \ Math.PI \ 2.0 \ this.revolutions; // Exponential growth based on the logarithmic spiral formula const radius \= Math.exp(this.growthRate \ angle); const tx \= Math.cos(angle) \ radius; const ty \= t \ 50 \- 25; // Linear vertical displacement const tz \= Math.sin(angle) \* radius; return optionalTarget.set(tx, ty, tz).multiplyScalar(this.scale); } }
Once the custom curve is mathematically defined, it is passed by reference into the THREE.TubeGeometry constructor1. The TubeGeometry class acts as a procedural mesh generator that extrudes a two-dimensional circular cross-section along the evaluated 3D path1. The constructor accepts arguments for the path (the curve instance), tubularSegments (the number of subdivisions along the length of the tube), radius (the thickness of the tube), radialSegments (the number of subdivisions around the cross-section), and closed (a boolean indicating if the ends should connect)1. Furthermore, developers can dynamically modify the radius of the tube along its length by overriding the curve logic or applying a custom taper function that modulates the radius based on the parameter u (equivalent to t), allowing the spiral tube to shrink to a point or swell like a biological structure36.
The Frenet-Serret Frame and the Singularity Problem
Extruding a circular cross-section along an arbitrary 3D curve requires calculating a localized, moving coordinate system at every discrete point to determine how the vertices of the cross-section should be oriented in world space. This is classically achieved using the Frenet-Serret frame, which consists of three orthonormal vectors: the Tangent ([Figure omitted from source export]), Normal ([Figure omitted from source export]), and Binormal ([Figure omitted from source export]).
In Three.js, TubeGeometry generates these frames internally utilizing the computeFrenetFrames algorithm37. The tangent vector [Figure omitted from source export] is calculated via the first derivative of the curve at point [Figure omitted from source export]. The normal vector [Figure omitted from source export] is typically found by taking the cross product of the tangent [Figure omitted from source export] and a global reference "up" vector (usually the positive Y-axis). The binormal [Figure omitted from source export] is then the cross product of [Figure omitted from source export] and [Figure omitted from source export].
However, severe mathematical singularities arise when the curve's tangent perfectly aligns, or nearly aligns, with the global reference "up" vector. The cross product of two parallel vectors yields a zero vector (or a highly denormalized vector due to floating-point imprecision)39. When this singularity occurs, the algorithm is forced to default to an arbitrary previous frame or a hardcoded fallback axis. Visually, this manifests as a violent, abrupt 90-degree or 180-degree twisting artifact (a "kink" or "pinch") in the generated tube geometry41.
To circumvent this mathematical instability, Three.js employs a technique known as the "Moving Frenet Frame" (also referred to mathematically as a Bishop Frame or a Rotation Minimizing Frame)39. Instead of calculating the normal independently at each step utilizing the fixed global up vector, the Bishop frame algorithm takes the normal from the immediately preceding segment and rotates it around the new tangent vector by the exact angle between the previous and current tangents39. This iterative approach ensures continuous, minimal-twist extrusion.
Despite this, boundary condition anomalies can still occur. For instance, if the generated curve is intended to form a closed loop (a toroidal spiral), the final computed frame might not align with the initial frame, resulting in a visible seam. To resolve this, developers must ensure the closed boolean parameter in the TubeGeometry constructor is explicitly set to true. This flag instructs the computeFrenetFrames function to calculate the total angular discrepancy between the start and end frames and distribute that residual torsion evenly and imperceptibly across every segment of the entire geometry37. If additional manual adjustments are required, developers can iterate over the generated BufferGeometry attributes, applying precise quaternions to specific vertex clusters to untwist targeted regions40.
GPU-Accelerated Procedural Generation: Fragment Shaders and Log-Polar Transformations
While generating explicit CPU-side geometry is suitable for structural, physical scene elements, true hypnotic visual phenomena—those meant to overwhelm the visual field with infinite depth—are most efficiently and elegantly engineered entirely in screen-space or object-space utilizing custom WebGL fragment shaders46. Rendering a mathematically complex spiral on a single two-triangle quad utilizing a ShaderMaterial is computationally lightweight, allowing for pixel-perfect procedural generation without the severe memory and processing overhead of allocating millions of discrete vertices46.
Cartesian to Polar and Log-Polar Mapping
In a GLSL (OpenGL Shading Language) fragment shader, the coordinate system provided to the programmer is inherently Cartesian, providing a vec2 representing the discrete [Figure omitted from source export] position of the current fragment, normalized via a resolution uniform. To draw and animate spirals intuitively, this two-dimensional space must first be mathematically transformed into polar coordinates50.
The fundamental transformation requires calculating the distance from the center (the radius, [Figure omitted from source export]) and the angle ([Figure omitted from source export]):
OpenGL Shading Language
// Normalize pixel coordinates to range \[-1, 1\] vec2 uv \= (gl\_FragCoord.xy / u\_resolution.xy) \* 2.0 \- 1.0;
// Correct the aspect ratio to prevent elliptical stretching uv.x \*= u\_resolution.x / u\_resolution.y;
// Convert Cartesian to Polar coordinates float r \= length(uv); float theta \= atan(uv.y, uv.x);
While linear polar coordinates are useful for simple radial gradients, mapping repetitive patterns onto them results in spirals that clump densely and illegibly at the origin, destroying the self-similar scale invariance required for the hypnotic effect. To map domains perfectly from macro to micro scales, a log-polar transformation is utilized52. By taking the natural logarithm of the radius, the multiplicative scaling operations in Cartesian space are elegantly converted into additive translational operations in log-polar space53.
[Figure omitted from source export]
In a GLSL shader, applying an inverse log-polar map effectively turns the act of zooming (scaling) into infinite, seamless linear scrolling along the newly defined [Figure omitted from source export] axis. By feeding these transformed coordinates into a periodic, repeating function (such as sin or fract), the shader produces an infinite inward or outward motion that perfectly loops, mimicking the endless descent of a hypnotic tunnel52. Applying a linear shear transformation to this space—specifically by adding a scalar multiple of the angle [Figure omitted from source export] to the logarithmic radius [Figure omitted from source export]—mathematically twists the concentric circles into continuous, flowing spirals52.
Analytical Anti-Aliasing via Screen-Space Derivatives
A profound technical challenge in rendering procedural mathematical spirals is the inevitable occurrence of severe aliasing—manifesting as jagged pixelation, stair-stepping edges, and distracting moiré patterns. This aliasing is particularly aggressive as the spiral arms converge at the singularity at the origin ([Figure omitted from source export]), or when rendering high-frequency, tightly wound lines receding into the distance52. Because a fragment shader evaluates pixels at discrete, sampled locations, sharp mathematical boundaries created by logical operations or step() functions will flicker wildly as the underlying continuous function crosses the fixed pixel grid9.
To maintain the psychological immersion of the hypnotic illusion, the edges of the spiral must be perfectly smooth, requiring anti-aliasing techniques. While brute-force Multisample Anti-Aliasing (MSAA) evaluates multiple points per pixel, it is computationally expensive and sometimes unsupported or insufficient for infinite-frequency procedural shaders56. The optimal, mathematically pure solution is analytical anti-aliasing utilizing the GLSL screen-space derivative functions dFdx, dFdy, and fwidth9.
The fwidth(v) function is a highly optimized hardware-level instruction that returns the sum of the absolute values of the partial derivatives in the screen's X and Y directions, effectively calculating abs(dFdx(v)) \+ abs(dFdy(v))9. Under the hood, modern GPUs process pixels not individually, but in 2x2 blocks known as "pixel quads"60. The GPU calculates dFdx and dFdy by rapidly comparing the value of the variable [Figure omitted from source export] across the pixels within this quad60.
Consequently, fwidth determines exactly how rapidly a variable [Figure omitted from source export] is changing between the current pixel and its immediate screen-space neighbors9. If [Figure omitted from source export] represents the calculated signed distance to the mathematical edge of the spiral arm, fwidth(v) provides the exact numerical width of a single physical screen pixel in the contextual units of that abstract distance field9.
This dynamic, pixel-width metric is then supplied directly to the smoothstep function, which performs Hermite interpolation between two defined boundaries58. Instead of a harsh binary cutoff that causes jagged aliasing, the mathematical edge transitions smoothly from 0.0 to 1.0 over the exact spatial span of a single pixel58:
OpenGL Shading Language
// Calculate the repeating distance field of the spiral float dist \= fract(log(r) \- theta \* 0.5 \+ u\_time);
// Calculate exactly how much 'dist' changes over one physical pixel float pixel\_width \= fwidth(dist);
// Interpolate smoothly over the calculated pixel width for a perfect edge float alpha \= smoothstep(0.5 \- pixel\_width, 0.5 \+ pixel\_width, dist);
This analytical approach guarantees that regardless of the user's zoom level, the screen resolution, or the extreme mathematical compression occurring at the singularity near [Figure omitted from source export], the edges of the spiral remain perfectly blended9. This mitigates moiré patterns entirely and stabilizes the visual field, which is critical for sustaining the V5/MT neurological adaptation63.
Procedural Chromaticity: Cosine Palettes
To elevate the spiral from a stark, monochromatic optical test into a compelling, aesthetic experience, complex procedural color palettes must be applied. Relying on traditional 2D texture lookups (sampling .png or .jpg files) for coloring is grossly inefficient and immediately breaks the illusion of infinite zoom scaling, as textures have fixed resolutions and will pixelate. Instead, purely mathematical color palettes are utilized. The industry standard for procedural coloring in demoscene and shader programming is the cosine-based palette, heavily popularized by rendering expert Iñigo Quílez8.
These continuous cosine palettes calculate exact RGB values at any given point using an oscillating trigonometric formula:
[Figure omitted from source export]
In this elegant formulation, [Figure omitted from source export] represents the normalized input parameter, typically the distance along the spiral or the transformed log-polar radius. The formula utilizes four vec3 (three-dimensional) parameters to define the spectrum:
1. Vector [Figure omitted from source export] (Baseline): Establishes the median base color of the gradient.
2. Vector [Figure omitted from source export] (Amplitude): Defines the magnitude of the color variation, effectively controlling the overall contrast. A large vector creates aggressive color swings, while a small vector produces muted, pastel variations8.
3. Vector [Figure omitted from source export] (Frequency): Sets how rapidly the colors cycle as [Figure omitted from source export] increases. Higher values produce dense, repeating rainbows, while lower values yield long, subtle gradients8.
4. Vector [Figure omitted from source export] (Phase Shift): Introduces an independent phase shift to the Red, Green, and Blue channels. Offsetting the channels prevents the colors from washing out to grayscale and is responsible for generating complex, shifting hues8.
| Procedural Palette Aesthetic | Vector a (Baseline) | Vector b (Amplitude) | Vector c (Frequency) | Vector d (Phase Shift) |
|---|---|---|---|---|
| Bioluminescent Ocean | (0.5, 0.5, 0.5) | (0.5, 0.5, 0.5) | (1.0, 1.0, 1.0) | (0.0, 0.33, 0.67) |
| Cyberpunk Neon | (0.2, 0.5, 0.3) | (0.0, 0.5, 0.7) | (1.0, 1.0, 1.0) | (0.0, 0.3, 0.7) |
| Molten Ember | (0.6, 0.0, 0.0) | (1.0, 0.0, 0.0) | (1.0, 0.0, 0.0) | (1.0, 0.0, 0.0) |
| Ethereal Vapor | (1.0, 0.4, 0.0) | (0.4, 0.8, 0.0) | (0.5, 0.3, 0.9) | (0.9, 0.6, 0.9) |
Table 1: Optimal vector configurations for procedural cosine palettes applied to hypnotic rendering, demonstrating the vast chromatic range achievable through pure mathematics.
\[cite: 66\]
By passing the log-polar spiral distance as the parameter [Figure omitted from source export] into this cosine function, the GPU can generate infinite, smoothly interpolating color gradients in real-time, completely devoid of memory bandwidth limitations, color banding, or resolution limits8.
Volumetric Rendering: Raymarching and Signed Distance Functions (SDFs)
While 2D fragment shaders excel at mapping planar surfaces, rendering a truly volumetric, three-dimensional hypnotic spiral tunnel—where lighting, shadows, and occlusion accurately simulate physical depth—requires abandoning traditional rasterization in favor of Raymarching10. Raymarching, and its most common variant, sphere tracing, evaluates complex geometry procedurally using Signed Distance Functions (SDFs)10.
Instead of projecting CPU-defined triangles onto a screen via a rasterizer, a raymarching shader casts a mathematical ray from the virtual camera's origin, passing through each pixel on the screen, and projecting out into the void of the mathematical scene volume10. The SDF is a mathematical formula that takes a 3D point in space as an input and returns a single float: the absolute shortest distance from that exact point to the surface of the nearest object10.
The sphere tracing algorithm marches the ray forward along its direction vector by this exact returned distance10. Because the SDF guarantees that no geometry intersects the ray within that calculated distance (the radius of the "sphere"), it is perfectly safe to jump forward in one massive step rather than taking thousands of tiny increments10. When the returned distance drops below a microscopic threshold, commonly defined as an EPSILON of [Figure omitted from source export], a surface hit is registered, and the loop terminates10. If the total distance traveled exceeds a MAX\_DIST limit, or the loop exceeds a MAX\_STEPS count, the ray is assumed to have missed all geometry and hit the background skybox10.
To create a mesmerizing spiral tunnel, a simple SDF (such as an infinite central cylinder, or an array of repeating boxes) is subjected to domain distortion72. Rather than attempting the nearly impossible task of writing a closed-form SDF formula for a complex, twisting 3D helix, the developer twists the entire 3D coordinate system space before the simple geometry is evaluated72.
If evaluating a point [Figure omitted from source export], the domain can be twisted along the depth (Z-axis) by applying a 2D rotation matrix to the [Figure omitted from source export] and [Figure omitted from source export] coordinates, where the angle of rotation is a direct function of [Figure omitted from source export] and time:
OpenGL Shading Language
// Calculate an angle that increases with depth and time float angle \= p.z \* 0.5 \+ u\_time; float s \= sin(angle); float c \= cos(angle);
// Construct a 2D rotation matrix mat2 rot \= mat2(c, \-s, s, c);
// Twist the X and Y coordinates of the space p.xy \*= rot;
// Evaluate a simple geometry (e.g., a hollow cylinder) in the twisted space float d \= length(p.xy) \- 2.0;
When this mathematically twisted space is passed into an SDF, the resulting rendered geometry appears to spiral endlessly toward the horizon, twisting and churning as time progresses10.
Boolean Operations and Dynamic Normals
SDFs allow for flawless, mathematically perfect Constructive Solid Geometry (CSG) operations. Forms can be blended, subtracted, or intersected using simple min and max operations. For organic, fluid-like spiral shapes, the standard min function is replaced by polynomial smooth minimum (smin) formulas, which elegantly merge intersecting volumes together like liquid mercury10.
| SDF Operation | Mathematical Representation | Visual Effect |
|---|---|---|
| Union | min(d1, d2) | Fuses two distinct volumes into one continuous object. |
| Subtraction | max(-d1, d2) | Carves the shape of d1 out of the volume of d2. Useful for hollowing out tunnels. |
| Intersection | max(d1, d2) | Retains only the overlapping volume where both objects exist simultaneously. |
| Smooth Union | Polynomial smin(d1, d2, k) | Blends two objects seamlessly with a filleted, organic transition controlled by parameter k. |
Table 2: Common Signed Distance Function boolean operations used to sculpt complex raymarched geometry.
\[cite: 10, 68, 72\]
To ensure that real-time physically based lighting (PBR) and shadows update correctly on this heavily warped geometry, normal vectors cannot be provided manually. Instead, they are calculated dynamically at the intersection point by sampling the SDF at infinitesimally small offsets along the X, Y, and Z axes, effectively taking the gradient of the distance field10.
A critical implementation detail when rendering raymarched scenes inside the standard Three.js mesh ecosystem is properly translating the world-space coordinates of the Three.js PerspectiveCamera into the local object-space of the mesh containing the raymarching shader. Without multiplying the camera's position by the inverse of the object's modelMatrix, the raymarched spiral will severely distort, warp, or vanish entirely if the mesh is translated, rotated, or scaled away from the world origin [Figure omitted from source export]73.
The WebGPU Era: Three.js Shading Language (TSL) and Node Materials
The architectural future of Three.js—and the most robust, scalable methodology for authoring hypnotic spirals—relies heavily on the adoption of WebGPU and the newly introduced Three.js Shading Language (TSL)4. Historically, integrating complex procedural generation into a scene required extending ShaderMaterial or RawShaderMaterial and injecting massive, monolithic strings of GLSL code5. This legacy process was inherently brittle, difficult to modularize, lacked code completion, and isolated the custom logic from the engine's built-in lighting, fog, and shadow models5.
With the comprehensive transition to the WebGPU backend, Three.js introduced Node Materials (e.g., MeshStandardNodeMaterial, MeshPhysicalNodeMaterial)5. TSL allows developers to author shaders purely in JavaScript using a functional, node-based programming paradigm. Instead of manually concatenating raw strings, developers compose logical operations using strongly typed JavaScript functions that return AST (Abstract Syntax Tree) nodes5. The Three.js engine dynamically traverses this tree at runtime and compiles it into heavily optimized WGSL (WebGPU Shading Language) or GLSL (for WebGL2 fallback), ensuring forward compatibility across multiple browser backends74.
In TSL, recreating the log-polar spiral with procedural cosine coloring transforms from an error-prone string exercise into a declarative, type-safe process. TSL automatically handles the complex varying interpolations, uniform declarations, and attribute bindings behind the scenes5:
JavaScript
import { Fn, uv, vec3, sin, cos, time, length, add, mul } from 'three/tsl'; import { MeshBasicNodeMaterial } from 'three/webgpu';
const hypnoticSpiral \= Fn(() \=\> { // Retrieve varying UV coordinates and center them const screenUV \= uv().sub(0.5); const radius \= length(screenUV); // TSL equivalent of GLSL atan(y, x) const angle \= Fn.atan2(screenUV.y, screenUV.x); // Mathematical domain manipulation for the spiral const spiral \= sin(radius.mul(20.0).sub(angle).add(time.mul(2.0))); // Inigo Quilez Cosine palette application const colorOutput \= vec3(0.5).add( vec3(0.5).mul(cos(time.add(spiral).mul(vec3(1.0, 1.0, 1.0)))) ); return colorOutput; });
// Create a WebGPU node material and assign the procedural logic const material \= new MeshBasicNodeMaterial(); material.colorNode \= hypnoticSpiral();
The true power of TSL is its unprecedented composability and modularity5. A technical artist can author the complex domain-warping logic of the spiral and assign it exclusively to the emissiveNode, roughnessNode, or displacementNode of a physically based material. This seamlessly integrates the procedural mathematics with the engine's built-in global illumination, HDRI environment mapping, and real-time shadow generation, vastly expanding the creative possibilities without requiring the developer to manually rewrite complex BRDF (Bidirectional Reflectance Distribution Function) lighting equations5.
GPGPU Compute Shaders and Particle-Based Spirals
Beyond rendering solid surfaces or volumetric raymarched fields, WebGPU introduces dedicated, native Compute Shaders to the web platform. This capability unlocks massive parallel processing that previously required complex, inefficient WebGL ping-pong buffer hacks via Framebuffer Objects (FBOs) to achieve6. Compute shaders are programs executed directly on the GPU, designed explicitly for arbitrary parallel mathematical calculations rather than the specific task of rasterizing geometry to a visual screen6.
For a hypnotic spiral effect, compute shaders permit the real-time, physics-based simulation of millions of independent particles caught in a logarithmic vector field or vortex11. The compute shader operates directly on a StorageBufferAttribute—a highly optimized memory buffer accessible natively by both the compute and rendering pipelines—containing the continuous positions, velocities, and lifespans of every individual particle80.
During each execution frame, the compute shader reads the current Cartesian position of a particle, converts it to polar coordinates, applies the mathematical derivative of a logarithmic spiral to update its velocity vector, adds physical forces like drag or turbulence via Simplex noise, and writes the newly integrated position back into the buffer11. Because this entire computational lifecycle occurs entirely on the GPU's VRAM without a single, latency-inducing round-trip memory transfer to the CPU, it enables real-time fluid simulations and particle counts (often exceeding hundreds of thousands) that are orders of magnitude higher than traditional CPU-bound JavaScript physics loops11. This allows for the generation of dense, ethereal, fluid-like spiral galaxies that react dynamically and instantly to user input or music data11.
The Post-Processing Pipeline: Finalizing the Hypnotic Effect
The final synthesis of the hypnotic spiral relies heavily on screen-space post-processing. Raw renders straight from the camera, regardless of their mathematical complexity, often lack the optical glow, chromatic blending, and cinematic finish associated with intense energetic phenomena. To finalize the aesthetic, a bloom filter is almost universally required.
Historically, post-processing in Three.js was orchestrated utilizing the EffectComposer, which managed a linear chain of render passes82. To add atmospheric, ethereal glow to the spirals, the UnrealBloomPass is deployed84. Inspired by the high-end rendering architecture of the Unreal Engine, this pass purposefully avoids relying on a single, computationally ruinous Gaussian blur84. Instead, it extracts the brightest pixels from the frame (based on a defined luminance threshold) and renders them into a mip-map chain—a sequence of progressively downscaled, half-resolution textures84. Varying blur radii are applied incrementally to these lower-resolution textures, and the results are then up-sampled and additively blended back together84. This technique yields an exceptionally smooth, wide-radius bloom that accurately mimics real-world camera lens diffraction at a fraction of the computational cost of a monolithic blur operation84.
However, the linear, conveyor-belt execution model of EffectComposer forces the GPU to read and write entire screen buffers to memory sequentially for every individual pass, creating significant bandwidth bottlenecks and hindering performance on mobile devices83. In the modern Three.js WebGPU architecture (r183+), this legacy system has been completely superseded by the RenderPipeline85.
The RenderPipeline leverages the TSL node-graph architecture to unify complex post-processing into a single, aggressively compiled shader execution wherever possible85. Rather than appending rigid pass objects to an array, effects are chained fluently as nested function calls:
JavaScript
import \* as THREE from 'three/webgpu'; import { pass, bloom, dotScreen } from 'three/tsl';
// Initialize the modern WebGPU RenderPipeline const renderPipeline \= new THREE.RenderPipeline(renderer);
// Define the rendering sequence as a composable TSL graph const sceneRender \= pass(scene, camera);
// Apply bloom with specific parameters: strength, radius, threshold const hypnoticGlow \= bloom(sceneRender, 1.5, 0.4, 0.85);
// Assign the final graph to the pipeline output renderPipeline.outputNode \= hypnoticGlow;
This node-based post-processing architecture allows for sophisticated branching logic that was previously arduous85. For example, selective bloom—where only the bright, glowing rings of the spiral bloom intensely, while the background geometry and UI remain perfectly sharp—can be achieved trivially by masking the node output mathematically in TSL. This completely eliminates the need to traverse and manipulate complex global layer masks or perform multiple heavy, redundant scene renders as was required with the EffectComposer85. The modern pipeline analyzes the complete effect graph abstractly and optimizes the GPU draw calls automatically, drastically reducing rendering overhead and allowing the WebGPU backend to leverage Multiple Render Targets (MRT) optimally, rendering depth, normal, and color passes simultaneously85.
Conclusion
The engineering of hypnotic spirals within Three.js traverses a vast, interdisciplinary spectrum of computer science and biology. It begins with the fundamental topology of logarithmic curves, ensuring the geometric expansion rates perfectly align with the cortical magnification properties of the human visual system to provoke strong, localized neurological responses in the MT/V5 visual cortex and induce profound motion aftereffects.
Transitioning from CPU-side explicit geometric structures using moving Bishop frames to suppress violent torsional artifacts, the computational paradigm shifts to advanced GPU-side fragment shading. Here, log-polar coordinate transformations simulate infinite, looping depth, while strict analytical anti-aliasing utilizing hardware-level subpixel derivatives preserves the illusion's structural integrity against jarring pixelation. Finally, the modern integration of WebGPU, the Three.js Shading Language (TSL), and Node Materials enables the procedural execution of these complex mathematical constructs at unprecedented performance levels. This unified architecture empowers compute shaders and graph-based post-processing pipelines to elevate abstract mathematical geometry into truly mesmerizing, neurologically active optical phenomena.
Works cited
1. Tube Geometry in threejs | Dustin John Pfister at github pages, https://dustinpfister.github.io/2023/06/02/threejs-tube-geometry/
2. BufferGeometry – three.js docs, https://threejs.org/docs/pages/BufferGeometry.html
3. The Built-In Geometries \- Discover three.js\!, https://discoverthreejs.com/book/first-steps/built-in-geometries/
4. I built a node-based editor for the new Three.js Shading Language, https://www.reddit.com/r/threejs/comments/1qk0s8z/i\_built\_a\_nodebased\_editor\_for\_the\_new\_threejs/
5. TSL: A Better Way to Write Shaders in Three.js, https://threejsroadmap.com/blog/tsl-a-better-way-to-write-shaders-in-threejs
6. GPGPU particles with TSL & WebGPU \- Wawa Sensei, https://wawasensei.dev/courses/react-three-fiber/lessons/tsl-gpgpu
7. The Mechanisms of the Visual System Behind Visual Illusions, https://pubmed.ncbi.nlm.nih.gov/34759062/
8. Generative Shader Color Palettes \- Offscreen Canvas, https://offscreencanvas.com/issues/generative-shader-color-palettes/
9. Using fwidth for distance based anti-aliasing \- numb3r23, http://www.numb3r23.net/2015/08/17/using-fwidth-for-distance-based-anti-aliasing/
10. ray marching (with THREE.js), https://barradeau.com/blog/?p=575
11. WebGPU Compute Shaders for Particle Simulations in Three.js, https://www.serdarozden.com/webgpu-compute-shaders-threejs-particle-guide
12. Interactive Galaxy with WebGPU Compute Shaders, https://threejsroadmap.com/blog/galaxy-simulation-webgpu-compute-shaders
13. The Logarithmic Spiral \- The Myth of the Golden Ratio, https://goldenratiomyth.weebly.com/the-logarithmic-spiral.html
14. Logarithmic Spiral, https://archive.lib.msu.edu/crcmath/math/math/l/l383.htm
15. Logarithmic spiral \- Wikipedia, https://en.wikipedia.org/wiki/Logarithmic\_spiral
16. Equiangular Spiral \- MacTutor History of Mathematics, https://mathshistory.st-andrews.ac.uk/Curves/Equiangular/
17. Logarithmic Spiral — Definition, Formula & Examples \- Mathwords, https://www.mathwords.com/l/logarithmic\_spiral.htm
18. Parametric modeling : Logarithmic spiral and superformula, https://www.hbruvry.com/research-parametric-modeling-2
19. Logarithmic Spiral \-- from Wolfram MathWorld, https://mathworld.wolfram.com/LogarithmicSpiral.html
20. Cortical Magnification in V1 – Introduction to Sensation and Perception, https://open.lib.umn.edu/sensationandperception/chapter/cortical-magnification-in-v1/
21. Cortical magnification \- Wikipedia, https://en.wikipedia.org/wiki/Cortical\_magnification
22. Preferred spatial frequency covaries with cortical magnification in, https://www.biorxiv.org/content/10.1101/2025.03.19.644195v2.full-text
23. Spatial frequency tuning in human retinotopic visual areas | JOV, https://jov.arvojournals.org/article.aspx?articleid=2122050
24. The Motion Aftereffect: Mechanisms and Variants \- ThinkIR, https://ir.library.louisville.edu/cgi/viewcontent.cgi?article=1014\&context=tce
25. Visual motion aftereffect in human cortical area MT revealed by, https://www.researchgate.net/publication/15446360\_Visual\_motion\_aftereffect\_in\_human\_cortical\_area\_MT\_revealed\_by\_functional\_magnetic\_resonance\_imaging
26. Functional MRI Studies of Human Visual Motion Perception, https://academic.oup.com/cercor/article-abstract/13/4/340/315701
27. Visual motion aftereffect in human cortical area MT ... \- PubMed, https://pubmed.ncbi.nlm.nih.gov/7753168/
28. The motion aftereffect \- PubMed, https://pubmed.ncbi.nlm.nih.gov/21227087/
29. Spiral aftereffect \- Michael Bach, https://michaelbach.de/ot/mot-adaptSpiral/
30. \[PDF\] Visual motion aftereffect in human cortical area MT revealed, https://www.semanticscholar.org/paper/Visual-motion-aftereffect-in-human-cortical-area-MT-Tootell-Reppas/cd4f641b2314290a413f8b1d9f1d14f974197153
31. Fraser spiral illusion \- Wikipedia, https://en.wikipedia.org/wiki/Fraser\_spiral\_illusion
32. Optical Illusions \- Vision and Eye Health, https://www.vision-and-eye-health.com/optical-illusions/
33. (PDF) The neural signature of the Fraser illusion \- ResearchGate, https://www.researchgate.net/publication/280220003\_The\_neural\_signature\_of\_the\_Fraser\_illusion\_an\_explorative\_EEG\_study\_on\_Fraser-like\_displays
34. The Curve class in threejs a general overview \- Dustin Pfister, https://dustinpfister.github.io/2022/06/17/threejs-curve/
35. TubeGeometry – three.js docs, https://threejs.org/docs/pages/TubeGeometry.html
36. Draw a custom tube geometry : r/threejs \- Reddit, https://www.reddit.com/r/threejs/comments/3se0xy/draw\_a\_custom\_tube\_geometry/
37. extrudePath.closed is ignored when generating Frenet frames, https://github.com/mrdoob/three.js/issues/32359
38. Wrong tangent at the end of the curve \- \#4 by PavelBoytchev, https://discourse.threejs.org/t/wrong-tangent-at-the-end-of-the-curve/49156/4
39. Drawing a long 3D tube · Issue \#905 · mrdoob/three.js \- GitHub, https://github.com/mrdoob/three.js/issues/905?timeline\_page=1
40. Inaccurate adjustment when cylinder is deformed \- three.js forum, https://discourse.threejs.org/t/inaccurate-adjustment-when-cylinder-is-deformed/50941
41. Threejs TubeGeometry: Applying custom curve causes unexpected, https://stackoverflow.com/questions/31660099/threejs-tubegeometry-applying-custom-curve-causes-unexpected-twisting
42. Frenet frame abruptly shifting along 3D curve \- McNeel Forum, https://discourse.mcneel.com/t/frenet-frame-abruptly-shifting-along-3d-curve/143741
43. Creating a long TubeGeometry along a long SplineCurve3 \- GitHub, https://github.com/mrdoob/three.js/issues/5503
44. How can I make good tube with three.js? for example railings, https://discourse.threejs.org/t/how-can-i-make-good-tube-with-three-js-for-example-railings/79506
45. Three.js Tunnel Effect: Buffer Data \+ Quaternions \- YouTube, https://www.youtube.com/watch?v=ZIGvMJ5N9Iw
46. Writing GLSL with three.js — Part 1 | by Dusan Bosnjak \- Medium, https://medium.com/@pailhead011/writing-glsl-with-three-js-part-1-1acb1de77e5c
47. Mini Lecture \- A GLSL Tutorial in Practice \- Plasma Pip, https://www.plasmapip.com/post/07\_mini-lecture-GLSL
48. ShaderMaterial – three.js docs, https://threejs.org/docs/pages/ShaderMaterial.html
49. Ray Marching in Three JS \- Medium, https://medium.com/@nabilnymansour/ray-marching-in-three-js-66b03e3a6af2
50. Shader coordinates \-\> sphere mapping : r/GraphicsProgramming, https://www.reddit.com/r/GraphicsProgramming/comments/17e24mc/shader\_coordinates\_sphere\_mapping/
51. Seamless Polar coordinates \- \#2 by mjurczyk \- three.js forum, https://discourse.threejs.org/t/seamless-polar-coordinates/67834/2
52. Screen-Space Effects Using Polar Coordinates Linear Transformations, https://iradicator.com/screen-space-effects-using-polar-coordinates-linear-transformations/
53. Log-spherical Mapping in SDF Raymarching \- osar.fr, https://www.osar.fr/notes/logspherical/
54. Python & OpenGL for Scientific Visualization \- LaBRI, https://www.labri.fr/perso/nrougier/python-opengl/
55. A spirals bonanza from a few simple polar formulas, https://inputrandomness.com/a-spirals-bonanza-from-a-few-simple-polar-formulas/
56. Antialiasing Approaches \- OpenGL \- Khronos Forums, https://community.khronos.org/t/antialiasing-approaches/53784
57. AAA \- Analytical Anti-Aliasing \- FrostKiwi's Secrets, https://blog.frost.kiwi/analytical-anti-aliasing/
58. Drawing antialiased circles in OpenGL \- rubendv.be, https://rubendv.be/posts/fwidth/
59. Anti Aliasing \- LearnOpenGL, https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing
60. AntiAliased grid lines(fwidth) \- Unity Discussions, https://discussions.unity.com/t/antialiased-grid-lines-fwidth/817945
61. How to antialias the sdf edge? : r/GraphicsProgramming \- Reddit, https://www.reddit.com/r/GraphicsProgramming/comments/1gqehg0/how\_to\_antialias\_the\_sdf\_edge/
62. Reference \- p5.js, https://p5js.org/reference/
63. What's the difference of using smoothstep and linear interpolation for, https://computergraphics.stackexchange.com/questions/14285/whats-the-difference-of-using-smoothstep-and-linear-interpolation-for-antialias
64. The Best Darn Grid Shader (Yet) \- Ben Golus \- Medium, https://bgolus.medium.com/the-best-darn-grid-shader-yet-727f9278b9d8
65. Mesh Gradient Playground : r/threejs \- Reddit, https://www.reddit.com/r/threejs/comments/1oaqaem/mesh\_gradient\_playground/
66. Erkaman/glsl-cos-palette \- GitHub, https://github.com/Erkaman/glsl-cos-palette
67. Ray marching \- Wikipedia, https://en.wikipedia.org/wiki/Ray\_marching
68. How to Create a Liquid Raymarching Scene Using Three.js Shading, https://tympanus.net/codrops/2024/07/15/how-to-create-a-liquid-raymarching-scene-using-three-js-shading-language/
69. Immersive Visualization of Flat Surfaces Using Ray Marching \- arXiv, https://arxiv.org/html/2506.07558v1
70. Using raymarched shaders as environments in 3D video games, https://researchdiscovery.drexel.edu/view/pdfCoverPage?instCode=01DRXU\_INST\&filePid=13321493720004721\&download=true
71. An Introduction to Raymarching \- Maxime Garcia, https://typhomnt.github.io/teaching/ray\_tracing/raymarching\_intro/
72. Shader Craft \- GLSL Shader Techniques \- Get Claude Skills, https://www.getclaudeskills.com/skills/shader-craft-minimax-ai
73. Raymarching Shader \- Converting camera position to object space, https://discourse.threejs.org/t/raymarching-shader-converting-camera-position-to-object-space/49315
74. WebGPU & TSL in Three.js — The new course \- YouTube, https://www.youtube.com/watch?v=8HeNnp9sdm4
75. Node based editor for TSL \- Showcase \- three.js forum, https://discourse.threejs.org/t/node-based-editor-for-tsl/89394
76. GPU-Side Physics: A Three.js WebGPU Compute Demo, https://www.webgpu.com/showcase/threejs-webgpu-compute-physics/
77. WebGPU & TSL Course \- Three.js Journey, https://threejs-journey.com/webgpu-tsl
78. Three.js Shading Language \- GitHub, https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language
79. Field Guide to TSL and WebGPU \- The Blog of Maxime Heckel, https://blog.maximeheckel.com/posts/field-guide-to-tsl-and-webgpu/
80. compute particles \- three.js webgpu, https://threejs.org/examples/webgpu\_compute\_particles.html
81. TSL – three.js docs, https://threejs.org/docs/pages/TSL.html
82. Post-processing \- Sangil Lee, https://sangillee.com/2025-01-15-post-processing/
83. pmndrs/postprocessing: A post processing library for three.js. \- GitHub, https://github.com/pmndrs/postprocessing
84. UnrealBloomPass – three.js docs, https://threejs.org/docs/pages/UnrealBloomPass.html
85. The Complete Guide to Three.js Post-Processing in 2026, https://threejsroadmap.com/blog/the-complete-guide-to-threejs-post-processing-in-2026
86. Unreal Bloom Selective \- Three.js Post Processing, https://waelyasmina.net/articles/unreal-bloom-selective-threejs-post-processing/