Speedy Bird Manual

Builder's Manual · Night Arcade Cabinet

Game Engine

The technical docs now sit inside the same arcade world as the game: a service panel for the speed curve, ReactLynx architecture, sprite engine, native hosts, and release pipeline.

8Manual pages
+1%Speed / pipe
3Build targets

Game Engine

The game engine lives in src/hooks/useGameEngine.ts. It handles the game loop, physics, collision detection, scoring, and state transitions.

State Machine

The game has three states:

STATE_READY (0) ──tap──> STATE_PLAY (1) ──collision──> STATE_OVER (2)
      ^                                                      │
      └──────────────────────tap─────────────────────────────┘
StateBirdPipesInput
ReadyHovers at Y=280, wing animation (20-frame interval)None on screenTap starts game
PlayFalls with gravity, flaps on tap, fast animation (4-frame interval)Spawn, scroll left, score on passTap = flap
OverFalls to ground, no animationFrozenTap resets to Ready

Game Loop

The loop runs via setInterval(tick, 17) targeting ~60 FPS. Each tick:

  1. Update bird — apply gravity, update velocity, clamp position, compute rotation, advance animation frame
  2. Update pipes — spawn new pipes on interval, move all pipes left, despawn off-screen pipes (incrementing score), check collisions
  3. Update scenery — scroll background and ground at their respective speeds
  4. Push render state — call setRenderState() with the current snapshot for React to render

Physics

All values are in pixels per frame (at 60 FPS):

ParameterValueEffect
Gravity0.28 px/frame²Downward acceleration
Flap velocity-7.25 px/frameUpward impulse on tap
Pipe base speed2.7 px/frameHorizontal scroll speed
Speed scaling+1% per pipespeed = 2.7 * (1 + score * 0.01)
Background scroll0.2 px/frameSlower parallax layer
Ground scroll2.7 px/frameMatches pipe speed

Bird Rotation

Rotation is determined by vertical velocity:

VelocityRotationVisual
<= -7.25 (rising fast)-15 degNose up
Between -7.25 and -5.250 degLevel
>= -5.25 (falling)70 degNose dive

During nose dive, the animation frame is locked to frame 1 (wings level).

Bird Animation

The bird has a 4-frame cycle: bird-0, bird-1, bird-2, bird-1 (ping-pong).

  • Ready state: frame advances every 20 ticks (slow flutter)
  • Play state: frame advances every 4 ticks (fast flapping)
  • Over state: locked to frame 2 (wings up) with nose-dive rotation

Collision Detection

Collision uses AABB (Axis-Aligned Bounding Box) with a circular bird hitbox approximated as a square:

Bird bounding box:
  left:   BIRD_X - BIRD_RADIUS (80 - 12 = 68)
  right:  BIRD_X + BIRD_RADIUS (80 + 12 = 92)
  top:    birdY - BIRD_RADIUS
  bottom: birdY + BIRD_RADIUS

Per pipe pair, two checks:
  Top pipe:    x to x+55, y to y+300
  Bottom pipe: x to x+55, y+300+150 to y+600+150

Ground collision triggers when birdY + BIRD_H/2 >= CANVAS_HEIGHT - GROUND_H.

Pipe Spawning

  • Interval: every 77 frames (~1.3s), adjusted by speed: Math.max(20, Math.round(77 / speedMultiplier))
  • Y position: random between -200 and -80 (controls gap vertical placement)
  • Gap size: 150px fixed
  • Despawn: when pipe.x < -55 (fully off-screen left), score increments

Scoring and Medals

Score increments by 1 each time a pipe scrolls off-screen. Best score persists within the session.

ScoreMedal
10+Bronze
25+Silver
50+Gold
100+Platinum

Audio

Five sound effects, managed by src/audio/audio.ts:

EventSoundFile
Tap/flapWing flapsfx_wing.wav
Pipe passedScore pointsfx_point.wav
Pipe collisionHitsfx_hit.wav
Ground collisionFallsfx_die.wav
Reset gameSwooshsfx_swooshing.wav

On web, audio uses HTMLAudioElement. On native platforms, it falls back to a native module stub (AudioModule).