Skip to content

jonobr1/react-two.js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

69 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

react-two.js

Version License

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>

Why react-two.js?

  • 🎨 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 and useTwo 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

What does it look like?

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>

Installation

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.

First Steps

Creating a Canvas

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>
  )
}

Adding Shapes

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>

Animating with useFrame

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" />
}

Accessing Two.js Instance

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)
  }, [])
}

API

Components

Core

  • <Canvas> β€” Main container that creates Two.js instance
  • <Group> β€” Container for organizing and transforming multiple shapes

Primitives

  • <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

Paths & Text

  • <Path> β€” Custom path with vertices
  • <Points> β€” Collection of points rendered in one draw call
  • <Text> β€” Text rendering

Advanced

  • <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

Hooks

useTwo()

Access the Two.js instance and canvas properties:

const { two, width, height } = useTwo()

Returns:

  • two β€” The Two.js instance
  • width β€” Canvas width
  • height β€” Canvas height

useFrame(callback)

Register a callback that runs on every animation frame:

useFrame((elapsed: number) => {
  // elapsed is time in seconds since animation started
})

Props

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}
/>

TypeScript

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} />
}

Examples

Rotating Group

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>
  )
}

Gradient Fill

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>
  );
}

Learn More

Development & Deployment

Building the Library

# 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

Publishing to NPM

  1. 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)
  2. Create a GitHub release with the new version tag. This automatically triggers npm publishing via GitHub Actions.

    Or publish manually:

    npm run publish:npm

GitHub Pages Deployment

The documentation site automatically deploys to GitHub Pages on every push to main. The site will be available at:

Manual Setup (if needed):

  1. Enable GitHub Pages in repository settings:

    • Go to Settings β†’ Pages
    • Source: "GitHub Actions"
  2. Set up NPM_TOKEN secret (for npm publishing):

    • Go to Settings β†’ Secrets and variables β†’ Actions
    • Add NPM_TOKEN with your npm access token

Local Development

# 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.

Acknowledgments

Built on top of Two.js by Jono Brandel. Inspired by Three.js and react-three-fiber.

About

πŸ“Ί A React renderer for Two.js

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

 

Packages

No packages published

Contributors 3

  •  
  •  
  •