Sky Roller gameplay

Dev Log — #002 Sky Roller

7-player ball race on a sky track. Dodge crates, collect buffs, ragdoll physics. Play instantly in your browser.

Sky Roller gameplay
▶ PLAY

Design Notes

Prototype #002 — a 7-player ball race. You against 6 AI on a curved sky track. Drag to steer, dodge crates, grab buffs. Wanted to see if this many 3D characters with skeletal animation and physics could run at 60fps on a phone. It can, barely.

Ball size is the core trade-off and it changes every race. Small balls are fast, but one crate sends you flying off the track. Iron balls are invincible but crawl at half speed — max 1/3 of racers can be iron in any round. The AI gets randomized balls each time, so sometimes you're weaving through a field of small balls while one iron just tanks through everything.

Three buff types: Launch pads shoot you 50 units into the air (stomach-drop feeling), Dash lets you smash through obstacles temporarily, Iron makes you invincible but slow. The launch pads ended up being my favorite — that bounce-twice-before-landing feeling is the closest thing to a rollercoaster in a browser game.

If I made a full version, I'd lean hard into verticality — ramps, half-pipes, maybe sections where the track goes upside down. The current track is mostly flat with curves, and the launch pads already proved that vertical movement is way more exciting than horizontal dodging.


Dev Log

The SkinnedMesh clone disaster

Needed 7 copies of the same 3D character. Used Three.js Object3D.clone(). Models appeared, no errors, looked fine — except every character was frozen in T-pose. No animation at all. Turns out clone() doesn't copy bone bindings for SkinnedMesh. There's zero indication anything is wrong. Looked it up and apparently it's a known Three.js behavior — SkeletonUtils.clone handles bones properly. Switched to that and it worked immediately.

AnimationClip sharing breaks things

After fixing clones, animations played on some characters but others randomly froze mid-run. The issue: sharing the same AnimationClips across 7 AnimationMixers causes bind conflicts. Each character needs its own cloned copy of every animation. Wasteful on memory? Technically yes, but 7 characters x 2 clips is nothing. Looked at how other Three.js projects handle this — same solution everywhere.

Ragdoll force clamping

First ragdoll attempt: characters just crumple on the spot. Added velocity-based launch force — then they flew to space. Ended up clamping the force and adding drag so the arc looks dramatic but stays in frame. There's a 3-second cooldown before restart too, which forces you to watch your own crash. Felt a little mean but it makes each wipeout actually register instead of just being a blip.


Credits

3D models by @quaternius

▶ Play Sky Roller


Built by Ariescar

Indie game developer exploring AI-assisted game production. Building 3D browser games with Three.js and Vibe Coding workflows.

X / Twitter · All Links · More Games