A personal playground of WebGL & audio experiments built with React Three Fiber. Spin up localhost:5174, grab a coffee, and click around.
MIT — see License & credits below. Have fun, fork it, break it, send weird PRs.
A few of the rooms currently living in here:
| Welcome | Lofi Donuts | Audio Galaxy | Moon Fox | Anime Objects |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
A few rooms are still in stealth mode and don't have a public preview — try them live instead 😉
- 9 routed experiences — each one is a self-contained sandbox you can visit at its own URL.
- Real-time audio — a custom Web Audio Analyser + Tone.js timelines drive meshes, particles, and shaders in the galaxy & donuts rooms.
- Custom GLSL shaders — wave, pattern, flag, and cursor shaders live next to each other so you can compare them side by side.
- GLTF models & Gaussian Splats — proper model loading, animations, and
Splat-based experiments. - Postprocessing — chromatic aberration, noise, and other effects you can dial in.
- Handy dev panel — global
<Leva>panel + a left-rail navigator so you never get lost. - Error boundaries — one bad shader won't take down the whole site.
Each route below is its own little world. The "Prod" column marks which ones are pinned in the production navigator (see project-settings.js / Toolbar/index.jsx).
| Route | Title | Prod | What it does |
|---|---|---|---|
/ |
Welcome | ✅ | GSAP typing intro, starfield, HTML overlay |
/galaxy |
Audio Galaxy | ✅ | Particle galaxy that dances to whatever you play |
/shaders |
Shaders Gallery | ✅ | Switch between wave / pattern / flag / cursor GLSL experiments |
/target-morph |
Moon Fox | ✅ | GLTF fox model that morphs into a particle cloud |
/donuts |
Lofi Donuts | – | 3D donuts, spring physics, postprocessing, lofi vibes |
/surface-map |
Surface Map | – | Delaunay-triangulated terrain built from x/y/z-data.json |
/charting |
Charting | – | 3D charts with drawn shapes & TransformControls |
/animatedObjects |
Anime Objects | – | 3D objects choreographed by a Tone.js + AudioGraph rig |
/lab-alpha |
Lab Alpha | – | Gaussian Splat experiments (still cooking) |
A small debug navigator sticks to the left side of the screen — click a card to jump between experiences. Production hides the dev rail and only shows the routes flagged production: true.
You'll want Node 18.20.8 (see .nvmrc). The project works with npm, pnpm, or bun — pick your favourite. The committed lockfile is bun.lock, so bun is the snappiest option.
# 1. Install
bun install # or: pnpm install / npm install
# 2. Run the dev server
bun run dev # or: pnpm dev / npm run dev
# → http://localhost:5174 (host 0.0.0.0 is on by default)bun run build # production build → dist/
bun run preview # serve the built dist/ locally
bun run lint # eslint, with --max-warnings 0- Custom port
5174(seevite.config.js). - GLSL files are first-class citizens —
vite-plugin-glsllets youimport.glslfiles as strings. - The dev server opens automatically unless it detects
SANDBOX_URL/CODESANDBOX_HOSTin the env.
three-library/
├── index.html # entry; <title> = "Haro's sandbox"
├── vite.config.js # port 5174, glsl plugin, host 0.0.0.0
├── vercel.json # SPA rewrite → /
├── public/
│ ├── audio/ # local music used by Donuts / Galaxy rooms
│ ├── models/ # GLTF: donut, Fox, Humburger, Moon_n_Clouds
│ ├── projects/ # README screenshots live here
│ ├── splats/ # Gaussian splat sources
│ └── textures/
└── src/
├── main.jsx # React root
├── Root.jsx # ⭐ React Router definition (lazy routes)
├── App.jsx # ⭐ Layout: left navigator + Leva + ErrorBoundary
├── project-settings.js # ⭐ Source of truth for the nav cards
├── settings.js
├── Components/
│ ├── WelcomePage/ # /
│ ├── Sandboxes/ # ⭐ one folder per experience
│ │ ├── _Template/ # copy this to start a new sandbox
│ │ ├── GalaxyParticles/
│ │ ├── Donuts/
│ │ ├── Shaders/ # wave/pattern/flag/cursor GLSL
│ │ ├── SurfaceMap/
│ │ ├── TargetMorph/
│ │ ├── Charting/
│ │ ├── AnimatedObjects/
│ │ └── LabAlpha/
│ ├── Audio/ # AudioAnalyser (Web Audio) + AudioGraph (reactflow)
│ ├── blocks/ # ProjectCard, etc.
│ ├── Canvases/ # DefaultCanvas wrapper
│ ├── Stages/ # Pre-baked scenes (BlueSky…)
│ ├── InfoWall/ # Collapsible info bubble
│ ├── Layout/ # Box, Center helpers
│ ├── Particles/, Toolbar/, UIAnimation/
│ └── Model.jsx
├── stores/ # Zustand: audioStore, flowStore, audioAnalyser
├── data/ # x/y/z sample datasets for SurfaceMap / Charting
└── helpers/ # data-processing utilities
Each "sandbox" is just a folder under src/Components/Sandboxes/ that exports an index.jsx rendering a Three.js <Canvas> and a Content.jsx with the actual scene. To add a new one:
-
Copy the template
cp -r src/Components/Sandboxes/_Template src/Components/Sandboxes/MyThing
-
Build the scene in
MyThing/Content.jsx. Drop in models, particles, shaders — whatever you want. -
Lazy-register the route in
src/Root.jsx:const MyThing = lazy(() => import('./Components/Sandboxes/MyThing/index.jsx')) // … { path: 'my-thing', element: <MyThing /> }
-
Add a nav card in
src/project-settings.js:{ title: 'My Thing', image: '/projects/my-thing-screenshot.png', desc: 'One-liner that sells the experience.', link: 'my-thing', },
Drop a preview at
public/projects/my-thing-screenshot.pngand it shows up automatically. -
Set
production: trueon the card once you're happy to show it in the production nav.
3D / WebGL three, @react-three/fiber, @react-three/drei, @react-three/cannon, @react-three/postprocessing
Animation
GSAP + @gsap/react, @react-spring/three, Framer Motion
Audio
Tone.js and a custom Web Audio analyser (src/Components/Audio/)
State & UI
Zustand (+ zustand/traditional middleware for ReactFlow), React Router, ReactFlow, Leva, Tailwind CSS, lucide-react
Utilities vite-plugin-glsl, delaunator, nanoid, tailwind-merge, react-error-boundary
Build Vite 5, ESLint, Prettier, PostCSS, Autoprefixer
The project ships with a vercel.json that rewrites every URL to /, so deep links like /galaxy work on Vercel as a single-page app. Push to a Vercel project and you're done.
In production, the left-rail dev navigator is hidden and only the routes flagged production: true are surfaced via the toolbar. Toggle that flag (in src/Components/Toolbar/index.jsx) to graduate a sandbox to the public menu.
MIT. Do whatever you want, just don't blame me if a shader sets your GPU on fire.
Music in public/audio/ (replace with proper attributions if you ship this publicly):
Chocolate_Sprinkle.opus— Lofi trackAll_ends_well.mp3— Lofi trackKygo & Selena Gomez - It Ain't Me.opus— Kygo & Selena Gomez (used in the Animated Objects room)
GLTF models in public/models/ (donut, Fox, Humburger, Moon_n_Clouds) belong to their respective creators.
Built with ☕ and WebGL.




