Skip to content

Releases: bitbybit-ar/bitbybit-run

v1.0.0 — BitByBit RUN

Choose a tag to compare

@analiaacostaok analiaacostaok released this 24 Jun 22:49

The first public release of BitByBit RUN — the full game, serverless
multiplayer, a global leaderboard, Nostr identity with Lightning zaps, and the
fake-ads scam museum. As an initial release, everything below is part of what
ships in 1.0.0.

Added

Gameplay

  • 2.5D runner race down a perspective athletics track, drawn entirely from
    shapes + emoji (no image assets) for a fast, lightweight load.
  • Energy / poison food loop: grab good food (⚡) to sprint, dodge junk (🍔)
    or fill the poison bar and get knocked back a chunk of track (bathroom break).
    Rocket boosters (🚀) give a timed speed burst.
  • Four animated characters (Sprinter, Barbie, T-Rex, Bitcoin), each on its
    own lane with a full run-cycle sprite.
  • Keyboard and touch controls — arrows/WASD on desktop, and on mobile an
    on-screen gamepad drawn in-canvas: ◀ ▶ lane buttons under the left thumb
    and a held ⚡ accelerate button under the right, so you can steer and
    accelerate at once
    (multitouch). The pad shows only on touch devices and in
    every mode (demo, practice, multiplayer); the canvas is tuned so taps never
    trigger page scroll or zoom.
  • Per-match seeded tracks: obstacle/food layout is derived from the match id,
    so every player in a race shares the exact same course.
  • Crowd signs: funny, localized slogans line the track like roadside
    billboards. The track is a fixed-width anchor and the side margins flex, so on
    wide screens the signs sit beside it; on narrow portrait phones (no
    roadside room) each sign instead hangs from an overhead gantry arch the
    runner drives under — one at a time, kept in a readable size band.
  • Free demo (no login) and a solo practice mode for warming up. The solo
    finish overlay restarts on a screen tap on touch devices ("tap to race
    again") and on the R key on desktop.
  • Lane-accurate food pickups: food resolves strictly against the runner's
    nearest lane, so sliding toward a booster never accidentally eats the junk in
    the lane you're leaving — booster gauntlets stay dodgeable by design.
  • Sound effects synthesized at runtime via the Web Audio API (no audio
    assets) for every cue — start, eating, lane changes, bathroom break, finish —
    with a persisted 🔊/🔇 mute toggle. Eating a rocket booster (🚀) plays a
    short music clip (the one sampled sound). See docs/GAME-DESIGN.md → "Audio".
  • Light/dark theme and a responsive layout from phone to desktop.

Multiplayer (serverless, over Nostr)

  • Lobby flow: create a race (with an optional race name), share an invite
    link, or join an open race from the browser; pick your runner/lane; the host
    starts (or it auto-starts when full). The host and track are read from the
    host's own presence, so the lobby is stable regardless of seat arrival order.
  • Host-only race start: the control (start) event is verified against the
    match host (signed by the host's identity), so a rogue peer subscribed to the
    channel can't force-start the race for everyone.
  • Realtime racing at ~5 Hz straight over public Nostr relays — no game
    server — with rivals shown as their actual animated characters plus a
    minimap.
  • Per-match session key signs the high-frequency frames locally, so
    Amber/NIP-46 users get zero prompts mid-race.
  • Reconnect & resume: a player can re-open the link and rejoin in progress
    (their position resumes from saved progress) without restarting the match.
  • Anti-cheat plausibility checks: speed, timestamps, finishing position, and
    per-race score are all bounded at the wire boundary, and frames are bound to
    the signer's announced session key.
  • Graceful endings: everyone runs their own line; finishers wait on an
    engaging spectator screen — a live countdown to the result, real-time
    progress bars of the rivals still racing, confetti for the leader, and rotating
    cheers. A runner still on the track gets a countdown banner once a rival
    crosses. Leaving a match is confirmed first and announced to the others.

Leaderboard

  • Global ranking by total wins, then by each player's personal best
    (their highest-scoring single race).
  • Sortable columns — Wins / Best / Races toggle the ranking — with
    pagination, podium styling, and the same table shared by the end-of-match
    results screen.
  • Standings persist to Neon Postgres when a match finishes — with retry on a
    transient network/5xx blip, so a race you played isn't dropped from the
    ranking by a single failed request.

Fake ads (Bitcoin literacy, played for laughs) 🎣

  • A built-in scam museum: ~18 deliberately fake crypto-spam banners line the
    desktop margins (sticky bottom banner on mobile), reproducing real-world bait
    — "You won 1 BTC!", "Send 1 BTC get 2 back", "Elon giveaway", "50% APY",
    "browser miner" — so players practice not clicking it.
  • Fake "watch an ad to keep playing" interstitial with a bogus "Skip in 5…"
    countdown that gates the close button — a knowing parody of the mobile-game
    dark pattern.
  • Every click lands on a "Gotcha" page with a scam-specific punchline and a
    friendly "This was a fake ad. No sats were harmed." disclaimer (noindex).
  • Spam respawns when dismissed (per-session), and clearing the whole pool
    earns a cheeky "You cleared the spam 🧹" reward. Full write-up in
    docs/GAME-DESIGN.md §10.

Identity, auth & Lightning

  • Nostr login via browser extension (NIP-07), pasted nsec, or NIP-46 bunker,
    using NIP-98 signed HTTP auth with durable single-use replay
    protection
    — login nonces live in a Postgres auth_nonces table, so a
    captured Authorization header can't be replayed by landing on a different
    serverless instance.
  • Rolling 7-day session: the JWT cookie is re-minted on every navigation, so
    an active player never gets logged out — a long match (even waiting in the
    lobby for opponents) can't outlive the session.
  • Signer survives reloads: extension and NIP-46 (Amber, nsec.app…) signers
    re-attach silently after a reload, so a logged-in user isn't left "logged in
    but unable to sign." The NIP-46 bunker connection is rebuilt from a persisted
    pointer (connection metadata, never the private key).
  • Profile sync pulls display name, avatar, and Lightning address from the
    user's Nostr kind:0 metadata.
  • ⚡ Zap the winner: tip over Lightning with WebLN, or — with no wallet — a
    BOLT11 QR + copyable invoice + lightning: deep link, with the amount
    confirmed before payment.

Platform

  • English / Spanish throughout (next-intl), with locale-aware routing.
  • SEO + social previews: favicon, per-locale Open Graph / Twitter images.
  • Installable PWA: web app manifest (with launcher shortcuts),
    code-generated app icons (any + maskable), theme-color, and a mobile-only
    "Install app" prompt
    (native install on Android, Add to Home Screen hint
    on iOS) that stays invisible on desktop.
  • Offline practice: a Serwist service worker precaches the single-player
    game (revisioned, at install) so practice works with no connection from the
    first load
    , while multiplayer stays online-only (/api is never cached) —
    the races browser disables hosting/joining offline and a banner tells the
    player practice still works. Network-only routes fall back to a localized
    offline page. See docs/PWA.md.
  • Security: rate limiting on sensitive API routes and framing/MIME/referrer
    response headers.
  • Automated tests + CI: Vitest unit suite (Nostr auth, schemas, multiplayer
    state, game logic, leaderboard) plus Neon-backed integration tests — including
    the durable auth_nonces replay guard — run on every push/PR alongside lint,
    typecheck, and a Prettier format:check (with a .prettierignore for build
    output and generated migration metadata). See docs/TESTING.md.
  • $0 infrastructure — Vercel + free public relays + Neon free tier +
    peer-to-peer Lightning.

Responsive & mobile UX

  • Phone-fit navbar: a compact xs button size (tighter padding, lighter
    offset shadow), shrunk locale/theme toggle and brand wordmark, and a tightened
    action-cluster gap keep the whole bar on a ~360px screen.
  • Icon-only login on mobile: the "Entrar" / "Login" navbar button collapses
    to a 👤 icon on phones (full label kept as its accessible name), mirroring the
    🏆 leaderboard button.
  • Single-line install prompt ("Agregá BitByBit RUN a tu pantalla de inicio" /
    "Add BitByBit RUN to your home screen") with a compact CTA, so the copy never
    gets cut off.
  • Square brand blocks in the favicon and generated app icons (three squares,
    not three half-height rectangles).
  • Readable food toast on phones: in portrait the in-canvas food toast drops
    below the overhead crowd signs and wraps long lines onto a second line, so both
    stay fully readable (desktop is unchanged).