<?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: Abisoye O</title>
    <description>The latest articles on DEV Community by Abisoye O (@abisoye).</description>
    <link>https://dev.to/abisoye</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F99mvlsfu5tfj9m7ku25d.png</url>
      <title>DEV Community: Abisoye O</title>
      <link>https://dev.to/abisoye</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abisoye"/>
    <language>en</language>
    <item>
      <title>Hidden Objects: an escape room where the narrator would rather you stayed</title>
      <dc:creator>Abisoye O</dc:creator>
      <pubDate>Sun, 01 Nov 2026 05:50:25 +0000</pubDate>
      <link>https://dev.to/abisoye/hidden-objects-an-escape-room-where-the-narrator-would-rather-you-stayed-5a65</link>
      <guid>https://dev.to/abisoye/hidden-objects-an-escape-room-where-the-narrator-would-rather-you-stayed-5a65</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week4-2026-10-26"&gt;Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I locked you in. The key gets you out, but you don't have it yet."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's the first thing the narrator says. It doesn't shout, and it doesn't rush you. It would just rather you stayed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Play it at &lt;a href="https://hiddenobjects.tech" rel="noopener noreferrer"&gt;hiddenobjects.tech&lt;/a&gt;&lt;/strong&gt;, with your sound on.&lt;/p&gt;

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

&lt;p&gt;If you've used Blender, Maya, or Unity, you know the &lt;strong&gt;outliner&lt;/strong&gt;: the panel that lists every object in a scene. Hidden Objects turns it into a puzzle.&lt;/p&gt;

&lt;p&gt;The room is drawn with pieces missing. The narrator gives you eight riddles, each describing an object that isn't in the picture. Click the matching name in the outliner, and the object appears and the next riddle begins. The last name is the &lt;strong&gt;key&lt;/strong&gt;, and the key opens the door.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A wrong name costs 25 points.&lt;/strong&gt; Three wrong names and the door stays shut.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;There's no countdown.&lt;/strong&gt; Riddles are better when you have time to think.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The eye icons can't cheat.&lt;/strong&gt; An object you haven't found yet stays hidden.&lt;/li&gt;
&lt;/ul&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%2Fjy6tts0mtfojv2c1wntu.png" 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%2Fjy6tts0mtfojv2c1wntu.png" alt="The intro screen. The narrator explains the rules before you enter the room." width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;Ghost in the Machine&lt;/strong&gt;, the ghost is the narrator: a voice living inside a scene file that has hidden your things. The objects are ordinary on purpose (a clock, a mirror, a vase, a lamp, a stool, a plant, a frame, and the key), and a pumpkin, a candle, and fairy lights dress the room for Halloween. Every line is written with younger players in mind. Miss a riddle, and you'll hear &lt;em&gt;"Wrong. I'm not in a rush."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the open-weight Gemma model comes in
&lt;/h2&gt;

&lt;p&gt;The narrator runs on &lt;strong&gt;&lt;a href="https://ai.google.dev/gemma" rel="noopener noreferrer"&gt;Gemma&lt;/a&gt;&lt;/strong&gt;, Google's family of &lt;strong&gt;open-weight&lt;/strong&gt; models, so anyone can run it themselves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;On the live site:&lt;/strong&gt; Gemma 4 31B (&lt;code&gt;gemma-4-31B-it&lt;/code&gt;) on &lt;strong&gt;DigitalOcean serverless inference&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On your own machine:&lt;/strong&gt; Gemma 3 4B (&lt;code&gt;gemma3:4b&lt;/code&gt;) through &lt;strong&gt;Ollama&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both get the same prompts and the same checks. Gemma has two jobs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Choosing what you look for next.&lt;/strong&gt; Before each riddle, the server tells Gemma which objects are still hidden, which you've found, and how many times you've missed. Gemma replies with the next object and a mood for the room's lighting. A real reply from the live site, in under a second:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mirror"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"mood"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"still"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"line"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"I see myself."&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The game only accepts an object that is &lt;strong&gt;still hidden&lt;/strong&gt;. A late or invalid reply falls back to my written order, so the game never waits on the model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Making the narrator sound different every play.&lt;/strong&gt; I wrote every riddle and line. Before one is spoken, Gemma rewrites it with the same meaning in new words, so a second play doesn't sound like a recording. From a local run, my line:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Mirror's up. Look once, then look away. The way out isn't on the other side."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;became:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"It's just the reflection, dear. Watch it carefully, then turn your eyes away – the answer hides somewhere else."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A rewrite only plays if it's &lt;strong&gt;finished&lt;/strong&gt; (two sentences at most), &lt;strong&gt;spoils nothing&lt;/strong&gt; (no object the original didn't name), and &lt;strong&gt;passes a filter for kids&lt;/strong&gt;. Otherwise my original line plays.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it an agent?&lt;/strong&gt; Yes, a small one. &lt;a href="https://dev.to/tyler007/the-anatomy-of-an-ai-agent-model-loop-tools-memory-207g"&gt;An agent is a model inside a loop&lt;/a&gt;: it sees the state, picks an action, and is called again to see the result. Gemma does that every turn. It has no tools, no memory of its own, and no final say, though, since the game can refuse any move. It's &lt;strong&gt;a ghost that's only allowed to move the furniture.&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%2F8vhbjq386gjh3cdnbk22.png" 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%2F8vhbjq386gjh3cdnbk22.png" alt="A round in progress. Three objects found, and the narrator is describing the stool." width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;a href="https://hiddenobjects.tech" rel="noopener noreferrer"&gt;hiddenobjects.tech&lt;/a&gt;&lt;/strong&gt; is the full game: room, voice, and Gemma on DigitalOcean. No login is needed. Choose &lt;strong&gt;Enter the room&lt;/strong&gt;, listen, and click the name you think the riddle means. Drag or use WASD to look around. With the voice off, every line still appears on screen.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;GitHub repository:&lt;/strong&gt; &lt;a href="https://github.com/AbisoyeOnanuga/hidden-objects" rel="noopener noreferrer"&gt;AbisoyeOnanuga/hidden-objects&lt;/a&gt; (MIT)&lt;/p&gt;

&lt;p&gt;To play locally, one PowerShell script installs Ollama and Gemma 3 4B. Then run &lt;code&gt;python server.py&lt;/code&gt; and open &lt;code&gt;http://127.0.0.1:8765/&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Three files for the page, one Python file for the server, no framework, and no build step.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Page:&lt;/strong&gt; plain HTML, CSS, and JavaScript, with the room drawn as SVG and a draggable camera that keeps every object in frame.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server:&lt;/strong&gt; Python's standard library only. &lt;code&gt;/act&lt;/code&gt; handles Gemma's turns, and &lt;code&gt;/speak&lt;/code&gt; handles the voice. API keys never reach the browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Voice:&lt;/strong&gt; ElevenLabs Flash v2.5, with each word appearing on screen as it's spoken.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Host:&lt;/strong&gt; a Render web service on &lt;strong&gt;hiddenobjects.tech&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
  click["You select an object in the outliner"] --&amp;gt; act["/act"]
  act --&amp;gt; gemma["Gemma: next object + reworded line"]
  gemma --&amp;gt; checks{"Game checks it"}
  checks --&amp;gt;|passes| voice["/speak: ElevenLabs"]
  checks --&amp;gt;|fails| script["My written line"] --&amp;gt; voice&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;The hardest part was turn-taking&lt;/strong&gt;, not the model. A narrator that talks over itself sounds broken, so every line goes through one queue. A late reply can't interrupt a riddle. A correct early click skips straight to the next riddle. A wrong click only counts once you've heard the whole riddle, and the ending line always plays alone.&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%2F7mwk86ddynnaon0xnn5g.png" 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%2F7mwk86ddynnaon0xnn5g.png" alt="Settings. Voice, sound effects, and soundtrack each have their own control." width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Because Gemma's weights are open, the narrator isn't locked to one company's servers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Same game, any host:&lt;/strong&gt; Gemma 4 on DigitalOcean online, Gemma 3 on my laptop offline. One environment variable switches between them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free iteration:&lt;/strong&gt; I tuned the checks against the local model, offline and at no cost, and the hosted model got the same rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It can't be taken away:&lt;/strong&gt; if the hosted model disappears, anyone can still play against a local Gemma, and with no model at all, my written script still runs the room.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemma:&lt;/strong&gt; chooses the next object, sets the mood, and rewords the narrator so each play sounds different, inside rules the game enforces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DigitalOcean:&lt;/strong&gt; serves Gemma 4 for the live site through serverless inference, at a fraction of a cent per game.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Render:&lt;/strong&gt; hosts the game as a web service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ElevenLabs:&lt;/strong&gt; gives the narrator its voice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.tech domain:&lt;/strong&gt; the game lives at &lt;a href="https://hiddenobjects.tech" rel="noopener noreferrer"&gt;hiddenobjects.tech&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>gemma</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Help, I'm using Houdini</title>
      <dc:creator>Abisoye O</dc:creator>
      <pubDate>Mon, 26 Oct 2026 05:50:47 +0000</pubDate>
      <link>https://dev.to/abisoye/help-im-using-houdini-3oci</link>
      <guid>https://dev.to/abisoye/help-im-using-houdini-3oci</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge: Week 3 — Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you've ever used Houdini for VFX, Procedural modelling, animation or CG  content creation then you're probably familiar with its help-browser. Houdini's help-browser is a very useful source of documentation for any user looking for more information about all parts of Houdini. However, It is not context-aware, and does not know how a user's node networks are wired, or what parameter settings have been applied to a given or selected node. I built a new shelf tool that stays on that displays more details about actively selected nodes and uses the currently installed local-help file that shipped with the user's version of Houdini.&lt;/p&gt;

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

&lt;p&gt;houdini-wizard is a super-charged help-browser shelf tool. With any node selected, it will display organised documentation that updates based on what node is actively selected in the node network viewer. You can continue work in the network panel, while the tool is open and it will keep updating its help information or minimise it to avoid taking up screen-space.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The coolest features this tool has that you won't find in a standard help-browser:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update help documentation for newly selected nodes.&lt;/li&gt;
&lt;li&gt;Shows node's Input and Output connection status.&lt;/li&gt;
&lt;li&gt;Adopts Houdini's existing Parameter organisation.&lt;/li&gt;
&lt;li&gt;Enriches Parameter documentation by including their tooltips, keeping all this info in one panel and not just in the UI.&lt;/li&gt;
&lt;li&gt;Maintains existing UI helper-text that users can access on-hover of parameter settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;GitHub repository:&lt;/strong&gt; &lt;a href="https://github.com/AbisoyeOnanuga/houdini-wizard" rel="noopener noreferrer"&gt;AbisoyeOnanuga/houdini-wizard&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;If you have not used Houdini before, a scene is built by wiring small boxes together in a network. Each box is a &lt;strong&gt;node&lt;/strong&gt;, its settings are &lt;strong&gt;parameters&lt;/strong&gt;, and each setting has a short hover tip. When a node cannot compute its result, Houdini raises a &lt;strong&gt;cook error&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The standard help browser opens the manual for that type of node, from the very top of the page. It does not know which node you clicked, what is wired into it, or which setting you are trying to understand.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;houdini-wizard&lt;/code&gt; sits beside your work and reads the room. You can also open it with nothing selected to browse the full help library by category, and the moment you click a node in your network, the view switches to that node.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it handles parameter tips:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;When the tip is already clear, it leaves it alone:&lt;/strong&gt; On an Ocean Spectrum node, the &lt;em&gt;Wind Speed&lt;/em&gt; tip already explains that &lt;em&gt;"Higher wind speeds create larger low-frequency waves."&lt;/em&gt; The tool keeps that exact sentence and simply places the slider's range in front of it, so you see the numbers and the explanation together.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When the tip is too thin, it makes it readable:&lt;/strong&gt; On a &lt;em&gt;Rotate&lt;/em&gt; parameter, the built-in tip is four words: &lt;em&gt;"Rotate angles in degrees."&lt;/em&gt; That tells you the unit, not how the slider behaves. Here, the tool asks Gemma for one plain sentence using the slider's actual range (0 to 360): &lt;em&gt;0 means no rotation, and positive and negative values turn in opposite directions.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When a node fails to cook:&lt;/strong&gt; If the error message already names a parameter, the tool jumps straight to that section of the manual without calling the model. If the error is vague, Gemma picks the closest heading from that node's help file, and the tool quotes the manual directly.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Most parameters never touch the model. If a tooltip already explains what happens when you raise or lower a value, rewriting it only wastes time and risks changing a good explanation.&lt;/p&gt;

&lt;p&gt;This check is the gate in front of Gemma. It looks for cause-and-effect words that are already in the help text, and only lets short, label-like tips pass through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_needs_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meaning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;_effect_clause&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meaning&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[A-Za-z0-9&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;]+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;meaning&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Wind Speed&lt;/em&gt; contains &lt;em&gt;"higher"&lt;/em&gt;, so &lt;code&gt;_effect_clause&lt;/code&gt; catches it and the original tooltip stays intact. &lt;em&gt;"Rotate angles in degrees"&lt;/em&gt; has no effect words and is only four words long, so it gets the one-line value guide.&lt;/p&gt;

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

&lt;p&gt;Each tool in the stack has one job, so the window stays fast while you are working in a scene:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Houdini Python (&lt;code&gt;hou&lt;/code&gt;) and PySide:&lt;/strong&gt; Runs inside Houdini to read the active node, its live input and output wires, its parameter tabs, and the slider ranges on the node you have open.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Installed Houdini Help (&lt;code&gt;$HFS/houdini/help&lt;/code&gt;):&lt;/strong&gt; Every node page, shelf step, and diagram is read directly from the zip archives that shipped with the user's installed version of Houdini, so the documentation always matches the software on screen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 3 4B (via Ollama):&lt;/strong&gt; Runs locally to handle the two places where a static page falls short: matching an unclear cook error to a help heading, and turning bare four-word parameter labels into a readable sentence about the slider's range.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focused Skill Files:&lt;/strong&gt; Instead of running an open-ended chat loop that might invent settings or try to art-direct the scene, Gemma is paired with two strict skill prompts. One only allows it to return an existing heading name from the file; the other only allows a single sentence using the numbers actually present on that parameter's slider.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Temporal (Python SDK):&lt;/strong&gt; Wraps the heading lookup in a durable workflow so a slow local model call can retry cleanly, and if Houdini closes mid-session, reopening the shelf on that node restores the same help card without re-running the model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entire:&lt;/strong&gt; Tracks the coding sessions behind the repo so you can query why specific guardrails exist—such as why the shelf skips Gemma whenever a parameter heading is already named.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A multi-process agent harness is for a loop: the model picks the next tool, and several processes keep a conversation going. This shelf does not need that. The path is already decided. Opening a node saves that card, whether or not the node is showing an error, a warning, or a message. Python quotes a heading that is already named, and that save does not call Gemma. Gemma runs inside a Temporal activity only when that text names no heading, and it may only return one heading from that file, or &lt;code&gt;none&lt;/code&gt;. If the call times out, the same run tries again, up to three times, so a second call cannot also succeed. The browser stays closed until you click &lt;strong&gt;Session log&lt;/strong&gt; or &lt;strong&gt;Developer monitor&lt;/strong&gt; on the panel. &lt;strong&gt;Session log&lt;/strong&gt; shows the newest node first, plus a &lt;strong&gt;Model&lt;/strong&gt; view for tokens in and out, time spent, and model memory, and links to the &lt;a href="https://entire.com/gh/AbisoyeOnanuga/houdini-wizard/session/e96d75ea-ea02-4990-b94a-81678a4c1465" rel="noopener noreferrer"&gt;public Entire session&lt;/a&gt; for how the code was built.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
  activeNode["active network node"] --&amp;gt; wizard["houdini-wizard shelf"]
  wizard --&amp;gt; helpFile["installed help file"]
  helpFile --&amp;gt; gemma["Gemma picks one heading, or a short value line"]
  gemma --&amp;gt; quote["wizard quotes that help section"]
  gemma --&amp;gt; noMatch["no match lists headings you can open"]
  quote --&amp;gt; temporal["Temporal keeps this card"]
  noMatch --&amp;gt; temporal
  temporal --&amp;gt; updated["you update the node"]&lt;/code&gt;&lt;/pre&gt;



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

&lt;p&gt;3D and VFX scenes are often under NDA, and artists regularly work on machines that cannot send scene data or node graphs to a cloud API. Just as important, Houdini changes from version to version—a generic web search or a cloud model trained on older forum posts will confidently point you to parameters that do not exist in your build.&lt;/p&gt;

&lt;p&gt;Building this with open-weight and open-source tools solves both problems at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local and private by default:&lt;/strong&gt; Running Gemma through Ollama on the artist's workstation means node names, cook errors, and studio paths never leave the machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grounded in the truth on disk:&lt;/strong&gt; By pairing an open-weight model with the documentation archives already installed with Houdini, the tool improves how help is organised and read without inventing parameter values. It follows the same philosophy Saketh Balijepalli described in &lt;a href="https://dev.to/sakethbalijepalli/nannadesk-an-ai-assistant-for-my-dad-thats-not-allowed-to-guess-242l"&gt;NannaDesk: An AI Assistant for My Dad That's Not Allowed to Guess&lt;/a&gt;: use the small local model for language, and keep the facts deterministic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspectable workflow and history:&lt;/strong&gt; Using Temporal and Entire means both the runtime retries and the development decisions behind the tool are open, reproducible, and easy for another developer or TD to inspect.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The artist stays in control of the shot. &lt;code&gt;houdini-wizard&lt;/code&gt; never changes a value, flips a flag, or wires a node for you—it makes the documentation you already have easier to read while you work.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemma:&lt;/strong&gt; To match vague cook errors to the right section of the manual and turn short parameter labels into clear slider explanations, while running locally through Ollama.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Temporal:&lt;/strong&gt; To store the tool's lookup history, retry local model calls when they time out, and reopen that same help card if Houdini closes while you are working on a node.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entire:&lt;/strong&gt; To record the agent sessions behind the build and make it easy to search why specific design choices and model guardrails exist in the codebase.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>Price Wire: Live-seller pricing &amp; listing copy (HF26 Week 2)</title>
      <dc:creator>Abisoye O</dc:creator>
      <pubDate>Fri, 16 Oct 2026 04:42:52 +0000</pubDate>
      <link>https://dev.to/abisoye/price-wire-price-your-used-electronics-and-paste-a-listing-in-minutes-hf26-week-2-3fii</link>
      <guid>https://dev.to/abisoye/price-wire-price-your-used-electronics-and-paste-a-listing-in-minutes-hf26-week-2-3fii</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;p&gt;You know the piece. You are not sure what to ask, especially minutes before a &lt;strong&gt;live marketplace stream&lt;/strong&gt; or a new listing, and you do not want an hour of tab switching.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Price Wire&lt;/strong&gt; is a prep notebook for &lt;strong&gt;live selling&lt;/strong&gt; and regular listings: eBay Live, TikTok Shop LIVE, Etsy, Facebook Marketplace, and similar. It does not plug into stream APIs. It helps in the minutes &lt;strong&gt;before&lt;/strong&gt; you go on camera or hit publish.&lt;/p&gt;

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

&lt;p&gt;A small web app: describe what you sell and the condition, tap &lt;strong&gt;Get price&lt;/strong&gt;, and receive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Similar sales&lt;/strong&gt; (live listings when SerpApi is on; bundled examples only if live search is off or empty)&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;price sheet&lt;/strong&gt; (suggested, quick sale, hold firm)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paste-ready title and description&lt;/strong&gt; (templates in the same response, not a second LLM write pass)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notebook-style UI, light/dark theme, labeled &lt;strong&gt;Copy&lt;/strong&gt; buttons on the listing draft.&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%2F7lm3if5dy6m371mg2mkh.png" 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%2F7lm3if5dy6m371mg2mkh.png" alt="Price Wire home screen: notebook layout, demo card, and links to the project repo" width="800" height="267"&gt;&lt;/a&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%2F61fl1smq56bs8n1ll2dm.png" 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%2F61fl1smq56bs8n1ll2dm.png" alt="The listing form with condition choices and service status along the top" width="800" height="641"&gt;&lt;/a&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%2Fm31q9ktxkkocu0gr4if2.png" 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%2Fm31q9ktxkkocu0gr4if2.png" alt="Suggested, quick sale, and hold firm prices after a search" width="800" height="859"&gt;&lt;/a&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%2F4hh0ihd2ktbdxbqbtkp5.png" 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%2F4hh0ihd2ktbdxbqbtkp5.png" alt="Similar listings with thumbnails, marketplace names, and links" width="800" height="716"&gt;&lt;/a&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%2F64k4260prdhpq459og7h.png" 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%2F64k4260prdhpq459og7h.png" alt="Listing draft with title, description, and copy buttons" width="800" height="608"&gt;&lt;/a&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%2F1zfwg78zgh8r59egnyy4.png" 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%2F1zfwg78zgh8r59egnyy4.png" alt="Price Wire in dark theme" width="799" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually powers this prototype
&lt;/h2&gt;

&lt;p&gt;I am not claiming a full agent platform or every sponsor integration end-to-end. &lt;strong&gt;This build is useful today&lt;/strong&gt; because of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://serpapi.com/" rel="noopener noreferrer"&gt;SerpApi&lt;/a&gt;&lt;/strong&gt; — pulls &lt;strong&gt;active&lt;/strong&gt; similar listings from shopping and marketplace-style search so your price sheet is grounded in what other sellers are listing &lt;strong&gt;today&lt;/strong&gt;, not a chat guess.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI title parsing&lt;/strong&gt; — &lt;strong&gt;&lt;a href="https://ai.google.dev/gemma" rel="noopener noreferrer"&gt;Gemma&lt;/a&gt;&lt;/strong&gt; / Gemini on Render, or Ollama locally, when configured; otherwise &lt;strong&gt;title rules&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pricing from similar sales&lt;/strong&gt; — median band and confidence labels from a price table; optional with &lt;strong&gt;&lt;a href="https://www.priorlabs.ai/" rel="noopener noreferrer"&gt;TabPFN&lt;/a&gt;&lt;/strong&gt; with a developer key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Template listing copy&lt;/strong&gt; — platform packets (Etsy-first) generated alongside the price sheet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://render.com" rel="noopener noreferrer"&gt;Render&lt;/a&gt;&lt;/strong&gt; — hosts the API and UI (&lt;a href="https://price-wire.onrender.com" rel="noopener noreferrer"&gt;price-wire.onrender.com&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Status chips show what is configured; &lt;strong&gt;offline chips still run&lt;/strong&gt; on bundled example sales so the User-flow can be tested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Live sale prep
&lt;/h2&gt;

&lt;p&gt;On a &lt;strong&gt;live marketplace stream&lt;/strong&gt;, viewers often check the same marketplaces on their phone while they watch. If your &lt;strong&gt;starting ask&lt;/strong&gt; is far above &lt;strong&gt;other sellers' active listings&lt;/strong&gt; for a similar item, you lose time negotiating on air or lose trust.&lt;/p&gt;

&lt;p&gt;Price Wire gives you a &lt;strong&gt;similar sales&lt;/strong&gt; table (live rows when SerpApi is on), a &lt;strong&gt;price sheet&lt;/strong&gt; to choose your floor and starting price, and &lt;strong&gt;paste-ready copy&lt;/strong&gt; for what you say on camera or list after the stream.&lt;/p&gt;

&lt;h2&gt;
  
  
  Walkthrough
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Title: &lt;code&gt;Hand thrown stoneware mug set of 2 matte glaze&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Condition: &lt;strong&gt;Used&lt;/strong&gt;, e.g. light studio wear&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get price&lt;/strong&gt; → &lt;strong&gt;Etsy&lt;/strong&gt; tab → &lt;strong&gt;Copy&lt;/strong&gt; title + description&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;More paths: &lt;a href="https://github.com/AbisoyeOnanuga/price-wire/blob/main/hacktoberfest-week2/WALKTHROUGH.md" rel="noopener noreferrer"&gt;WALKTHROUGH.md&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Demo:&lt;/strong&gt; &lt;a href="https://price-wire.onrender.com" rel="noopener noreferrer"&gt;price-wire.onrender.com&lt;/a&gt; (rate limits: ~8 quotes/min per visitor, ~30/day shared UTC)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local:&lt;/strong&gt; &lt;a href="https://github.com/AbisoyeOnanuga/price-wire" rel="noopener noreferrer"&gt;github.com/AbisoyeOnanuga/price-wire&lt;/a&gt; — &lt;code&gt;npm install&lt;/code&gt;, &lt;code&gt;npm run dev&lt;/code&gt;. Works without keys using examples + rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it could go next
&lt;/h2&gt;

&lt;p&gt;The repo includes &lt;strong&gt;hooks and samples&lt;/strong&gt; for a richer product; they are &lt;strong&gt;not&lt;/strong&gt; part of the live demo story yet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tiger Data&lt;/strong&gt; — save and search your own sale history (schema + seed in repo; production DB was not live for this submission).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mastra&lt;/strong&gt; — tools are registered; the HTTP path is a &lt;strong&gt;fixed pipeline&lt;/strong&gt;, not a multi-step agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sentry&lt;/strong&gt; — optional &lt;code&gt;pricing.run&lt;/code&gt; span; room for fuller quote tracing later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TabPFN&lt;/strong&gt; — stronger when comp sets grow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Details: &lt;a href="https://github.com/AbisoyeOnanuga/price-wire/blob/main/hacktoberfest-week2/FUTURE.md" rel="noopener noreferrer"&gt;FUTURE.md&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent session (how it was built)
&lt;/h2&gt;


&lt;div class="ltag-agent-session"&gt;
  &lt;div class="agent-session-header"&gt;
    
    &lt;span class="agent-session-tool-icon-badge" title="GitHub Copilot"&gt;
&lt;/span&gt;
    &lt;span class="agent-session-title"&gt;Price Wire HF26 Week 2 — prototype UX and listing draft&lt;/span&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-scroll"&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Price Wire: HF26 Side Hustle — electronics comp pricing + listing copy prototype.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Shipped flat-repo app, simplified seller conditions, platform copy packets, tier 0 demo. UX: field descriptions, notebook chrome, interactive demo card, DEV draft 4857325 for proofread before publish.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-footer"&gt;
    &lt;span class="agent-session-meta"&gt;
        2 of 2 messages
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Why live listings beat guessing on stream
&lt;/h2&gt;

&lt;p&gt;A generic chatbot does not show you &lt;strong&gt;other sellers' current listing titles and prices&lt;/strong&gt; for your item. On a live sale, that is what you are competing with in the moment.&lt;/p&gt;

&lt;p&gt;SerpApi feeds &lt;strong&gt;today's shopping and marketplace search results&lt;/strong&gt; into the similar-sales table. You use those rows plus the price sheet to pick a &lt;strong&gt;credible starting ask&lt;/strong&gt; and the template copy for your pitch. Bundled examples in the repo are only a fallback when live search is off.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/AbisoyeOnanuga/price-wire" rel="noopener noreferrer"&gt;https://github.com/AbisoyeOnanuga/price-wire&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;small&gt;

**Fine print**

*AI disclosure.* I wrote and edited this post. Drafting and structure were assisted by AI coding agents while I built Price Wire.

*Prototype disclaimer.* Hacktoberfest demo, not financial or legal advice. Verify fees, shipping, and marketplace rules before you list.

*Post-deadline update (19 Oct 2026).* After the submission window, this article and the [judging disclaimer](https://github.com/AbisoyeOnanuga/price-wire/blob/main/JUDGING-DISCLAIMER.md) were updated so copy matches what you can verify on the hosted demo. One **bug fix** restores the intended SerpApi path (live similar listings when keyed; repo examples only when live search is unavailable—not mixed into live quotes). Optional stack (Tiger, Mastra agent loop, deep Sentry) remains future work, not live-demo claims.

&lt;/small&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Trail Sketch: a field-study guide for drawing and painting outdoors</title>
      <dc:creator>Abisoye O</dc:creator>
      <pubDate>Mon, 12 Oct 2026 06:57:11 +0000</pubDate>
      <link>https://dev.to/abisoye/trail-sketch-a-field-study-for-drawing-and-painting-outdoors-449c</link>
      <guid>https://dev.to/abisoye/trail-sketch-a-field-study-for-drawing-and-painting-outdoors-449c</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;Trail Sketch is a phone map for choosing a plein-air drawing or painting spot, then leaving with a short plan.&lt;/p&gt;

&lt;p&gt;Pick what you want to study. Nearby places line up as cards: a photo when Wikipedia has one, a feel word, and how far the walk is.&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%2F56sdxakixb63zicjrrek.png" 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%2F56sdxakixb63zicjrrek.png" alt="Nearby places in Trail Sketch, with photos, feel words, and walking distance" width="390" height="844"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use the map&lt;/strong&gt; button tucks that list away. &lt;strong&gt;Hide&lt;/strong&gt; leaves the pins.&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%2Fbt2m2b6ampmc8qz6odf5.png" 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%2Fbt2m2b6ampmc8qz6odf5.png" alt="The map after the place list is tucked away, with scene pins for water and trees" width="390" height="844"&gt;&lt;/a&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%2Fnqwli8b94wzwonbe7ofv.png" 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%2Fnqwli8b94wzwonbe7ofv.png" alt="The same map after Hide. The pins stay on the water and the trees" width="390" height="844"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open a place and the photo stays beside the weather. Graphite and ink get a value plan. Watercolor and oil add three pigments. You decide what stays on the page. Accepting a place saves the date, medium, and weather on this phone, and marks the pin. A studied place can be deleted.&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%2F2l32qbpn41icr8u4d5mx.png" 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%2F2l32qbpn41icr8u4d5mx.png" alt="The High Park watercolor sheet: photo beside the weather, a value plan, and three pigments" width="390" height="844"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://trail-sketch.onrender.com" rel="noopener noreferrer"&gt;trail-sketch.onrender.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;visit the link to see the early prototype.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/AbisoyeOnanuga/trail-sketch" rel="noopener noreferrer"&gt;https://github.com/AbisoyeOnanuga/trail-sketch&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;One MapLibre map provides the opensource map library. OpenStreetMap lists what is nearby. Ranking stays on the phone. Open-Meteo describes the weather and lighting conditions. Gemma 4 writes the plan when you ask for one. ElevenLabs reads it aloud when an API key is present. A stored library of studied locations stays on the device.&lt;/p&gt;

&lt;p&gt;Lenis scrolls the place list and the study sheet. The map keeps its own pan. The busy rings are recolored loaders from &lt;a href="https://github.com/uiverse-io/galaxy" rel="noopener noreferrer"&gt;Uiverse Galaxy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Two other Touch Grass projects inspire the focus of trail sketch to minimise screen dependency or use and encourage real-world interaction. &lt;a href="https://dev.to/esimuda/name-it-then-look-up-a-field-guide-where-the-phones-job-ends-after-one-photo-3bbi"&gt;Spotted&lt;/a&gt; names one thing and asks you to look up. &lt;a href="https://dev.to/darrenmakes/fieldmemo-keep-the-phone-in-your-pocket-talk-to-it-get-a-field-journal-at-home-32bo"&gt;fieldmemo&lt;/a&gt; leaves the phone in a pocket and writes the journal later, on your own machine. Trail Sketch uses that same restraint: the map does the choosing, and Gemma writes one plan when you ask, so you are ready to start studying the location with your pencil or paint.&lt;/p&gt;

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

&lt;p&gt;Trail Sketch is for choosing a place to draw, then leaving the screen. That choice should not depend on a closed map account or a model key. OpenStreetMap lists what is nearby. MapLibre and OpenFreeMap draw it. Wikimedia supplies a photo when one exists. Open-Meteo describes the light. The map and the search work with no keys, so the guide is usable before any paid service is connected.&lt;/p&gt;

&lt;p&gt;The plan is the part that uses a model. Gemma is open-weight, so the same request can go to Google's endpoint or to a local process by changing a base URL. The wording of a study is not locked to one hosted model. Places already studied stay on the phone, not inside a closed map's saved list. Open source is what makes the guide available, and what keeps the painter's places and the plan's model from belonging to a single service.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Agent Session snippet
&lt;/h2&gt;

&lt;p&gt;Guiding map interactions, what data is kept for artists about their chosen locations, and improving some UI-scaling issues:&lt;/p&gt;


&lt;div class="ltag-agent-session"&gt;
  &lt;div class="agent-session-header"&gt;
    
    &lt;span class="agent-session-tool-icon-badge" title="Gemini CLI"&gt;
&lt;/span&gt;
    &lt;span class="agent-session-title"&gt;Trail Sketch mobile field explorer&lt;/span&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-scroll"&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Trail Sketch should suggest study places from the artist's interests when the phone loads, with visual previews. A feel word or a short description should rank the nearest walkable place. Accepting a place catalogues the date, medium, and weather, and marks the pin as studied. Google sign-in can key that library later. The light, middle, and dark boxes are a suggested plan, not a finished palette.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Nearby places come from an OpenStreetMap Overpass bbox query, ranked on the phone by feel, interests, and walking distance. A named place farther than a short ride is replaced with the nearest listed study. Gemma writes the accepted study as JSON. ElevenLabs is ready to narrate when its key is on the server. Studies stay in local storage, keyed by a Google subject once sign-in is configured.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-fieldcard"&gt;field-card&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;watercolor study for a nearby pond&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;watercolor study for a nearby pond&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Gemma 4 returned a three-value plan and three pigment swatches. The key and the raw response stayed on the server.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;On a phone the place list disappears, buttons are too large, and the top of the results card is cropped. Wide layout and vertical scroll are fine. Map pins should be more visual. The selected study should keep its preview beside the written plan and the narration. Update the Entire session and the unpublished DEV draft.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;On a narrow screen the place sheet now starts below the search bar and the list scrolls inside it, one card per row. Wide screens keep a two-column list. Pins are small scene drawings for water, trees, viewpoints, buildings, and ridges. Medium, distance, near-me, and studied controls use the same kind of marks. The study sheet keeps the preview image next to the place name, the weather line, and the plan that can be read aloud.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-footer"&gt;
    &lt;span class="agent-session-meta"&gt;
        4 of 4 messages
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Process snapshot.&lt;/strong&gt; &lt;a href="https://entire.io/gh/AbisoyeOnanuga/trail-sketch/commit/b36b3d8df8e4058e8f7581c328118dd2dfa9ee11" rel="noopener noreferrer"&gt;The checkpoint on the screenshot commit&lt;/a&gt; holds the session stored with that commit, so a viewer can read the project's process there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sponsor tools used
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://ai.google.dev/gemma" rel="noopener noreferrer"&gt;Gemma&lt;/a&gt;&lt;/strong&gt; writes the study plan when you ask.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://render.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Render&lt;/strong&gt;&lt;/a&gt; hosts the page and API access.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://elevenlabs.io" rel="noopener noreferrer"&gt;&lt;strong&gt;ElevenLabs&lt;/strong&gt;&lt;/a&gt; reads the plan aloud and starts the process of stepping away from your screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://entire.io/gh/AbisoyeOnanuga/trail-sketch/commit/b36b3d8df8e4058e8f7581c328118dd2dfa9ee11" rel="noopener noreferrer"&gt;Entire&lt;/a&gt;&lt;/strong&gt; stores the checkpoint of the agent session used to build this.&lt;/p&gt;

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