<?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: Olabowale Babalola Israel</title>
    <description>The latest articles on DEV Community by Olabowale Babalola Israel (@esimuda).</description>
    <link>https://dev.to/esimuda</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%2F4177961%2Ff321558a-6979-45f1-8fd8-8889eab7f77b.png</url>
      <title>DEV Community: Olabowale Babalola Israel</title>
      <link>https://dev.to/esimuda</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/esimuda"/>
    <language>en</language>
    <item>
      <title>Name it, then look up: a field guide where the phone's job ends after one photo</title>
      <dc:creator>Olabowale Babalola Israel</dc:creator>
      <pubDate>Mon, 12 Oct 2026 00:18:32 +0000</pubDate>
      <link>https://dev.to/esimuda/name-it-then-look-up-a-field-guide-where-the-phones-job-ends-after-one-photo-3bbi</link>
      <guid>https://dev.to/esimuda/name-it-then-look-up-a-field-guide-where-the-phones-job-ends-after-one-photo-3bbi</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;p&gt;Most nature apps have the same quiet problem. You see a bird, you lift your phone, and by the time the app has told you its name, the bird has gone and you're still reading about it.&lt;/p&gt;

&lt;p&gt;I wanted the opposite. In Spotted, getting the name is the quick bit. Then the app asks for something harder: put the phone down for one minute and actually look at the thing.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Spotted&lt;/strong&gt; is a pocket field guide that runs on your phone, in the browser. You take or upload one photo of a bird, lizard, insect, tree or plant. An open model suggests a name from the field guide. Then a button called &lt;strong&gt;Look up&lt;/strong&gt; asks a second open model, Gemma, for &lt;em&gt;one&lt;/em&gt; thing to notice. The screen dims to a 60-second timer. When the minute ends there's a soft chime and one question: &lt;strong&gt;What did you notice?&lt;/strong&gt; Your answer is saved into the sighting.&lt;/p&gt;

&lt;p&gt;That minute is the whole point. The name, the facts, the feed, the map: all of that is there to get you to the minute and then get out of the way.&lt;/p&gt;

&lt;p&gt;A few details I cared about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It admits when it doesn't know.&lt;/strong&gt; If the top match scores under 0.12, or is less than 0.04 ahead of the runner-up, Spotted doesn't name anything. It says &lt;strong&gt;Not in my guide yet&lt;/strong&gt;, shows the closest two or three as "maybes", and lets you save the sighting under your own label. A confident wrong name is worse than no name, especially for someone just starting to learn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The guide is local.&lt;/strong&gt; It has 114 species. Many are things you actually meet in West African compounds, streets and parks: pied crows, laughing doves, rainbow agamas, neem, flamboyant, bitter leaf, the village weaver. It also keeps some familiar species from elsewhere so it isn't lost on another continent. Habitat, diet, behaviour and conservation status are written into the app, and every species links to the source of those facts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rare animals don't get exact pins.&lt;/strong&gt; Sharing a location is off until you turn it on. Threatened species, plus a few timber trees marked sensitive, are rounded to a cell about 11 km across &lt;em&gt;before&lt;/em&gt; anything reaches the server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It works offline.&lt;/strong&gt; Once the models are cached, naming and Look up run without signal. Notes you save offline wait on the phone and sync later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A small social trail.&lt;/strong&gt; There's a feed, comments, reactions ("wonder", "seen it", "protect"), a map and a life list, so a sighting can be shared. It's deliberately light, though. Comments appear straight away, and then there's nothing to scroll.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's for anyone who has wondered "what &lt;em&gt;is&lt;/em&gt; that?" about a bird on a fence or a lizard on a wall, and wants an answer that ends with them looking up instead of down.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Live app:&lt;/strong&gt; &lt;a href="https://spotted-91b2.onrender.com" rel="noopener noreferrer"&gt;https://spotted-91b2.onrender.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's on Render's free plan, so if nobody has visited for a while the first load takes about a minute to wake up. After that it's quick.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/vu_tGydYkGI" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The video is real footage of the live site in a phone-sized browser. The model download, Gemma's thinking time and the 60-second timer are sped up, and labelled as sped up on screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it in 60 seconds:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the app and tap &lt;strong&gt;Open the field&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Tap a reference photo (the pied kingfisher is a clear one), or upload your own.&lt;/li&gt;
&lt;li&gt;On the result, press &lt;strong&gt;Look up&lt;/strong&gt;. The first time, Gemma downloads into your browser (about 308 MB, so use Wi-Fi). Then the screen dims and gives you one thing to notice.&lt;/li&gt;
&lt;li&gt;When the minute ends, or when you tap &lt;strong&gt;I looked&lt;/strong&gt;, answer &lt;strong&gt;What did you notice?&lt;/strong&gt; and save the note.&lt;/li&gt;
&lt;/ol&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/Esimuda" rel="noopener noreferrer"&gt;
        Esimuda
      &lt;/a&gt; / &lt;a href="https://github.com/Esimuda/spotted" rel="noopener noreferrer"&gt;
        spotted
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Spotted: snap nature, an open-weight model names it, share it with your community
    &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;Spotted&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;See nature. Share it. You photograph a bird, animal, insect, or plant. An open model suggests the name. Then you share the sighting, or you just look up again.&lt;/p&gt;
&lt;p&gt;The product name is one constant, &lt;code&gt;APP_NAME&lt;/code&gt; in &lt;a href="https://github.com/Esimuda/spotted/src/config/brand.ts" rel="noopener noreferrer"&gt;&lt;code&gt;src/config/brand.ts&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The demo trail is fictional and West African: Lekki Conservation Centre, Okomu National Park, Obudu Mountain Resort, and Yankari Game Reserve. The guide also includes species from elsewhere, so a walk outside Nigeria still gets a name. Reference photos are credited in &lt;a href="https://github.com/Esimuda/spotted/public/seed/credits.json" rel="noopener noreferrer"&gt;&lt;code&gt;public/seed/credits.json&lt;/code&gt;&lt;/a&gt;. The people in the feed are not real.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Verify in 60 seconds&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Live app: &lt;a href="https://spotted-91b2.onrender.com" rel="nofollow noopener noreferrer"&gt;https://spotted-91b2.onrender.com&lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the field tab and run a reference photo (pied kingfisher is a clear one).&lt;/li&gt;
&lt;li&gt;On the result, press &lt;strong&gt;Look up&lt;/strong&gt;. The first time, Gemma 3 270M downloads in the browser. The screen then dims to a 60-second timer and one thing to notice.&lt;/li&gt;
&lt;li&gt;When the minute ends, or when…&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/Esimuda/spotted" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;MIT licensed. If you want to look at the interesting parts first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/lib/identify/rank.ts     the "not sure" rule
src/lib/identify/look.ts     Gemma in the browser: one thing to notice
src/components/look-up.tsx   the dimmed minute, the chime and the question
src/data/more-species.ts     the West African additions to the guide
src/lib/privacy.ts           opt-in pins, softened cells for sensitive species
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Spotted is a Next.js PWA with a small SQLite-backed API for the trail. The two jobs that need AI both run on open models in the browser through &lt;a href="https://github.com/huggingface/transformers.js" rel="noopener noreferrer"&gt;Transformers.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Naming: CLIP ViT-B/32.&lt;/strong&gt; I use &lt;code&gt;Xenova/clip-vit-base-patch32&lt;/code&gt; (MIT), an 8-bit ONNX build of OpenAI's CLIP, as a zero-shot classifier. Every species in the guide becomes a text prompt. The photo is compared with all of them, and the scores are a softmax across the whole guide. The guide works as an allow-list: CLIP can only answer with a species that has written facts behind it, so it can't invent an animal.&lt;/p&gt;

&lt;p&gt;The scores are spread across 114 options, so the numbers look modest. On my reference pied kingfisher photo, the top match was pied kingfisher at 25%, with the next name at 10%. That lead is what the rule in &lt;code&gt;rank.ts&lt;/code&gt; checks for. Below 0.12, or with a gap under 0.04, you get maybes instead of a name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Look up: Gemma 3 270M.&lt;/strong&gt; This is the heart of the app. When you press Look up, the page loads &lt;code&gt;onnx-community/gemma-3-270m-it-ONNX&lt;/code&gt; and runs it right there in the browser: WebGPU with the &lt;code&gt;q4f16&lt;/code&gt; build where it's available, and WASM with &lt;code&gt;q4&lt;/code&gt; where it isn't. Getting the official weights to run on the WASM runtime took one small change. A gather index in the graph needed casting to int32, and that patched graph ships in &lt;code&gt;public/models/gemma&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Gemma's job here is narrow on purpose. It gets the species name and the guide's behaviour sentence, and has to answer in one sentence that starts with "Watch". For the pied kingfisher, the sentence it gave on my test run was &lt;em&gt;"Watch it hunt this way."&lt;/em&gt; Simple, and it points you at the right thing, because pied kingfishers hover over the water before they dive. If Gemma's answer is the wrong shape, or the phone can't run it, the app falls back to the guide's own behaviour line and labels it &lt;strong&gt;Field guide&lt;/strong&gt;. The minute still happens either way.&lt;/p&gt;

&lt;p&gt;I kept Gemma away from the facts deliberately. A 270M-parameter model is small enough to run on a phone, and too small to trust with a conservation status. So the facts come from the guide and its sources, and Gemma only gives the nudge.&lt;/p&gt;

&lt;p&gt;Some real numbers from testing:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What&lt;/th&gt;
&lt;th&gt;Measured&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gemma download, first time only&lt;/td&gt;
&lt;td&gt;about 308 MB, then cached&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma load from cache (WASM, q4)&lt;/td&gt;
&lt;td&gt;1,679 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gemma generating the one sentence (WASM)&lt;/td&gt;
&lt;td&gt;about 20 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLIP naming a photo once cached&lt;/td&gt;
&lt;td&gt;about 7 s in a headless phone-sized browser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Render free instance waking from sleep&lt;/td&gt;
&lt;td&gt;about 55 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;About 20 seconds for one sentence on WASM is slow, so the app shows a calm "Finding one thing" screen while it works. I decided that was an acceptable trade for now: a short wait in exchange for a full minute of looking up, with nothing leaving the phone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where it gets things wrong.&lt;/strong&gt; Here's what I saw testing with Creative Commons photos at my desk:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pied kingfisher: named correctly.&lt;/li&gt;
&lt;li&gt;A giant land snail, which isn't in the guide: &lt;strong&gt;Not in my guide yet&lt;/strong&gt;, with gecko, sun squirrel and Nile monitor as low maybes. That's the behaviour I wanted.&lt;/li&gt;
&lt;li&gt;Village weavers: the weak spot. One male came back as "Looks like little bee-eater", another as "not sure", and a nest-building male as yellow-billed kite. General-purpose CLIP doesn't know African weavers well.&lt;/li&gt;
&lt;li&gt;A termite mound: called an African forest elephant at 35%, which is funny and wrong. Big brown shape in a field.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's why the "not sure" state exists and why "Looks like" is worded more softly than "This looks like". It's also why the next item below is a better vision model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hosting.&lt;/strong&gt; The app runs on Render's free web service from a &lt;code&gt;render.yaml&lt;/code&gt; blueprint, with a cheap &lt;code&gt;/api/health&lt;/code&gt; check. The free instance has about 512 MB of RAM, which isn't enough to host CLIP and Gemma on the server, and I like that constraint. It pushes the AI onto the phone, which is where it should be for something you use outdoors. Render serves the app, the trail and the model files. The visitor's phone does the thinking.&lt;/p&gt;

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

&lt;p&gt;For this project, the closed version would have been a worse product, not just a more expensive one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No signal, still works.&lt;/strong&gt; The places worth looking up are often the places where the signal drops. Once the open weights are cached, CLIP still names things and Gemma still finds you something to notice, with no network at all. A closed API stops working right where the walk starts getting good.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The photo stays on the phone.&lt;/strong&gt; Naming doesn't need your picture to leave your device. For a rare animal, a photo plus GPS is a map to it. Open models running locally, plus the softened pins, mean that data doesn't have to sit on someone else's server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No meter on curiosity.&lt;/strong&gt; There's no bill for each name. A community trail that charges per question is a trail that teaches people to ask fewer questions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I could change the model.&lt;/strong&gt; When Gemma's WASM run failed on an index type, I could open the graph and fix it. When CLIP turned out to be weak on weavers, I could see why, and I know exactly what replaces it: &lt;a href="https://huggingface.co/imageomics/bioclip" rel="noopener noreferrer"&gt;BioCLIP&lt;/a&gt; (MIT), a CLIP trained on the tree of life. The guide is just a list of prompts, so a better open model means swapping a file, not signing a new vendor contract.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;To be straight about where it stands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A proper walk.&lt;/strong&gt; I've tested Spotted at my desk with reference photos, not yet on a real walk with my own pictures. That's the next thing, and it'll show whether 114 species is enough for a Benin City street or a Lagos compound.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BioCLIP.&lt;/strong&gt; It's the specialist model I wanted from the start. It isn't bundled because there's no Transformers.js ONNX export of its weights yet. Once there is one, it replaces CLIP and the weaver problem should mostly go away.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More of the guide.&lt;/strong&gt; More West African birds, insects and trees, with sources, and local names next to the English ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Look up on older phones.&lt;/strong&gt; Twenty seconds on WASM is too long. I want to try a shorter prompt and streaming the first words as they come.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Credits and licences
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Code: MIT, &lt;a href="https://github.com/Esimuda/spotted" rel="noopener noreferrer"&gt;https://github.com/Esimuda/spotted&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CLIP ViT-B/32 via &lt;code&gt;Xenova/clip-vit-base-patch32&lt;/code&gt;: MIT&lt;/li&gt;
&lt;li&gt;Gemma 3 270M Instruct via &lt;code&gt;onnx-community/gemma-3-270m-it-ONNX&lt;/code&gt;: &lt;a href="https://ai.google.dev/gemma/terms" rel="noopener noreferrer"&gt;Gemma Terms of Use&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Transformers.js (&lt;code&gt;@huggingface/transformers&lt;/code&gt;): Apache-2.0&lt;/li&gt;
&lt;li&gt;Reference photos in the app: Wikimedia Commons, each credited in &lt;code&gt;public/seed/credits.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Photos in the demo video: "Pied kingfisher (Ceryle rudis rudis) male" and "Giant tiger land snail (Achatina achatina) Ghana", both by Charles J. Sharp, CC BY-SA 4.0, via Wikimedia Commons&lt;/li&gt;
&lt;li&gt;Map data: © OpenStreetMap contributors&lt;/li&gt;
&lt;li&gt;The people on the demo trail are fictional. Their photos are openly licensed reference images, not their own.&lt;/li&gt;
&lt;/ul&gt;

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