three
R3F Globe
A rotating wireframe globe rendered with @react-three/fiber, composed over canvas-wrapper so it inherits WebGL feature-detect, lazy mount, and a reduced-motion / no-WebGL poster fallback. The <Canvas> scene is dynamic-imported ssr:false (R3F can't SSR), reads contract color tokens onto its material, and disposes its geometry/material on unmount.
Install
1. Register the namespace (once per project):
json
// components.json — register the @bottega namespace once
{
"registries": {
"@bottega": { "url": "https://bottega.ariacode.ca/r/{name}.json" }
}
}2. Add the component:
bash
npx shadcn add @bottega/r3f-globeUsage
Usagetsx
<R3fGlobe />Props
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | — | |
| aspect | string | 1 / 1 | Aspect-ratio of the mount box. Default "1 / 1". |
| minHeight | string | — | Min-height of the mount box, forwarded to canvas-wrapper. Default "20rem". Set "0" when the parent already constrains height so the globe stays square (tracks `aspect`) instead of being floored at 20rem in a tight container. |
Source
r3f-globe.tsxtsx
"use client";
import dynamic from "next/dynamic";
import { CanvasWrapper } from "@/registry/three/canvas-wrapper/canvas-wrapper";
import { GlobePoster } from "./globe-poster";
// R3F cannot SSR — load the <Canvas> scene client-side only. While it loads
// (and on every guarded path) the poster is what shows.
const GlobeScene = dynamic(() => import("./globe-scene"), {
ssr: false,
loading: () => <GlobePoster />,
});
export interface R3fGlobeProps {
className?: string;
/** Aspect-ratio of the mount box. Default "1 / 1". */
aspect?: string;
/**
* Min-height of the mount box, forwarded to canvas-wrapper. Default "20rem".
* Set "0" when the parent already constrains height so the globe stays square
* (tracks `aspect`) instead of being floored at 20rem in a tight container.
*/
minHeight?: string;
}
/**
* A rotating wireframe globe rendered with @react-three/fiber, composed over
* canvas-wrapper so it inherits the full 3D contract: WebGL feature-detect,
* lazy mount, and a reduced-motion / no-WebGL poster fallback. The scene is
* dynamic-imported ssr:false (R3F can't SSR) and disposes its GPU resources on
* unmount.
*/
export function R3fGlobe({ className, aspect = "1 / 1", minHeight }: R3fGlobeProps) {
return (
<CanvasWrapper
className={className}
aspect={aspect}
minHeight={minHeight}
poster={<GlobePoster />}
>
<GlobeScene />
</CanvasWrapper>
);
}
Dependencies
- three
- @react-three/fiber
- @bottega/canvas-wrapper
- @bottega/tokens