This is a recap of my experimental project Quatrefoil. I want to share ideas in trying to make myself a virtual DOM based framework for Three.js . It’s not really a framework people may use. But I think the informations I got is useful if we want to explore 3D apps in the future.

A bit History

Almost a year ago, I built 2 libraries based on ClojureScript. The 2 years before that I spent quite a lot time writing an app in React, which made me believe I should pick ClojureScript as my primary language.

Respo: virtual DOM based MVC library like React

Quamolit: Respo rendered to Canvas with animations

Since Canvas APIs is slow comparing to WebGL APIs, I though about using Three.js as a backend and made a little experiment. I didn’t finish the demo called Quatrefoil. Recently I did some refactoring work on Respo and though maybe I can finish Quatrefoil now.

Features to offer

When I look at the Three.js examples, they like Web development in the old days. I guess really world apps would have more mature components in architecture. Maybe we can also try React-like solution for WebGL.

I know someone tried WebGL in React, I just don’t know the details. Anyway when I’m talking about that, I’m talking about these features:

Declarative virtual DOM writing

State management like React

Animation state defined in a Component

For declarative programming, you may already known. Virtual DOM is a great solution to decouple the business code and the renderer backend. It also make development easy by introducing hot code swapping. We all like that.

And for state management, as our apps grow, it’s always a piece we need. Nowadays people are familiar with the concepts of global store and component level states, as well as uni-directional data flow, which starts from the database and ends in screen pixels. There might be other ways, I just believe it’s the nearest one we can get.

For animations, it’s almost a state management problem. The main difference is the state changes of animations is triggered by time and user actions, unlike component state changes which is only triggered by use actions. I want the power of defining animations just like writing a component. So such feature is built inside Quatrefoil.

One more thing is persistent data structure, which is essential to uni-directional data flow and optimizations of component tree rendering. I’m not repeating the details here.

Animation State

In React, animation is mostly handled in CSS. Well, I believe that’s wrong, it’s not obeying MVC patterns, where’s the animation state stored? In React Native projects, I see animation states stored in component state. That might better. I think we can do more, because animation state is like a loop and can be triggered frequently by time. So I use another state called instants to store it.

As I explained in Respo, component states is in a tree rather than in each components. The benefit is we can reuse the shouldComponentUpdate solution here to reduce duplicated computations by comparing the reference of collections or values. Now for an app there are 3 global states: Store, States, Instants. They consist the ‘M’ in MVC.

However implementing Instants is very tricky since the animations may trigger itself of an another animation. I can’t describe it with only text. Luckily the underneath theory of animations is still state machine manipulated by time, so there must be a way out.

Problems

There are also other difficulties in making it really work, for example:

Geometry is hard to patch

No group-level opacity, scaling

Not pure enough

Performance

Object3D elements are not like DOM, they need to geometries, which is most easy to modify at runtime, at least not as easy as DOM APIs. I’m still need to learn Three.js to see if that works well.

And to build apps, CSS is still cool. I can mark a whole component with opacity 0.5 to create a fade-out. We need similar features in Three.js to make it easier.

Also in my codebase, there are drawbacks too. Virtual DOM based solution is relatively slow comes with its flexibilities. I don’t think this LUC optimization is enough. Also the side-effects inside rendering process makes me worried. There’s still a lot areas to explore.

Conclusion

I’m happy that my prototype is working. I made a playlist on Youtube to explain Quatrefoil. You may check it out: