A React renderer for Two.js β bringing declarative, component-based 2D graphics to React. Build interactive SVG, Canvas, or WebGL scenes using familiar React patterns.
npm install react-two.js react react-dom two.jsimport { Canvas, Rectangle, useFrame } from 'react-two.js'
function RotatingRectangle() {
const ref = useRef()
useFrame((t) => ref.current.rotation = t * 0.5)
return <Rectangle ref={ref} radius={50} fill="#00AEFF" />
}
<Canvas width={800} height={600} autostart={true}>
<RotatingRectangle />
</Canvas>- π¨ Declarative 2D Graphics β Describe your Two.js scene using React components
- β‘ Renderer Agnostic β Switch between SVG, Canvas, and WebGL without changing code
- πͺ React Hooks β Built-in
useFramefor smooth animations anduseTwofor instance access - π¦ Fully Typed β Complete TypeScript support with proper types for all components
- π― Zero Overhead β Direct mapping to Two.js primitives with no performance penalty
- π Everything Works β All Two.js features work seamlessly in React
Create complex 2D scenes using React components:
import { Canvas, Group, Rectangle, Circle, Star, useFrame } from 'react-two.js'
function Scene() {
const groupRef = useRef()
useFrame((elapsed) => {
groupRef.current.rotation = Math.sin(elapsed) * 0.5
})
return (
<Group ref={groupRef} x={400} y={300}>
<Rectangle width={100} height={100} fill="#FF6B6B" />
<Circle radius={40} fill="#4ECDC4" x={60} />
<Star innerRadius={20} outerRadius={40} sides={5} fill="#FFE66D" x={-60} />
</Group>
)
}
<Canvas width={800} height={600} type="webgl">
<Scene />
</Canvas>npm install react-two.js react react-dom two.jsRequirements as peer dependencies:
- React 18.3+
- Two.js v0.8.21+
Important
react-two.js is a React renderer, it must pair with a major version of React, like react-dom.
The <Canvas> component is your entry point. It creates a Two.js instance and manages the rendering context:
import { Canvas } from 'react-two.js'
function App() {
return (
<Canvas
width={800}
height={600}
type="SVGRenderer"
autostart={true}
>
{/* Your scene goes here */}
</Canvas>
)
}Important
Canvas Children Restrictions: Similar to react-three-fiber, the <Canvas> component only accepts react-two.js components as children. DOM elements like <div> or <span> cannot be used inside Canvas. Place UI elements outside the Canvas:
// β
Correct
<div>
<Canvas>
<Circle radius={50} />
</Canvas>
<div className="controls">UI here</div>
</div>
// β Incorrect - will trigger warnings
<Canvas>
<div>This will warn</div>
<Circle radius={50} />
</Canvas>All Two.js primitives are available as React components:
<Canvas width={800} height={600} autostart={true}>
<Circle radius={50} fill="#00AEFF" x={400} y={300} />
<Rectangle width={100} height={60} stroke="#FF0000" linewidth={3} />
<Polygon sides={6} radius={40} fill="#00FF00" />
</Canvas>The useFrame hook runs on every frame, perfect for animations:
import { useRef } from 'react'
import { Rectangle, useFrame } from 'react-two.js'
function AnimatedRectangle() {
const ref = useRef()
useFrame((elapsed) => {
ref.current.rotation = elapsed * 0.5
ref.current.scale = 1 + Math.sin(elapsed) * 0.2
})
return <Rectangle ref={ref} width={50} height={50} fill="#00AEFF" />
}Use useTwo to access the underlying Two.js instance:
import { useTwo } from 'react-two.js'
function Component() {
const { two, width, height } = useTwo()
useEffect(() => {
two.play();
console.log('Canvas size:', width, height)
console.log('Two.js instance:', instance)
}, [])
}<Canvas>β Main container that creates Two.js instance<Group>β Container for organizing and transforming multiple shapes
<Circle>β Circle with radius<Rectangle>β Rectangle with width and height<RoundedRectangle>β Rectangle with rounded corners<Ellipse>β Ellipse with width and height<Line>β Straight line between two points<Polygon>β Regular polygon with specified sides<Star>β Star shape with inner and outer radius<ArcSegment>β Arc segment with start and end angles
<Path>β Custom path with vertices<Points>β Collection of points rendered in one draw call<Text>β Text rendering
<Image>- Basic image class inspired by Figma<Sprite>β Animated sprite sheets<ImageSequence>β Animated image sequence<LinearGradient>β Linear gradient fill<RadialGradient>β Radial gradient fill<Texture>β Texture mapping
Access the Two.js instance and canvas properties:
const { two, width, height } = useTwo()Returns:
twoβ The Two.js instancewidthβ Canvas widthheightβ Canvas height
Register a callback that runs on every animation frame:
useFrame((elapsed: number) => {
// elapsed is time in seconds since animation started
})All Two.js properties work as React props:
<Circle
radius={50}
fill="#00AEFF"
stroke="#000000"
linewidth={2}
opacity={0.8}
x={400}
y={300}
rotation={Math.PI / 4}
scale={1.5}
/>Full TypeScript support with ref types for all components:
import { useRef } from 'react'
import { Circle, RefCircle } from 'react-two.js'
function Component() {
const circleRef = useRef<RefCircle | null>(null)
useEffect(() => {
if (circleRef.current) {
circleRef.current.rotation = Math.PI / 4
}
}, [])
return <Circle ref={circleRef} radius={50} />
}function RotatingGroup() {
const ref = useRef()
useFrame((t) => ref.current.rotation = t)
return (
<Group ref={ref}>
<Rectangle width={100} height={100} fill="#FF6B6B" />
<Circle radius={50} fill="#4ECDC4" x={120} />
</Group>
)
}function () {
const [gradient, setGradient] = useState(null);
const updateRef = useMemo((ref) => {
if (ref) {
setGradient(ref);
}
}, [setGradient]);
return (
<Canvas width={800} height={600}>
<LinearGradient
ref={updateRef}
x1={0} y1={0}
x2={100} y2={100}
stops={[
{ offset: 0, color: '#FF6B6B' },
{ offset: 1, color: '#4ECDC4' }
]}
/>
<Rectangle width={200} height={200} fill={gradient} />
</Canvas>
);
}- Two.js Documentation β Complete Two.js API reference
- Two.js Examples β Interactive examples and demos
- Two.js Repository β Source code and issues
- Two.js Tutor on ChatGPT - Talk to a custom ChatGPT trained on Two.js and react-two.js
# Build the library for npm distribution
npm run build:lib
# Build the documentation site
npm run build:docs
# Preview the documentation locally
npm run preview:docs# Install dependencies
npm install
# Start development server (documentation)
npm run dev
# Run tests
npm test
# Run linting
npm run lintThe development server runs the documentation site which imports the library components directly from the lib/ directory, allowing you to see changes in real-time.
Built on top of Two.js by Jono Brandel. Inspired by Three.js and react-three-fiber.