How this site was built.
You’re looking at it. Designed and shipped with Claude. Here’s the build, in the order you just experienced it, with each piece shown running.
The whole home is one 3D world
There are no sections stacked under a hero. The home is a single WebGL stage: the name EDDIE JUNG sits in soft clay-stone, and scrolling travels the camera through the whole story: an ethos line, the three cases, how I work, the numbers, contact. The name never leaves the frame; it reshapes. As you pass each station the stone letters morph into that station's word: AUTOCRM, PETLOVER, SUBLY, then PROCESS, then a single giant 3 for the three shipped products, taking on that case's colour, so the identity literally becomes the work.
The name, hand-built in three.js
No 3D-library abstraction. React Three Fiber wouldn't size its canvas in this Next build, so the name is vanilla three.js: I own the sizing, the render loop, the cleanup, and the context-loss recovery. A self-hosted studio environment lights the stone, so nothing is fetched at runtime; letters are tracked apart so the chunky glyphs stay legible. The morph reuses one builder, the same bevelled extrusion re-running for every word, and a segment-based hand-off cross-fades between them so the letters swap cleanly instead of smearing through each other.
Every case shows the work
No raw screenshots. Each case rides into the stage with its product framed in a browser mockup, glowing on the dark ground: traffic lights, a URL, a page that looks open right now, and links out to a full case page for the depth. The proof is visible before you read a word.

Dark to enter, warm to read
The stage is a dark, immersive world; the case pages open dark to bridge it, then settle into a warm off-white for comfortable long-form reading. One blue means action, and each case spends a single accent of its own: AutoCRM indigo, Petlover amber, Subly blue. Type carries three roles: the chunky 3D name and Poppins nameplates for the cases, Instrument Serif for headlines, and the system SF stack for body, all self-hosted with next/font, nothing fetched at runtime.
Headline 600
The invisible part
Then I made it behave.
The chrome name is WebGL, but it stays disciplined: a single draw, a self-hosted studio environment so nothing is fetched, and a proper cleanup on unmount. The abstraction (React Three Fiber) wouldn’t size its canvas in this Next build, so I dropped to vanilla three.js and took control of the sizing, the render loop, and context-loss recovery myself. On a machine without WebGL it falls back to the name in serif, which still reads, and prefers-reduced-motion stops the drift.
The stack
- Framework
- Next.js 16 · App Router
- Language
- TypeScript
- Styling
- Tailwind v4 · CSS-first design tokens
- 3D
- vanilla three.js · clay-stone name, scroll-driven camera
- Motion
- three.js raf · scroll-linked stations morph the name · CSS keyframes · no motion library
- Type
- helvetiker (3D name) · Poppins (case nameplates) · Instrument Serif (headlines) · SF (body)
- Cases
- one data file per case · the renderer never changes
The process
Built with Claude: design and code in one loop.
To be clear, this isn’t an AI-generated template. I’m a product designer: every type choice, grid, and interaction here is a deliberate call, not a default. Claude is the tool that lets me move fast. The design judgment is mine.
I don’t hand a design to engineering and wait. I work in a tight loop: a direction is mocked up on the real page, compared against alternatives, and it doesn’t ship until it survives the screenshot test, the same way every case in this portfolio was made.
That’s the whole pitch: velocity and rigor, together. This site is the proof: designed, built, hardened, and shipped the same way I’d build for a team.