<?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: Javier Cristóbal</title>
    <description>The latest articles on DEV Community by Javier Cristóbal (@crjstobal).</description>
    <link>https://dev.to/crjstobal</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%2F4090801%2F58da60bc-2cf2-4998-948e-6d52e1b0fe35.jpg</url>
      <title>DEV Community: Javier Cristóbal</title>
      <link>https://dev.to/crjstobal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/crjstobal"/>
    <language>en</language>
    <item>
      <title>Redactator: a tool that blacks out private data, and it never uploads your files!</title>
      <dc:creator>Javier Cristóbal</dc:creator>
      <pubDate>Wed, 14 Oct 2026 17:12:43 +0000</pubDate>
      <link>https://dev.to/crjstobal/redactator-a-tool-that-blacks-out-private-data-and-it-never-uploads-your-files-4013</link>
      <guid>https://dev.to/crjstobal/redactator-a-tool-that-blacks-out-private-data-and-it-never-uploads-your-files-4013</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I edit videos for clients. A lot of that work is screen recordings: someone walks through their CRM, their admin panel, their inbox. And every one of those recordings is full of other people's data. Customer names, emails, phone numbers, the card on file, the billing address.&lt;/p&gt;

&lt;p&gt;Before a video can go public, someone has to hide all of that. Today that means scrubbing frame by frame and drawing rectangles by hand, or uploading the client's raw footage to an online "AI redaction" service. The second option has an obvious problem: to protect the data, you send the data to a stranger.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redactator&lt;/strong&gt; is a desktop app that does the boring part locally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drop photos, PDFs and screen recordings. Several at once.&lt;/li&gt;
&lt;li&gt;Tick what to hide: names, faces, emails, phone numbers, addresses, birth dates, ID numbers, card and bank details, passwords and API keys, licence plates.&lt;/li&gt;
&lt;li&gt;Add anything only you know about. My car's plate, &lt;code&gt;9256YT&lt;/code&gt;, means nothing to a model, so there is a field for exact text. It still matches when OCR reads it as &lt;code&gt;9256 YT&lt;/code&gt; or &lt;code&gt;9256VT&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Say what must stay visible, like your own studio's name.&lt;/li&gt;
&lt;li&gt;Review every finding, untick what should stay, draw extra boxes by hand, and export clean copies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The output is &lt;strong&gt;solid black boxes, never blur&lt;/strong&gt; (blur can be reversed). PDFs get &lt;strong&gt;true redaction&lt;/strong&gt;: the text under each box is deleted from the file, not just covered. Clickable &lt;code&gt;mailto:&lt;/code&gt; links and document metadata go too. Videos are re-rendered with the boxes following the text while it scrolls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who would pay for it?&lt;/strong&gt; Video editors and agencies who turn client screens into tutorials, support teams who send screenshots to vendors, and freelancers who reuse client work as portfolio samples. They redact every week, and they are exactly the people who shouldn't be uploading client files to a random website.&lt;/p&gt;

&lt;p&gt;The business model is classic open source: the code is free (AGPL), and the paid product is convenience, a signed one-click installer for Mac and Windows with the models bundled, sold once. No server means no per-file cost, so a one-time price actually works.&lt;/p&gt;

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

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/1235916606" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://crjstobal.github.io/redactator/" rel="noopener noreferrer"&gt;https://crjstobal.github.io/redactator/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The video is generated by a script in the repo: it drives the real interface with results from real runs of the engine on the sample files, and the narration is made with ElevenLabs.&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/crjstobal" rel="noopener noreferrer"&gt;
        crjstobal
      &lt;/a&gt; / &lt;a href="https://github.com/crjstobal/redactator" rel="noopener noreferrer"&gt;
        redactator
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Black out private data in photos, PDFs and videos, entirely on your own computer. Gemma 4 + GLiNER2-PII + local OCR.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/crjstobal/redactator/docs/logo.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcrjstobal%2Fredactator%2FHEAD%2Fdocs%2Flogo.png" width="220" alt="Redactator, a small robot holding a big black marker"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Redactator&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Drop photos, PDFs or screen recordings, tick what to hide, get back clean copies with solid black boxes.&lt;/strong&gt; Everything runs on your own computer: open-weight models (Gemma 4 and GLiNER2-PII) read the text, nothing is uploaded, and there is no per-file bill.&lt;/p&gt;
&lt;p&gt;Made for freelancers and small teams who share client material all day: video editors cutting tutorials from a client's dashboard, support agents sending screenshots, consultants forwarding invoices.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Website and demo video:&lt;/strong&gt; &lt;a href="https://crjstobal.github.io/redactator/" rel="nofollow noopener noreferrer"&gt;crjstobal.github.io/redactator&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What it does&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Photos and screenshots&lt;/strong&gt;: finds the private text and faces, paints opaque boxes (never blur, which can be reversed), and strips EXIF and GPS data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PDFs&lt;/strong&gt;: true redaction. The text under each box is deleted from the file, not just covered, so it cannot be copied or searched. Clickable &lt;code&gt;mailto:&lt;/code&gt; links under a box and document metadata are removed too. Scanned pages and screenshots pasted into a PDF are read with…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/crjstobal/redactator" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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

&lt;p&gt;Redactator is Python, with a small HTML interface in a native window (pywebview). Everything that reads your files runs on your machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reading the file.&lt;/strong&gt; Text comes from RapidOCR (PaddleOCR models on ONNX Runtime), which returns a box for every word. PDFs use their own text layer through PyMuPDF, and fall back to OCR for scanned pages or screenshots pasted into the document. Faces come from OpenCV's YuNet, a 230 KB model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finding the private bits: three detectors, merged.&lt;/strong&gt; This is the part I iterated on most.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fixed patterns&lt;/strong&gt; for data with a known shape: emails, phone numbers, card numbers (with a Luhn check), IBANs, plates, API keys. No model, so never a miss.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://huggingface.co/fastino/gliner2-privacy-filter-PII-multi" rel="noopener noreferrer"&gt;GLiNER2-PII&lt;/a&gt;&lt;/strong&gt;, a 0.2B open model (Apache 2.0) trained only to find personal data, in 7 languages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 4 E4B&lt;/strong&gt; through Ollama, for anything that needs judgement: full postal addresses, company names, or a description you type, like "my client's company".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I started with Gemma alone, and my first test leaked a name. Gemma read 25 lines of a fake CRM, found three customers and skipped the fourth, &lt;em&gt;Maria Lopez Garcia&lt;/em&gt;, on every row. It turned out recall dropped when I sent long batches, so I cut them from 60 lines to 20. Then I stopped trusting any single model: GLiNER2-PII finds names with 99% confidence, Gemma handles nuance, and anything either of them recognises once is hidden everywhere it appears in the file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A few problems worth sharing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ollama's structured output wasn't available for Gemma 4&lt;/strong&gt; in my version (&lt;code&gt;501: structured output is unavailable&lt;/code&gt;), so the JSON schema goes in the prompt and the reply is validated with Pydantic, with one retry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GLiNER over-predicts.&lt;/strong&gt; It tagged the column header "Email" as an email address. Structured labels now have to look right: an email needs an &lt;code&gt;@&lt;/code&gt;, a phone number needs digits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overlapping findings can leak.&lt;/strong&gt; If "Daniel Okafor, Brightlane Ltd." and "Daniel Okafor" are both found, unticking the long one used to reveal the name too, because only one box was stored. Now every finding keeps its own boxes, and there's a test for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Videos are expensive, screen recordings mostly aren't.&lt;/strong&gt; I sample four frames per second and skip any frame that barely changed, so a mostly static recording costs a handful of OCR passes. Between two samples, a frame gets the boxes of both, which covers text while it scrolls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On my M1 Max, a screenshot takes about 12 seconds, a one-page PDF about 20, and a 6-second scrolling recording about 27.&lt;/p&gt;

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

&lt;p&gt;For this product, open isn't a nice-to-have. It's the whole point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The privacy paradox only goes away locally.&lt;/strong&gt; A redaction tool built on a cloud API asks you to upload the document you want to protect. With open-weight models running on your laptop, the promise "your file never leaves your computer" is literally true, and anyone can read the code to check it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A specialised small model beat a general big one where it mattered.&lt;/strong&gt; The most important job here is not missing a name. A 0.2B open model trained only on personal data was more reliable at that than a general LLM, and I could combine the two because both run locally with no extra cost per call.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The economics only work without a meter.&lt;/strong&gt; Video editors redact every week. With a per-call API, every export costs money and the price has to be a subscription. With local models, processing is free, so I can sell a one-time installer and still give the full source away.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It works where the files are.&lt;/strong&gt; On a train, in a client's locked-down network, on an air-gapped machine. Swap Gemma for a bigger model with one environment variable, or fine-tune the PII model for medical forms or legal discovery, without asking anyone.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Best Use of Gemma&lt;/li&gt;
&lt;li&gt;Best Use of ElevenLabs&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Play Bomberman in your real neighbourhood!</title>
      <dc:creator>Javier Cristóbal</dc:creator>
      <pubDate>Sat, 10 Oct 2026 19:34:45 +0000</pubDate>
      <link>https://dev.to/crjstobal/play-bomberman-in-your-real-neighbourhood-3log</link>
      <guid>https://dev.to/crjstobal/play-bomberman-in-your-real-neighbourhood-3log</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;&lt;strong&gt;Street Bomber&lt;/strong&gt; is Bomberman played on the real streets around you.&lt;/p&gt;

&lt;p&gt;The map is your neighbourhood. Every crossing is a place to plant a bomb, and the blast runs down the real street in a straight line, like the original game. The twist: &lt;strong&gt;you have no bombs until you go outside and find one.&lt;/strong&gt; You walk to a corner, photograph whatever is there, and an open-weight vision model running on your phone turns it into a bomb:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You photograph&lt;/th&gt;
&lt;th&gt;You get&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;⚡ Lamp post&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Spark&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Runs down the whole street, straight&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🚦 Traffic light&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Crossfire&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Turns every corner, takes the area around it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🌳 Tree&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Roots&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Keeps growing into the streets next to it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;♻️ Bin&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Scrap&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Gives you one bomb back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;💧 Fountain&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Flood&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Washes rival streets back to neutral&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🛡️ Bench&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Fort&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Its streets can't be stolen for 5 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anything else&lt;/td&gt;
&lt;td&gt;🧨 Firecracker&lt;/td&gt;
&lt;td&gt;Just your corner. Get closer to something real.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Own every street around a city block and &lt;strong&gt;the whole block is yours&lt;/strong&gt;. The blocks are computed from the street graph itself, so any neighbourhood on Earth works.&lt;/p&gt;

&lt;p&gt;Two rules exist only to get you off the screen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One bomb a day.&lt;/strong&gt; You can save up to three. Closing a block or recycling a bin earns one back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One object, one corner.&lt;/strong&gt; The same kind of object on the same corner is spent for 6 hours. You will start noticing which corners have a fountain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything you weaponise goes into a &lt;strong&gt;street album&lt;/strong&gt; with your own photo. Your streets stay yours until a rival bombs them.&lt;/p&gt;

&lt;p&gt;It is for anyone who already walks the dog, goes for a run or does the school run and would like a reason to take the long way round.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Play it:&lt;/strong&gt; &lt;a href="https://crjstobal.github.io/street-bomber/" rel="noopener noreferrer"&gt;https://crjstobal.github.io/street-bomber/&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On a phone, outside: allow location and camera, walk to a crossing, press &lt;strong&gt;Plant bomb&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;At a desk: without GPS it opens a demo city (central Madrid). Click the map or use WASD to walk, and feed the camera a photo file. Demo mode recharges bombs every 15 seconds.&lt;/li&gt;
&lt;li&gt;The first visit downloads the vision model once (99 MB, then cached), so use Wi-Fi.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/1234693434" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;A note on the video: &lt;strong&gt;real streets are private data&lt;/strong&gt;, so I recorded it in demo mode, in central Madrid, with a simulated camera fed with Wikimedia Commons photos. The model is real: every frame you see classified was classified by SigLIP in the browser.&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/crjstobal" rel="noopener noreferrer"&gt;
        crjstobal
      &lt;/a&gt; / &lt;a href="https://github.com/crjstobal/street-bomber" rel="noopener noreferrer"&gt;
        street-bomber
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Bomberman on your real streets. Photograph what is on the corner; an open-weight model on your phone turns it into your bomb.
    &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;Street Bomber&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Bomberman on your real streets. Walk to a corner, photograph what is there, and an
open vision model running &lt;strong&gt;on your phone&lt;/strong&gt; turns it into your bomb. A lamp post
becomes a blast that runs the whole street; a tree grows roots into the next block
a bin recycles into more ammo.&lt;/p&gt;
&lt;p&gt;Built for the DEV Hacktoberfest 2026 Open-Source AI Challenge, Week 1: &lt;em&gt;Touch Grass&lt;/em&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How it plays&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;The map is your neighbourhood: real streets from OpenStreetMap, crossings are where you plant.&lt;/li&gt;
&lt;li&gt;You must physically be at a crossing (GPS) and take a live photo there.&lt;/li&gt;
&lt;li&gt;The photo decides the bomb:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You photograph&lt;/th&gt;
&lt;th&gt;Bomb&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lamp post&lt;/td&gt;
&lt;td&gt;⚡ Spark&lt;/td&gt;
&lt;td&gt;Runs down the whole street in a straight line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Traffic light&lt;/td&gt;
&lt;td&gt;🚦 Crossfire&lt;/td&gt;
&lt;td&gt;Turns every corner, takes the whole block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tree&lt;/td&gt;
&lt;td&gt;🌳 Roots&lt;/td&gt;
&lt;td&gt;Keeps growing into neighbouring streets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bin&lt;/td&gt;
&lt;td&gt;♻️ Scrap&lt;/td&gt;
&lt;td&gt;Gives you one bomb back right away&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/crjstobal/street-bomber" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;No build step, no backend. One HTML file, one ES module for vision, and two small scripts that precompute data. MIT licensed.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;The street graph.&lt;/strong&gt; The game asks OpenStreetMap (through the Overpass API) for every walkable street within 500 m, then turns it into a graph: crossings are nodes, stretches of street are edges. A blast follows a street from a crossing and keeps going straight through the next crossings as long as it doesn't have to turn more than about 60°. City blocks are the &lt;em&gt;faces&lt;/em&gt; of that planar graph, found by walking every half-edge and always taking the next turn. Central Madrid alone has 174 of them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The eyes.&lt;/strong&gt; I tested three open models on 32 street photos before picking one:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Correct&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CLIP ViT-B/32&lt;/td&gt;
&lt;td&gt;26/32&lt;/td&gt;
&lt;td&gt;fast, but every tree failed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLIP ViT-B/16&lt;/td&gt;
&lt;td&gt;28/32&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SigLIP base&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;30/32&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the two "misses" were wide shots of an avenue&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;SigLIP runs in the browser with &lt;strong&gt;Transformers.js&lt;/strong&gt; on WASM, int8 quantised. Classification is zero-shot: I describe each object in a few phrases ("a lamp post", "a street light pole"…) and compare the photo against them. I also added &lt;em&gt;decoy&lt;/em&gt; classes (a wall, a building, a car, a person, the pavement) so a random shot falls back to a firecracker instead of being forced into the closest bomb. Below a confidence threshold it tells you to get closer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The trick that open weights made possible.&lt;/strong&gt; SigLIP has two halves: one that reads text, one that looks at images. My text never changes (it's the same object descriptions for every player), so I run the text half &lt;strong&gt;once, on my laptop&lt;/strong&gt;, and ship the result as a 184 KB JSON file. The phone downloads &lt;strong&gt;only the vision half: 99 MB instead of 211 MB&lt;/strong&gt;, and a photo takes about a second. You can't split a model you can't download.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Saving.&lt;/strong&gt; Progress, the album (with small thumbnails) and the street map of your area live in the browser's local storage, on your phone only.&lt;/p&gt;

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

&lt;p&gt;Look at what this game handles: &lt;strong&gt;photos of the street you live on, tagged with where you were standing.&lt;/strong&gt; That is about as sensitive as personal data gets. With an open-weight model running on the device, the honest answer to "where do my photos go?" is: nowhere. There is no server. I didn't have to write a privacy policy because there is nothing to protect.&lt;/p&gt;

&lt;p&gt;It also matters for the shape of the game:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It costs nothing per player.&lt;/strong&gt; A closed vision API would charge for every photo of every player, forever. That's the difference between a game anyone can host on GitHub Pages and one that needs a business model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I could take the model apart.&lt;/strong&gt; Precomputing the text side and shipping only the vision encoder is what made it phone-sized. That needs the weights.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anyone can add a bomb.&lt;/strong&gt; A new object (a post box, a statue) is one line of text in &lt;code&gt;classes.json&lt;/code&gt; and one script run. No retraining, no permission, no API change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It works with bad signal.&lt;/strong&gt; Once the model is cached, recognising objects needs no network at all. Only the street map does, and it's cached per area.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The map data is open too: the whole game exists because people mapped their streets on OpenStreetMap.&lt;/p&gt;

&lt;h2&gt;
  
  
  I took it outside
&lt;/h2&gt;

&lt;p&gt;I tested the first version on my own phone, around my own streets. It was fun, and it was also clearly unfinished. That walk changed the game more than any planning did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The first load was slow&lt;/strong&gt;, because the game asks a public OpenStreetMap server for every street around you. Now the street map is cached per area, and the second visit is instant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Closing the app lost everything.&lt;/strong&gt; Now your territory, your bombs and your album are saved on the phone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Painting streets had no goal.&lt;/strong&gt; Closing whole blocks came straight out of that walk, and it is now the heart of the game.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It should pull you back outside, not keep you on the screen.&lt;/strong&gt; So: one bomb a day, and streets that stay yours until someone takes them. The game wants you to come back tomorrow, on foot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm not showing footage of that walk. Those are my streets, and that is exactly the kind of data this game is built to keep private.&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;Street photos in the demo video come from Wikimedia Commons: street tree by Fons Heijnsbroek (CC0), traffic light in Darwin by Dietmar Rabich (CC BY-SA 4.0). Map data © OpenStreetMap contributors. Voice-over generated with ElevenLabs.&lt;/p&gt;

&lt;p&gt;Go outside. Take your block!&lt;/p&gt;

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