Joshua Opolko

VR Visual Effects That Exploit the Visual Cortex: 11 Psychedelic Techniques

Swirling neon psychedelic visual effects rendered in a VR environment, showing fractal color patterns
At a glance
  • The visual cortex occupies 50-55% of the cerebral cortex. These 11 techniques are calibrated to overwhelm it in the style of SteamVR psychedelic apps
  • Every demo is live in the page: sliders adjust shader parameters in real time. Set them before tapping Enter VR since the browser's DOM controls are hidden in immersive mode. Head tracking is live in all demos; tilt your phone to pan the view on mobile.
  • All demos are Three.js r169 via CDN importmap, lazy-initialized on scroll, no build step required

Your visual cortex dedicates 50-55% of the cerebral cortex to processing what you see and burns glucose at a rate that outpaces oxygen supply. The 2025 MICrONS connectome mapped 523 million simultaneous neural connections in a single cubic millimeter of visual cortex, all running in parallel, all susceptible to being overwhelmed by the right kind of input. That is the physiological foundation of psychedelic VR.

These 11 techniques come from the tradition of immersive visual environments designed not to represent reality but to saturate the systems that process it. Each is implemented here as a live Three.js WebGL demo. Sliders below each canvas change shader parameters in real time. On a Meta Quest, click Enter VR to open a full immersive-VR session via the WebXR Device API with head tracking and stereo rendering. See the neuroscience breakdown for the perceptual mechanisms each technique exploits.

Key takeaways

Why Three.js for browser VR

Three.js r169 exposes raw GLSL shader control via ShaderMaterial, handles WebXR stereo rendering for the Quest browser natively, and is deliverable as a single HTML file with CDN imports. Babylon.js is a viable alternative with stronger built-in scene management for complex multi-object environments. For raw shader VFX with minimal overhead and the highest quality of AI code generation, Three.js wins on simplicity. No build pipeline. No install. The demos on this page load Three.js from jsDelivr CDN and initialize lazily as you scroll.

What are the 11 psychedelic VR techniques?

1. Flow-based UV distortion

Exploits: MT/V5 motion processing + gap-filling

Three overlapping noise fields advance at different rates, creating liquid "breathing" motion the brain interprets as purposeful but cannot resolve into a stable object. The interference patterns between the three fields continuously dissolve any structure the pattern-recognition system starts to form, keeping MT/V5 firing without ever delivering a coherent motion vector. Speed controls animation rate; Warp sets how strongly the noise fields distort the UV lookup; Saturation goes from pastel to fully neon.

Three.js WebGL
Core GLSL (fragment shader)
float t = uTime * 0.35 * uSpeed;
vec2 n1 = vec2(noise(vUv*2.0+t*0.7), noise(vUv*2.0+t*0.7+5.2)) * 2.0 - 1.0;
vec2 n2 = vec2(noise(vUv*5.0-t*0.45+3.7), noise(vUv*5.0-t*0.45+9.1)) * 2.0 - 1.0;
vec2 n3 = vec2(noise(vUv*11.0+t*0.22+7.3), noise(vUv*11.0+t*0.22+1.5)) * 2.0 - 1.0;
vec2 w = vUv + n1*uWarp + n2*uWarp*0.5 + n3*uWarp*0.25;
float c = noise(w*5.0 + vec2(t*0.25,-t*0.18));
gl_FragColor = vec4(hsv2rgb(vec3(c + t*0.08, uSat, 1.0)), 1.0);
AI demo prompt

Create a self-contained Three.js r169 WebGL demo (single HTML file, importmap CDN) showing psychedelic flow-based UV distortion. Orthographic camera, fullscreen PlaneGeometry(2,2), ShaderMaterial. Fragment: 3 overlapping noise-field flow layers at different speeds. Full HSV spectrum cycling with uTime. uSpeed, uWarp, uSat uniforms driven by range sliders below the canvas. 300px canvas height.

2. Fractal kaleidoscope

Exploits: scale-invariant pattern recognition + V4 color processing

Mandelbrot iteration combined with N-fold rotational symmetry generates a self-similar pattern the brain keeps trying to read at every zoom level and keeps failing. The scale-invariant object recognition system fires continuously because the same structure recurs at every scale; the V4 color area is simultaneously flooded with rapidly cycling hue at maximum saturation. Symmetry slider sets the fold count: low values create wide, angular sectors; high values produce dense mandala geometry.

Three.js WebGL
Core GLSL (fragment shader)
vec2 uv = (vUv - 0.5) * 2.0;
uv.x *= uRes.x / uRes.y;
float angle = atan(uv.y, uv.x) + uTime * uRotSpeed;
float r = length(uv);
float sectors = uSymmetry * 2.0;
angle = mod(angle, 2.0*PI / sectors);
angle = abs(angle - PI / sectors);
uv = vec2(cos(angle), sin(angle)) * r;
vec2 c = uv * uZoom + vec2(-0.4, sin(uTime*0.07)*0.1);
vec2 z = vec2(0.0); float iter = 0.0;
for (int i = 0; i < 16; i++) {
  if (dot(z,z) > 4.0) break;
  z = vec2(z.x*z.x-z.y*z.y+c.x, 2.0*z.x*z.y+c.y); iter += 1.0;
}
gl_FragColor = vec4((iter < 16.0) ?
  hsv2rgb(vec3(iter/16.0 + uTime*0.06, 0.97, 1.0)) : vec3(0.0), 1.0);
AI demo prompt

Create a self-contained Three.js r169 WebGL demo showing a psychedelic fractal kaleidoscope. Fullscreen quad, orthographic camera, ShaderMaterial. Fragment: uSymmetry-fold rotational symmetry applied to UV, then 16-iteration Mandelbrot with HSV coloring and animated hue cycling. uRotSpeed, uZoom, uSymmetry uniforms on sliders. Maximally saturated. 300px canvas, dark background.

3. GPU particle vortex with additive trails

Exploits: object segmentation + motion coherence detection

Dense GPU particle systems with additive blending create structures that appear to emerge, coalesce, and dissolve continuously. The object-segmentation system works at its limit: it keeps seeing entities that immediately dissolve back into the field. Each particle follows a unique 3D Lissajous orbit so the global vortex has internal structure the brain can almost parse, producing the characteristic sense of organized intelligence in the noise. In VR, the stereo depth makes the orbital structure appear genuinely three-dimensional around the viewer.

Three.js WebGL
Core GLSL (vertex + fragment)
// Vertex: Lissajous orbit per particle
float t = uTime * aSpeed * uOrbitSpeed + aPhase;
vec3 pos = vec3(
  aRadius * uSpread * cos(t) * cos(t * 0.37 + 1.0),
  aRadius * uSpread * sin(t * 1.31) * 0.7,
  aRadius * uSpread * sin(t) * cos(t * 0.73 + 2.1)
);
gl_PointSize = clamp(130.0 / -mvPos.z, 1.0, 12.0);

// Fragment: soft disc with additive glow
vec2 pc = gl_PointCoord - 0.5;
if (length(pc) > 0.5) discard;
float a = 1.0 - smoothstep(0.1, 0.5, length(pc));
gl_FragColor = vec4(vCol * uGlow, a * 0.9);
AI demo prompt

Create a self-contained Three.js r169 WebGL demo showing a psychedelic GPU particle vortex. 4000 THREE.Points with ShaderMaterial. Each particle has aPhase, aRadius, aSpeed attributes. Vertex shader animates unique Lissajous 3D orbit with uTime. uOrbitSpeed, uSpread, uGlow uniforms on sliders. Fragment: soft disc, additive blending, depthWrite:false. Colors by phase through HSV. Camera rotates slowly. 300px canvas.

4. Chromatic aberration (fracture mode)

Exploits: binocular fusion + color-detail channel separation

Extreme chromatic aberration separates RGB channels with a quadratic offset that accelerates toward the edges, creating a tripling of the image that the binocular fusion system tries and fails to merge. The brain's color-detail channel receives conflicting signals from each eye. Pulsing the intensity slowly means the image continuously falls apart and tries to reassemble. In VR, each eye receives a slightly different aberration pattern, compounding the fusion failure.

Three.js WebGL
Core GLSL (fragment shader)
float pat(vec2 uv) {
  float r = length(uv - 0.5); float a = atan(uv.y-0.5, uv.x-0.5);
  return sin(r*uFrequency - uTime*uPatSpeed + a*5.0)*0.5 + 0.5;
}
vec2 dir = normalize(vUv - 0.5); float dist = length(vUv - 0.5);
float ab = dist*dist * uAberration * (sin(uTime*0.55)*0.45 + 0.8);
gl_FragColor = vec4(pat(vUv+dir*ab*1.5), pat(vUv), pat(vUv-dir*ab*1.5), 1.0);
AI demo prompt

Create a self-contained Three.js r169 WebGL demo showing extreme chromatic aberration. Fullscreen quad, ShaderMaterial. Fragment: a polar-coordinate sinusoidal ring pattern function(uv) using uFrequency and uPatSpeed. Apply quadratic RGB channel separation (offset = dist*dist * uAberration, pulsing with sin(time)). Each channel samples the pattern at a different UV offset. uAberration, uFrequency, uPatSpeed sliders. 300px canvas.

5. Infinite tunnel (depth cue overload)

Exploits: looming response + vergence-accommodation conflict

A tunnel rendered in polar coordinates with continuously advancing depth creates persistent looming motion the brain cannot habituate to, because it never arrives. The vergence-accommodation system drives the eyes to converge on approaching geometry and finds nothing solid. Rush Speed controls how fast the tunnel appears to advance; Symmetry sets angular sector count (higher = denser, more disorienting wall patterns); Brightness scales overall output without changing the color balance.

Three.js WebGL
Core GLSL (fragment shader)
vec2 uv = vUv * 2.0 - 1.0; uv.x *= uRes.x / uRes.y;
float r = length(uv); float angle = atan(uv.y, uv.x);
float depth = 0.4 / (r + 0.005);
float td = mod(depth - uTime * uRushSpeed, 1.0);
float ta = mod(angle / (PI / uSymmetry), 1.0);
float stripes = sin(ta*28.0+uTime*0.5)*0.5+0.5;
float rings   = sin(td*22.0-uTime*2.0)*0.5+0.5;
vec3 col = hsv2rgb(vec3(td*0.55+uTime*0.07, 0.97, 1.0))
           * stripes * rings * uBrightness;
col *= 1.0 - smoothstep(0.6, 1.05, r);
gl_FragColor = vec4(col, 1.0);
AI demo prompt

Create a self-contained Three.js r169 WebGL demo showing a psychedelic infinite tunnel. Fullscreen quad, ShaderMaterial. Fragment: polar coordinate mapping, depth = 0.4/r, animate with mod(depth - uTime*uRushSpeed, 1.0). uSymmetry angular sectors. Stripe and ring interference. HSV color cycling. uRushSpeed, uSymmetry, uBrightness sliders. Vignette at edges. 300px canvas.

6. Volumetric god rays (radial light scattering)

Exploits: brightness sensitivity + peripheral motion detection

Three light sources orbit through a pulsing nebula, each carrying its own color that cycles through the full spectrum as they move. Because they are spaced 120 degrees apart in the color wheel and rotating together, the combined light never settles: it rolls continuously through red, green, blue, amber, and violet in overlapping sweeps. A breathing pulse compresses and expands the whole ray field at whatever rate you set, giving it a heartbeat. The effect is strongest at the edges of your vision: your brain's fast-motion detection system, built to catch danger in the periphery, keeps firing because nothing ever stops moving. In VR, turning your head drags the ray field with you before it snaps back, creating the sensation of swimming through something with physical weight.

Three.js WebGL
Core GLSL (fragment shader)
// 3 orbiting sources, 36-sample radial accumulation + breathing pulse
vec2 lp1=vec2(0.5+cos(uTime*0.42*uOrbitSpeed)*0.28, 0.5+sin(uTime*0.31*uOrbitSpeed)*0.22);
vec2 lp2=vec2(0.5+cos(uTime*0.37*uOrbitSpeed+2.094)*0.24, 0.5+sin(uTime*0.27*uOrbitSpeed+2.094)*0.18);
vec2 lp3=vec2(0.5+cos(uTime*0.51*uOrbitSpeed+4.189)*0.20, 0.5+sin(uTime*0.44*uOrbitSpeed+4.189)*0.16);
float pulse=0.65+0.35*sin(uTime*uPulseRate*6.283);
float w=0.04; float acc1=0.0,acc2=0.0,acc3=0.0;
vec2 d1=(vUv-lp1)/36.0, d2=(vUv-lp2)/36.0, d3=(vUv-lp3)/36.0, s1=vUv, s2=vUv, s3=vUv;
for (int i = 0; i < 36; i++) {
  s1-=d1; s2-=d2; s3-=d3;
  acc1 += (exp(-length(s1-lp1)*28.0) + noise(s1*9.0+uTime)*0.03) * w;
  acc2 += (exp(-length(s2-lp2)*28.0) + noise(s2*9.0-uTime)*0.03) * w;
  acc3 += (exp(-length(s3-lp3)*28.0) + noise(s3*9.0+uTime*1.3)*0.03) * w;
  w *= 0.96;
}
acc1*=uIntensity*pulse; acc2*=uIntensity*pulse; acc3*=uIntensity*pulse;
vec3 c1=hsv2rgb(vec3(uTime*0.05, 0.95, 1.0));
vec3 c2=hsv2rgb(vec3(uTime*0.05+0.333, 0.95, 1.0));
vec3 c3=hsv2rgb(vec3(uTime*0.05+0.667, 0.95, 1.0));
float bg=fbm(vUv*3.0+uTime*0.04)*0.12+fbm(vUv*7.0-uTime*0.06)*0.05;
gl_FragColor=vec4(hsv2rgb(vec3(uTime*0.02,0.75,bg))+c1*acc1+c2*acc2+c3*acc3,1.0);
AI demo prompt

Create a self-contained Three.js r169 WebGL demo showing triple-source volumetric god rays with breathing pulse. Fullscreen quad, ShaderMaterial. Fragment: three light sources orbit via sin/cos(uTime*uOrbitSpeed) spaced 2.094 rad apart. 36-sample radial accumulation using exp(-od*28)*w, w starts 0.04 decaying by 0.96 each step. Each source has its own hue cycling at 0.333 offsets. pulse=0.65+0.35*sin(uTime*uPulseRate*6.283) multiplied to intensity. Two-octave FBM nebula background. uIntensity, uOrbitSpeed, uPulseRate sliders. 300px canvas.

7. Displacement mapping (breathing surfaces)

Exploits: surface normal processing (V2/V3) + proprioceptive conflict

Animated vertex displacement across a 64x64 mesh creates the "breathing floor" effect familiar from psychedelic experiences. V2 and V3 cortical areas process surface curvature and depth discontinuities; a gently undulating mesh creates continuous non-zero input with no stable resting state. The grid overlay makes the vertex density visible. In Quest VR with head tracking, tilting your head toward the mesh amplifies the proprioceptive conflict between visual motion and vestibular stillness.

Three.js WebGL
Core GLSL (vertex shader)
vec3 pos = position; float ws = uWaveSpeed;
float h = sin(pos.x*2.2+uTime*0.6*ws) * sin(pos.y*2.2+uTime*0.45*ws) * uAmplitude;
h += sin(pos.x*6.0+uTime*1.3*ws) * sin(pos.y*4.5+uTime*1.1*ws) * uAmplitude * 0.33;
h += sin((pos.x+pos.y)*5.5+uTime*1.9*ws) * uAmplitude * 0.16;
pos.z += h; vH = h;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
AI demo prompt

Create a self-contained Three.js r169 WebGL demo showing a psychedelic breathing displacement surface. PlaneGeometry(4,4,64,64), perspective camera looking down at an angle. ShaderMaterial: vertex displaces Z with 3 sin() wave frequencies * uAmplitude * uWaveSpeed. Fragment: HSV color-by-height with uTime hue cycling, plus fract(vUv*uGridDensity) grid overlay. uAmplitude, uWaveSpeed, uGridDensity sliders. 300px canvas.

8. Temporal dithering (phosphene induction)

Exploits: temporal integration window + afterimage generation

The visual cortex integrates frames over a window of approximately 100ms. Concentric rings animated at high radial frequency, combined with slowly rotating spokes, produce patterns that change faster than the temporal integration window can cleanly separate. The result is an afterimage-like overlay: you see both the current frame and the previous frame simultaneously, like phosphenes (the visual phenomena caused by pressure or electrical stimulation of the visual cortex). The FBM breathing envelope prevents perceptual adaptation.

Three.js WebGL
Core GLSL (fragment shader)
vec2 uv = vUv - 0.5; float r = length(uv); float a = atan(uv.y, uv.x);
float rings  = sin(r * uRingFreq - uTime * 20.0) * 0.5 + 0.5;
float spokes = sin(a * uSpokeCount + uTime * 3.2) * 0.5 + 0.5;
float breathe = fbm(vUv * 3.5 + uTime * uBreatheSpeed) * 0.7 + 0.35;
float pattern = (rings * spokes + fbm(vUv*9.0-uTime*0.38)*0.28) * breathe;
pattern *= 1.0 - smoothstep(0.28, 0.62, r);
vec3 col = mix(vec3(0.05,0.0,0.22), vec3(1.0,0.88,1.0), pattern);
col += vec3(0.75,0.25,1.0) * pow(pattern, 3.0) * 2.5;
gl_FragColor = vec4(col, 1.0);
AI demo prompt

Create a self-contained Three.js r169 WebGL demo showing a psychedelic phosphene pattern. Fullscreen quad, ShaderMaterial. Fragment: polar coordinates, concentric rings at uRingFreq pulsing at 20 rad/s, uSpokeCount radial spokes rotating. FBM envelope at uBreatheSpeed. Vignette centered. Deep purple to white-purple color, additive highlight. uRingFreq, uSpokeCount, uBreatheSpeed sliders. 300px canvas.

9. Multi-layer parallax (depth field saturation)

Exploits: motion parallax + dorsal-stream depth processing

Five transparent cloud-shader planes at different Z depths with an oscillating camera create motion parallax: the monocular depth cue the brain uses to infer depth from a moving viewpoint. Unlike stereo depth, motion parallax is processed independently in the dorsal visual stream, so it reads as compelling depth even on a flat screen. In Quest VR with head tracking, turning your head produces the parallax motion naturally without camera scripting, making the depth layers feel genuinely spatial.

Three.js WebGL
Core GLSL (fragment, shared across layers)
// uSeed is unique per plane (0.1, 0.3, 0.5, 0.7, 0.9)
vec2 uv = vUv + vec2(uTime * uDriftSpeed * uSeed, uTime * uDriftSpeed * 0.7);
float cloud = fbm(uv * uCloudScale + uSeed * 5.0);
cloud = smoothstep(0.15, 0.55, cloud);
vec3 col = hsv2rgb(vec3(uSeed * 0.18 + uTime * 0.04, 0.92, 1.0));
gl_FragColor = vec4(col * cloud * 1.8, cloud * 0.72);
AI demo prompt

Create a self-contained Three.js r169 WebGL demo showing multi-layer psychedelic parallax. 5 transparent PlaneGeometry meshes at Z depths -2 to 0. Each has a ShaderMaterial with FBM cloud shader (uSeed unique per plane, uCloudScale and uDriftSpeed shared). Camera oscillates left-right by parallaxAmount (JS range slider). Additive/transparent blending. HSV hue per layer. 300px canvas, black background.

10. Procedural environment generation

Exploits: scene construction (ventral stream) + environmental presence

FBM terrain that continuously evolves prevents the ventral visual stream from constructing a stable scene model. The landscape shifts, recolors, and morphs in a way that suggests biological growth rather than mathematical generation. In Quest VR with head tracking and stereo rendering, the terrain appears to surround the viewer at full scale, making it the most immersive of the 10 techniques. Terrain Scale changes the spatial frequency of landscape features; Color Speed controls hue cycling rate across height bands.

Three.js WebGL
Core GLSL (vertex + fragment)
// Vertex: multi-octave FBM terrain
float h = fbm(position.xz * uTerrainScale + uTime*0.025) * 2.4;
h += fbm(position.xz * uTerrainScale * 3.5 + uTime*0.065) * 0.55;
pos.y += h - 0.9; vH = pos.y;

// Fragment: height-based hue cycling
float t = clamp((vH + 0.8) / 2.6, 0.0, 1.0);
float hue = t * 0.62 + uTime * uColorSpeed;
vec3 col = hsv2rgb(vec3(hue, 0.93, 0.88+t*0.12)) * (0.45 + t*0.8);
gl_FragColor = vec4(col, 1.0);
AI demo prompt

Create a self-contained Three.js r169 WebGL demo showing a psychedelic procedural alien terrain. PlaneGeometry(8,8,64,64) rotated flat. ShaderMaterial: vertex FBM displacement using uTerrainScale. Fragment: height-based HSV color with hue cycling at uColorSpeed. Camera orbits slowly via JS state controlled by cam-speed slider. Add 600 star Points above terrain. FogExp2 dark purple. 300px canvas.

11. Volumetric light field (depth of field + spectral cycling)

Exploits: monocular depth (bokeh focal plane) + V4 chromatic saturation + motion parallax

Real cameras have a focal plane: objects at one distance are sharp while everything nearer or farther blurs into round highlights called bokeh. This demo renders that honestly by reading the scene's depth buffer through a post-processing pass and blurring each pixel by how far it sits from a chosen focal distance, rather than applying a flat screen-space filter. Hundreds of glowing orbs cycle through the full color spectrum at staggered phase offsets, so the whole volume rolls through a continuous chromatic wave as the camera auto-orbits. Near orbs slide past far ones with true motion parallax while the depth blur dissolves background clusters into dreamy haze and holds foreground clusters sharp until the focal plane sweeps past them. Rack the Focus slider to send the sharp band traveling front to back. Open the Aperture to flood the field in bokeh circles. Click anywhere to plant a light that stays anchored in world space as the camera moves around it. In VR the artificial bokeh switches off and your own two eyes supply the real thing.

Three.js WebGL · DoF
Core setup (DoF post-processing + spectral cycling)
// Post-processing stack reads the depth buffer for true bokeh
composer.addPass(new RenderPass(scene, camera));
bokeh = new BokehPass(scene, camera, { focus: 11.0, aperture: 0.0042, maxblur: 0.012 });
composer.addPass(bokeh);
composer.addPass(new UnrealBloomPass(size, strength, radius, threshold));
composer.addPass(new OutputPass());

// Per-frame: roll each orb's hue by its unique phase offset
const hue = (o.userData.hueBase + t * hueSpeed * 0.03) % 1.0;
o.material.color.setHSL(hue, 0.95, 0.5);
o.material.emissive.setHSL(hue, 0.95, 0.5);

// In VR: bypass composer so the headset gets direct framebuffer access
if (renderer.xr.isPresenting) renderer.render(scene, camera);
else composer.render();
AI demo prompt

Create a self-contained Three.js r169 WebGL demo showing a psychedelic depth-of-field light field. 150 IcosahedronGeometry(1,3) orbs at random positions in a ±8×4×9 volume, MeshStandardMaterial with a unique HSL hueBase per orb (i/150). EffectComposer with RenderPass, BokehPass (focus 11, aperture 0.0042, maxblur 0.012), UnrealBloomPass (strength 0.78), OutputPass. OrbitControls autoRotate. Per-frame: cycle each orb's color and emissive via setHSL((hueBase+t*hueSpeed*0.03)%1, 0.95, 0.5). Click canvas to spawn a glowing orb with PointLight anchored in world space. In VR bypass composer and render direct. Sliders: Focus (4-22), Aperture (0-10), Bloom (0-1.6), Hue Speed (0.1-3), Drift (0.1-2). 300px canvas.


What is the WebXR performance budget on Meta Quest?

TechniqueTypeQuest 3 (90Hz)Quest 2 (72Hz)
Flow UV distortionFragment shader2-3ms3-5ms
Fractal kaleidoscopeFragment shader2-4ms4-6ms
Particle vortex (4k)Points / vertex1-2ms2-3ms
Chromatic aberrationFragment shader1-2ms2-3ms
Infinite tunnelFragment shader1-2ms2-3ms
God rays (24 samples)Fragment shader3-5ms5-7ms
Displacement (64x64)Vertex + fragment2-3ms3-4ms
Temporal phospheneFragment shader1-2ms2-3ms
Parallax layers (5)Multi-draw2-4ms3-5ms
Procedural terrainVertex + fragment2-3ms3-5ms
Volumetric light field (DoF + bloom)EffectComposer4-6ms7-10ms
Practical stack (3-4 combined)6-9ms9-13ms

Quest 2 budget is 13.9ms total per frame. Combining more than 3-4 effects requires adaptive quality: monitor performance.now() per frame and step down shader complexity (reduce loop iterations, halve resolution) if frame time exceeds 11ms. Quest 3 has approximately 2x GPU throughput, making 4-5 combined effects feasible at 90Hz.


Frequently asked questions

What makes VR visual effects psychedelic?

Psychedelic VR effects work by simultaneously overwhelming multiple visual cortex processing streams: motion detection in MT/V5, color processing in V4, scale-invariant pattern recognition, and temporal integration. The visual cortex dedicates 50-55% of the cerebral cortex to vision, making it highly susceptible to calibrated perceptual overload. See the full neuroscience breakdown.

Can I run these VR effects in the browser without Unity?

Yes. Three.js with ShaderMaterial exposes raw GLSL and supports the WebXR Device API natively in Meta Quest Browser. All 11 demos on this page are self-contained. On Quest, open this page in the browser, scroll to any demo, and tap Enter VR to start an immersive-VR session with stereo rendering and head tracking.

How do I enter VR from the browser on Meta Quest?

Open this page in Meta Quest Browser. Scroll to any demo and tap the Enter VR button below the canvas. The browser requests permission for an immersive-vr session via the WebXR Device API. The demo renders in full stereo at the Quest's native refresh rate (72Hz on Quest 2, 90Hz on Quest 3). Press the menu button to exit and return to the page.

What is the performance budget for psychedelic VR on Meta Quest?

Quest 3 targets 90Hz (11.1ms frame budget); Quest 2 targets 72Hz (13.9ms). Fullscreen GLSL fragment shaders cost 2-5ms. GPU particles cost 1-3ms. Running 3-4 combined effects is feasible with adaptive quality reducing shader iteration counts at runtime when frame time exceeds 11ms.

Which visual effects cause the strongest perceptual response in VR?

Fractal kaleidoscopes are consistently the strongest because they simultaneously overload scale-invariant pattern recognition, V4 color processing, and spatial mapping. Tunnel effects rank second by exploiting the looming response. Flow distortion ranks third by overloading MT/V5 motion processing. Combining any two produces the most intense perceptual response within a safe frame budget.


Sources