Back to Case Files
BNR-CF-02Coffee Roastery · 3D·Specialty Coffee·Sousse, Tunisia·2026

Kahwa Lab

A French-language site for a Sousse specialty coffee roaster and coffee bar, built on Next.js 16 with a scroll-driven React Three Fiber hero, hand-drawn SVG roast data and a five-locale interface.

Visit live site
Kahwa Lab — Coffee Roastery · 3D homepage built by BreakNRoot

120

Instanced beans

05

Locales

06

Origin pages

Kahwa Lab roasts specialty coffee on site at 14 rue Ali Bach Hamba in downtown Sousse, a few steps from Bab Bhar, and runs a coffee bar alongside the roastery. The business sells six single origins at a time (Ethiopia Yirgacheffe, Kenya Nyeri, Colombia Huila, Brazil Cerrado, Guatemala Antigua and Sumatra Wahana), pours an espresso bar and slow brew menu, and teaches barista, cupping and latte art workshops in small groups. The site had to carry all of that: a catalogue, a menu, a workshop programme and a booking path, without becoming a generic template.

The build is a Next.js 16 App Router project on React 19 and Tailwind CSS v4, deployed on Vercel. The landing hero is a real-time WebGL scene rendered with React Three Fiber: a procedurally lathed porcelain cup, a points-based steam system, and 120 instanced coffee beans orbiting the cup on independent radii and spin rates, all driven by a camera rig that reads scroll progress through a smoothstep curve and adds pointer parallax. Every canvas in the project is capability-gated. The page probes for WebGL2 or WebGL and checks prefers-reduced-motion before mounting, and falls back to a hand-drawn SVG cup with CSS keyframe steam when either check fails.

Editorial motion is handled with GSAP and Lenis. The homepage carries a pinned five-step 'de la cerise à la tasse' sequence where each photograph is revealed by an animated clip-path as the scroll scrubs the timeline, plus clip-path mask reveals, parallax photography and IntersectionObserver counters. The origin detail pages carry two purpose-built SVG charts, a five-axis sensory radar and a quadratic-smoothed roast curve with a first-crack marker, both recoloured per origin and both labelled for screen readers. The whole content layer is typed as a per-locale record, so French, English, Arabic, Russian and German copy sits in the same data files and the Arabic locale flips the document direction to RTL.

// challenge

The Challenge

A roaster whose product is invisible on a screen needed a site that would communicate craft rather than list SKUs. The brief demanded a genuinely three-dimensional centrepiece and a scroll narrative from cherry to cup, but the audience is a walk-in café clientele in Sousse browsing on mid-range phones over Tunisian mobile networks, and a WebGL scene that stutters or fails silently would be worse than no scene at all. On top of that the content itself is dense and technical (six origins, SCA scores, roast profiles, sensory profiles, a four-category menu, four workshop formats) and had to be readable by locals in French and Arabic as well as by the seasonal visitors who make up a large share of Sousse footfall.

// solution

What We Built

We built the site as a Next.js 16 App Router application in TypeScript with Tailwind CSS v4. The hero is a React Three Fiber scene composed entirely in code, with no imported model: the cup is a lathe geometry generated from a point profile with a subtle radial ripple, the crema is a ring mesh over a circle mesh, the steam is a 90-point buffer geometry recomputed each frame, and 120 coffee beans are drawn as a single instanced mesh with per-instance colours from a five-tone roast palette. A rig component lerps camera position and look target against a scroll progress ref and mixes in pointer parallax on the scene group. Both canvases in the project (the hero and the rotating Fibonacci bean cluster on the catalogue header) sit behind a WebGL probe, a reduced-motion check and, for the cluster, an IntersectionObserver so the context is only created when the section is near the viewport. Scroll choreography runs on GSAP with ScrollTrigger and SplitText over Lenis smooth scrolling, including a pinned clip-path sequence, batched mosaic reveals and parallax images, all short-circuited under prefers-reduced-motion. The origin sheets, roast curves and sensory radars are drawn as accessible inline SVG with no charting dependency. Reservation and contact both post to Next.js route handlers that revalidate every field server side, carry honeypot fields, and return field-level error maps that the client re-renders with aria-invalid and focus management.

// outcome

The Outcome

Kahwa Lab is live on Vercel with seven routes plus six statically generated origin pages, a sitemap that enumerates them and CafeOrCoffeeShop structured data carrying the address, geo coordinates, phone and the full weekly opening schedule. The 3D hero runs on capable devices and degrades to a static SVG composition everywhere else, so the page is legible with WebGL disabled, with JavaScript off for the headline, and under reduced-motion settings. The roastery can publish a new origin by adding one typed entry with its roast curve, sensory profile and accent colour, and the page, the catalogue card, the charts and the sitemap entry all follow. The content layer is already authored in French, English, Arabic, Russian and German behind a persisted locale switcher with RTL handling, which gives the shop a path to the international visitors it serves without a second build.

Engineering log
[01]

Code-generated WebGL hero scene

src/components/three/CoffeeScene.tsx builds the entire hero in Three.js primitives: a lathe-geometry cup with a rippled profile, a torus handle, a crema ring, a 90-point steam system recomputed per frame, and 120 coffee beans drawn as one instanced mesh with per-instance colours and independent orbit radii, spin and wobble.

[02]

Scroll-driven camera rig with pointer parallax

A Rig component reads a scroll progress ref from the sticky 190vh hero section, applies a smoothstep ease, and lerps camera position and look target from a tight close-up out to a wide orbit while the scene group tilts toward the pointer.

[03]

Capability-gated 3D with SVG fallbacks

HeroCanvas.tsx and BeanClusterCanvas.tsx probe for WebGL2/WebGL and prefers-reduced-motion before dynamically importing the scene, and render hand-drawn SVG replacements (HeroFallback.tsx, a rotating bean rosette) otherwise. The catalogue cluster additionally waits on an IntersectionObserver with a 120px root margin.

[04]

Pinned cherry-to-cup scroll sequence

src/components/home/CherryToCup.tsx pins the section with GSAP ScrollTrigger and scrubs a timeline that reveals five photographs through animated clip-path insets with a counter-scaling image and cross-fading captions, plus a progress bar. Reduced-motion users get the same five steps as a static list.

[05]

Hand-built SVG roast and sensory charts

RadarChart.tsx plots a five-axis sensory profile as pure SVG polygons; RoastCurve.tsx renders bean temperature against time with quadratic smoothing through midpoints, a dashed first-crack marker, a filled area and a drop-temperature label. Both take the origin's accent colour and expose a text summary through role="img" and aria-label.

[06]

Five-locale content layer with RTL

src/i18n typs every string as a per-locale record across site, menu, cafes and ateliers data, ships French, English, Arabic, Russian and German dictionaries, persists the choice in localStorage, and sets document lang and dir so Arabic renders right to left.

Stack
Framework
Next.js 16React 19TypeScript
3D & motion
React Three FiberThree.jsDreiGSAPLenis
Styling & infra
Tailwind CSS v4Vercel
See it in production

Live in production

Kahwa Lab is running in production today. Open it, then tell us what you want built — BreakNRoot engineers systems like this one from first prototype to production.

Adjacent records
>_ BREAKNROOT//SYSTEM.ONLINE