The more surprising/interesting thing to me is that it uses React. I'd be curious to see a performance breakdown (how much headroom is left for a more complex game?)
I am also curious how Clojure(Script)'s persistent data structures work out for data structures that update 30 or 60 times per second. That's a lot of allocation and deallocation
You could argue that Clojurescript early adoption of React was one of the reasons for it's rise. The early work of David Nolan (Om) and Dan Holmsand (Cloact->Reagent) were, at least in my opinion, pretty influential. Clojure's immutable data structures were (are) a perfect fit. iirc, the fact that "shouldComponentUpdate" could be performant with equality was a huge, easy performance/simplicity win. I may be way off about that, if so, I apologize.
Om was late, not early, around mid 2015, turned out to be experiment and eventual abandonware. There were much earlier react wrappers, and frameworks like reagent that remain popular today. Dave was influencial in cljs but don't think he ever got a full spa framework off the ground, unless it happened in last few years
You are right. Equality checks for any complex data-structure in JS (and TypeScript) are cumbersome as hell, yet for a React architecture they are crucial for performance.
This example has less than 20 components in total and the max depth is 3. (The whole arena is a single object). And it's still using 10% of cpu. Production games have a lot more components in comparison:
The baseline performance for any sort of react-based web app is going to be pretty bad if you're comparing it to a state-of-the-art game engine. The build status page for the CI/CD pipeline we use at my work has around 2x the CPU usage as this demo, for instance. It would be surprising if cljs's persistent data structures are incurring any real user-perceivable cost over JS arrays and maps, given how small this project is.
That being said, it would be interesting to know how much of a penalty you pay as N gets big using a deeply nested persistent record vs a flatter component system with immutable persistent structures vs a pile of mutable structures.
React-three-fiber is a renderer for Threejs but does not introduce overhead. Games and webgl is loop driven, so React solves that with a hook, useFrame, which binds components to the render-loop in a managed way. It could in theory outperform Threejs because it can schedule: https://twitter.com/0xca0a/status/1383165072554532865 or scale quality: https://twitter.com/0xca0a/status/1407371461447368705 These things would require a framework around Threejs.
Re React, it just uses the same interface: in this case performance is basically just what threejs' performance is (there's naturally a very slight overhead, but what you're looking at is a very thin wrapper over three)
Edit: a sibling mentioned the React ART library and Ink, which are other good examples of the same thing. You can also see same principle used for many of the React animation libraries -- they use the same semantics, so they interop with "normal" React code just fine, but in actuality they're using the underlying animation APIs directly, bypassing the repatively expensive reconciliation process.
There's a lot you can do with a custom reconciler. I didn't look to see if that's what's going on, but it's the foundation for many React adaptations to unlikely interfaces, such as Ink and some of Netflix's smart tv UIs.
It is a using custom renderer indeed: https://github.com/pmndrs/react-three-fiber it doesn't wrap Threejs, just expresses it via JSX similar to how react-dom expresses the dom.
Is this doing any dom stuff in gameplay after React optimizes away unchanged elements? Looks like just a WebGL canvas. I'd guess the React/dom time ends up near invisible in a profile.
It looks really cool (I love the flat poly aesthetic), however some hopefully helpful feedback:
- Framerate isn't wonderful (20 - 30 fps on my laptop, which will happily run graphically more intensive JS demos at 60fps usually), and I see you're using React: is using a relatively heavy framework the best way to go here? Possibly this is fine and the optimisation is required in other areas instead (e.g., are you creating loads of garbage?),
- Car physics and handling is way off: clearly for this game realistic handling probably isn't the goal, but it's bad by the standards of more recent arcade racers (Burnout et al, Cel Damage for something that has a slightly similar aesthetic), or 1980s style 2D racers like OutRun (or more recently 80s/early 90s-esque racing games).
It's certainly an interesting demo - and, as I say, I love the way it looks - but in terms of demonstrating ClojureScript as a viable platform for game development, definitely needs more work. And in terms of this being a game, it's a long way from that: no objectives, no other drivers (depending on the objectives, may or may not be required), no hazards, pickups, etc., no sound, and so on.
Thank you for the great feedback! The goal was just to show the ClojureScript version of the original demo (the first version of it). So there is no collision detection, sound, etc. I think ClojureScript has too many things to provide in this field.
It's definitely an interesting demo and certainly not the first time a less obvious (i.e., imperative) language has been used in game dev: just today on a separate discussion people were talking about use of GOAL (a compiled dialect of LISP) in PS1 game development. Pretty cool stuff.
> Framerate isn't wonderful (20 - 30 fps on my laptop, which will happily run graphically more intensive JS demos at 60fps usually)
Something I'm curious about is whether the frames are dominated by game logic (ClojureScript/React) or by graphics. If your laptop doesn't have a discrete card, and the author hasn't taken steps to optimize the graphical side via culling, etc, then your fps may not be representative of ClojureScript/React-based games in general
Dell XPS with both onboard and discrete graphics. Funnily enough I just tried it on my 2015 MBP, which likewise has two GPUs, and - ridiculously - it runs much more smoothly.
It looks quite familiar, it generates a plain data structure and reacts on a set of user inputs. I‘d have to look up how this communicates with threejs (which is done via a wrapper library) and what the semantics of that is, but otherwise the code looks clean and simple to me.
It doesn't appear to have any collision detection at all. You can drive through walls, over water, through barriers.
The world state seems to be limited to the 2D velocity and 2D position of the vehicle. There's no instability in the vehicle, no loss of control, no loss of traction, spins, brakes locking up.
I guess my point is there's nothing going on under the hood. This could be done in any language that's got an OpenGL API. (or D3D, GLES, Vulkan...) I'm not sure what the takeaway is.
It's just a tech demo I guess. Should be simple to get car physics working, but getting full collision detection working would be another matter entirely.
Serious question: how long have you had the machine? If it's more than a year or two you might want to consider opening it up and blowing out all the dust and fluff. I have a 2015 model that runs it just fine, but would really have struggled two weeks ago before I gave it a clean out. Feels like I just upgraded the thing.
I generally do this every year or two but recently I've been doing a lot of work on the house so it's been particularly dusty with debris from plasterboard, cutting timber, sanding, etc.
This site should be called Hipster News. I feel like the more obscure a project is, the higher the chance you'll see it on HN. Meanwhile, the bread and butter of regular programmers (c#/php/java) gets barely any mention here (and when it does, it's for major lang releases and it's typically poopooed hard) and you basically see ZERO threads about the news from within these huge ecosystems.
Clojure is hardly what I’d call an “obscure” language. I’ll never understand that insane amount of offense people take from others sharing their personal work built with tools they enjoy/ see fit.
> gets barely any mention here (and when it does, it's for major lang releases and it's typically poopooed hard) and you basically see ZERO threads about the news from within these huge ecosystems.
Sounds like you’re projecting or something. C# tends to get a lot of love and while you’ll probably still find some negative comments about PHP or Java here, there’s always enough people praising them for what they’ve provided.
Don’t you see value in looking at projects in the cutting edge? Ideas from Clojure already appear in more mainstream languages. This is your chance to be ahead of the curve and maybe even learn techniques you can apply today.
I am also curious how Clojure(Script)'s persistent data structures work out for data structures that update 30 or 60 times per second. That's a lot of allocation and deallocation