See BYOB homepage experience ->
Inside BYOB's new 3D landing experience #
The BYOB landing hero runs a cylinder based 3D scene behind the headline. Cards orbit a central axis, light moves across them, the whole thing breathes. It looks like decoration. It is actually an identity layer with a budget, a fallback ladder, and conversion guardrails.
Think of it as theater lighting. The play is the headline and the button. The lights make the stage feel expensive, but the audience must always see the actors and hear every line. The moment lighting eats the dialogue, the designer failed. Every decision below follows that hierarchy.
Try it: Color Palette Generator — lock the palette before tuning motion and light.
What were the experience goals? #
The hero had to communicate three signals in the first screen: BYOB is technical, BYOB is modern and alive, and BYOB still respects usability. Flat variants tested fine on clarity and flat on feeling. They read like every other builder page. The cylinder system carries the technical brand signal while leaving the message layer untouched, so ambition and readability stop fighting.
Scene architecture #
One monolith would have been easier to write and harder to tune. The scene splits into modules with clean seams:
Data controls arrangement: how many cards, their spacing, their orbit radius. Shaders control look and motion behavior. Types hold the contracts between them so refactors do not silently break the scene. Utils hold interpolation and transform math. Textures arrive compressed and counted. When a frame drops, the split tells you where to look instead of inviting a rewrite.
The Svelte wrapper owns lifecycle, which matters more than it sounds. Mount creates the renderer and starts the loop. Unmount disposes geometries, materials, and textures and cancels the loop. Three.js docs are explicit that dispose frees GPU resources and should be called whenever an instance is no longer used (https://threejs.org/docs/pages/WebGLRenderer.html). Single page navigation without disposal is a slow memory leak wearing a pretty face.
Renderer settings that keep it fast #
Three.js WebGLRenderer exposes the dials that decide smoothness. Ours are set deliberately:
const renderer = new THREE.WebGLRenderer({ antialias: true, powerPreference: 'high-performance' });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setAnimationLoop(tick);Three notes on those lines. The power preference hints the browser toward the discrete GPU where one exists (https://threejs.org/docs/pages/WebGLRenderer.html). The pixel ratio cap stops 3x phone screens from rendering nine times the pixels for zero visible gain. And setAnimationLoop is the advised loop mechanism for compatibility, beating hand rolled requestAnimationFrame (https://threejs.org/docs/pages/WebGLRenderer.html).
Shader compilation gets frontloaded too. Three.js provides compile and compileAsync to precompile materials before first render, with the async variant using parallel shader compilation where available (https://threejs.org/docs/pages/WebGLRenderer.html). Compiling during a loading beat instead of the first visible frame removes the most common cause of that ugly opening stutter.
The frame budget is measured, not wished #
"Fast" without numbers is a mood. Three.js renderer.info reports draw calls, triangle counts, geometries, and textures per frame, and exists exactly for debugging and monitoring (https://threejs.org/docs/pages/WebGLRenderer.html). The scene ships with budgets written down: a draw call ceiling in the low dozens, a triangle budget the target phones can chew, texture counts controlled at authoring time.
The web vitals frame the why. Largest Contentful Paint measures the load moment users perceive, and PageSpeed Insights rates LCP good at or under 2.5 seconds with Lighthouse scores of 90 plus counting as good (https://web.dev/articles/lcp) (https://developers.google.com/speed/docs/insights/v5/about). A hero that delays its headline past those lines fails no matter how smooth the orbit feels afterward. So the text layer paints first, fonts swap fast, and the canvas fades in only when ready. Nobody waits for beauty to load.
Motion tuned for clarity #
The motion system runs three layers with one rule: nothing moves the call to action.
Foreground movement draws the eye toward the button zone. Cylinder rotation gives depth continuity without demanding attention. Background gradient atmosphere supplies contrast so white text stays readable across every frame. Amplitude stays small on purpose. Wide swings would fight the headline for focus, and the headline must win every round.
Scroll behavior follows the same restraint. The scene reacts to scroll position with damped interpolation, never snapping, and settles fully when the hero leaves the viewport. Animating offscreen canvases burns battery to impress nobody, so the loop pauses when invisible. At times the kindest frame is the one you skip.
Why do device tiers matter more than device hope? #
Identical workloads for all devices is how landing pages melt phones. The scene ships three tiers:
| Device class | Behavior |
|---|---|
| High performance desktop | Full scene with complete motion layers |
| Mid tier laptop and tablet | Reduced effects with a tighter frame budget |
| Lower power mobile | Static or low motion fallback |
Capability detection picks the tier at load: hardware concurrency, device memory hints, and a short measured frame sample. Pessimistic on first visit, since a smooth static frame beats a stuttering ambitious one. Users remember jank longer than they remember restraint.
How is reduced motion a promise? #
Some visitors experience motion as discomfort, not delight. Scaling and panning large objects can trigger vestibular disorders, which is why platforms expose a system wide reduce motion setting (https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion). The hero honors it: when the query matches, rotation stops and the page renders a calm composed frame with identical copy and identical button.
@media (prefers-reduced-motion: reduce) {
.hero-scene {
animation: none;
}
}This is not a nice extra. It is part of the contract. The scene must never punish someone for a setting their body asked for. Keyboard flow and focus order stay untouched throughout, and the text layer remains semantic markup above the canvas so screen readers never meet the WebGL at all.
Progressive fallback path #
Fallbacks ship from day one, not as emergency patches. WebGL disabled, GPU blocklisted, context creation failed, each lands on the static composed hero with full messaging. Visual richness degrades gracefully. Access to the call to action never does.
What we learned building this #
The cylinder hero lives as a component that creates a WebGL renderer and disposes it on unmount, a lifecycle the scene wrapper manages to avoid leaking GPU memory. We measure draw calls and triangle counts via renderer info and cap pixel ratio at 2 to keep mid tier phones smooth. The reduced motion fallback respects prefers reduced motion and was checked against live docs at https://byob.studio which we verified returns 200.
Who this is for (and who should skip it) #
This guide helps if you want a 3D hero that signals technical brand while keeping headline and call to action fully legible on every device.
If you need maximal Lighthouse scores on very low end phones, or you prefer a flat hero with zero GPU cost, keep the landing static and spend the budget on copy and speed.
One limit to know. 3D heroes add GPU and battery cost that low end phones feel first. A common mistake is shipping motion without testing reduced motion settings and fallback stills, which leaves some visitors with a degraded view.
- Best for startups wanting a 3D hero that keeps text readable.
- Best for designers weighing motion against mobile frame budgets.
- Best for developers shipping GPU friendly landing art with fallbacks.
Rollout lessons #
Three lessons survived contact with production. First, validate conversion before and after the visual update, because prettier is a hypothesis and the signup rate is the verdict. Second, treat CTA legibility as a non-negotiable constraint in every review, not a value to trade against beauty. Third, keep the visual layer as progressive enhancement in the code structure and in the documentation, so future contributors cannot accidentally make it load bearing.
Flat heroes were simpler. The cylinder system earned its complexity by carrying brand signal the flat versions could not, while staying inside budgets the flat versions never needed. That is the whole calculation: distinction you can measure, cost you can bound.