A portfolio that lists what someone can do is a résumé with better typography. I wanted a site that demonstrates it instead — something you move through rather than scroll past.
The idea
Rooms with doors. Clear text labels standing in 3D space that you click to travel. A skill tree that is a literal tree: I edit src/content/skills/tree.yaml, push, and new branches grow. The shape of what I know becomes the shape you navigate.
The constraint that made it work
Every room exists twice. /space renders a Three.js world; /skills and /projects render the identical links as plain crawlable HTML, generated from the same source file. If WebGPU is missing, the GPU is weak, the visitor prefers reduced motion, or a crawler arrives, the site collapses gracefully to the map and loses nothing. The 3D is the treatment. The structure is the content.
How it’s built
- Astro content collections as the single source of truth — profile, projects, and the skill tree are data with schemas, not markup. Bad data fails at build instead of in front of you.
- Three.js through a shared
@steventrueba/three-kitpackage: mount and dispose, camera rig, HTML label layer, and a frame budget that bails to the fallback before it stutters. - Cloudflare Workers for hosting, R2 for models and audio, Wrangler for deploys.
- Cursor for day-to-day editing, Claude Code for multi-file refactors and repo archaeology.
What vibe coding actually looks like here
Not “generate me a website.” It looks like keeping a monorepo legible enough that an agent can work inside it — small packages with clear seams, Zod schemas that make invalid content loud, and runbooks in docs/ops/ so DNS, R2, and deploy steps survive the gap between sessions.
The agent is only ever as good as the structure you hand it. Most of the work is building that structure.