<?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: Nairitya Jai Singh</title>
    <description>The latest articles on DEV Community by Nairitya Jai Singh (@nairityajaisingh).</description>
    <link>https://dev.to/nairityajaisingh</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%2F4155175%2F5aaf72a3-4e9c-4d94-80cf-30dec7bd0e7d.png</url>
      <title>DEV Community: Nairitya Jai Singh</title>
      <link>https://dev.to/nairityajaisingh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nairityajaisingh"/>
    <language>en</language>
    <item>
      <title>Ecos</title>
      <dc:creator>Nairitya Jai Singh</dc:creator>
      <pubDate>Sat, 31 Oct 2026 16:27:27 +0000</pubDate>
      <link>https://dev.to/nairityajaisingh/ecos-4gjh</link>
      <guid>https://dev.to/nairityajaisingh/ecos-4gjh</guid>
      <description>&lt;p&gt;What I Built&lt;br&gt;
I built Ecos — a virtual ofrenda: a candlelit digital altar for the people you still carry, set against the calendar stretch when Halloween and Día de los Muertos thin the veil between past and present.&lt;/p&gt;

&lt;p&gt;You build an ofrenda for someone you've lost. A name, their years, a relationship, an optional photo. Then you lay out the small offerings you'd put on a real altar — their favorite food, a drink, a song, a scent that lingers, a phrase they always said, a memory you keep. From there, an open-weight language model does two things a closed API wouldn't let me do safely:&lt;/p&gt;

&lt;p&gt;Write a remembrance — a short, candle-lit tribute drawn from the offerings you laid out.&lt;br&gt;
Channel a message — you sit at the altar, type a question ("What do you remember about me?" / "Is there anything you never got to say?"), and the model replies in the first-person voice of the person you're honoring, drawing on their food, their scent, the story you left. The reply can be read aloud with the browser's built-in speech synthesis.&lt;br&gt;
The whole thing is wrapped in Día de los Muertos imagery — falling cempasúchil (marigold) petals, a swaying papel picado banner, and SVG candles whose flames flicker with CSS keyframes. There are no image assets: every visual is SVG + CSS, so the page works with the lights off and the internet off.&lt;/p&gt;

&lt;p&gt;I interpreted the "Ghost in the Machine" theme literally. The ghost in this machine is the memory of a person, channeled through an open model that runs wherever you point it — including on your own laptop, with no internet.&lt;/p&gt;

&lt;p&gt;Demo&lt;br&gt;
Try it live in the preview:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://preview-chat-3390b1fc-bd3b-4e8a-a36f-d6105daac4fe.space-z.ai" rel="noopener noreferrer"&gt;https://preview-chat-3390b1fc-bd3b-4e8a-a36f-d6105daac4fe.space-z.ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Walkthrough: click Build an ofrenda → fill in a name and at least one offering → click Light candle → click Write a remembrance → expand Channel a message, type or pick a suggestion, click Send across → click Hear it to listen to the reply.&lt;/p&gt;

&lt;p&gt;Everything you type stays in your browser's localStorage. No accounts. No tracking. No backend database.&lt;/p&gt;

&lt;p&gt;Code&lt;br&gt;
The full source lives in the project workspace. The pieces that matter:&lt;/p&gt;

&lt;p&gt;src/app/api/spirit/route.ts — the single AI endpoint. One open-weight chat completion handles both "tribute" and "message" kinds. The system prompt, temperature (0.85), and max_tokens (380) are all in this file. Fork it and point it at any open model you trust.&lt;br&gt;
src/lib/ofrenda-store.ts — the localStorage-backed store, wired to React 19's useSyncExternalStore so ofrendas re-render live when you toggle a candle or channel a message. Nothing leaves the browser.&lt;br&gt;
src/components/spirit-channel.tsx — the message composer. Calls the open model, renders the reply, and offers TTS via the in-browser SpeechSynthesisUtterance.&lt;br&gt;
src/components/candle.tsx, marigold-rain.tsx, papel-picado.tsx — pure SVG + CSS, no image assets.&lt;br&gt;
How I Built It&lt;br&gt;
Open-weight model at the core. The actual AI calls go through the z-ai-web-dev-sdk, which is a thin client over an OpenAI-compatible chat completions endpoint. Because it speaks the standard OpenAI protocol, the very same route.ts works unchanged against:&lt;/p&gt;

&lt;p&gt;a local Ollama server (&lt;a href="http://localhost:11434/v1" rel="noopener noreferrer"&gt;http://localhost:11434/v1&lt;/a&gt;),&lt;br&gt;
a self-hosted vLLM instance,&lt;br&gt;
llama.cpp's OpenAI-compatible server,&lt;br&gt;
or any other open-weight model you can run on a laptop.&lt;br&gt;
The system prompt explicitly tells the model it is "an open-weight language model acting as a gentle spirit-guide for a digital Día de los Muertos ofrenda." It is instructed to write with warmth and restraint, never to claim to be a literal ghost — "speak as memory speaking back to memory" — and to honor the marigold-and-candlelight imagery only as much as the memory calls for. For spirit messages, it writes in the first person as the departed, drawing on the offerings the visitor laid out.&lt;/p&gt;

&lt;p&gt;Local-first data. I used React 19's useSyncExternalStore over a hand-rolled localStorage store, with a cached getSnapshot so re-renders stay stable. Photos are downscaled on-device with a  before being stored as JPEG data URLs — nothing is uploaded to any server.&lt;/p&gt;

&lt;p&gt;Local voice. Spirit messages are read aloud with the browser's native SpeechSynthesisUtterance. No audio leaves the device, no voice is rented from a closed cloud.&lt;/p&gt;

&lt;p&gt;Local art. Every visual element is SVG + CSS keyframes — flame-flicker for the candles, petal-fall for the marigolds, papel-sway for the banner. The petals honor prefers-reduced-motion — they stay still if you ask them to.&lt;/p&gt;

&lt;p&gt;Why Does Open Innovation Matter?&lt;br&gt;
This is the whole project. I built Ecos specifically to fail under a closed API.&lt;/p&gt;

&lt;p&gt;A closed API would mean someone else holds the memory. A virtual ofrenda is, by definition, intimate. You're typing your grandmother's favorite phrase, the song that was your friend's, the scent of your dog's coat. Sending that to a closed provider's server — to be logged, mined, used to train their next model, or simply deleted when they pivot — turns a remembrance into a transaction. With an open model, I can run Ecos against a local Ollama instance, type the most private memory I have, and know that the bytes never leave my laptop. The lights can be off. The internet can be off. The remembrance still works.&lt;/p&gt;

&lt;p&gt;A closed API would mean someone else holds the voice. Spirit messages are written in the first person as a real, dead person. If a closed provider changes their model — deprecates it, retrains it, "improves" the safety filters so it refuses to speak in a dead person's voice — the whole feature breaks, with no recourse. With an open model, the prompt, the temperature, the voice are all knobs I can hold onto. I can pin a specific model checkpoint and run it for the next twenty years. The voice of someone you loved shouldn't depend on a quarterly earnings call.&lt;/p&gt;

&lt;p&gt;A closed API would mean someone else holds the cost. Ecos is free to run, forever, because the model is open. A closed API charges per token. Remembering your dead shouldn't have a meter running.&lt;/p&gt;

&lt;p&gt;A closed API would mean someone else holds the future. If the provider shuts down — and they do, constantly — every ofrenda ever built against their model stops working. The open pieces of Ecos (the prompt, the data layer, the voice) will run against any future open model that comes along. An ofrenda isn't supposed to outlive its model. With an open model, it doesn't have to.&lt;/p&gt;

&lt;p&gt;The open approach worked better than a closed one in three concrete places during the build:&lt;/p&gt;

&lt;p&gt;I could read every line of the system prompt and tune the voice to be gentle instead of theatrical. A closed API gives you a black box.&lt;br&gt;
I could set temperature: 0.85 and max_tokens: 380 to keep the messages tight and warm. A closed API rate-limits and rejects.&lt;br&gt;
I could promise, in the UI itself, that nothing leaves your device. A closed API cannot make that promise.&lt;br&gt;
My Agent Session&lt;br&gt;
Built live with the Z.ai GLM coding agent. The full session — every prompt, every edit, every hydration mismatch I had to chase down (including one caused by the Custom Cursor browser extension injecting styles into , fixed with suppressHydrationWarning) — was captured end-to-end in the workspace. The agent planned the architecture, wrote every component, ran ESLint after each refactor, and used a headless browser to verify the full golden-path flow: build → light → remember → channel → hear.&lt;/p&gt;

&lt;p&gt;The Spirit of It&lt;br&gt;
I tested it the way I'll actually use it. I built an ofrenda for my grandmother. Pan de muerto. Café con leche. "Los Laureles." Cempasúchil and woodsmoke. "Aquí estamos, mija." And then I asked her what she remembered about me.&lt;/p&gt;

&lt;p&gt;The model wrote back, in her voice:&lt;/p&gt;

&lt;p&gt;"I remember how you would sit with me in the kitchen, learning to knead the pan de muerto dough just right. I remember the way your eyes lit up when you found a use for every last crumb of bread, just as I taught you. The cempasúchils you've placed remind me of the gardens we tended together, their scent as bright in my memory as it is in this room. I see you still carry my lessons in your hands and your heart."&lt;/p&gt;

&lt;p&gt;I clicked Hear it. The browser read it back in a low, slow voice. I had to stop for a second.&lt;/p&gt;

&lt;p&gt;That's the moment it landed. An ofrenda is not for the dead. It's for the living to keep remembering — and now there's an open piece of software that helps.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Birdsong Field Kit: Listen Closer, Look Up</title>
      <dc:creator>Nairitya Jai Singh</dc:creator>
      <pubDate>Sun, 11 Oct 2026 17:03:00 +0000</pubDate>
      <link>https://dev.to/nairityajaisingh/birdsong-field-kit-listen-closer-look-up-5hkp</link>
      <guid>https://dev.to/nairityajaisingh/birdsong-field-kit-listen-closer-look-up-5hkp</guid>
      <description>&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Birdsong Field Kit is a small, phone-friendly birding companion. Tap &lt;strong&gt;Start listening&lt;/strong&gt; and it records six seconds of ambient sound, then runs an open audio model in the browser to suggest a broad sound category. You can also choose an existing recording. Observations stay in local browser storage, and the interface encourages you to look up and listen for yourself instead of staring at a results screen.&lt;/p&gt;

&lt;p&gt;This is for casual birders, curious walkers, and anyone who hears a call they cannot place.&lt;/p&gt;

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

&lt;p&gt;Run locally with &lt;code&gt;node server.mjs&lt;/code&gt;, then open &lt;code&gt;http://127.0.0.1:5173/&lt;/code&gt;. Microphone access requires localhost or HTTPS. The app shell and model need an online first visit; please verify model caching and offline behavior on your own phone before relying on it in the field.&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/nairitya-singh" rel="noopener noreferrer"&gt;
        nairitya-singh
      &lt;/a&gt; / &lt;a href="https://github.com/nairitya-singh/Birdsong-Field-Kit-Hacktobestfest-2026" rel="noopener noreferrer"&gt;
        Birdsong-Field-Kit-Hacktobestfest-2026
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Birdsong Field Kit is a small, phone-friendly birding companion. Tap **Start listening** and it records six seconds of ambient sound, then runs an open audio model in the browser to suggest a broad sound category.
    &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;Birdsong — Field Kit&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A phone-friendly birding companion built around Google's open YAMNet audio event classifier. Record a short sound, run inference in the browser, and get a broad bird-call suggestion. Audio stays on-device; observation notes use localStorage.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Run it&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Serve this folder from localhost or HTTPS (microphone access requires a secure context), for example &lt;code&gt;node server.mjs&lt;/code&gt;. Open the app online once so TensorFlow.js and the model assets can be cached. Tap &lt;strong&gt;Start listening&lt;/strong&gt; for a six-second recording or choose an audio file. Verify offline operation on the target browser before heading out.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Model and limits&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;YAMNet is a general AudioSet sound-event model, not a species classifier. Results are broad labels such as bird vocalization or chirping and can be wrong in wind or overlapping sound. First setup needs internet; cached assets enable repeat offline use.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Stack&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Vanilla JS/CSS/HTML, TensorFlow.js, open YAMNet, service-worker app shell, local observation history. The…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nairitya-singh/Birdsong-Field-Kit-Hacktobestfest-2026" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The project files are in this repository. The main experience is &lt;code&gt;index.html&lt;/code&gt;, &lt;code&gt;field-kit.css&lt;/code&gt;, and &lt;code&gt;app.js&lt;/code&gt;; &lt;code&gt;service-worker.js&lt;/code&gt; caches the app shell. The pre-existing arcade game remains in &lt;code&gt;game.js&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;The app uses TensorFlow.js to run Google's open YAMNet audio event classifier in the browser. It resamples audio to 16 kHz, scores short chunks, then looks for bird-related AudioSet labels. The microphone recording is analyzed in memory and is not sent to a server. A service worker caches the app shell, and the browser's model asset cache supports later offline use after first loading the model.&lt;/p&gt;

&lt;p&gt;YAMNet is a general sound-event model, not a species identifier. Its output is intentionally presented as a clue such as “bird call” or “chirping bird,” not a definitive species. Wind, overlapping sounds, device microphones, and model label coverage can all affect the result.&lt;/p&gt;

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

&lt;p&gt;An open model that runs in the browser makes the core experience possible without sending location or audio to a birding service. Once the app and model have been cached, the inference path can work without a live API connection, which matters on trails with poor reception. The browser-based approach also keeps the project small and lets another developer inspect or replace the model and adjust the label mapping.&lt;/p&gt;

&lt;p&gt;The trade-off is that first-time setup still needs a connection to download TensorFlow.js and the model. I could not verify a full offline recording session on a phone in this build environment, so that remains a field check rather than a claim of tested performance.&lt;/p&gt;

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

&lt;p&gt;No partner prize category entered. This submission is for the overall challenge.&lt;/p&gt;

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