✊✌✋ — A demo to evaluate react-three-fiber and its ecosystem
I read a lot about react-three-fiber (abbreviated with r3f) and wanted to give it a try. So this demo is primarily a technical evaluation with a fun factor. If you don’t know r3f, I recommend to read about it first. In short, it’s a React reconciler which renders your components into a WebGL context instead of the familiar
ReactDom. If you are new to ThreeJS, I won’t recommend to start with r3f.
I consider myself a seasoned React and a decent ThreeJS developer. But since it’s my first encounter with r3f, there definitely might be parts I don’t know about. So please provide me feedback if I made mistakes here.
The gist of the demo
In general, it’s a digital adaption of the “rock, scissors, paper” game, which we call “Schere, Stein, Papier” in German (what makes me wonder who changed the order of words while translating it). Since it’s a game it has obviously game logic — basically which gesture beats another one. And it also featuers different game states.
For a more immersive visual experience I included animations for both, 2D and 3D elements.
The hands you’ll see are 3D elements, whereas the GUI is represented in 2D.
But now, let’s get started with my two cents’ about r3f and its close friends:
I really like the sorting of Thoughtworks tech radar into adopt, trial, assess, and hold. So I’ll try something similar here:
Clearly r3f itself. The advantages are huge if you happen to already know React. A declarative scene graph is a big plus and you can use everything you like about React / JSX for ThreeJS.
If you need access to ThreeJS itself, call
useThree hook and it returns an instance of it. This is limited only to components which reside inside r3fs’
Canvas. But I don’t think this is an issue. The only case I can come up with is an multi-frontend app, but then you can just import ThreeJS as a module. Because r3f includes ThreeJS as a
peerDependencyand relies on you to provide it.
For performance, I didn’t measure any metrics myself, but r3f promises not to slow down your ThreeJS render loop.
In this demo, I also built a hybrid of a 2D HTML interface and a 3D WebGL context. And to be able to write both with React and JSX is very soothing.
A minor downside is documentation. On the one hand side, it could be a little more verbose from my point of view, and on the other, I’d really like to see a documentation with a smart search. Maybe it could even span all the projects of the r3f ecosystem. Ever used tailwindcss’ search? Then you know what I’m talking about.
I learned a lot in the given examples (which are great by the way) which I didn’t always found in the documentation. A little quest? What’s the
useGLTF actually returning? Don’t look at the code 😉 I know that’s picky since it’s an open-source project with a lot of work people put into this for free. But still, this is something which can make r3f excel even more.
It’s not quite clear to me if r3f is compatible with every upcoming version of ThreeJS automatically, or might there be some work on rf3’s side I don’t want to wait for. Let’s say ThreeJS adds a new flash primitive in the shape of a⚡. Can I just say
<flash />? I think that’s kind of the way React’s reconcilers should work. But that is for sure not my field of expertise so maybe these questions can be answered by an expert here.
It comes without saying but if you really need to squeeze your bundle size though, you should think twice before adding another framework on top of it to your project.
With r3f comes
Drei, a growing list of helpers around r3f and ThreeJS / WebGL in general. I only used two of them here —
useGLTF comes with a
preload method and I was missing in the documentation, what it does exactly. But looking at its implementation clarified that it uses the preload mechanism of its included loaders. The included loaders are actually
use-asset which comes with r3f and
GLTF of ThreeJS. Of course, preloading makes more sense and fun in a general place or when you start-up your app — not in a component that renders later.
An open question to me is, if preload adds up to the state of
useProgress. This could be something of the documentation to clarify.
I think Zustand is worth to try furthermore. I really like it’s intuitive approach and simplicity. But for me, it has to stand the test of time in a more complex application.
useStore returns everything you need, state, and actions. I have not tested async actions yet, which are still cumbersome when using React-Redux.
Its transient updates can solve problems which happen to increase since React introduced hooks. Still, I need to test it in an app without a WebGL context to see if the lack of re-renders is a blessing or a curse.
Also, gltfjsx needs further exploration from my side. It worked quite well in this demo project. But since the
.glb models I used were simple shapes, I need to test it with a more complex scene to make a clear statement. Moreover, I also started this process independently and afterwards included the resulting component into my app. I didn’t figure out yet how to integrate into my workflow more smoothly.
For React Spring, I need to use it one more time to get a clear picture. I read Josh W Comeau’s Article about spring based physics and agree that they feel more fluid and organic. But in the context of this demo, I didn’t find a non-complicated way for the wiggle animation of the choosing pose.
It is keyframe based, which seems a little too complicated for me with React Spring, or rather it is not the general scope of spring based animations. If someone can point me in a direction, it would be much appreciated.
In the end, I rely once again on animejs which I used a lot of times. It has some downsides and is not exclusively focused on React. So it has no built-in solution for animations when a component unmounts but keyframes and chained animations are straightforward.
Nothing on hold right now 📭
So I think I barely cracked the surface here of what the r3f ecosystem has to offer. And since my first expression is really good, I am looking forward to adding physics, do some postprocessing of my scene or even go into virtual reality. Jump ahead!