React Renderer for Three.js
github.com
github.com
Benefits include complete control at frame and pixel level, being cross-platform (same code runs on web, iOS, macOS, Linux), and having access to third-party C/C++ libraries for 3D graphics.
There's some overhead but it's negligible (assuming you're not making overly redundant API calls.)
If your data isn't structured for fast rendering, it doesn't matter much what language you're using; they'll all be too slow.
[0] https://github.com/emscripten-core/emscripten/blob/main/src/... [1] https://github.com/emscripten-core/emscripten/blob/main/test...
Desktop GL emulation is just a layer on top OpenGL ES if, for example, you're still using OpenGL's fixed function pipeline (deprecated 13 years ago.)
A C++ application compiled via Emscripten ships (a fairly large amount) of JS glue code that exposes all relevant Browser APIs like WebGL, Fetch or other HTML5 stuff to the actual WASM program. As others commented, for WebGL an additional API translation is applied. If the source targets OpenGL ES 2 (or 3 for WebGL 2), this step has almost no overhead however.
The idea is that it does more cacheing of things like uniform locations and such so you do very fast in-memory lookups in WASM without hitting the JS Api as much.
In the future this will be obsolete since WebGPU has a more optimal API to begin with, and Rust/WASM won't need to go through the JS layer due to "interface types"
We switched https://flux.ai from vanilla ThreeJS to R3F and it’s been a huge productivity gain for the whole team!
Less code, that is more capable and more reusable!
In case anyone is interested, we are hiring: https://coda.io/@flux-ai/flux-jobs
PCB layouting hasn’t publicly shipped yet though
three.js isn't dom elements updated in js. The state of each object is updated in the scene depending on more than whether they changed.
Where three.js lacks abstraction is a component system, in plain js, to organise application with decent patterns. Most three apps are a big blob or code.
The underlying abstraction model of having a tree of components and re-rendering only the parts that have changed between renders doesn’t map to the hardware at all, meaning you’ll waste most of the HW performance just on maintaining the abstraction.
You’ll also get zero benefits from the third-party libraries - there’s nothing in them that can help you with stuff that matters, like minimizing amount of the GPU state transitions for example or minimizing amount of GPU/CPU syncs.
It will be scenegraphs all over again, and the graphics industry has ditched these long ago in favor of simpler models, for good reasons.
Long story short, the happy path in graphics programming is very narrow and fragile, and you typically want to structure your abstraction around it.
If you have a coffee cup on a table in VR, is that coffee cup a child of the table? How do you move the coffee cup off the table and put it onto another table? Is it now a child of that other table? What about the coffee in the cup? Is that a child of the cup? How do you change properties of the coffee without necessarily accessing the table and the cup?
Developers working on 3D systems have developed much better paradigms than the DOM for dealing with this problem. An Entity-Component-System architecture with "constraints" is the current best solution. In that architecture, you would create a coffee cup "entity" with a mesh "component" with another "constraint" component, constraining that coffee cup to the table (or better yet, mass component acted on by a physics system). Then you can simply remove the constraint component when removing the cup from one table, and re-add the constraint component when adding it to the other table.
Overall, I think web developers are in for some intense learning and paradigm shifts if 3D becomes the norm.
As for the gorilla-banana problem, I would think all objects in a scene would be under the root, with the exception of pieces that make up a thing and rarely separate (wheels on a car, for example).
Additionally, you can throw OOP in that mix as well, because Three.js has it's own whole OOP-style framework, that you're strapping declarative React on top of with this renderer. Reminds me of Jonathan Blow's talk on the end of civilization via endless layers of abstraction[1].
I really think, when it's ready, a Bevy[2]-style system either native or compiled to WASM with WebGPU will be ideal.
And while I'm airing opinions (forgive me), I think writing shaders now is like SQL 30 years ago. Developers left optimizing difficult--according to them--SQL to database administrators by abstracting it away into ORMs. If history is any indicator, I think we'll be having the same arguments on Hacker News 30 years from now about 3D frameworks vs writing shaders directly as we're having now about ORMs vs writing SQL directly.
This provides tons of benefits, so for example you can also decide to iterate over the entites by shader program and gain significant speedups for graphics processing, or maintain components that roughly sort them by their position in world space for physics and culling or lighting, etc.
For a crude analogy, imagine if Document.querySelectorAll() were a zero-cost abstraction, i.e. it ran as fast as iterating over linear memory. In practice this isn't how it turns out with an ECS, but it's much closer and you can get this kind of performance for the "hot path" kind of queries.
To add to the sibling comment, there's another wonderful Rust ECS called shipyard[0] and I helped write a scenegraph for it (which I really need to update, one of these days)[1]
There's some excellent demos of how this works with this library with a full physics engine. Loads great even on my phone.
Let's say you're building a game where you want a sphere to stick to whatever player you throw it at. How would you do that with a scene graph/OOP model? It'd be awkward, removing objects from one parent and adding them to another. Even more awkward if it's a complex object and you only want a part of that complex object to stick to the player. ECS + a constraint or physics system does a decent job (not perfect) of handling this in a relatively elegant and performant way.
I've used Three.js enough--built my portfolio[1] out of it, and then switched to Babylon when I realized how little I liked Three.js. For the record, I also dislike Babylon.
could you go more into detail what you mean when you say "anything non trivial"? is there a real example of something that would not be possible to create in, say, threejs?
const mesh = useRef()
...
<mesh ref={mesh} ...
You'll be rendering an undefined element (before the ref has a chance to attach).Also, the TypeScript example makes me head hurt.
const ref = useRef(null!)
Ah, yes. A non-null null literal....no, no, definitely not. Must've gone crazy for a second there.
I don't really like this though, although interesting, it feels like a hack and might not integrate well with tooling (e.g. the Typescript example).
How I would have implemented it was exposition a Mesh component which wraps this, and a useMesh hook to wrap and type the ref.
I don’t understand your first issue. The component is assigned to the ref, not the other way around, so why would it render `undefined`? It’s possible that `mesh.current` is undefined at first render, but that shouldn’t matter for the component, only for the reference.
const mesh = useRef()
<mesh />
The underlying JavaScript (i.e. not JSX) on the first render , is React.createElement(mesh /* { current: undefined } */, { ref: mesh } )
In fact, I don't even think it matters which render you're talking about. It's still rendering a ref (again, { current: <undefined or a Three.MESH, I guess> }). That doesn't seem right to me.
Pretty confusing though, would have been better to call it `meshRef`. I also expected these components to be capitalised, but it probably makes sense in the way that in the dom renderer default components are lowercase as well.
The reason r3f uses lower-case names for built-in components is to distinguish them from your own components; from the documentation: "It merely expresses Three.js in JSX: <mesh /> becomes new THREE.Mesh(), and that happens dynamically." So whenever you see <mesh /> or anything else lower-case it is just an JSX alias for a Three.js core component. Note that they're not HTML tags in the resulting output; since they're rendered inside <Canvas />, they're transformed to Three.js automatically.
null! is a common typescript thing, it is a semantic guarantee that the ref is static and hence will be available. this saves you the if (ref.current) { ... } check.
const ref = useRef()
useEffect(() => console.log(ref), [])
return <div ref={ref} />
will return { current: [dom node] } const ref = useRef()
useEffect(() => console.log(ref), [])
return <mesh ref={ref} />
will return { current: [mesh node] } const mesh = useRef<THREE.Mesh>(null); // mesh has type RefObject<THREE.Mesh | null>
...
useFrame((): void => {
if (mesh.current != null) {
mesh.current.rotation.x += 0.01;
}
});
...
return <mesh ref={mesh} ... />
As others have mentioned, the ref will typically attach by the time a `useEffect` hook is called, but for safety it's nice to have the null check. const mesh = useRef(...
assigns an instance of something (`React.mutableRefObject`) to a variable in scope, but <mesh ...
after compiling into normal JavaScript and becomes (0, _jsxRuntime.jsxs)("mesh"...
(see `console.log(__SANDBOX_DATA__.data.transpiledModules['/src/App.js:'].source.compiledCode) `)So that's why you're not seeing the editor or runtime complain about this. `<mesh` (lowercase), as with other lowercased react elements get translated into `Something('mesh'`, and doesn't require a defined component variable.
Think this:
const div = 'not a div -- i am a string'
return <div>{div}</div>
Just one of the many gotchas of many layers of JavaScript/TypeScript/React/etc... programming environments.> Is there an error in the examples? You have
const mesh = useRef()
...
<mesh ref={mesh} ...
> You'll be rendering an undefined element (before the ref has a chance to attach).…as follows:
1. On that last line, <mesh> is just a regular element[0].
2. Ref assignment makes this element’s instance accessible within component code[1] under a constant, here coincidentally (and confusingly, I must say) named “mesh”. The constant could’ve been named anything else, like “el”, and the example would work exactly the same way:
const el = useRef()
...
<mesh ref={el} ...
3. How come the constant in the original example does not shadow the equivalently named built-in JSX element? Well, there is a convention/hard-coded rule in React/JSX/TSX where it simply would not resolve lowercase identifiers to custom components. If we change “mesh” to “Mesh” in the original example, then the app would attempt to use the ref constant as a (malformed) custom component, and predictably throw.[0] https://www.w3.org/TR/2016/CR-SVG2-20160915/shapes.html#Mesh...
[1] https://reactjs.org/docs/refs-and-the-dom.html#refs-and-func...
Reusable components are easy in a 3d engine like 3js. You can still program declaratively if you liked. It’s claim to outperform raw threejs is surely untrue. React is also bad for animations, and they recommend you sort of use reacts “back door” to do complex animations. 3d engines are all about animations. You could use redux easily without react if you liked. I bet you still have to learn a new API.
This doesn’t seem that useful. Am I mistaken? (Honestly curious)
That said, I bet it was interesting and pleasantly challenging to write
We’re truly free to make a <Modal /> however we like. Perhaps not even in those tags. We just don’t know it yet.
The reality is it’s a good abstraction because it’s so decoupled from the DOM, but it’s associated with the DOM and web mainly for historical reasons.
It’s also worth noting that there are similar extensions to other languages that are similarly render-agnostic.
Certainly you can map this api to a variety of other APis, which I’m sure is what they did with React Native, but it was built with the DOM tree structure in mind.
I think it’s one of the most brilliant things frontend has ever created along with Jquery, but they are both slaves to the DOM.
This isn’t a property of JSX, it’s a property of a virtual DOM. The former is typically used with the latter, but don’t have to be. SolidJS is an example of JSX without VDOM. It compiles to plain DOM operations, you only have a component tree during development. And like React, its compiler was designed to be render-agnostic and can be/is used in other environments.
It’s funny you should mention Portal here. I am working on a technique/hopefully eventual library to transparently (without requiring developer intervention) use Portals as a partial hydration solution—completely sidestepping the tree structure and only rendering interactive components. I believe it will be framework agnostic for anything that provides (or can provide) a hyperscript/createElement function and Portal-like functionality. And like those frameworks, it’s just a declarative data structure and can render to anything.
> Certainly you can map this api to a variety of other APis, which I’m sure is what they did with React Native, but it was built with the DOM tree structure in mind.
I’ve spent a lot of time (maybe too much time) looking at the underlying renderer abstractions of React, Preact, Solid, JSX Lite, several others.
The only one tightly coupled to DOM is Preact (and even that isn’t totally coupled). In fact that coupling is one of the major advantages Preact has in terms of package size.
React’s design has a separate renderer interface/abstraction that is primarily oriented around state reconciliation; the DOM implementation is just one of many.
Solid’s JSX (implemented in a Babel transform somewhat misleadingly called dom-expressions) is similarly decoupled from its DOM implementation with an abstract renderer interface. The difference is rather than state reconciliation it’s reactive.
JSX Lite’s render target is even more abstract, it renders an intermediate data structure that can be transformed to other component libraries, and even some design apps.
You can implement a JSX transform to basically any render target, without React. You can even skip the entire notion of state, events, interaction.
I even use it on my personal site to generate PNGs at build time! Unless you’re looking at my source code you’d never know it.
the other thing you say, that react is bad for animations — r3f operates outside of react, there is no overhead, it actually quite easily outperforms threejs. but there are many other benefits, it will usually save you lots of code, and it can be more memory efficient, see this thread: https://twitter.com/0xca0a/status/1426924274527477764
the biggest advantage is the component model, because it allows for a true eco system, something that threejs does not otherwise have due to the lack of a common ground. and interop. every react library can now act on meshes and materials.
That idea didn’t come out of the blue, it came from html, it came from the DOM.
If I give you a blank sheet of paper and say ‘write me a rendering api’, and you immediately reach for a tree structure, I’d be compelled to say you are influenced by html.
I feel like the watershed moment for us will be that moment in the Matrix where the kid tells Neo ‘there is no tree, there is no spoon’.
Edit (full quote from The Matrix):
Do not try and bend the spoon, that's impossible. Instead, only try to realize the truth... There is no spoon... Then you'll see that it is not the spoon that bends, it is only yourself.
We have been bending over for the DOM for quite some time now, I think it’s time we explore.
————————
Edit 2 (being rate limited), reply to some posts below:
Interestingly enough, ever major performance trick on the frontend requires breaking out of the tree structure. If you want a data table with a notable amount of rows, you have to break out and start defining heights and positions and calculate what to show manually. In other words, the free stuff we were supposed to get from the tree were not free.
My irreverence for the DOM comes from the fact that we have to negate it, ignore it, to achieve certain things.
So in the end I wonder, why bother with it at all?
One of the first steps of this is to gather all the nodes in the graph, flattening it into a list, and then start filtering and sorting it: for every opaque object, you likely toss it in Z-pre and opaque buckets (for objects visible through the main frustum), and a shadow caster bucket (per shadowed light frustum!). So the renderer itself really prefers lists of lists, it does not have trees internally.
React-Three-Fiber seems to take the DOM-equivalent tree, sort it, and then construct a Three.JS scene graph from it, and then Three.JS's render method starts from that scene graph soup and does the above. So one might argue that the tree is a DOM-like interface you're adding on top of Three.JS's scene graph.
I haven’t really encountered anything that can’t be represented well in a tree, especially with context providers in the mix.
there are dozens, hundreds of demos now that are testament to this approach: https://docs.pmnd.rs/react-three-fiber/getting-started/examp... this is slowly becoming the norm of how you write a 3d app or game.
Having a new set of "primitives" that map to three.js objects and being able to render them in a React application makes so many things easier. It's also just way less code to write compared to standard three.js.
RE: animation performance, I haven't had any issues with it. I presume either they're doing a bunch of optimizations, or the concerns are greatly exaggerated. You can check out an app I built using it if you want some proof: https://beatmapper.app/
R3F gets you up to speed really quick and helps to easily onboard a larger engineering team and stay productive
At some point your scenes will become complex enough that you will want to start using instanced meshes or just move all critical things into shaders all together…and you totally can do that.
In our case r3f made these performance optimization even easier because it’s so modular
The solution it uses for performance is... punting your calculations to the next frame if you didn't make it this frame. They call this "the scheduler". Turns out this makes no sense in any serious context if you want your 3D frame to be coherent.
I'm sure this is helpful for some people, but I can't rely on it when making serious applications. There's lots of things you can punt to the next frame, but ideally that should be decided per system, and not a global framework.
Keep in mind that rendering here is still happening every frame, so the only thing that's happening is 2,000 transform updates for cubes. Inexplicably, without the scheduler that punts updates to the next frame, it takes 700ms to do this [1]. For 2,000 matrix muls. That's 3ms per cube. What on earth is this doing?
[0] https://twitter.com/0xca0a/status/1199997552466288641 [1] https://twitter.com/0xca0a/status/1199997561358213120
If you want to go fast in this space then you need to care about data layout and how the system is structured end-to-end. Calling a function per object is going to hit a wall regardless of how you schedule.
Hundreds/Thousands of updates is not small but it's also not massively impressive either. I've done ~2,800 node scene graphs on underpowered ARM chips back in '09 at 60FPS including rendering. You have to use NEON, and be aware of your caches. No scheduling magic is going to change that unless you're just deferring work which sounds like what may be happening there.
FWIW I've also done this in Java via FlatBuffers(which uses ByteBuffer internally) to keep data coherency when driving animations frames so it doesn't require dropping down to C/C++/Rust(although C#'s value types do make it easier).
But in Three.JS the actual updates to the tree should be cheap, right? There's no reflow, you're just setting values in memory to be used by the next render frame. If so, that changes the calculus.
There's also the fact that in an app, it's rare for actual state updates (and therefore React renders) to happen on every frame; usually it's only on interactions. Maybe the occasional animation (if it can't be handled by native CSS animations). Whereas in graphical contexts like this, it's much more likely you'll have lots of objects in continuous motion (and therefore continuous re-renders).
I can see the productivity gains being worth it for a lot of simpler use-cases, but I'm skeptical about the performance claims when you start to get into complex scenes with lots of entities.
I'm not sure that's a fair explanation for why. It's totally possible to come up with new paradigms that are useful even though nobody's thought of them before.
I would think the main issue will be around JavaScript's tendency (cultural, syntactic, etc) to casually create and release objects all over the place, constantly. There's nothing intrinsically wrong with this, but it seems problematic for this use-case.
Example: JavaScript doesn't have named function parameters, because instead you just create and destructure an object:
function foo({ param1, param2, param3 }) {
}
foo({ param1: 'a', param2: 'b', param3: 'c' })
The syntax encourages this, the React docs encourage this. JSX itself does this for every element you render. And for normal JavaScript usecases it works just fine. But when you're running this logic every frame, I would guess it will limit you at a certain point.Despite that, I think people are onto something with the broader idea of coding a 3D scene declaratively. I'm just skeptical that React or its norms are the right path to doing it at scale.
I agree on the performance aspect, any inner-loop stuff always was down in a native language or heavily JIT'd path, but even then data layout drove it even more which usually required structuring the upstream systems ahead of the core logic. It's the reason why there's no "one-size fits all" game engine. They all make very discrete trade-offs in terms of entity counts, open world vs constrained layout and the like.
What on earth is all that time spent on? Doing ~2000 3x3 matrix ops should take a modern processor a few hundred usec surely?
To put the silliness of the 2000 number in context, look here at a showcase of the Unity ECS system from years (!) ago: https://software.intel.com/content/www/us/en/develop/article...
Their starting setup achieves 16000 textured and complex (relatively) models @ 30fps. Which is already much more than the "optimized" thing is achieving here. And it doesn't "cheat" by pretending to be fast via simply not doing to updates that are expected. And once they apply the various optimizations with memory layout etc... they get to 150000 (!) textured models moving about on screen @ 30 fps. So let's say 75000 @ 60fps, which is more than 35x as many objects, and the objects are much more complex.
Am I missing something? Why is "2000 cubes @ 60fps" extraordinary?
[0] https://github.com/pmndrs/react-three-fiber/blob/e3a71baad42...
async function test() {
const chars = `!"§$%&/()=?*#<>-_.:,;+0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`
const font = await new Promise((res) => new THREE.FontLoader().load("https://raw.githubusercontent.com/drcmda/scheduler-test/master/public/Inter%20UI_Bold.json", res))
console.time("test")
for (let i = 0; i < 510; i++) {
new THREE.TextGeometry(chars[Math.floor(Math.random() * chars.length)], {
font,
size: 1,
height: 0.5,
curveSegments: 80,
bevelEnabled: false,
})
}
console.timeEnd("test")
}
test()
// To really drive it home you'd have to repeat it every two seconds ...
// setInterval(test, 2000)
how react 18 concurrency works exactly, i think that's not the right place to churn through it. the react team has published tons of reading material as well as public talks.this is the test you are referring to: https://docs.pmnd.rs/react-three-fiber/advanced/scaling-perf...
the github repo now contains a vanilla test that you can run
It can "effortlessly outperform" only if we're talking about throughput, not latency here -- the scheduler ensures that less is done each frame so we can meet 60fps each frame, at the expense of having things done frames later than when they probably should have been.
I'm aware this is all a React feature. I disagree with the React team that "concurrency" is a usable solution to performance in all cases. But I can respectfully disagree with them about that. I can understand why a scheduler helps improve user-perceived performance. I'm happy to talk about what I believe are the tradeoffs.
Regardless of all of that, updating 2,000 cubes should never cause 700ms of load to begin with. The test you linked me to is not the same test. The test in the tweet is seen here [0], and has no artificial runtime delay as far as I can tell. For extra irony, note that they already have to bypass React (which is described as ItemSlow), in favor of the "Zustand approach", aka modifying things imperatively.
Remember, Three.JS is already running every frame, and rendering every frame, with or without a scheduler. That means that the 700ms overhead has to be coming from the React / R3F part of the demo.
[0] https://github.com/pmndrs/react-three-fiber/blob/e3a71baad42...
if it interests you, read up on react 18 concurrency, this is the bit you are missing in this discussion.
I'm very familiar with React 18 concurrency, and gave my detailed analysis of it. The documentation you linked even confirms my analysis of it deferring work across frames:
> it can potentially defer load and heavy tasks
I've already given my feedback about that approach. I heavily suspect the overhead here is all React's reconciler / differ, as Svelte, which has no scheduler, performs similarly to the concurrent React mode[2].
[0] https://twitter.com/0xca0a/status/1199997552466288641 [1] See the description in the panel here. It's talking about React 18 concurrency. https://github.com/pmndrs/react-three-fiber/blob/e3a71baad42... [2] https://twitter.com/Rich_Harris/status/1200805237948325888
some got it in the wrong throat, so i changed the test to actually pit it against a vanilla counterpart, and they were silent. the real test, contest that please, let the zustand thing go.
That said, I don't know why you entered into the conversation by asserting properties about a different test than the one that started the conversation. I recognize that TextGeometry is slow and CPU-heavy, and that the deferred work approach has some value in helping to manage that, but the cube test we started the discussion with had no artificial delay as far as I can tell, nor do I see it really doing any CPU-heavy work. For cases without any obvious CPU-heavy work, where does the 700ms overhead come from?
> and it stupidly and naively lets react churn through the whole graph 60fps, something you would under no circumstance do
Iterating over 2,000 objects is something we do all the time in game engines (where I'm from and where I work). I've written particle systems that handle far more than that; I just checked the particle system for a game I'm working on, and the simulation time maxes out at <1ms, and I haven't even SIMD'd it, though it is somewhat SoA'd. React's inability to handle a low workload like 2,000 items is why I believe React is a poor fit for serious 3D applications.
And yes, I would argue against React 18 Concurrency's approach as a general design. Deferring work between frames is an incredibly valuable tool, but I don't believe it's something that validly can be done globally, or that it's a solid basis for a 3D framework. It trades low latency for high throughput, and I believe that's a tradeoff that should be made by the application author.
Multiplayer games and VR often require very careful controlled latency, and having unpredictable latency can make your game unplayable, or make someone incredibly motion sick.
We're clearly going in circles on this point; I'll shut up at this point because clearly we're at an impasse, and you're (completely validly) unwilling to discuss the cubes example that started things, which I would prefer to cross-examine in more detail. My approach to performance analysis is to profile things, understand bottlenecks, and come up with targeted fixes before going with more global approaches with large tradeoffs, so I'd be personally be more interested in knowing where the time is spent.
Finally, and this is my experience speaking as a game engine engineer, I think you should think more about how much work you expect to be able to do in one frame, and set your sights there. You can easily update 2,000 objects with minimal overhead.
try racing game for instance: https://twitter.com/0xca0a/status/1400164834243719173
or space game: https://twitter.com/0xca0a/status/1184586883520761856
you won't find react in the browsers perf readout except for short blips when the tree structure is changed. you do not update fast things with setState. since games are render-loop driven, you mutate, and that is also how r3f works.
as for react 18, yes, it works global. the entire component tree is virtual and can be prioritized. you could say, this thing back there is less important than physics driving my rocket, defer please. this will be an incredible tool for games going forward.
Have we gotten so bloated with framework on top of framework that even this is deemed an impossible load?
If you write straight-up WebGL code 2000 cubes at 60fps should be a walk in the park for any modern PC.
But if you want to drive a canvas based render context. You're going to want to control the render loop for your own application.
Performance there is domain specific.
<View3D>
<Box position={[1, 0, 0]} color="green" />
<Box position={[-1, 0, 0]} color="red" />
</View3D>
[1] https://www.npmjs.com/package/@standard/viewIts an online IDE for a number of CodeCAD packages to help lower the barrier to this paradigm.[2]
Going from knowing nothing about 3d, just hacking up example code it's been easy to put something respectable together without much dedicated learning. Im super grateful to the pmndrs team
[1] https://cadhub.xyz/dev-ide/cadquery [2] https://news.ycombinator.com/item?id=27649270
but they also allow you to make your own renderer (https://github.com/facebook/react/tree/main/packages/react-r...) which then defines its own elements. you can try a mini threejs renderer here: https://codesandbox.io/s/reurope-reconciler-hd16y
What?
<cube id="myCube" x="0" y="0" z="0" width="10px" height="10px" length="10px" onClick="someFoo()" onMouseOver="someOtherFoo()" onTouchStart="someBar()">
<video src="blah.mp4" rotateX="45deg" rotateY="30deg" autoplay="true" loop="true" onClick="document.querySelector('#myCube').rotateX(45);">
...
No reason the above can't be done. But many people will come up with lame excuses about why we shouldn't have nice things.
as for react, it merely expresses threejs, and adds something which three doesn't have: self contained components that are now sharable. something like this: https://twitter.com/0xca0a/status/1394697847556149250 just didn't exist in the web previously.
https://github.com/create3000/x_ite/wiki/Sensing-viewer-acti...
We have been investing in building ourselves a asset pipeline backend and it’s been a dramatic improvement.
Simply scripting Blender and other tools on a EC2 instance to optimize assets and then deliver them via cloudfront. Works really well
The thing I’ve been trying say all along is, I want applications using the same renderer at a primitive level.