Speedy Bird

Flappy Bird where every pipe you clear makes the game 1% faster.

Loading main.web.bundle…

Press Space or Enter while the game has focus, or click or tap it, to flap. Fly through the gaps. Each pipe scores a point and makes the game 1% faster.

Tap or click the game, or press Space while it has focus.

No runs yetLoading

Pipes cleared
0
Speed
1.00×
Scroll
2.70px/step
Next pipe every
77steps
Next medal
Bronze in 10
Best
0

The game is the ReactLynx app itself, main.web.bundle in a <lynx-view>. It reports these values through SpeedyBirdModule.

Sheet 1 · Speed by score

The speed curve

Speed is 1 + score ÷ 100: each point adds 1% to how fast the pipes and ground scroll. Pipes also spawn closer together until score 276, where the gap between them stops shrinking at 20 steps.

Speed, scroll distance, and pipe interval by score
ScoreSpeedScrollPipe everyMedal
01.00×2.70px77 steps · 1.28 sStart
101.10×2.97px70 steps · 1.17 sBronze
251.25×3.38px62 steps · 1.03 sSilver
501.50×4.05px51 steps · 0.85 sGold
1002.00×5.40px39 steps · 0.65 sPlatinum
2003.00×8.10px26 steps · 0.43 s
2763.76×10.15px20 steps · 0.33 sPipes stop getting closer
Speed rises in a straight line from 1× at score 0 to 3.76× at score 276.1×2×3×4×050100150200250276scorespeed
Dots mark the medal scores. Computed from engine.ts when this page was built.

Sheet 2 · One bundle, three hosts

The same game on Android, iOS, and the Web

bun run build produces one Lynx bundle. Each host is a thin native shell that loads it and answers the same five calls through a native module named SpeedyBirdModule: sound, the saved best score, and screen-reader announcements.

  1. main.lynx.bundleReactLynx · one build
  2. AndroidKotlin · LynxView
  3. iOSSwift · LynxView
  4. Web<lynx-view>
How each host implements SpeedyBirdModule
CallAndroidiOSWeb
play(sound)SoundPoolAVAudioPlayerWeb Audio
stopAudio()SoundPool.autoPauseAVAudioPlayer.stopstop every source
loadPreferences(callback)SharedPreferencesUserDefaultslocalStorage
savePreferences(json)SharedPreferencesUserDefaultslocalStorage
announce(message)Live regionVoiceOver announcementaria-live region

The build checks each host's source for these methods, so this table fails the build if it goes out of date.

Sheet 3 · What runs where

The frame loop runs on Lynx's main thread

Lynx has two threads: a main thread that owns the screen and a background thread for app logic. Taps, the simulation, and every per-frame style change stay on the main thread, so a flap shows up in the next frame. React on the background thread only redraws the score and overlays when they change.

  1. Steps. Elapsed time becomes fixed 1/60 s steps, so speed never depends on the display's refresh rate.
  2. Render. render() writes transforms with setStyleProperties; React is not involved.
  3. Publish. publish() crosses to the background thread only when the score, state, or sounds change.
src/hooks/useGame.ts, line 189
const frame = () => {
  handle = 0;
  if (paused) return;
  const now = Date.now();
  const elapsed = now - lastTime;
  lastTime = now;
  if (game.gameState === STATE_PLAY && elapsed >= STALL_PAUSE_MS) {
    paused = true;
    publish([]);
    return;
  }
  const steps = consumeElapsed(clock, elapsed);
  const sounds: SoundName[] = [];
  for (let index = 0; index < steps; index++) {
    const transition = step(game);
    game = transition.state;
    sounds.push(...transition.sounds);
  }
  render();
  publish(sounds);
  // Stop the loop once nothing can change until the next tap.
  if (!isIdle(game)) handle = requestFrame(frame);
};

Manual

Read how it is built

  1. 1 Overview

    1. 1.1 About Lynx

      ReactLynx concepts used by Speedy Bird: native rendering, built-in elements, CSS, threads, and native modules.

    2. 1.2 Architecture

      Project layout, component tree, what runs on each Lynx thread, the test suite, and the web surfaces.

  2. 2 Engine

    1. 2.1 Game engine

      The pure rules engine, main-thread frame loop, physics, collisions, scoring, restart lock, and host bridge.

    2. 2.2 Assets and sprites

      Sprites embedded in the bundle, tile-based pipes, the sound files, keeping the website copies in sync, and credits.

  3. 3 Deploy

    1. 3.1 Getting started

      Install dependencies and run the ReactLynx app, web hosts, documentation site, and native hosts.

    2. 3.2 Native host apps

      Build and test the Kotlin Android and Swift iOS hosts: native bridge, lifecycle, UI tests, and signing.

    3. 3.3 CI/CD pipeline

      Build checks, iOS UI tests, Android build releases, unsigned iOS archives, and immutable versioned releases.

  4. 4 Maintenance

    1. 4.1 Dependencies and upgrades

      Verified dependency versions, native toolchain requirements, compatibility holds, and the upgrade verification process.

Open the manual