Inspiration

The idea came from that specific moment right after waking up — when a dream is still vivid but already dissolving at the edges. Fragmented, slightly uncanny, but beautiful in a way that's hard to explain afterward. I wanted to build something that captured that feeling rather than just looking "futuristic" or "sci-fi," which is where most 3D web showcases tend to default.

I also wanted to challenge myself technically. I had never used Three.js, GSAP, or the Web Audio API before this hackathon — so this project became as much about learning a new creative toolkit as it was about building something visually striking.

What it does

Somnia is a scroll-driven 3D website structured as four distinct "dream rooms," each a fully independent Three.js scene:

  • The Crystal Rain — glass shards suspended in a cold blue void around a glowing glass orb
  • Where Time Softens — melting clocks with dripping golden hands that never tell the right time
  • Infinite Reflection — an endless mirror corridor receding into darkness toward a glowing figure watching from the far end
  • Where Things Bloom — flowers that breathe open and closed in a slow, hypnotic rhythm

As you scroll, GSAP choreographs each room's reveal — text fades in, the 3D canvas scales into view, and a divider animates between sections. A toggleable ambient soundscape (built entirely with the Web Audio API, no external audio files) responds subtly as you move through the site, and the typography reacts to mouse movement with layered parallax depth.

There's also a small hidden detail: clicking the logo triggers a "Deep Dream" mode that shifts the entire color palette.

How we built it

Everything lives in a single self-contained HTML file — no build step, no framework, no external 3D models or textures.

  • Three.js (r128) powers all four room scenes plus a full-screen ambient starfield background, each with independent cameras, lighting rigs, and procedurally constructed geometry (no imported assets — every crystal, clock hand, mirror panel, and petal is built from primitive geometries and custom shapes)
  • GSAP + ScrollTrigger drives the reveal choreography, syncing text and 3D canvas opacity/position to scroll position
  • Web Audio API generates the entire ambient soundscape live in-browser: layered oscillator drones tuned to an open-fifth chord, subtle LFO vibrato, a shimmer pad, and filtered noise for texture
  • Vanilla JavaScript handles the custom cursor, parallax tracking, section navigation, and the animated loading sequence

Since I'd never touched any of these libraries before, my workflow leaned heavily on iterative prompting with Claude — describing the mood and behavior I wanted for each room, then refining the generated Three.js code through several passes of visual feedback.

Challenges we ran into

The biggest challenge was depth and visibility in pure 3D scenes with no reference experience to draw from. My first version of the mirror corridor room ("Infinite Reflection") technically rendered correctly, but a single oversized, near-opaque mirror plane sat directly in front of the camera and blocked the entire view — so the room just looked like a black screen. Diagnosing that took carefully walking through each mesh's opacity and z-position rather than assuming the lighting was the problem.

I also ran into a subtle animation bug in the bloom room where flower petals appeared to "glitch" or convulse — caused by re-randomizing rotation values inside the render loop every frame instead of computing them once and animating smoothly from a fixed base. That was a good lesson in the difference between randomness for variety (set once) versus randomness inside a loop (chaos).

Lastly, navigation links initially used standard href="#section" anchors, which triggered an unexpected "leaving site" interstitial in the environment I was testing in. Switching all navigation to JavaScript scrollIntoView() calls via button event listeners fixed it cleanly.

Accomplishments that we're proud of

Going from zero experience with Three.js to four fully custom, independently lit 3D scenes — each with its own mood, color language, and animation behavior — within a single hackathon. I'm especially proud of the procedural audio engine; building an entire ambient soundscape from raw oscillators instead of relying on audio files felt like a meaningful technical stretch, and it makes the experience feel considered rather than decorative.

I'm also proud that the whole thing is a single HTML file with zero dependencies beyond CDN script tags — no build pipeline, no node_modules, nothing to configure. Anyone can open it and it just works.

What we learned

That 3D web development is less about complex math and more about patiently composing light, material opacity, and camera position until a scene reads correctly — small adjustments (an opacity value, a light's distance falloff) can be the difference between an empty black canvas and an immersive space. I also learned the importance of separating "computed once" state from "recomputed every frame" state in animation loops, since conflating the two is an easy way to introduce visual chaos that looks like a bug but is really a logic issue.

On the audio side, I learned the basics of additive synthesis and how layering simple sine/triangle oscillators with slight detuning and panning can create a surprisingly rich, ambient texture without a single sample file.

What's next for Somnia

A few directions I'd like to explore: adding a fifth "room" that ties the narrative together at the threshold between sleep and waking, introducing more interactive elements within each room (rather than purely observational scenes), and experimenting with post-processing effects like bloom and depth-of-field via Three.js's EffectComposer to push the dreamlike quality even further. I'd also like to optimize performance further for lower-end mobile devices, since the current experience is heaviest on the mirror corridor room.

Built With

  • geometry
  • lighting
  • materials-gsap-+-scrolltrigger-?-scroll-driven-animation-choreography-web-audio-api-?-fully-procedural-ambient-soundscape-vanilla-javascript-?-custom-cursor
  • navigation-html5-/-css3-?-layout
  • parallax
  • responsive-design
  • three.js-(r128)-?-3d-scenes
  • typography-google-fonts-?-cormorant-garamond
Share this project:

Updates

Submission history