<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohan Prasath P</title>
    <description>The latest articles on DEV Community by Mohan Prasath P (@mohanprasath).</description>
    <link>https://dev.to/mohanprasath</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4154254%2F031e96ad-2c9a-40b7-8a7e-fa72c506a72f.jpg</url>
      <title>DEV Community: Mohan Prasath P</title>
      <link>https://dev.to/mohanprasath</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mohanprasath"/>
    <language>en</language>
    <item>
      <title>Urban Drift: A Walking Game That Fits on One Sheet of Paper</title>
      <dc:creator>Mohan Prasath P</dc:creator>
      <pubDate>Mon, 12 Oct 2026 06:52:07 +0000</pubDate>
      <link>https://dev.to/mohanprasath/urban-drift-a-walking-game-that-fits-on-one-sheet-of-paper-2bl8</link>
      <guid>https://dev.to/mohanprasath/urban-drift-a-walking-game-that-fits-on-one-sheet-of-paper-2bl8</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I spend most of my day in front of a screen as an engineering student. Urban Drift is my attempt to use one for a minute so I can put it down for the next hour.&lt;/p&gt;

&lt;p&gt;It turns a neighborhood into a printable scavenger hunt on one A4 sheet. You enter an area, pick a difficulty tier and a walking radius, and print the card. The laptop is used for under a minute, and the walk itself is just paper. It is for anyone who wants a reason to walk their own neighborhood.&lt;/p&gt;

&lt;p&gt;I built and tested it in under five hours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Live: &lt;a href="https://urban-drift-opal.vercel.app/" rel="noopener noreferrer"&gt;https://urban-drift-opal.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mohanprasath-dev" rel="noopener noreferrer"&gt;
        mohanprasath-dev
      &lt;/a&gt; / &lt;a href="https://github.com/mohanprasath-dev/urban-drift" rel="noopener noreferrer"&gt;
        urban-drift
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Screen-free neighborhood scavenger hunt. Real map data, a local Ollama model writes the riddles, a code verifier checks every clue, and you print one A4 card and walk.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Urban Drift&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Screen-free neighborhood scavenger hunt. Real map data, a local Ollama model writes the riddles, a deterministic code verifier checks every clue, and you print one A4 card and walk.&lt;/p&gt;
&lt;p&gt;Built for the DEV Hacktoberfest Open-Source AI Challenge Week 1 (Touch Grass).&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Architecture Diagram&lt;/h2&gt;
&lt;/div&gt;

  &lt;div class="js-render-enrichment-target"&gt;
    &lt;div class="render-plaintext-hidden"&gt;
      &lt;pre&gt;flowchart TD
    User([Player Input: Neighborhood, Tier, Radius]) --&amp;gt; UI[Next.js 14 App Router]
    UI --&amp;gt; API[/api/generate POST]
    API --&amp;gt; WF[Mastra Sequential Workflow: hunt]

    subgraph Workflow [6-Step Hunt Workflow]
        S1[1. fetchPlaces] --&amp;gt;|SerpApi or Disk Cache| S2[2. buildFactSheets]
        S2 --&amp;gt;|Safety Filters + Normalization| S3[3. selectClues]
        S3 --&amp;gt;|Deterministic Tier Templates| S4[4. writeClues]
        S4 &amp;lt;--&amp;gt;|Verify-Retry Loop 0..3| Ollama[Local Ollama: llama3.2]
        S4 --&amp;gt; S5[5. verifyClues]
        S5 --&amp;gt;|Deterministic Rule Audit| S6[6. assembleCard]
    end

    WF --&amp;gt; CardData[Card Payload + Metadata]
    CardData --&amp;gt; PrintView[/card: Print-Ready View]
    PrintView --&amp;gt; PrintSheet([A4 Printed Sheet: 5 Clues + Key])

    WF -.-&amp;gt;|Observability Spans &amp;amp; Breadcrumbs| Sentry[Sentry Agent Tracing]
&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;span class="js-render-enrichment-loader d-flex flex-justify-center flex-items-center width-full"&gt;
    &lt;span&gt;
      &lt;span class="sr-only"&gt;Loading&lt;/span&gt;
&lt;/span&gt;
  &lt;/span&gt;



&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Core Principles&lt;/h2&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Code owns facts: Place names, addresses, coordinates, and…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mohanprasath-dev/urban-drift" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;MIT licensed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Next.js 14 handles the UI. A 6-step Mastra workflow does the work: fetch places, build fact sheets, select clues, write clues, verify clues, assemble the card. SerpApi supplies the place data, and an open-weight Llama model writes the wording.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    User(["Neighborhood, Tier, Radius"]) --&amp;gt; UI["Next.js 14"]
    UI --&amp;gt; API["/api/generate"]
    API --&amp;gt; WF["Mastra workflow: hunt"]
    subgraph Workflow
        S1["fetchPlaces"] --&amp;gt; S2["buildFactSheets"]
        S2 --&amp;gt; S3["selectClues"]
        S3 --&amp;gt; S4["writeClues"]
        S4 &amp;lt;--&amp;gt;|"retry 0..3"| LLM["Llama 3.2"]
        S4 --&amp;gt; S5["verifyClues"]
        S5 --&amp;gt; S6["assembleCard"]
    end
    WF --&amp;gt; Card["/card print view"]
    WF -.-&amp;gt; Sentry["Sentry tracing"]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;The rule that shaped the build: code owns the facts, the model owns only the wording.&lt;/strong&gt; Place names, addresses, coordinates, and ratings come from real map data and are extracted by plain code. The model never picks places and never calls tools. It rewrites a factual template into a riddle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The verifier.&lt;/strong&gt; Every riddle is checked before it reaches the card. A clue is rejected if it leaks the answer, invents a number, or adds a sensory detail that is not in the data. A rejected clue is retried up to three times. If all retries fail, the card falls back to the base clue. I tested this with a planted fault: I fed in an invalid rating, and the verifier caught and rejected it. 31 Vitest unit tests cover the geo math, safety filters, fact normalization, clue tiers, and verifier rules, and all 31 pass.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sentry Agent Tracing.&lt;/strong&gt; Each clue records its tier, attempt count, source, and verifier failures as span attributes, and every verification decision leaves a breadcrumb. With &lt;code&gt;PLANT_FAULT=1&lt;/code&gt;, the trace shows the first attempt rejected and the retry. &lt;code&gt;npm run gate:sentry&lt;/code&gt; reproduces this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What did not work.&lt;/strong&gt; A local end-to-end run took 17.32 seconds, and a cached replay took 5.78 seconds. That is too slow to host on Vercel, so I added a Groq path for the live demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Because the model is open-weight Llama, I choose where it runs. On my laptop it runs through Ollama, and clue writing needs no cloud AI service. A closed API would not give me that.&lt;/p&gt;

&lt;p&gt;The same Llama family also runs on Groq, and I switch between the two with environment variables. That is how I got a live demo without changing any workflow code. On the live demo, the clue prompt is sent to Groq.&lt;/p&gt;

&lt;p&gt;Either way, the neighborhood query goes to SerpApi, and traces go to Sentry.&lt;/p&gt;

&lt;p&gt;The walk is different. The card is paper, so there is no GPS polling, no data connection, and no tracking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;Best Use of Sentry Agent Tracing, Best Use of Mastra, Best Use of SerpApi&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
  </channel>
</rss>
