Inspiration

"Fly Me to the Moon" made us ask one question: if Earth ended tomorrow and you could bring one thing, what would it be? Everyone has an answer, and it's usually something within arm's reach. We wanted a game where that answer actually matters: the real object next to you becomes your gear, changes your strategy, and shows up in your ending.

Who it's for, and the problem

It's for anyone with an iPhone, and for rooms full of people (a hackathon, a class, a party) who want to play something together in a few minutes.

  • Most games pull you away from the room you're in, and they start with a download and an account.
  • Most AI-powered games let the model improvise freely, so outcomes feel random, unfair, or just wrong.

Our approach: iMessage is the controller (nothing to install, and everyone already knows how to use it), your real object is the game piece, and the AI is boxed in. It only recognizes things and understands words; the game rules decide every number. A shared big screen lets a whole room launch together.

What it does

  1. Text the ship. You message the ship AI over iMessage (a Photon Spectrum agent): "Earth has hours left. You can bring one thing with you. Send me a photo of it."
  2. Bring one real thing. Snap a photo of anything nearby, and Gemini picks one of 12 fixed modifications for it. A scarf becomes an Impact Pad, a Coke can a Fuel Side Pod, house keys a Hatch Repair Wrench, a potted plant a Water Recycler.
  3. Fly 5 stages: liftoff, the debris belt, deep space, lunar orbit and the landing. You manage fuel, oxygen and hull, pick 3 upgrades (12 upgrades, 4 combos, legendary drops) and face random events and interludes.
  4. Just say what to do. From stage 2 on there are no menus. Type "strap my scarf to the nose as a bumper" and the ship understands. Your item unlocks moves other players don't get, including hidden ones you only find by trying them.
  5. A real choice. In lunar orbit the ship breaks. Do you tear apart the thing you brought to survive, or keep it and take the riskier path?
  6. An ending that remembers. Touchdown, adrift or lost: the ending says whether your item made it, you get a score card, and Gemini writes a short captain's log of your run. The score rewards playing well, not fast: 200 for a touchdown, plus whatever fuel, oxygen and hull you have left, +40 per combo and +60 if the thing you brought survived.

The phone alone is enough to play the whole game. Everything below is optional:

  • Personal bridge: a live web page (behind a random, unguessable link) on your laptop with your rocket, gauges, gear slots and a holographic scan of your item.
  • Big screen for events: everyone who scans the QR code boards the same launch. There's a 30-second boarding countdown, a full-screen 3·2·1 LIFTOFF, then a 5-minute flight with a live mission feed and a best-landing leaderboard. A podium ceremony closes the round, and the next one starts on its own.
  • About 20 seconds to join: open dingn0823.github.io/moon, type a nickname and your iPhone number, scan the QR code and hit send. The server registers you with Photon automatically, and the laptop page turns into your bridge as soon as your first text arrives.
  • English and Chinese: texting "join" or "加入" picks the language for the whole run.

How we built it

  • One TypeScript process on one laptop (Node.js 24 with native type stripping) runs messaging, game state, the web server, live updates and the public tunnel.
  • Photon Spectrum (spectrum-ts, iMessage provider) handles incoming texts and photos (HEIC), typing indicators, iMessage screen effects and proactive pushes. New players are registered through the Photon project API, and each one texts the shared number Photon assigns them.
  • A pure game engine: step(state, input) returns the new state plus messages, and a seeded RNG lives in the save. Every number, rarity and outcome is in rules code and JSON content: 12 mods, 12 upgrades, 4 combos, 13 events, 6 interludes and 3 endings, in English and Chinese.
  • Gemini (Gemini 3.5 Flash-Lite, falling back to 3.1 Flash-Lite) has exactly three jobs:
    • classify the photo into one of the 12 mods;
    • map free text onto one of the moves the content already defines;
    • narrate the ending.

Every response is JSON, validated against the fixed lists, with hard timeouts (photo 10 s, parsing 3 s, narration 5 s). A rate-limited model is swapped for the next one, and if every model is limited the game shows numbered options instead.

  • Input understanding runs in a fixed order: number, then keywords, then AI, then one clarifying question, then numbered options. Most replies never reach the AI, so a typical run makes only 4–5 Gemini calls. Typed item names are checked against about 1,300 everyday object names in English and Chinese first, so the game still knows what you brought when Gemini is busy.
  • Reliability: per-player serial queues, message dedupe and state versions (duplicate or late messages are dropped), saving before sending, and pure-JS HEIC → JPEG conversion.
  • Web: plain HTML, CSS, SVG and JavaScript, no framework. A Cloudflare quick tunnel gives the laptop a public https URL. A GitHub Pages short link follows the tunnel: the server rewrites it through the GitHub API whenever the tunnel URL changes.
  • Balance by simulation: a script plays thousands of runs with three player styles. Random choices land about 34% of the time, and a careful player lands about 91%. 53 automated tests cover the engine, input parsing, dedupe, rounds and the big screen.

What we built during the build window

Everything in the repo was built during the official build window (Sep 25–27). We started from a design doc after the prompt came out. The first commit landed Saturday afternoon, and by Saturday night friends were playing full runs on their own iPhones. We kept playtesting and building through the night: joining from a laptop, the bridge, the big screen with automatic rounds, the Chinese version and a rebalance.

Challenges and surprises

  • Live updates vanished through the tunnel. Server-Sent Events worked locally but never arrived through the Cloudflare quick tunnel, which buffers them. HTTP/2, turning off compression and padding didn't help. We rewrote every live view as long polling, and updates now arrive in about 0.2 s.
  • The public URL changes on every restart. We built a short link on GitHub Pages that the server updates itself.
  • Email-based iMessage identities are rejected by Photon's shared numbers. One tester's iPhone started new conversations from an email address, and none of their messages reached us. The join page now has a prominent tip telling people which setting to change.
  • iPhone photos arrive as HEIC, so we decode them in pure JavaScript (this works on Windows).
  • Gemini setup:
    • school Google accounts couldn't create API keys;
    • the 2.5 models returned 404 for new keys;
    • the free tier rate-limits fast, so we added per-model fallback.
  • The first version was too easy. Our simulator landed about 96% of runs, and a playtester said every run felt the same. We rebalanced: a 100-point start with scaled costs, ±25% variance, a random stage-4 crisis and random interludes.
  • Keeping free text fair: the AI can only choose moves that already exist in the content. Negation ("don't swerve, punch it") is handled before anything reaches the AI.

Accomplishments that we're proud of

  • Friends and teammates played complete runs on their own iPhones over real iMessage. A brand-new number could join through the page and start playing right away.
  • The object you bring genuinely changes the game: different moves, hidden options, and an ending that remembers it.
  • It costs $0 to run: free tiers and one laptop.
  • It's bilingual end to end, and automated tests check that a Chinese run never shows English and an English run never shows Chinese.

What we learned

  • Boxing in the AI (a fixed menu, validated JSON, no numbers from the model) made the game more reliable and more fun.
  • Messaging is a great game controller: nothing to install, notifications built in, and everyone already knows how to use it.
  • Test the network path on day one. SSE through tunnels cost us hours.

What's next

  • Android support over SMS/RCS.
  • Group chats as crews that vote on each move.
  • More items, events and combos, plus weekly missions.
  • Cloud hosting, so the game doesn't depend on one laptop.

Photon Bonus Track

The entire game is played by texting a Photon Spectrum agent over iMessage. Photos come in; typing indicators, iMessage effects and proactive pushes go out. Players are registered automatically through the Photon project API.

Credits

  • Our team: the concept, game design and design doc (rules, where the AI is and isn't allowed to decide, architecture), content direction, playtesting with friends on real iPhones, and every product decision.
  • AI tools: Claude Code (Anthropic) was our AI pair programmer. It wrote most of the code and first drafts of the game text under our direction. Google Gemini runs inside the game.
  • Services: Photon Spectrum (iMessage), Google Gemini API, Cloudflare Tunnel, GitHub Pages.
  • Open-source libraries: spectrum-ts, qrcode, heic-decode, jpeg-js, TypeScript.
  • Art and data: icons are system emoji, and everything else is hand-written CSS and SVG. No datasets were used.

Built With

Share this project:

Updates

Submission history