<?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: Vaibhav Agrawal</title>
    <description>The latest articles on DEV Community by Vaibhav Agrawal (@vaibhav_agrawal_562).</description>
    <link>https://dev.to/vaibhav_agrawal_562</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%2F4163101%2F4c54b8e9-57d5-4fd9-a69c-64094ec907de.png</url>
      <title>DEV Community: Vaibhav Agrawal</title>
      <link>https://dev.to/vaibhav_agrawal_562</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vaibhav_agrawal_562"/>
    <language>en</language>
    <item>
      <title>Touch Grass Birder: On-Device Bird ID in the Browser with Open-Weight AI</title>
      <dc:creator>Vaibhav Agrawal</dc:creator>
      <pubDate>Sat, 10 Oct 2026 15:54:50 +0000</pubDate>
      <link>https://dev.to/vaibhav_agrawal_562/touch-grass-birder-on-device-bird-id-in-the-browser-with-open-weight-ai-355f</link>
      <guid>https://dev.to/vaibhav_agrawal_562/touch-grass-birder-on-device-bird-id-in-the-browser-with-open-weight-ai-355f</guid>
      <description>&lt;ul&gt;
&lt;li&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;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Touch Grass Birder is an offline, on-device bird call identifier that runs entirely in your browser. Record 6 seconds of a bird call, get a species ID in seconds, then put your phone away and go find the bird.&lt;/p&gt;

&lt;p&gt;It identifies 6,522 species using the BirdNET v2.4 open model, running locally on your device via ONNX Runtime WebAssembly. There is no server, no API key, and no internet required after the first load.&lt;/p&gt;

&lt;p&gt;It's for anyone who's ever heard a bird on a trail, pulled out their phone, and realized their bird ID app doesn't work — because it needs a server round trip, and there's no signal where the birds actually are.&lt;/p&gt;

&lt;p&gt;The whole design is built around minimizing screen time. The user taps "Record 6 seconds," sees the result, and is told to pocket their phone and go find the bird. The screen is the shortest part of the experience.&lt;/p&gt;

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

&lt;p&gt;Live app: &lt;a href="https://hacktoberfest-week1-challenge.vercel.app/" rel="noopener noreferrer"&gt;https://hacktoberfest-week1-challenge.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/competitive-programmer04/_hacktoberfest_week1_challenge" rel="noopener noreferrer"&gt;https://github.com/competitive-programmer04/_hacktoberfest_week1_challenge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With network — first-time setup:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ql2b567t8tuqaiq3d8s.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ql2b567t8tuqaiq3d8s.jpeg" alt="With internet connection only for the first time" width="720" height="1399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Airplane mode. No network. Still identifying birds.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3on6sthh9iedjdi4uv2p.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3on6sthh9iedjdi4uv2p.jpeg" alt="Without internet connection for each subsequent request after the very first request but the bird's photo will not download because I am fetching it from iNaturalist page" width="720" height="1399"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Repo: &lt;a href="https://github.com/competitive-programmer04/_hacktoberfest_week1_challenge" rel="noopener noreferrer"&gt;https://github.com/competitive-programmer04/_hacktoberfest_week1_challenge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Key files:&lt;/p&gt;

&lt;p&gt;frontend/src/audio.js — resampling and 3-second chunking with 1.5s overlap&lt;/p&gt;

&lt;p&gt;frontend/src/inference-worker.js — ONNX Runtime WebAssembly session, sigmoid post-processing&lt;/p&gt;

&lt;p&gt;frontend/src/model.js — model download, Cache Storage, and worker orchestration&lt;/p&gt;

&lt;p&gt;frontend/src/pages/Record.jsx — the recording UX and result display&lt;/p&gt;

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

&lt;p&gt;The entire stack is open-source. This project uses an open-weight model, an open-source inference framework, and local inference.&lt;/p&gt;

&lt;p&gt;The stack:&lt;/p&gt;

&lt;p&gt;BirdNET v2.4 — an open acoustic classifier from the Cornell Lab of Ornithology. 6,522 species, open weights, trained on real-world field recordings. I used the INT8 ARM variant (converted by tphakala) — ~47 MB, optimized for mobile CPUs.&lt;/p&gt;

&lt;p&gt;ONNX Runtime Web — the open-source inference engine. Runs the model via WebAssembly directly in the browser, no installation, no backend.&lt;/p&gt;

&lt;p&gt;React + Vite — the frontend.&lt;/p&gt;

&lt;p&gt;vite-plugin-pwa — makes the app installable and offline-capable.&lt;/p&gt;

&lt;p&gt;The pipeline:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Record 6 seconds via MediaRecorder, producing a WebM/Opus blob.

Decode and resample to 48 kHz using the Web Audio API.

Chunk into 3-second windows with 1.5-second overlap.

Send each chunk to a Web Worker running ONNX Runtime WebAssembly.

Run inference — the model outputs logits for 6,522 species.

Apply sigmoid to convert logits to confidence scores.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Sort and filter — top match plus alternatives, with a low-confidence fallback if nothing scores above 25%.&lt;/p&gt;

&lt;p&gt;The caching strategy: the service worker precaches the app shell and the ONNX Runtime WASM files. The 47 MB BirdNET model is downloaded from Hugging Face on first load and cached in the browser's Cache Storage by model.js. After first load, every subsequent visit serves everything from disk — no network required.&lt;/p&gt;

&lt;p&gt;A few things I had to learn the hard way:&lt;/p&gt;

&lt;p&gt;PWAs can't run a Python backend. My first version was FastAPI + Python BirdNET. It worked, but it required a laptop nearby. If the model doesn't run on the phone, "offline" is marketing, not engineering. Porting to ONNX Runtime Web meant rewriting the entire inference pipeline in JavaScript.&lt;/p&gt;

&lt;p&gt;The ONNX Runtime WASM file is 14 MB, not the 3 MB I assumed. Workbox's default precache limit is 2 MiB, so the build failed until I raised maximumFileSizeToCacheInBytes.&lt;/p&gt;

&lt;p&gt;BirdNET uses sigmoid, not softmax. It's a multi-label classifier — multiple species can be present simultaneously. I initially used softmax and got nonsensical confidence scores.&lt;/p&gt;

&lt;p&gt;Threaded WASM requires SharedArrayBuffer, which needs COOP/COEP headers. Single-threaded WASM is slower but works everywhere without special server config, and it's fast enough for a 3-second chunk.&lt;/p&gt;

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

&lt;p&gt;This project literally would not exist without open-source AI.&lt;/p&gt;

&lt;p&gt;Offline is only possible with open weights. A closed bird ID API requires a network round trip. The best places to hear birds — deep forest, high alpine, remote wetland — are exactly where that round trip fails. Only an open-weight model can be downloaded to the device and run locally. This isn't a nice-to-have; it's the entire premise.&lt;/p&gt;

&lt;p&gt;Privacy by architecture, not policy. A rare sighting is sensitive. It reveals where you were, when you were there, and what you saw. With a closed API, that data goes to a company server. With BirdNET running on-device, the audio never leaves your phone. Not because of a privacy policy because there is no server to send it to.&lt;/p&gt;

&lt;p&gt;Zero marginal cost. No API bills, no rate limits, no monthly fees. A free public tool is only viable when the marginal cost of one more user is zero. With open weights, it is.&lt;/p&gt;

&lt;p&gt;Portability and no lock-in. The same BirdNET model runs on Python, Node.js, a Raspberry Pi, and — as here — in the browser via ONNX Runtime. If a better runtime appears tomorrow, you swap it in without retraining. No vendor owns your pipeline.&lt;/p&gt;

&lt;p&gt;Inspectable and modifiable. Anyone can inspect the model, fine-tune it on local species, or replace it with a different classifier. A closed system gives you a black box and a rate limit. This gives you a file and a license.&lt;/p&gt;

&lt;p&gt;The challenge asked for open innovation, and the honest answer is that the open pieces aren't a bonus feature bolted onto a closed core. They are the product.&lt;/p&gt;

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