DEV Community

Sandeep Kumar
Sandeep Kumar

Posted on

OpenQuest: an open-source mobile web app that sends you on location-based outdoor quests

Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass Submission 🌿

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass

What I Built

OpenQuest is an AI-powered adventure generator that encourages users to step outside, explore their surroundings, and complete real-world quests. Instead of giving endless recommendations or summaries, it creates actionable challenges that push people to interact with places, people, and experiences around them.

OpenQuest Cover Image

The idea is that once you accept, your phone's internet is cut for an hour. No doomscrolling. Navigation and emergency calls still work. You walk there, take the photo, and an AI model checks it. Pass, and the phone unlocks. Run out the clock, and it unlocks anyway. There's a 24-hour panic PIN for emergencies, because a lock you can't escape is a hostage situation, not a habit.

It's for anyone who has said "I'll just check my phone for a minute" and looked up an hour later. It's also for people who don't trust an app to lock their phone unless they can read how it works.

Here's the loop:

  1. Get a quest. A small model running in your browser looks at real places near you (from OpenStreetMap), the time of day and the weather, and writes a quest.
  2. Phone locks. A tiny Android companion app cuts other apps' internet for the hour.
  3. Take the photo. The photo's GPS has to land inside the quest radius first. Only then does the model look at what's in the picture.
  4. Unlock. Pass and you're free. If the hour ends, you're free anyway. ### Where it actually stands

Quest lifecycle

stateDiagram-v2
    [*] --> pending: generated
    pending --> active: user accepts, phone locks
    pending --> abandoned: user gives up
    active --> submitted: photo taken
    submitted --> verified: judge passes, phone unlocks
    submitted --> failed: judge or GPS rejects
    failed --> submitted: retry while time remains
    active --> expired: 60 min elapsed
    failed --> expired: 60 min elapsed
    active --> abandoned: panic PIN
    verified --> [*]
    expired --> [*]
    abandoned --> [*]

Video Walkthrough

Code

🌿 OpenQuest

Open-source quests that lock you out until you touch grass.

An on-device AI writes a short outdoor quest, your phone locks until you've done it, and the same AI checks your photo. No cloud model, no tracking, no server you don't control.

CI License: Apache 2.0 Status: pre-alpha PRs welcome Hacktoberfest 2026 GitHub stars GitHub issues

React 19 TypeScript Vite 8 Tailwind CSS 4 PWA WebGPU Kotlin Cloudflare Workers

Live demo · Video · How it works · Architecture · Get started · Roadmap


📸 Screenshots

Home Active quest Set your area
OpenQuest home page on a phone An active quest with distance and direction The location hint screen

Mobile-first and responsive from 320 px to desktop. Quests in these screenshots are sample data; on-device generation needs WebGPU.

🌐 Live demo

🚀 Try it: the web app is live at openquest-pi.vercel.app. The Android companion and Worker are not published yet.

Link
Web app (PWA) openquest-pi.vercel.app
Companion APK TODO: add the GitHub Releases link once a release is cut
Worker (optional sync) TODO: add URL once deployed

🎬 Demo video

🚧 Coming soon. The shot list is in docs/DEMO_SCRIPT.md.

Demo video placeholder

✨ What

…

Apache-2.0. It's a pnpm monorepo: the PWA in apps/pwa, the Android companion in apps/companion, an optional Cloudflare Worker in apps/worker.

How I Built It

The model. Gemma 4 E2B, run in the browser through Transformers.js on WebGPU, inside a Web Worker so the UI doesn't freeze. There are two builds: a 2-bit mobile one (about 2.6 GB) and a 4-bit one (about 3.4 GB). No API key, no server, no per-quest cost.

Writing a quest. The app asks OpenStreetMap's Overpass API for places within about 2 km, adds time, season and weather, and gives the model a short list of real candidates. The model has to answer in JSON that matches a schema. If it doesn't, or if the quest fails the safety check, the app falls back to a hand-written template instead of showing you something strange.

The safety filter. An LLM telling people to go outside needs a net under it. Every quest goes through a plain regex filter that rejects climbing, swimming, trespassing, foraging, approaching animals or strangers, and so on. It's deliberately dumb and deliberately readable, so anyone can open the file and argue with it.

Judging the photo. The model's verdict is advisory. The check runs in this order: is the photo's GPS inside the quest radius? If not, it fails no matter what the model says. A model can be talked into believing a stock photo is a bakery. A coordinate can't.

The lock. A web page can't lock a phone, so a small Kotlin app does it: a VpnService that drops traffic, and a localhost server (127.0.0.1:7777) that the web app talks to. Every request is HMAC-signed and rejected if it's more than 30 seconds old, so nothing on the network, and no other app, can trigger a lockout.

For phones that can't run the model. An optional Cloudflare Worker acts as a mailbox: the phone sends the photo, a laptop that can run Gemma judges it and sends the verdict back.

🏗️ Architecture

OpenQuest is two required parts and one optional part.

flowchart LR
    subgraph Phone["📱 Phone"]
        subgraph PWA["PWA (React + Vite)"]
            UI[UI<br/>React Router]
            QS[Quest service<br/>+ safety filter]
            DB[(IndexedDB<br/>quests, photos)]
            subgraph W["Web Worker"]
                G[Gemma 4 E2B<br/>Transformers.js]
            end
        end
        subgraph C["Android companion (Kotlin)"]
            HS[Localhost server<br/>127.0.0.1:7777]
            VPN[VpnService<br/>lockout]
            KS[(Keystore<br/>panic PIN)]
        end
    end

    OSM[(OpenStreetMap<br/>Overpass)]
    WX[(Open-Meteo<br/>weather)]

    subgraph CF["☁️ Cloudflare (optional)"]
        WK[Worker<br/>Hono + GitHub OAuth]
        D1[(D1)]
        R2[(R2 photos)]
    end

    Laptop[💻 Laptop PWA<br/>runs Gemma, judges]

    UI --> QS
    QS --> DB
    QS <--> G
    QS -- POIs --> OSM
    QS -- weather --> WX
    QS -- "HMAC-signed JSON" --> HS
    HS --> VPN
    HS --- KS
    UI -. field mode .-> WK
    WK --- D1
    WK --- R2
    Laptop -. polls mailbox .-> WK

Why Does Open Innovation Matter?

If OpenQuest were built on a closed API, every one of those would flow through someone else's server. Your coordinates, your photos, a bill per quest, and a verdict from a model you can't inspect, which stops working the day the API changes or the money runs out.

Open weights changed what was possible:

  • The judge runs on your device. Your photo never leaves your phone. A closed API can promise that. An on-device model lets you check it.
  • The lock is about 900 lines of Kotlin. You can read the thing that controls your phone's network in an afternoon.
  • The safety rules are a file, not a policy. If the filter is too strict or too loose, you send a pull request, instead of an email to a support address.
  • It costs nothing to run per quest, so there's no reason to ever add ads or a subscription to pay for inference. I'll be fair about the price. On-device means a 2.6–3.4 GB first download, and it needs a browser with WebGPU. That's a real cost. For this app, I'd rather pay it in gigabytes than in trust.

## Final Thoughts

The internet is full of products competing for attention.
OpenQuest explores a different question:

What if AI's best contribution isn't keeping us online longer, but giving us a reason to close the laptop and go somewhere?

Sometimes the next adventure is only a few steps away.
OpenQuest simply gives you a nudge to find it.

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.