HOW THIS SITE WAS BUILT

A cube that solves itself as you scroll, and everything behind it.

This page is a case study of itself: what stack we use, what decisions we made and what it measures. No rounded figures: these are from the latest build.

100 · 100 · 100 · 100

Desktop Lighthouse: performance, accessibility, best practices and SEO.

3

Languages with their own URLs, hreflang and full content: Spanish, English and Portuguese.

2

Draw calls per frame to render the entire cube.

1:1

Cube frames per screen frame while anything moves, at 60, 120 or 144 Hz.

0

Frames longer than 50 ms across a full run, measured on real GPU.

7

Turns in the solution, one per section: the cube arrives solved at the contact form.

DECISIONS

The cube is solved by scrolling, not by a video

A fixed seven-move scramble; the solution is that list reversed. Each section fires one turn, and a queue guarantees no turn is left halfway even if you scroll fast. You reach the contact form with the cube solved: the metaphor is literal.

Poses are derived from the layout, not from constants

Where the cube sits in each section is measured live in the DOM: the free column to the right of the text on desktop, the band reserved above each panel on phones. Change the content — or the language, which changes how long every sentence is — and the cube recalibrates itself. An E2E test walks seven points of the page and checks it never covers a single letter.

Three languages, one route tree

The whole site lives under `/[lang]`, with the same neutral-English segments for all three languages. Copy lives in typed dictionaries: add a key in Spanish and forget it in English or Portuguese and the build fails. The root detects the browser language and redirects, and every page declares its hreflang alternates.

One single clock

The GSAP ticker drives Lenis, ScrollTrigger and the poses, and renders the cube with advance() in that same frame. The cadence is chosen by counting frames against the measured refresh rate: even at any hertz, never a frame behind the text.

What you can't see, you don't pay for

WebGL boots on the visitor's first sign of life. Off screen, the cube isn't drawn. Nothing fixed to the viewport runs infinite animations. At rest, 60 fps on desktop and 30 on phones.

Genuinely accessible

Real text behind every effect, AA contrast measured by axe on each build, 44 px touch targets, a native accordion, and a visible toggle to reduce motion on top of the system one.

STACK

  • Next.js 16 and React 19

    App Router, per-language routes with root params, static pages, AVIF/WebP images and route transitions with the View Transitions API.

  • React Three Fiber + Three.js

    The cube: 27 pieces and 54 stickers in two draw calls with instancing, Phong material and three lights.

  • GSAP + ScrollTrigger + Lenis

    One clock for everything: smooth scroll, per-section choreography and the cube render in the same frame.

  • Tailwind CSS 4

    Our own token system: six face colours, an accent that changes per section and self-hosted typefaces.

  • Vitest + Playwright + axe

    Unit and E2E tests, including the ones that check the cube never covers text at any screen size or in any language.

  • Resend + Zod

    A form with validation, honeypot, submission limits and a direct reply to the visitor.

All of this is what we do for our clients. If you want a site measured like this, here's how we build websites.