Skip to content

Leva

Import

import { useControls } from 'leva'

Video Lecture

Section Video Links
Leva Leva Leva

Description

Leva is a GUI component that you can add to your React Three Fiber application and interact with your scene.

We need to install the dependency.

npm install leva@0.9.34 --save-dev

Warning

There is a problem with bundling the colour picker component in leva@0.9.35, so if you experience the error, then try installing the version before using npm install leva@0.9.34 --save-dev

To create a GUI that modifies some state in our component, we also need to import useControls.

import { useControls } from 'leva'

And create a useControls hook.

const color = useControls({
  value: 'green',
})

And then use it. E.g.,

<Canvas>
  <color attach="background" args={[color.value]} />
</Canvas>

The Leva GUI will show a color picker, and when you change the color, it will update the background color of the canvas in real time.

Note that options created within the useControls hook, will be persisted between React re-renders. This is similar to how useState works.

If you created your control options outside the useControls hook, and passed them in as a variable or object, such as I have in the below example, then you may need to consider using useMemo since every time any control is used, it will cause react to re-render the component where the useControls hook was declared.

There are many Leva GUI controls, such as text input, checkbox, sliders, radio buttons and more. You can even add folders and subfolders and hide/show them.

In this lesson we will demonstrate a few controls, but we will see Leva quite a lot during the course, so you will see many other examples of how to use it.

./src/App.jsx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import { Canvas } from '@react-three/fiber'
import Polyhedron from './Polyhedron'
import * as THREE from 'three'
import { useMemo } from 'react'
import { Stats, OrbitControls } from '@react-three/drei'
import { useControls } from 'leva'

export default function App() {
  const polyhedron = useMemo(
    () => [
      new THREE.BoxGeometry(),
      new THREE.SphereGeometry(0.785398),
      new THREE.DodecahedronGeometry(0.785398),
    ],
    []
  )

  const options = useMemo(() => {
    return {
      x: { value: 0, min: 0, max: Math.PI * 2, step: 0.01 },
      y: { value: 0, min: 0, max: Math.PI * 2, step: 0.01 },
      z: { value: 0, min: 0, max: Math.PI * 2, step: 0.01 },
      visible: true,
      color: { value: 'lime' },
    }
  }, [])

  const pA = useControls('Polyhedron A', options)
  const pB = useControls('Polyhedron B', options)

  return (
    <Canvas camera={{ position: [1, 2, 3] }}>
      <Polyhedron
        position={[-1, 1, 0]}
        rotation={[pA.x, pA.y, pA.z]}
        visible={pA.visible}
        color={pA.color}
        polyhedron={polyhedron}
      />
      <Polyhedron
        position={[1, 1, 0]}
        rotation={[pB.x, pB.y, pB.z]}
        visible={pB.visible}
        color={pB.color}
        polyhedron={polyhedron}
      />
      <OrbitControls target-y={1} />
      <axesHelper args={[5]} />
      <gridHelper />
      <Stats />
    </Canvas>
  )
}

./src/Polyhedron.jsx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import { useRef, useState } from 'react'

export default function Polyhedron({ polyhedron, color, ...props }) {
  const ref = useRef()
  const [count, setCount] = useState(2)

  console.log(polyhedron[count].uuid)

  return (
    <mesh
      {...props}
      ref={ref}
      onPointerDown={() => {
        setCount((count + 1) % 3)
      }}
      geometry={polyhedron[count]}
    >
      <meshBasicMaterial color={color} wireframe />
    </mesh>
  )
}

Configuring Leva

Normally, you can create a Leva GUI just by using the useControls hook somewhere in your application.

If you want to configure the appearance of the Leva GUI, then you can also add the <Leva> component to your App.jsx and set some attributes.

E.g., To have the Leva GUI fully collapsed by default,

import { Leva } from 'leva'

export default function App() {
  return (
    <>
      <YourExistingComponents />
      <Leva collapsed />
    </>
  )
}

The options are,

<Leva
  theme={myTheme} // you can pass a custom theme (see the styling section)
  fill // default = false,  true makes the pane fill the parent dom node it's rendered in
  flat // default = false,  true removes border radius and shadow
  oneLineLabels // default = false, alternative layout for labels, with labels and fields on separate rows
  hideTitleBar // default = false, hides the GUI header
  collapsed // default = false, when true the GUI is collpased
  hidden // default = false, when true the GUI is hidden
/>

Another option for styling Leva is to manage the CSS styles directly.

E.g., Adding this to your style.css will modify the Leva GUI width.

#leva__root > * {
  width: 400px;
}

Or, you could even scale it 50%

#leva__root > * {
  scale: 50%;
}

Working Example

<>
Leva (Working Example) sbedit.net
Leva github.com/pmndrs
Object3D threejs.org sbcode.net
MeshBasicMaterial threejs.org sbcode.net
OrbitControls threejs.org sbcode.net

GitHub Branch

git clone https://github.com/Sean-Bradley/React-Three-Fiber-Boilerplate.git
cd React-Three-Fiber-Boilerplate
git checkout leva
npm install
npm start

Comments