React Three Fiber lets you describe a Three.js scene declaratively, as JSX, and lets React's reconciler manage the scene graph instead of hand-rolled imperative Three.js code. For a portfolio, that's the difference between a background effect being a maintainable component and a black box.
The starfield background
The background you see behind the hero and contact sections is a single Points mesh: a few thousand particles positioned randomly inside a sphere using maath's random.inSphere helper, rotated slowly every frame with useFrame. It's cheap to render because it's one draw call, not thousands of individual objects.
One subtle bug worth knowing about: if the particle count isn't a multiple of the position stride (3 for x/y/z), the last point reads past the end of the array and produces NaN when Three.js computes the bounding sphere. Newer Three.js versions warn about it loudly; older ones stayed silent. Always size your buffers as a clean multiple of 3.
Loading models without blocking the page
GLTF models are loaded with drei's useGLTF and wrapped in a Suspense boundary with a lightweight loader component, so the rest of the page renders immediately while the model streams in over the network.
Frustum culling, memoized camera/GL settings, and keeping particle counts modest matter far more for perceived performance than any individual shader trick.
Performance basics that actually move the needle
Memoizing camera and renderer settings so they don't get recreated every render, disabling frustum culling on objects that always fill the viewport anyway, and capping devicePixelRatio with dpr={[1, 2]} keep the 3D scenes smooth on mid-range laptops without touching a single shader.



