Hi everyone ![]()
I’ve been building La Brute Legacy, a turn-based browser fighting game - a modern remake of the classic French game La Brute / MyBrute (Motion-Twin, 2008), which ran on Flash and shut down when Flash died. The whole thing is rendered with Three.js.
Combat is fully automatic and deterministic (seeded RNG), so every fight can be replayed turn-for-turn from stored data. Characters, weapons and hit reactions are voxel models animated in real time.
A few Three.js implementation details I’m happy with:
- Single
<Canvas>for the entire app. Instead of spinning up a WebGL context per component, the whole site runs one full-viewport canvas and uses drei’s<View>portals tied to each component’s DOM bounds. The brute preview, the combat scene, weapon and potion viewers are all separate<View>s on the same context. frameloop="demand"- the GPU only renders on actual state changes, which keeps it cheap enough to run even while ad/idle content sits on the page.- GLTF caching + shared draco/meshopt setup so switching between dozens of weapon models doesn’t re-fetch or re-decode.
- Built on react-three-fiber + drei, with GSAP driving the combat tweens and camera moves.
Stack: Three.js / R3F / drei, Next.js App Router, React 19, PostgreSQL.
It’s a non-commercial fan project. Happy to answer anything about the single-canvas / multi-<View> architecture, it was the trickiest part to get right and I’d love feedback from people who’ve pushed that pattern further.
Thanks for taking a look! ![]()


