Cinematic scrollytelling experience built with Next.js 15, React Three Fiber (R3F), GSAP, Lenis smooth scroll, and custom GLSL Shaders.
It takes the user on a continuous journey through different scales of physical reality—from a visible white pixel on a screen down to the molecular, atomic, quantum, and planck scales, then into a warping black hole and a space-folding singularity, before zooming out to a cosmological dawn and an infinite loop of recursion.
The experience is divided into three distinct phases:
-
Intro Phase (
intro):- A static futuristic HUD overlays the screen, displaying telemetry scan data, coordinates of the central anomaly (mass, distance, R.A., dec.), a live scale index list, and a miniature fluctuating spectral analysis graph.
- The user is prompted with staggered cinematic voice-overs: "The smallest object ever discovered." followed by "The last unanswered question."
- Clicking "BEGIN INVESTIGATION" transitions the state.
-
Entering Phase (
entering):- The HUD panels fade out smoothly, and a full-screen transition flash triggers.
- An introductory "warp whoosh" sound sweeps through the audio context.
- The camera begins an accelerated lerp zoom towards the central anomaly (the crystal pixel), moving from
$Z = 480$ down to the threshold of$Z = 1.8$ , where it transitions to active mode.
-
Active Phase (
active):- The interactive scrolling is unlocked.
- Smooth Lenis scrolling progresses the scroll value from
0.0to1.0, driving camera movement, post-processing bloom/chromatic intensity, narrative panel updates, and real-time audio modulation.
graph TD
subgraph UI Layer (HTML & DOM)
EP[Experience.tsx]
LP[LenisProvider.tsx]
SP[ScrollProvider.tsx]
NP[NarrativePanel.tsx]
SC[ScrollProgress.tsx]
CC[CustomCursor.tsx]
CB[ClickToBegin.tsx]
end
subgraph R3F WebGL Canvas Layer
MC[MainCanvas.tsx]
CR[CameraRig.tsx]
GD[GlobalDust.tsx]
PP[PostProcessing.tsx]
subgraph Scene Modules
SC00[Scene00_Observatory.tsx]
SC01[Scene01_Pixel.tsx]
SC02[Scene02_Digital.tsx]
SC03[Scene03_Molecular.tsx]
SC04[Scene04_Atomic.tsx]
SC05[Scene05_QuantumField.tsx]
SC06[Scene06_BlackHole.tsx]
SC07[Scene07_EventHorizon.tsx]
SC08[Scene08_Singularity.tsx]
SC09[Scene09_Revelation.tsx]
SC10[Scene10_CosmicZoom.tsx]
SC11[Scene11_InfiniteRecursion.tsx]
end
end
subgraph State Management & Utilities
UA[useAudio.ts]
UM[useMouseParallax.ts]
USP[useScrollProgress.tsx]
SCFG[sceneConfig.ts]
NARR[sceneNarratives.ts]
ACT[activeScene.ts]
end
EP --> SP
EP --> LP
LP --> MC
LP --> NP
LP --> SC
LP --> CC
LP --> CB
MC --> CR
MC --> GD
MC --> PP
MC --> SC00
MC --> SC01
MC --> SC02
MC --> SC03
MC --> SC04
MC --> SC05
MC --> SC06
MC --> SC07
MC --> SC08
MC --> SC09
MC --> SC10
MC --> SC11
CR -.-> USP
CR -.-> UM
CB -.-> UA
CB -.-> USP
NP -.-> USP
NP -.-> ACT
ACT -.-> SCFG
SC00 -.-> USP
SC01 -.-> USP
SC02 -.-> USP
SC03 -.-> USP
SC04 -.-> USP
SC05 -.-> USP
SC06 -.-> USP
SC07 -.-> USP
SC08 -.-> USP
SC09 -.-> USP
SC10 -.-> USP
SC11 -.-> USP
stateDiagram-v2
[*] --> Intro : Initial Load
Intro --> Entering : User Clicks "BEGIN INVESTIGATION"
note right of Entering
- Trigger synth Warp Whoosh sound
- Fade out DOM HUD Elements
- Perform camera zoom: Z=500 -> Z=0
end note
Entering --> Active : Camera passes Z=1.8
note right of Active
- Unlock Lenis Scroll
- Show Narrative Overlay
- Activate relative scene visibility
end note
Active --> Active : User Scrolls (0.0 <= progress <= 1.0)
note right of Active
- Interpolate camera position/lookAt via keyframes
- Modulate audio parameters (frequency, tempo, volume)
- Transition between 12 progressive scales
end note
Active --> Intro : Page Reload / Reset
Singularity/
├── app/ # Next.js Application router
│ ├── globals.css # Main styling, custom fonts, cursor and HUD declarations
│ ├── layout.tsx # Root HTML wrapper
│ └── page.tsx # Renders the main Experience component
├── components/ # React components
│ ├── Experience.tsx # Orchestrator wrapping canvas & DOM panels in Providers
│ ├── canvas/ # React Three Fiber components
│ │ ├── CameraRig.tsx # Handles camera movement, keyframes, mouse parallax, jitter
│ │ ├── GlobalDust.tsx # Renders floating space particles in background
│ │ ├── MainCanvas.tsx # Renders Canvas, scene layers, post-processing stack
│ │ └── PostProcessing.tsx # Dynamic Bloom, Vignette, Noise, HueSaturation, Chromatic Aberration passes
│ ├── scenes/ # Individual R3F interactive scene modules
│ │ ├── Scene00_Observatory.tsx # Cybernetic observation window and scanning lasers
│ │ ├── Scene01_Pixel.tsx # Single monolithic bright pixel and concentric rings
│ │ ├── Scene02_Digital.tsx # Orthogonal digital lattice of colored subpixels
│ │ ├── Scene03_Molecular.tsx # Covalent bonding models of Water (H2O) and Benzene (C6H6) molecules
│ │ ├── Scene04_Atomic.tsx # Raymarched Bohr orbits with physical proton/neutron nucleus
│ │ ├── Scene05_QuantumField.tsx # Fluctuating wave-function lattice and tunneling particles
│ │ ├── Scene06_BlackHole.tsx # Gravitational lensing raymarching accretion disk
│ │ ├── Scene07_EventHorizon.tsx # Point-of-no-return space-time stretch and particle drag
│ │ ├── Scene08_Singularity.tsx # Ultimate dimensional collapse and light warp
│ │ ├── Scene09_Revelation.tsx # Climax: cosmic dust, colorful stellar nebulas
│ │ ├── Scene10_CosmicZoom.tsx # Zooming out: galaxies condensing back to particles
│ │ ├── Scene11_InfiniteRecursion.tsx# Mirroring self-similarity loop
│ │ └── shared/ # Shared helper meshes for scenes
│ │ ├── MoleculeMesh.tsx # Builds cylinder bonds and CPK sphere atoms
│ │ └── ShaderPlane.tsx # Utility plane with shader resolution calculation
│ └── ui/ # UI components overlaying WebGL
│ ├── ClickToBegin.tsx # Cyberpunk telemetry HUD, interactive CTA button
│ ├── CustomCursor.tsx # Smoothly tracking dot and lag ring (mix-blend diff mode)
│ ├── LenisProvider.tsx # Initializer for smooth-scrolling wrapper
│ ├── NarrativePanel.tsx # Interactive scrolly text panel aligned to scene ranges
│ ├── ScrollProgress.tsx # Simple bottom loading progress bar
│ └── Typography.tsx # Text configuration helper
├── hooks/ # Custom React hooks
│ ├── useAudio.ts # Web Audio API context synth (oscillators, filters, gain nodes)
│ ├── useMouseParallax.ts # Captures viewport cursor coords for camera offset
│ └── useScrollProgress.tsx # React context for tracking global page scroll
├── lib/ # Logic & static configurations
│ ├── activeScene.ts # Computes current active scene range from progress
│ ├── chemistry.ts # Defines atom CPK values and molecular coordinates (benzene, water)
│ ├── gsapAnimations.ts # Shared GSAP helpers
│ ├── sceneConfig.ts # Defines the 11 scroll ranges and opacity formulas
│ └── sceneNarratives.ts # Copy and titles for narrative scrollytelling panel
├── public/ # Static files
│ └── audio/ # Audio folder containing .gitkeep
├── shaders/ # GLSL shaders (custom raymarching/fields)
│ ├── accretionDisk.frag.glsl # Swirling black hole accretion disk representation
│ ├── atomOrbital.frag.glsl # Basic atomic visualizer
│ ├── atomOrbital.vert.glsl # Vertex distortion for atomic orbitals
│ ├── atomRaymarch.frag.glsl # Raymarches Hydrogen-like orbitals (1s, 2p, 3dxy probability fields)
│ ├── blackhole.frag.glsl # Einstein ring and black hole event horizon projection
│ ├── blackhole.vert.glsl # Screen-aligned quad shader vertex setup
│ ├── digitalPixel.frag.glsl # Renders digital grid subpixels
│ ├── particleSystem.vert.glsl# Vert modification for particle scale/decay
│ ├── quantumField.frag.glsl # Probability wave visualization
│ ├── quantumField.vert.glsl # Fluctuating wave function surface displacements
│ ├── quantumVolume.frag.glsl # 3D noise warp representing quantum foam
│ └── singularity.frag.glsl # Raymarched space-folding coordinates
├── tsconfig.json # TypeScript config
├── eslint.config.mjs # ESLint setup
├── next.config.ts # Webpack configurations (includes raw-loader for GLSL imports)
└── package.json # Project dependencies and execution scripts
1. Web Audio Synthesis Engine (useAudio.ts)
Instead of relying on heavy external audio files, SINGULARITY uses a fully synthetic Web Audio API oscillator bank to dynamically synthesize the cinematic soundscape.
graph TD
subgraph Space Drone (Ambient Layer)
O1[Triangle Osc @ 55Hz (A1)]
O2[Sawtooth Osc @ 110Hz (A2)]
F1[Lowpass Filter @ 180Hz]
G1[Drone Gain Node]
O1 --> F1
O2 --> F1
F1 --> G1
end
subgraph Heartbeat (Event Horizon Zone)
O3[Sine Osc @ 55Hz / 44Hz]
G2[Heartbeat Gain Node]
O3 --> G2
end
subgraph Black Hole Rumble (Sub-bass)
O4[Sawtooth Osc @ 32Hz - 26Hz]
F2[Resonant Lowpass Filter @ 65Hz]
G3[Rumble Gain Node]
O4 --> F2
F2 --> G3
end
subgraph Warp Whoosh (Intro Transition Effect)
NS[Noise Buffer Source]
O5[Sub Oscillator: Sweeping Sine]
F3[Bandpass Filter @ 80Hz - 2800Hz]
G4[Noise Gain Node]
G5[Sub Gain Node]
NS --> F3
F3 --> G4
O5 --> G5
end
G1 --> Dest[AudioContext Destination]
G2 --> Dest
G3 --> Dest
G4 --> Dest
G5 --> Dest
-
Drone Synth: An A1 triangle wave (
$55\text{ Hz}$ ) detuned by$-5$ cents and an A2 sawtooth wave ($110\text{ Hz}$ ) detuned by$+5$ cents are fed into a lowpass filter. The filter's cutoff is continually modulated ($170\text{ Hz} \pm 60\text{ Hz}$ ) in step with the scroll position, creating a breathing sensation. -
Heartbeat Synth: Triggered via a self-scheduling
setTimeoutloop. It generates a double-thump (lub-dub) using two rapidly decaying oscillators at$55\text{ Hz}$ and$46\text{ Hz}$ , offset by$0.25\text{ s}$ . As the user scrolls into the Event Horizon and Singularity ranges:-
Volume scale: Linearly ramps from
$0$ up to$0.45$ . -
Tempo rate: Accelerates the interval between beats from
$1400\text{ ms}$ down to$600\text{ ms}$ .
-
Volume scale: Linearly ramps from
-
Black Hole Rumble: A low sub-frequency sawtooth wave (
$32\text{ Hz}$ ) processed by a high-resonance lowpass filter ($Q = 7$ , cutoff at$65\text{ Hz}$ ) to generate a heavy sub-bass drone when scrolling through the black hole phases ($0.44 - 0.66$ ). The frequency drops from$32\text{ Hz}$ to$26\text{ Hz}$ to simulate gravitational redshift. -
Warp Whoosh: Created dynamically using a custom white noise buffer (
$1.5\text{ s}$ ) filtered through a sweeping bandpass filter ($80\text{ Hz}$ up to$2800\text{ Hz}$ and back to$100\text{ Hz}$ ) combined with a sweeping sine oscillator ($45\text{ Hz} \rightarrow 550\text{ Hz} \rightarrow 25\text{ Hz}$ ).
2. Camera Rig Interpolation & Mechanics (CameraRig.tsx)
The CameraRig handles all spatial transformations inside the canvas. It does this through:
-
Keyframe LERP Interpolation: Moves the camera position and focal target smoothly by indexing the current scroll position into a predefined keyframe map containing 13 positions (ranging from
$Z = 500$ down to$Z = 2$ , then expanding out back to$Z = 500$ ). Keyframe easing uses the cubic Hermite formula:$$f(t) = t^2 \times (3 - 2t)$$ -
Mouse Parallax Offset: Injects real-time mouse translation coordinates smoothly using a dampening lerp factor:
$$\text{Target} = \text{KeyframePos} + \text{MouseParallax}$$ -
Quantum & Singularity Jitter: When in the Quantum Field (
$0.33 - 0.44$ ) or Singularity ($0.66 - 0.76$ ) phases, high-frequency white noise displacements are injected into the camera positions to simulate chaotic quantum fluctuations and gravitational turbulence:$$\delta x = (\text{noise}(t \times 0.5) - 0.5) \times 0.15$$ -
Black Hole Orbital Swirl: While traversing the accretion disk, the camera is swept in a partial circular orbit around the central core using:
$$x_{\text{add}} = \cos(\theta) \times 12 \times lt, \quad z_{\text{add}} = \sin(\theta) \times 12 \times lt$$
Each scale range is enhanced with highly optimized custom shaders rendered via screen-aligned quads in ShaderPlane.tsx:
-
Hydrogen-like Atomic Orbitals (atomRaymarch.frag.glsl): Performs volumetric raymarching over mathematical probability densities of hydrogen-like electron orbitals:
-
$1s$ orbital:$\psi_{1s}(r) \propto e^{-2.2r}$ -
$2p_x, 2p_y, 2p_z$ orbitals:$\psi_{2p}(r) \propto x^2 r^2 e^{-r}$ -
$3d_{xy}$ orbital:$\psi_{3d}(r) \propto xy e^{-0.9r}$
-
- Quantum Foam Volume (quantumVolume.frag.glsl): Simulates virtual particle foam by warping local UV spaces using coordinate warping (domain distortion) and high-frequency sinusoidal noise representations.
- Black Hole Lensing (blackhole.frag.glsl): Simulates the ray-traced look of an Einstein Ring by bending screen pixels around a gravitational mass index, resulting in starlight distortion.
| Scene Index | Scale Range | Phase Key | Title | Visual Features | Shader Used |
|---|---|---|---|---|---|
Scene00 |
Intro / Exit | intro |
The Observatory | Holographic scanner rings, scanning laser lines, crystal pixel core | None (Basic Materials) |
Scene01 |
0.00 - 0.08 |
pixel |
The Visible World | Solid monolithic white pixel block, outer wire shell, concentric glow rings | None |
Scene02 |
0.08 - 0.16 |
digital |
Digital Structure | Orthogonal grid matrices, red/green/blue subpixel emitters | digitalPixel.frag |
Scene03 |
0.16 - 0.24 |
molecular |
Matter | Interactive 3D molecular structures of Water ( |
None (Mesh Standard) |
Scene04 |
0.24 - 0.33 |
atomic |
Atomic Scale | Proton/Neutron nucleus, orbiting Bohr electrons, raymarched electron cloud | atomRaymarch.frag |
Scene05 |
0.33 - 0.44 |
quantumField |
Quantum World | Wave function displacement lattice, potential energy barrier, tunneling particle | quantumVolume.frag |
Scene06 |
0.44 - 0.57 |
blackHole |
Singularity | Giant event horizon ring, orbiting stellar dust, space lensing | blackhole.frag |
Scene07 |
0.57 - 0.66 |
eventHorizon |
Event Horizon | Time-stretched particle stream, orbital drag, extreme chromatic aberration | accretionDisk.frag |
Scene08 |
0.66 - 0.76 |
singularity |
Beyond | Higher-dimensional coordinates raymarching, light warp field | singularity.frag |
Scene09 |
0.76 - 0.85 |
revelation |
Revelation | Cosmic dust, stellar nebula cloud fields, galactic cluster cores | None (Instanced Particle) |
Scene10 |
0.85 - 0.93 |
cosmicZoom |
Cosmic Zoom | Exploding particle sphere, universe condensation | None |
Scene11 |
0.93 - 1.00 |
infiniteLoop |
Infinite Recursion | Self-similar loop mirroring Scene 00 anomaly | None |
- Clone and Install Dependencies:
npm install
- Run in Development Mode:
npm run dev
- Build and Start Production Server:
npm run build npm start