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.js
import { Canvas, Circle, useFrame } from 'react-two.js'
function RotatingCircle() {
const ref = useRef()
useFrame((t) => ref.current.rotation = t * 0.5)
return <Circle ref={ref} radius={50} fill="#00AEFF" />
}
<Canvas width={800} height={600}>
<RotatingCircle />
</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
useFrame
for smooth animations anduseTwo
for 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.js
Requirements 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, just like react-dom, react-native, etc.
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="svg" // 'svg' | 'canvas' | 'webgl'
autostart={true}
>
{/* Your scene goes here */}
</Canvas>
)
}
All Two.js primitives are available as React components:
<Canvas width={800} height={600}>
<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 { Circle, useFrame } from 'react-two.js'
function AnimatedCircle() {
const ref = useRef()
useFrame((elapsed) => {
ref.current.rotation = elapsed * 0.5
ref.current.scale = 1 + Math.sin(elapsed) * 0.2
})
return <Circle ref={ref} radius={50} fill="#00AEFF" />
}
Use useTwo
to access the underlying Two.js instance:
import { useTwo } from 'react-two.js'
function Component() {
const { instance, width, height } = useTwo()
useEffect(() => {
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)
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
# 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
-
Increment version (choose one):
npm run version:patch # Bug fixes (0.1.0 β 0.1.1) npm run version:minor # New features (0.1.0 β 0.2.0) npm run version:major # Breaking changes (0.1.0 β 1.0.0)
-
Create a GitHub release with the new version tag. This automatically triggers npm publishing via GitHub Actions.
Or publish manually:
npm run publish:npm
The documentation site automatically deploys to GitHub Pages on every push to main
. The site will be available at:
- Live URL: https://jonobr1.github.io/react-two.js
-
Enable GitHub Pages in repository settings:
- Go to Settings β Pages
- Source: "GitHub Actions"
-
Set up NPM_TOKEN secret (for npm publishing):
- Go to Settings β Secrets and variables β Actions
- Add
NPM_TOKEN
with your npm access token
# Install dependencies
npm install
# Start development server (documentation)
npm run dev
# Run tests
npm test
# Run linting
npm run lint
The 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.