The full, copy-pasteable prompt I used to build a 3D Flappy Bird-style plane game with Three.js and Vite — physics-driven pitch, glTF propeller animation, AABB collision, and clean game states.
Overview
This is a build prompt for a 3D Flappy Bird-style game — a low-poly
voxel plane that flaps through pairs of obstacle walls — written as a
single-page web app with
Three.js and Vite. The
whole point of the prompt is one detail: making the flight
feel real. Instead of snapping the plane's rotation on
keypress, the pitch is driven by vertical velocity and smoothly damped
toward a target angle every frame, so the nose eases up after a flap and
tips forward as it falls.
What it produces: a side-scrolling 3D scene, a glTF
plane with a continuously spinning propeller (baked animation clip),
gravity + flap-impulse physics, velocity-driven pitch with damping,
recycled obstacle pipes with AABB collision, scoring with a best-score
tracker, and start / playing / game-over states — all frame-rate
independent via requestAnimationFrame and delta time.
The prompt
Copy this into any AI app-builder (Replit). It assumes you've uploaded a
rigged glTF plane model with a baked
"Armature|prop spin" animation clip.
Build a 3D Flappy Bird-style game as a single-page web app using
Three.js (import via CDN or npm), running in a Node/static environment
with Vite. ASSETS: I've uploaded a glTF model (scene.gltf + scene.bin +
textures folder) of a low-poly voxel plane. It's rigged with a skeleton
and already has a baked animation clip named "Armature|prop spin" that
spins the propeller bone. Load the model with GLTFLoader, add it to the
scene, get its AnimationMixer, find the clip by that name, play it in a
loop (THREE.LoopRepeat), and update the mixer every frame with the clock
delta — the propeller should be visibly spinning at all times,
independent of game state. CAMERA & SCENE: Side-scrolling view
(camera fixed, looking at the plane from the side, slightly above), like
classic Flappy Bird but in 3D. Simple sky-colored background, maybe a
subtle scrolling ground/horizon for depth cues. Plane stays at a fixed X
position; the world scrolls toward the camera. PHYSICS (the part I care
about most — make it feel real, not arcade-y): - Constant downward
gravity acceleration on the plane's vertical velocity. - Pressing
spacebar (or click/tap) applies an upward impulse to velocity (like a
flap/thrust). - The plane's pitch should be driven by vertical velocity,
NOT by whether the key is held: map velocity to a target pitch angle
(falling fast = nose tilts down/forward, strong upward velocity right
after a flap = nose tilts up/backward), then smoothly interpolate
(lerp/damping, not snapping) the model's current rotation toward that
target every frame so it eases in and out. Clamp the tilt to a
reasonable max angle (±25-35°) so it doesn't flip. - Keep horizontal
position fixed; only Y (height) and pitch rotation change. PIPES /
OBSTACLES: Instead of pipe sprites, use pairs of rectangular meshes
(THREE.BoxGeometry, solid material) — one from a gap going down, one
from the same gap going up — spawned at fixed horizontal spacing
off-screen right. Randomize gap position (optionally slightly randomize
gap size within a min/max). Move all active pairs toward the plane at a
constant speed each frame (same as the ground scroll), recycle/despawn
pairs once they pass behind the camera, and spawn new ones to keep a
steady stream. Use simple AABB (bounding box) collision between the
plane's box and each wall box — on collision, trigger game over. SCORING
& STATES: +1 score each time the plane passes a pair (compare plane
X or scroll distance, not on collision). Track and display best score.
Include start screen, playing state, and game-over screen with restart
(space or click). Show current score during play. POLISH (nice to have):
subtle camera shake or screen flash on collision, a particle or
scale-pulse effect on the plane when scoring, controls limited to
spacebar/click so it works on mobile via tap. Structure the code cleanly
(separate modules for scene setup, physics, pipes, and game state), and
make sure the render loop uses requestAnimationFrame with delta time so
speed is frame-rate independent.
Why the physics prompt is written this way
Most Flappy Bird clones rotate the sprite based on whether the button is
pressed. That reads as rigid and mechanical. The trick here is
decoupling rotation from input entirely:
-
Velocity is the single source of truth. Gravity pulls
velocity down every frame; a flap adds an upward impulse. Both height
and pitch are derived from that one number.
-
Pitch is a target, not a state. Map current vertical
velocity to a target angle, then damp toward it (
current += (target - current) * k). The nose lifts and settles on its own — no snapping.
-
Everything is delta-timed. Multiplying movement and
damping by the frame delta keeps the feel identical at 60fps and
144fps.
Notes on the glTF propeller
The propeller spin is deliberately independent of game state. It's a
baked clip ("Armature|prop spin") played on loop through an
AnimationMixer that ticks every frame with the clock delta
— so the prop keeps turning on the start screen, mid-flight, and on game
over. If your model's forward axis differs, the pitch axis in the
physics step (X vs. Z rotation) is the one line you'll adjust.