M4RKYU.SYSEdition 2027
Skip to content
LOCEN/Ontario · CA/▸logs · implementing 3d graphics in react 9mgStandbyOK/--:--:--EST
M4M4RK_YUportfolio
  • BuildBuild
    BuildOverview
    • WorkSelected case studies and write-ups
    • GamesPlayable prototypes and game-dev logs
  • GalleryGallery
    GalleryOverview
    • PhotosPhoto collections and visual experiments
    • ShopPrints, posters, and one-off objects
  • WritingWriting
    WritingOverview
    • BlogLong-form devlogs and field notes
    • NotesShort observations, links, snippets
  • ResourcesResources
    ResourcesOverview
    • Tools38 in-browser developer utilities
    • LinksDaily-use dev and design bookmarks
  • AboutAbout
  • ContactContact
中文

syndicated · dev.to / @markyu

React Three Fiber: Build a 3D Scene Without Fighting React

A code-first React Three Fiber setup with lighting, controls, materials, and the mistakes that make your first scene render black.

Published
May 4 '24
·
Reading time
3 min read
·
Reactions
51
·
Comments
1
reactthreejswebdevgraphics
View on dev.toDiscuss

On this page

  • The Pieces That Matter
  • Do Not Start With a Model Loader
  • Add Motion Carefully
  • Add a Floor
  • My Defaults
  • What I Would Avoid
  • Debug Checklist

If your first React Three Fiber scene renders as a flat black circle, nothing is wrong with you. You probably created geometry without a useful camera, material, light, or controls.

Here is the smallest setup I would start with today.

npm create vite@latest r3f-scene -- --template react
cd r3f-scene
npm install three @react-three/fiber @react-three/drei
npm run dev

Replace src/App.jsx with this:

import { Canvas } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import "./App.css";

function Sphere() {
  return (
    <mesh>
      <sphereGeometry args={[1.5, 48, 48]} />
      <meshStandardMaterial color="#e11d48" roughness={0.45} metalness={0.1} />
    </mesh>
  );
}

export default function App() {
  return (
    <main className="stage">
      <Canvas camera={{ position: [0, 1.5, 5], fov: 45 }}>
        <color attach="background" args={["#101114"]} />
        <ambientLight intensity={0.45} />
        <directionalLight position={[4, 6, 3]} intensity={1.8} />
        <Sphere />
        <OrbitControls enableDamping />
      </Canvas>
    </main>
  );
}

And give the canvas real space:

html,
body,
#root {
  width: 100%;
  height: 100%;
  margin: 0;
}

.stage {
  width: 100vw;
  height: 100vh;
  background: #101114;
}

That is already a complete 3D scene: canvas, camera, mesh, geometry, material, light, and controls.

The Pieces That Matter

React Three Fiber is not "Three.js but React-looking." It is a React renderer for Three.js. The JSX tags are still Three concepts.

<mesh>
  <sphereGeometry args={[1.5, 48, 48]} />
  <meshStandardMaterial color="#e11d48" />
</mesh>

The mesh is the object. The geometry is the shape. The material is how the surface responds to light.

If you skip material, you do not have a visible surface worth looking at. If you skip light while using meshStandardMaterial, the object can look black. If you skip camera positioning, your object may be technically there but framed badly.

Do Not Start With a Model Loader

A common beginner mistake is loading a GLB model before you understand the scene. That makes debugging miserable because every issue looks like an asset problem.

Start with a primitive:

function Box() {
  return (
    <mesh rotation={[0.4, 0.4, 0]}>
      <boxGeometry args={[2, 2, 2]} />
      <meshStandardMaterial color="#22c55e" />
    </mesh>
  );
}

If the box renders, your React, canvas, camera, lighting, and CSS are fine. Then add models.

Add Motion Carefully

Animation in React Three Fiber usually belongs in useFrame. Do not animate by putting React state updates in a render loop unless you want unnecessary rerenders.

import { useFrame } from "@react-three/fiber";
import { useRef } from "react";

function SpinningSphere() {
  const ref = useRef();

  useFrame((_, delta) => {
    ref.current.rotation.y += delta * 0.6;
  });

  return (
    <mesh ref={ref}>
      <sphereGeometry args={[1.5, 48, 48]} />
      <meshStandardMaterial color="#38bdf8" roughness={0.35} />
    </mesh>
  );
}

This changes the Three object directly. React does not need to rerender 60 times per second just because a sphere rotates.

Add a Floor

A floating object can look fake even when the code is correct. Add a simple floor so light and position become easier to read.

function Floor() {
  return (
    <mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -1.6, 0]}>
      <planeGeometry args={[20, 20]} />
      <meshStandardMaterial color="#27272a" />
    </mesh>
  );
}

Then use it:

<Canvas camera={{ position: [0, 1.5, 5], fov: 45 }}>
  <color attach="background" args={["#101114"]} />
  <ambientLight intensity={0.45} />
  <directionalLight position={[4, 6, 3]} intensity={1.8} />
  <SpinningSphere />
  <Floor />
  <OrbitControls enableDamping />
</Canvas>

My Defaults

For a first production-ish scene, I would use:

  • Vite instead of Create React App.
  • sphereGeometry, not old sphereBufferGeometry examples.
  • meshStandardMaterial for realistic light response.
  • OrbitControls while developing, even if you remove it later.
  • One ambient light and one directional light before getting fancy.
  • Fixed canvas height. Most "my scene is blank" bugs are CSS bugs.

What I Would Avoid

I would not start with physics, post-processing, GLTF models, shadows, or scroll-driven camera animation.

Those are fun, but they multiply the number of things that can be wrong. Get one primitive on screen first. Make it lit. Make it move. Then build.

Debug Checklist

  • Canvas has width and height.
  • Canvas is imported from @react-three/fiber.
  • Camera is far enough back to see the object.
  • Material matches your lighting setup.
  • Object is near [0, 0, 0].
  • DevTools console has no asset import errors.
  • Controls are enabled while debugging.

That is the base. Once this renders, everything else is iteration.

Related reading

Next.js Images Without CLS: My LQIP Blur-Up Setup

A practical Next.js image optimization guide for zero CLS layouts, blur placeholders, dimensions, remote images, and production image hygiene.

nextjs

React 19 Micro-Interactions Without Layout Jank

A practical React 19 micro-interactions guide focused on motion boundaries, CSS transitions, optimistic UI, reduced motion, and performance.

react

Free 3D Asset Sites I’d Actually Use in a WebGL Project

A practical 2026 guide to free 3D asset sources for games, Blender, and WebGL, with license checks, optimization tips, and production workflow advice.

gamedev

originally published

This post first ran on dev.to. Comments and reactions live there.

Continue on dev.to
PreviousVS Code Themes I Can Actually Code In for 8 HoursA practical 2026 refresh of VS Code themes, focused on readability, contrast, fatigue, and real daily developer use.
Back to all posts
NextCloud Architecture Choices I Would Not OvercomplicateA practical 2026 cloud architecture guide for developers choosing between client-server, distributed systems, microservices, serverless, and cloud-native platforms.
Back to archive
M4RKYUM4RKYUM4RKYUM4RKYUM4RKYUM4RKYUM4RKYUM4RKYU
Crafted since 2024
ZhenXiao Mark YuZhenXiao Mark Yu
get in touch

Saw something here?Tell me about it.

It's a portfolio, not a service · but I read every note — drop a line if anything here resonated, or just to say hi.

Start a conversation
open channel

say hi anytime · 2026

--:--:--ESTOntario, Canada
  • Email
  • GitHub
  • dev.to
  • LinkedIn
  • Twitter / X
  • Instagram
  • Facebook
  • YouTube
  • CodePen
  • Spotify
  • Snapchat

Newsletter

Get the occasional dispatch

Notes and logs from m4rkyu.com — short, dated, no noise. Unsubscribe anytime.

Work

Production builds, games, and visual archives.

  • Projects
  • Games
  • Archive
  • Logs

Resources

Daily-use tools and a personal link library.

  • Search
  • Latest
  • Tools
  • Links
  • Notes
  • Topics
  • Shop
RSSJSON feed

Studio

Background, contact, and channels for collaboration.

  • About
  • Contact
  • Changelog
  • Colophon
  • Resumepending

Socials

Find me on the usual feeds.

  • GitHub
  • dev.to
  • LinkedIn
  • Twitter / X
  • Instagram
  • Facebook
  • YouTube
  • CodePen
  • Spotify
  • Snapchat
  • Email
© 2026 ZhenXiao Mark Yumarkyu0615@gmail.com
  • Email
  • GitHub
  • dev.to
  • LinkedIn
  • Twitter / X
  • Instagram
  • Facebook
  • YouTube
  • CodePen
  • Spotify
  • Snapchat
PrivacyTermsBuilt with Next.js 16 · React 19 · Tailwind 4