Flappy Animal 🐦
A flap-and-dodge platformer where your tap-rate evolves your animal through ten tiers
Flappy Animal is a single HTML file that takes the classic flap-and-dodge formula and adds a twist: your animal evolves as you play. You start as a snail and progress through ten tiers up to a phoenix, with each evolution triggered every 10 pipes passed. Higher tiers come with new colors, new "shot" emojis on tap, and a faster, more responsive feel.
The game uses a single tap input — tap to flap and rise, gravity pulls you down. Pipes scroll from the right; threading the gap between them earns one point. Hitting a pipe or the ground ends the round.
Delivery
1 HTML file
Dependencies
0 installed
Levels
10 tiers
Evolve every
10 pipes
Control
1 tap
Storage
localStorage
Every 10 pipes passed, your animal evolves to the next tier. Each evolution comes with a new color theme, a new "shot" emoji visualization on tap, and a brief flash effect. The progression is one-way — you don't drop tiers, you only climb.
The physics model is the classic flap-and-dodge formula: gravity continuously pulls the bird down, and each tap snaps the velocity to a fixed upward value. There's no acceleration on tap — the velocity is set, not added — which gives the predictable, controllable feel the genre needs.
Gravity
0.42 px/frame²
Flap velocity
−7.2 px/frame
Pipe width
74 px
Hitbox ratio
0.18
Base pipe spacing
360 px
Min pipe spacing
300 px
The hitbox ratio of 0.18 means the actual collision box is much smaller than the visible emoji — this is intentional. Big, friendly emojis are easier to see and root for, but a generous hitbox would make the game too forgiving. Shrinking the collision area lets the visual character stay readable while keeping difficulty honest.
The game scales difficulty subtly as score climbs. Pipe spacing tightens from the base value down toward the minimum as score increases, in measured steps tracked by diffStep. Pipe gap heights and patterns vary so memorizing isn't an option. The effect: early pipes feel easy, mid-game requires real timing, and the highest tiers demand near-perfect rhythm.
The game tracks taps-per-second in a rolling window (tapsInWindow array). This is used for visual feedback — fast-tapping bursts trigger more dramatic shot effects and a rainbow trail effect — without directly affecting physics. The character emoji's drop-shadow glow is also influenced by tap intensity.
HTML + CSS + Vanilla JS
Entire game, single file
No framework
HTML5 Canvas 2D
All game rendering — bird, pipes, shots, background
Native browser
requestAnimationFrame
60fps game loop, DPR-aware
Native browser
Web Audio API
Synthesized flap and level-up tones
Native browser
localStorage
Best score, scoreboard, name persistence
Native browser
Sounds are synthesized on the fly using oscillators, not loaded as audio files. The flap sound is a quick 260Hz square wave that pitches up at higher levels — a small tone(freq, dur, type, gain) helper handles creation. This keeps the file size tiny and means no asset preloading delay.
Cheers play at random intervals when the player is doing well; the next cheer time is scheduled relative to score milestones so they feel deserved, not random.
The canvas is sized at innerWidth × devicePixelRatio and scaled back down via ctx.setTransform. Retina displays get crisp pixel-perfect rendering without any per-frame cost. Resize listener re-sizes on rotation and window resize.
Pipes are drawn as rectangles with a slight inset on edges, colored per current level. Each pipe pair carries a precomputed gap-center and gap-height. As pipes scroll left, their x position decreases; when fully off-screen, they're removed from the pipes array. New pipes spawn from the right at the current spacing distance.
Each tap spawns a "shot" particle — the level's emoji — that travels outward from the bird with random angle and lifetime. Particles update positions and opacity per frame and are removed when fully transparent. The pool isn't object-pooled; objects are created and garbage-collected per shot, which is fine for the small particle counts involved.
One CFG-style constants block holds every tunable parameter. A LEVELS array holds the 10 tier definitions. The gs game state object holds runtime values: bird position, velocity, pipes array, current score, current level, frame counter, etc.
The main loop is a single requestAnimationFrame tick: apply gravity, advance pipes, detect collisions, redraw. Game states (start screen, playing, scoring, scoreboard) are handled by switching on gs.state; the same loop reads the state and decides what to render and update.
Persistence: best score, top scoreboard entries, and the player's name are saved as JSON in localStorage. The scoreboard caps at a fixed number of entries; new high scores prompt for a name on submit.