• Stars
    star
    1,606
  • Rank 27,960 (Top 0.6 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 3 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

💪📦 Flexbox for react-three-fiber

@react-three/flex

Build Status Version Downloads Discord Shield

Placing content in THREE.js is hard. @react-three/flex brings the webs flexbox spec to react-three-fiber. It is based on Yoga, Facebook's open source layout engine for react-native.

npm install @react-three/flex

These demos are real, you can click them! They contain the full code, too.

Table of contents

Usage

Simply create layouts by wrapping your 3D objects in different <Box /> instances inside a <Flex /> container. This way they will be automatically placed in the 3D space following the flexbox specification just like in the DOM.

import { Flex, Box } from '@react-three/flex'

const Layout = () => (
  <Flex justifyContent="center" alignItems="center">
    <Box centerAnchor>
      <mesh geometry={box} />
    </Box>
    <Box centerAnchor flexGrow={1}>
      <mesh geometry={torus} />
    </Box>
  </Flex>
)

You can tweak the container and the boxes using standard CSS flex properties, like flexDirection or justifyContent for the container and flexGrow for the boxes. There are also shorthands, like align and justify. See the props docs below for more info.

Anchors

When positioning items, react-three-flex needs to know where the object anchor is: Yoga Layout expects the object position to be relative to the upper left corner, which is the same as the DOM expects.

Most THREE.js geometries, though, are positioned relative to the object center. To tell react-three-flex that your <Box /> positioning is relative to the center you need to set the centerAnchor prop to true.

<Box centerAnchor>
  <mesh geometry={sphere} />
</Box>

If you nest <Box /> elements, though, you need to set it to false. See Nesting.

Anchors

Stretching

By default @react-three/flex controls elements position only. In some cases you may want to control element sizing too. Since @react-three/flex has no information about how the inner content size works, you need to set your content size manually. To do so @react-three/flex provides you the container size in two ways:

  • Using a children render function:
<Flex>
  <Box width="auto" height="auto" flexGrow={1} centerAnchor>
    {(width, height) => <Plane args={[width, height]} />}
  </Box>
</Flex>
  • Using a hook:
function Inner() {
  const [width, height] = useFlexSize()
  return <Plane args={[width, height]} />
}

function Outer() {
  return (
    <Flex>
      <Box width="auto" height="auto" flexGrow={1} centerAnchor>
        <Inner />

Remember that the useFlexSize hook works ONLY if your <Box/> is outside the component.

Invalidation and Reflow

While the DOM's Flexbox has full control over all the changes of the tree, @react-three/flex runs on React, hence it has no way to know if a children size or shape has changed. For performance reasons Flex layout calculation does not run every frame, and it has to be triggered manually in some cases.

What will trigger a reflow:

  • <Flexbox/> props changes (alignItems, size, ...)
  • <Box/> props changes (flexGrow, margin, ...)
  • <Flexbox/> and <Box/> rerenders with children differences
function AnimatedBox() {
  // Since <Box/> is inside the component, setting the state will rerender it, thus causing a reflow.
  // ⚠️ If <Box/> were outside this component, this would NOT cause a reflow!
  const [state, setState] = useState(true)
  useInterval(() => setState((s) => !s), 1000)
  return (
    <Box centerAnchor>
      <mesh>
        <boxBufferGeometry attach="geometry" args={[state ? 10 : 30, 10, 10]} />

This will NOT cause a reflow!

function AnimatedBox() {
  // ⚠️ Setting state does not rerender <Box/> since it's in the parent
  // ‼️ No Reflow!!
  const [state, setState] = useState(true)
  useInterval(() => setState((s) => !s), 1000)
  return (
    <mesh scale={[state ? 1 : 3, 1, 1]}>
      <boxBufferGeometry attach="geometry" />
    </mesh>
  )
}

function Layout() {
  return (
    <Flex>
      <Box centerAnchor>
        <AnimatedBox />

For every other case (setting size with the useFrame hook, performing react-spring animation, or <Box/> are not rerendered) you'll need to manually cause a reflow, using the useReflow() hook. Reflows requests are batched every frame so you can call it from hundreds of components without performance issues.

Animation with useFrame():

function AnimatedBox() {
  const ref = useRef()
  const reflow = useReflow()
  useFrame(({ clock }) => {
    ref.current.scale.x = 1 + Math.sin(clock.getElapsed())
    reflow()
  })
  return (
    <Box centerAnchor>
      <mesh ref={ref}>

<Box/> outside of component:

function AnimatedBox() {
  const [state, setState] = useState(true)
  useInterval(() => setState((s) => !s), 1000)
  const reflow = useReflow()
  useEffect(reflow, [state])
  return (
    <mesh ref={ref} scale={[state ? 1 : 3, 1, 1]}>

Sizing

@react-three/flex differs from DOM Flexbox in that it relies on a parent container for the root flex. It is required to specify its dimensions using size prop for wrapping and to be responsive.

<Flex flexDirection="row" flexWrap="wrap" size={[300, 200, 0]}>
  {/* ... */}
</Flex>

⚠️ WATCH OUT! Yoga flexbox engine uses whole integer numbers to perform layout calculation to preserve precision - @react-three/flex multiplies every element size and flex prop by the scaleFactor of the root flex container. By default it's 100, and works well for small scenes. If you use a different scene scale, make sure to tweak it accordingly.

Bounds

Axis Orientation

Another important difference with DOM Flexbox is that you have to specify the plane of the container in 3D. The elements will be positioned in the 2D plane given by the two axes, using width and height calculated along the two axes.

The 2D flex container width and height will be calculated by looking at the size prop with respect of the chosen axes (100 for x and 200 for y in this example).

The default plane is xy, the other possibilites are yz and xz.

<Flex plane="xy" size={[100, 200, 0]}>
  {/* ... */}
</Flex>

Axes Orientation

Margin and Padding

For every <Flex /> and <Box /> component you can specify the margin and padding like in DOM elements.

<Flex flexDirection="row" size={[300, 200, 0]} padding={30} margin={5}>
  <Box padding={5} marginTop={5} centerAnchor>
    <mesh geometry={sphere} />
  </Box>
</Flex>

Margin

Nesting

Since a <Flex /> component works the same way as a DOM one, you can easily make complex layouts by nesting flex containers.

<Flex flexDirection="row" flexWrap="wrap" size={[50, 0, 0]}>
  <Box centerAnchor>
    <mesh geometry={sphere} />
  </Box>
  <Box flexDirection="column" flexWrap="no-wrap">
    <Box centerAnchor>
      <mesh geometry={sphere} />
    </Box>
    <Box centerAnchor>
      <mesh geometry={box} />
    </Box>
  </Box>
</Flex>

Measuring the container

When building responsive layouts you might need to synchronize the size of the 3D Flex container with the DOM, for example to synchronize scroll position or to modify the height of a scroll container. To make it easier, you can use the onReflow prop on the root <Flex> component that will be called every time the flex layout is recalculated - e.g. when any content changes.

<Flex onReflow={(totalWidth, totalHeight) => ...}>
 {/* ... */}
</Flex>

API

You can find a full list of props here.

<Flex
  size={[1, 1, 1]} // Total size of the flex container, see above
  position={[0, 0, 0]} // Default - position for the flex container in the scene
  direction="ltr" // Default - right to left or right to left
  plane="xy" // Default - plane axes, see above
  scaleFactor={100} // Default - integer scale factor, see above (Sizing)
  onReflow={fn} // Called everytime the layout is recalculated
  {...R3FlexProps} // Standard Flexbox props, described below
>
  <Box>{/* ... */}</Box>
</Flex>
<Box
  centerAnchor // If the inner content position is relative to its center, see above (Anchors)
  {...R3FlexProps} // Standard Flexbox props, described below
>
  <mesh geometry={box} />
</Box>

Or you can pass a function as children:

<Box>{(width, height) => <Model width={width} height={height} />}</Box>

Flexbox props

Both <Flex/> and <Box /> components share the same Flexbox props API from Yoga. The library also provides string and number inputs for convenience and shorthands.

Example:

// Flex with padding top set to 10, alignItems to 'center', justifyContent to 'space-around' and flexWrap to 'wrap'
<Flex pt={10} align="center" justify="space-around" wrap="wrap">
  {/* ... */}
</Flex>

More Repositories

1

zustand

🐻 Bear necessities for state management in React
TypeScript
40,808
star
2

react-spring

✌️ A spring physics based React animation library
TypeScript
27,160
star
3

react-three-fiber

🇨🇭 A React renderer for Three.js
TypeScript
25,320
star
4

jotai

👻 Primitive and flexible state management for React
TypeScript
16,893
star
5

use-gesture

👇Bread n butter utility for component-tied mouse/touch gestures in React and Vanilla Javascript.
TypeScript
8,537
star
6

valtio

💊 Valtio makes proxy-state simple for React and Vanilla
TypeScript
8,257
star
7

drei

🥉 useful helpers for react-three-fiber
JavaScript
7,122
star
8

leva

🌋 React-first components GUI
TypeScript
4,528
star
9

gltfjsx

🎮 Turns GLTFs into JSX components
JavaScript
3,949
star
10

use-cannon

👋💣 physics based hooks for @react-three/fiber
TypeScript
2,654
star
11

react-three-next

React Three Fiber, Threejs, Nextjs starter
JavaScript
2,140
star
12

postprocessing

A post processing library for three.js.
JavaScript
2,100
star
13

racing-game

🏎 Open source racing game developed by everyone willing
TypeScript
2,094
star
14

react-xr

🤳 VR/AR with react-three-fiber
TypeScript
1,890
star
15

suspend-react

🚥 Async/await for React components
TypeScript
1,308
star
16

react-postprocessing

📬 postprocessing for react-three-fiber
JavaScript
1,009
star
17

detect-gpu

Classifies GPUs based on their 3D rendering benchmark score allowing the developer to provide sensible default settings for graphically intensive applications.
TypeScript
979
star
18

lamina

🍰 An extensible, layer based shader material for ThreeJS
TypeScript
976
star
19

its-fine

🐶🔥 A collection of escape hatches for React.
TypeScript
891
star
20

react-use-measure

🙌 Utility to measure view bounds
TypeScript
799
star
21

react-nil

⃝ A react null renderer
TypeScript
772
star
22

react-three-rapier

🤺 Rapier physics in React
TypeScript
765
star
23

maath

🪶 Math helpers for the rest of us
TypeScript
755
star
24

threejs-journey

⚛️ Bruno Simons journey demos in React
TypeScript
685
star
25

three-stdlib

📚 Stand-alone library of threejs examples designed to run without transpilation in node & browser
JavaScript
624
star
26

react-three-editor

🔌 A one of a kind scene editor that writes changes back into your code
TypeScript
602
star
27

react-three-a11y

♿️ Accessibility tools for React Three Fiber
TypeScript
507
star
28

react-zdog

⚡️🐶 React bindings for zdog
JavaScript
441
star
29

use-asset

📦 A promise caching strategy for React Suspense
TypeScript
414
star
30

react-three-offscreen

📺 Offscreen worker canvas for react-three-fiber
TypeScript
397
star
31

drei-vanilla

🍦 drei-inspired helpers for threejs
TypeScript
364
star
32

ecctrl

🕹️ A floating rigibody character controller
TypeScript
349
star
33

tunnel-rat

🐀 Non gratum anus rodentum
TypeScript
287
star
34

react-three-lgl

🔆 A React abstraction for the LGL Raycaster
TypeScript
260
star
35

market

📦 Download CC0 assets ready to use in your next 3D Project
JavaScript
249
star
36

react-three-csg

🚧 Constructive solid geometry for React
TypeScript
242
star
37

gltf-react-three

Convert GLTF files to React Three Fiber Components
JavaScript
230
star
38

component-material

🧩 Compose modular materials in React
TypeScript
161
star
39

env

💄 An app to create, edit, and preview HDR environment maps in the browser
TypeScript
143
star
40

use-p2

👋💣 2d physics hooks for @react-three/fiber
TypeScript
141
star
41

react-ogl

🦴 A barebones react renderer for ogl.
TypeScript
139
star
42

react-spring-examples

JavaScript
138
star
43

react-three-gpu-pathtracer

⚡️ A React abstraction for the popular three-gpu-pathtracer
TypeScript
125
star
44

react-three-lightmap

In-browser lightmap/AO baker for react-three-fiber and ThreeJS
TypeScript
123
star
45

cannon-es-debugger

Wireframe debugger for use with cannon-es https://github.com/react-spring/cannon-es
HTML
103
star
46

rafz

💍 One loop to frame them all.
TypeScript
96
star
47

website

Poimandres developer collective website
JavaScript
87
star
48

swc-jotai

Rust
85
star
49

assets

📦 Importable base64 encoded CC0 assets
Makefile
84
star
50

react-three-scissor

✂ Multiple scenes, one canvas! WebGL Scissoring implementation for React Three Fiber.
TypeScript
81
star
51

eslint-plugin-valtio

An eslint plugin for better valtio experience
JavaScript
69
star
52

react-spring.io

✌️ A spring physics based React animation library
TypeScript
56
star
53

react-three-babel

🛍 A Babel plugin that automatically builds the extend catalogue of known native Three.js elements
TypeScript
53
star
54

r3f-website

Website for React Three Fiber
JavaScript
26
star
55

market-assets

JavaScript
19
star
56

react-three-8thwall

JavaScript
17
star
57

drei-assets

JavaScript
16
star
58

discord

🤖 Poimandres Discord Bot
TypeScript
10
star
59

react-three-jolt

⚡ Jolt physics in React
CSS
10
star
60

branding

TypeScript
7
star
61

market-assets-do

JavaScript
5
star
62

envinfo

Easily collect useful information for bug reports
JavaScript
4
star
63

leva-wg

1
star