How I Built an Offline-First Party Game with Next.js and Capacitor (and Shipped It to Google Play) A developer shipped Imposter Word, a free pass-the-phone social deduction game for Android, built with Next.js, TypeScript and Capacitor. The game uses a three-tier word provider that tries a Gemini 2.5 Flash Lite call through a server route, falls back to a cached IndexedDB store, then to a bundled word list, keeping the API key server-side and validating that hints never reveal the word. A service worker precaches every route at install time, and the build fails if the route list drifts from the client copy. I recently shipped Imposter Word , a pass-the-phone social deduction game, to Google Play. Most players get a secret word. One or more imposters get only a vague hint. Everyone gives clues, argues, votes, and tries to catch the imposter before the imposter works out the word. It's a free game, built with Next.js, TypeScript and Capacitor. The interesting part wasn't the game rules. It was making a web stack behave like a native app that works on a train with no signal, then getting it through Google's release process. This post covers the architecture decisions that mattered, the bugs that cost me the most time, and what I'd do differently. Try it: Imposter Word on Google Play https://play.google.com/store/apps/details?id=com.hafizsyedahmedali.imposterword · Source on GitHub https://github.com/HafizSyedAhmedAli/Imposter-Word-Game A party game gets played in cars, cafés, hostels and living rooms with bad Wi-Fi. That gave me three rules: gemini-2.5-flash-lite for word and hint generation, called only from a server route The game engine never talks to the AI or to IndexedDB directly. It only knows a small interface: export interface WordProvider { generateRoundContent category: Category, difficulty: Difficulty, options?: { signal?: AbortSignal; excludeWords?: string ; language?: GameLanguage; }, : Promise