Skip to content

Mesh, Geometry, Material

See how an imperative mesh setup becomes nested JSX with constructor args and material props.

Pinned example stack

react@19.1.1react-dom@19.1.1@react-three/fiber@9.3.0three@0.180.0

Exact Conversion

Switch between the React Three Fiber and Three.js examples, then test the R3F result in the live preview below.

React Three Fiber
import { Canvas } from '@react-three/fiber';
function HeroSphere() {
return (
<mesh>
<sphereGeometry args={[1, 32, 16]} />
<meshStandardMaterial color="#f97316" metalness={0.2} roughness={0.25} />
</mesh>
);
}
export default function App() {
return (
<div style={{ height: '100vh', background: '#0f172a' }}>
<Canvas camera={{ fov: 50, position: [0, 0.6, 4] }} dpr={[1, 2]}>
<color attach="background" args={['#0f172a']} />
<ambientLight intensity={0.35} />
<directionalLight position={[2, 3, 4]} intensity={1.6} />
<HeroSphere />
</Canvas>
</div>
);
}

Live preview

What Changed

  • new THREE.Mesh(geometry, material) becomes a <mesh> with geometry and material children.
  • Constructor arguments move into args.
  • Material option objects become regular JSX props like color, metalness, and roughness.
  • The scene still needs light because meshStandardMaterial behaves the same in both APIs.

The geometry and material are not “special React children.” They are still the same underlying Three.js objects. R3F just lets you express the ownership structure directly in the markup instead of building the hierarchy in separate variables.