<?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: Blaise Labs</title>
    <description>The latest articles on DEV Community by Blaise Labs (@blaiselabs).</description>
    <link>https://dev.to/blaiselabs</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%2F1915433%2F62669115-68cd-4eaf-9c5f-be1e21e35b35.jpg</url>
      <title>DEV Community: Blaise Labs</title>
      <link>https://dev.to/blaiselabs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/blaiselabs"/>
    <language>en</language>
    <item>
      <title>From Spec-Driven to Faith-Driven Development</title>
      <dc:creator>Blaise Labs</dc:creator>
      <pubDate>Sat, 31 Oct 2026 14:49:06 +0000</pubDate>
      <link>https://dev.to/blaiselabs/a-float-broke-my-refund-rule-and-leviticus-had-an-opinion-1399</link>
      <guid>https://dev.to/blaiselabs/a-float-broke-my-refund-rule-and-leviticus-had-an-opinion-1399</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;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F13ay3t4sw8dnksrjyeta.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F13ay3t4sw8dnksrjyeta.gif" alt="specdeck-spirit, a broken rule printed with its passage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have a small tool called specdeck that keeps a project's rules as requirements, each with a statement, a reason and a check. Here's one from an example shop project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rules.decimal-money&lt;/span&gt;
  &lt;span class="na"&gt;statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Money amounts shall be Decimal values, with no float anywhere in the shop package.&lt;/span&gt;
  &lt;span class="na"&gt;rationale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;A float total once made a refund one cent short and the accounts would not reconcile.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For this week's challenge I added one layer on top. It takes the reason behind each rule and goes looking for it in a spiritual text you choose. When an agent then puts a float in the money code, this is what comes out.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;specdeck: rule rules.decimal-money broken
  "Ye shall do no unrighteousness in judgment, in meteyard, in weight, or in measure." (Leviticus 19:35)
FAILED tests/test_rules.py::test_money_never_touches_float
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I know how that sounds. It's a little funny, and I think that's fine. But the verse is also correct. Somebody really did care about short measures thousands of years ago.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/BlaiseLabs/specdeck-spirit" rel="noopener noreferrer"&gt;specdeck-spirit&lt;/a&gt; is a fork of specdeck. Everything specdeck does still works, and there's a new command on top.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;specdeck spirit fetch quran-pickthall
specdeck spirit align &lt;span class="nt"&gt;--text&lt;/span&gt; quran-pickthall
specdeck spirit show
specdeck spirit keep rules.decimal-money
specdeck spirit &lt;span class="nb"&gt;read&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For each reason in your spec and for the project's purpose, it proposes a passage, says how the passage bears on the reason, and suggests what to read further. You keep the ones that mean something to you and reject the rest. Passages you keep show up under the rule in AGENTS.md and CLAUDE.md, so the next agent session sees them too, and under the rule when it breaks.&lt;/p&gt;

&lt;p&gt;It comes with ten texts, which is what I could find openly licensed in English. That's the King James Bible, the Tanakh, the Qur'an, the Dhammapada, the Bhagavad Gita, the Kojiki, the Tao Te Ching, the Analects, the Meditations of Marcus Aurelius and the Book of Mormon. That list isn't a judgement about what counts, so &lt;code&gt;specdeck spirit add-text&lt;/code&gt; takes any text of your own.&lt;/p&gt;

&lt;p&gt;To be plain about what's new, specdeck itself existed before this week. The spirit layer, its tests and the fork are what I built for this challenge.&lt;/p&gt;

&lt;p&gt;For the Ghost in the Machine theme I took the side about honoring the past. These are some of the oldest things anyone wrote down about why to do things right, and their authors are long dead, so this puts their words next to the reasons in a modern codebase. It's for people who build software and also read one of these texts, and who want the two in the same place.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;The recording at the top of this post is the tool running on an example shop project. Here's the same rule, the same reason, and what came back from each text on a local Gemma.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Text&lt;/th&gt;
&lt;th&gt;Passage for "a float made a refund one cent short"&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bible&lt;/td&gt;
&lt;td&gt;"Ye shall do no unrighteousness in judgment, in meteyard, in weight, or in measure." (Leviticus 19:35)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tanakh&lt;/td&gt;
&lt;td&gt;The same verse, in the 1917 translation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qur'an&lt;/td&gt;
&lt;td&gt;"O my people! Give full measure and full weight in justice, and wrong not people in respect of their goods." (Surah Hud 11:85)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dhammapada&lt;/td&gt;
&lt;td&gt;"Life is hard for the conscientious, always seeking purity, neither clinging nor rude, pure of livelihood and discerning." (Dhammapada 245)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Analects&lt;/td&gt;
&lt;td&gt;Confucius on rectifying names, because if names aren't correct, affairs can't succeed (XIII.III)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kojiki&lt;/td&gt;
&lt;td&gt;No passage fits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Book of Mormon&lt;/td&gt;
&lt;td&gt;No passage fits&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each search only ever sees one text, so nothing here was comparing notes. The Bible and the Tanakh share that verse, so them agreeing makes sense, but the Qur'an got to the same idea through its own verse and the Analects got to something close from a completely different direction. An honest measure turns out to be a very old concern.&lt;/p&gt;

&lt;p&gt;The rule about tests landed somewhere I liked too. Its reason says a failing rule test is the rule being broken, not a flaky test to skip, and the Qur'an came back with "Confound not truth with falsehood, nor knowingly conceal the truth" (Surah Al-Baqara 2:42).&lt;/p&gt;

&lt;p&gt;The full output for ten texts is in &lt;a href="https://github.com/BlaiseLabs/specdeck-spirit/blob/main/examples/agent-rules/SPIRIT.md" rel="noopener noreferrer"&gt;SPIRIT.md&lt;/a&gt;. You can also clone the repo and run &lt;code&gt;examples/agent-rules/spirit-demo.sh&lt;/code&gt;, which uses the saved results and doesn't need a model.&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/BlaiseLabs" rel="noopener noreferrer"&gt;
        BlaiseLabs
      &lt;/a&gt; / &lt;a href="https://github.com/BlaiseLabs/specdeck-spirit" rel="noopener noreferrer"&gt;
        specdeck-spirit
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A fork of specdeck that reads the why of each rule in your spec next to a spiritual text you choose, with open models running locally
    &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;specdeck-spirit&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;A fork of &lt;a href="https://github.com/BlaiseLabs/specdeck" rel="noopener noreferrer"&gt;specdeck&lt;/a&gt; that reads the why of each rule in your spec next to a spiritual text you choose.&lt;/p&gt;

&lt;p&gt;specdeck keeps each rule as a requirement with a statement, a reason and a check. This fork adds one layer on top of those reasons. For each one, open models running on your own machine look through the Bible, the Qur'an, the Dhammapada, the Kojiki or any text you add, and propose the passage that speaks to it. You keep the ones that mean something to you and reject the rest. When a rule breaks, its passage is printed under it.&lt;/p&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;specdeck: rule rules.decimal-money broken
  "Ye shall do no unrighteousness in judgment, in meteyard, in weight, or in measure." (Leviticus 19:35)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Everything else specdeck does is unchanged, and it's all documented below the line further down.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Try it&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;You need &lt;a href="https://ollama.com" rel="nofollow noopener noreferrer"&gt;Ollama&lt;/a&gt; with two open models.&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;ollama pull gemma4:12b-it-qat&lt;/pre&gt;…
&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/BlaiseLabs/specdeck-spirit" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;The original, without the spirit layer, is at &lt;a href="https://github.com/BlaiseLabs/specdeck" rel="noopener noreferrer"&gt;BlaiseLabs/specdeck&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;A reason like "the float made a refund one cent short" shares no words with Leviticus, so plain search finds nothing. It takes three steps.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Gemma 4 12B says what human concern sits under the reason, leaving the technology behind, and what words this text uses for it.&lt;/li&gt;
&lt;li&gt;BM25 looks for those words and EmbeddingGemma looks for that meaning, across every passage of the text. The best 8 go on.&lt;/li&gt;
&lt;li&gt;Gemma picks one by its number, or says none fits.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The third step is the design decision I care about most. People read these as scripture, and a model that writes a verse that doesn't exist would be putting words in a holy text. So the model only ever answers with a number. The quote comes out of the fetched text, and &lt;code&gt;specdeck spirit check&lt;/code&gt; compares every quote with the text again. There's a test that has the model try to slip in its own wording, and it can't.&lt;/p&gt;

&lt;p&gt;Being allowed to say nothing mattered as well. The prompt says none fitting is a fine answer, and 9 of the 50 reason and text pairs came back with no passage. The Kojiki declined three of its five, which seems right for a chronicle of deities when you ask it about internationalization.&lt;/p&gt;

&lt;p&gt;Choices go in a &lt;code&gt;spirit.yaml&lt;/code&gt; you commit with your project. A passage stays a proposal until a person keeps it, one you reject isn't offered again, and if a reason changes, &lt;code&gt;check&lt;/code&gt; tells you the passage is out of date.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is it any good?
&lt;/h3&gt;

&lt;p&gt;I wanted some check that this wasn't just pattern matching on nothing. For each passage it chose, I gave Gemma that passage and a random one from the same text, with no sign of which was which, and asked it to score each from 0 to 3 on whether it speaks to the concern. Chosen passages averaged 1.98 and random ones 0.49, and the chosen one scored higher in 32 of 41.&lt;/p&gt;

&lt;p&gt;That's the same model marking its own homework, so all it shows is that it beats chance. Reading through them, some are good and some are a stretch. Leviticus 19:35 came back for a rule about UTC timestamps too, and that's mostly the word "measure" doing the work. And all 41 passages affirmed the reason. The prompt allows a passage to challenge you, and none did, which I'd like to fix, since a text that only ever agrees with you isn't doing much.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I got here
&lt;/h3&gt;

&lt;p&gt;I should say this wasn't my plan for the week. I spent most of it on a project that tried to rewrite LLM code into lines humans had already written, using an index of millions of Python files. It kept not working, but it did teach me something. In one small program, the person's request decided at most 10 of 70 observable behaviours and the model decided 58 on its own. What gets lost with LLM code isn't so much who typed it. It's the why.&lt;/p&gt;

&lt;p&gt;Then I ran out of time, and I had a tool that already stores the why. Honoring the past is part of this week's prompt, and these are about the oldest writings on why anyone should bother doing things right.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running It on My Own Work
&lt;/h2&gt;

&lt;p&gt;After the shop example I ran it against several of my own projects. Each one got a spec with its rules and reasons, and each spec got aligned with the King James Bible. That came to 65 reasons and 53 passages. Here are some of the ones that stuck with me and how I might read them.&lt;/p&gt;

&lt;p&gt;The verse that came back most, four times, was "Providing for honest things, not only in the sight of the Lord, but also in the sight of men" (2 Corinthians 8:21). Part of that is Gemma reaching for a safe verse. But a lot of my rules really are about not fooling myself with a good looking number, so I can't argue with it.&lt;/p&gt;

&lt;p&gt;For a rule that keeps rewriting text until the reader can follow it, I got "except ye utter by the tongue words easy to be understood, how shall it be known what is spoken?" (1 Corinthians 14:9). The way I read that, if someone can't follow what I made, that's on me and not on them.&lt;/p&gt;

&lt;p&gt;For a rule about renaming a variable everywhere it's used, I got "He that is faithful in that which is least is faithful also in much" (Luke 16:10). That's a lot of weight for a variable name. I still take it to mean the small stuff is where you find out how you actually work.&lt;/p&gt;

&lt;p&gt;For a rule about sharing things at a steady pace, I got "bring forth fruit with patience" (Luke 8:15). I build a lot faster than I share, so I might read that as permission to slow down.&lt;/p&gt;

&lt;p&gt;For a rule that keeps an approval page off the public internet, I got "Let not the gates of Jerusalem be opened until the sun be hot" (Nehemiah 7:3). That one barely needs interpreting.&lt;/p&gt;

&lt;p&gt;Some of them pushed back, even when the tool didn't say so. "God hath made man upright; but they have sought out many inventions" (Ecclesiastes 7:29) was marked as agreeing with one of my rules. Read it properly and the inventions are the problem. I start a lot of projects, so I took that one personally.&lt;/p&gt;

&lt;p&gt;The only passage marked as a challenge was "The desire of the slothful killeth him; for his hands refuse to labour" (Proverbs 21:25). It came back for a rule that stops me from counting work as avoided when I've only moved it somewhere else. Fair enough.&lt;/p&gt;

&lt;p&gt;One of them fooled me. "Out of the earth shall others grow" (Job 8:19) looked lovely next to a rule about giving people a path to learn on. Then I read the verses around it. They're about people who forget God being uprooted, and the others growing are their replacements. The tool looks at one verse at a time, so read the chapter before you keep one.&lt;/p&gt;

&lt;p&gt;None of this is the Bible talking about my code. A model picked these and I'm the one deciding what they mean. What I got out of it is simpler than that. Be honest about what I measured, make things people can follow, take care with the small stuff, and maybe start fewer things.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Faith is private.&lt;/strong&gt; Which text you read, and which of your project's reasons you hold it next to, is nobody's business. Gemma and EmbeddingGemma run locally through Ollama, so none of that leaves the machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's a lot of embedding for a joke that turned out useful.&lt;/strong&gt; The Bible alone is 31,102 verses, and it took about half an hour on a base Mac mini. Running that locally costs nothing, so I could index all ten texts without thinking about it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The texts are open because people made them open.&lt;/strong&gt; Sefaria, SuttaCentral, Project Gutenberg, Wikisource and the people behind the open Bible and Qur'an datasets did the real work here, and the &lt;a href="https://github.com/BlaiseLabs/specdeck-spirit#readme" rel="noopener noreferrer"&gt;README&lt;/a&gt; lists each text with its source and licence. Bhikkhu Sujato put his translation in the public domain on purpose. Anyone can add a tradition I missed, and I missed a lot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One limit comes with that. Old translations are the ones anyone may share, so they carry the views of their translators, and many Muslims hold that a translation of the Qur'an is an interpretation and not the Qur'an itself. This isn't religious advice either. A model finding a connection doesn't mean a tradition teaches it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Spirit of It
&lt;/h2&gt;

&lt;p&gt;The challenge's closing date is Halloween, right as Día de los Muertos begins, and both are about the dead still having something to say to us. I think that's what this is, in a small and slightly ridiculous way. Somebody wrote down that a false weight is wrong long before anyone had a refund to get wrong, and now it prints under my test failure.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma.&lt;/strong&gt; Gemma 4 12B finds the concern under each reason and picks the passage, and EmbeddingGemma searches every passage of every text, all running locally through Ollama.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;I built this with a lot of help from an AI coding assistant. The idea and the design decisions are mine.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>gemma</category>
      <category>python</category>
    </item>
    <item>
      <title>GuessWithAnki: Using computer science and Anki to learn more vocabulary with less memorization</title>
      <dc:creator>Blaise Labs</dc:creator>
      <pubDate>Mon, 26 Oct 2026 06:16:30 +0000</pubDate>
      <link>https://dev.to/blaiselabs/guesswithanki-study-less-learn-more-japanese-chinese-english-and-medicine-21on</link>
      <guid>https://dev.to/blaiselabs/guesswithanki-study-less-learn-more-japanese-chinese-english-and-medicine-21on</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;  &lt;iframe src="https://www.youtube.com/embed/j-xJ8mhyt0E" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I'm still a beginner in Japanese, and I've always been amazed watching more advanced learners go through flashcards full of words they've never seen before and still guess the reading and meaning. To me, Japanese text basically looked like hieroglyphics.&lt;/p&gt;

&lt;p&gt;Then, after a while of doing my own vocab cards, it started happening to me too. Every now and then I'd see a word for the first time, take a guess, flip the card, and be exactly right.&lt;/p&gt;

&lt;p&gt;So I got curious and tried to actually measure how often that's possible, by breaking words into the pieces they're built from and checking whether those pieces give the word away. That led me down a rabbit hole of greedy algorithms and graph theory. The idea is that if you study the right building blocks first, a lot of new words become guessable without having to memorize them individually.&lt;/p&gt;

&lt;p&gt;The result is &lt;a href="https://github.com/BlaiseLabs/GuessWithAnki" rel="noopener noreferrer"&gt;GuessWithAnki&lt;/a&gt;, an Anki add-on that reorders your deck so you can guess the meaning, and often the pronunciation, of a lot of cards on your first try.&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%2Fglft9zbbass21tl122r5.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%2Fglft9zbbass21tl122r5.png" alt="A card for 電気, guessed on first sight" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;If you've already learned the pieces that make up a word, you can often figure out what it means without ever having studied the word itself. For example, suppose you've already studied&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;電車 (でんしゃ), train&lt;/li&gt;
&lt;li&gt;天気 (てんき), weather&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You've now encountered 電 pronounced as でん and 気 pronounced as き. GuessWithAnki recognizes this and moves 電気 (でんき) (electricity) forward in your deck, since you already know how to read its kanji in this word and have some clues about its meaning. Instead of memorizing 電気 entirely from scratch, you have a good chance of guessing it correctly the first time you see it.&lt;/p&gt;

&lt;p&gt;A card you get right the first time you see it is what I call a free card, since you never had to learn it the hard way. GuessWithAnki looks for the words you're likely to figure out on your own, then puts them right after the cards that teach their pieces.&lt;/p&gt;

&lt;p&gt;This builds on &lt;a href="https://github.com/BlaiseLabs/GuessWithKanji" rel="noopener noreferrer"&gt;GuessWithKanji&lt;/a&gt;, my first add-on, which only worked for Japanese. This time I wanted to see how far the idea goes beyond Japanese, so it now handles five kinds of decks.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Deck&lt;/th&gt;
&lt;th&gt;What counts as a piece&lt;/th&gt;
&lt;th&gt;When a word is guessable&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Japanese&lt;/td&gt;
&lt;td&gt;A kanji paired with its reading in that word (電 read as でん)&lt;/td&gt;
&lt;td&gt;Both the meaning and reading follow from its pieces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chinese&lt;/td&gt;
&lt;td&gt;A character paired with its pinyin syllable and tone (开 read as kāi)&lt;/td&gt;
&lt;td&gt;Both the meaning and pinyin follow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Korean&lt;/td&gt;
&lt;td&gt;A syllable with the Chinese character it comes from (학 from 學, study)&lt;/td&gt;
&lt;td&gt;The meaning follows from its parts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;English&lt;/td&gt;
&lt;td&gt;A prefix, root, or suffix (un-, employ, -ed)&lt;/td&gt;
&lt;td&gt;The meaning follows from its parts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Medical&lt;/td&gt;
&lt;td&gt;A Greek or Latin root or affix (hepat, -itis)&lt;/td&gt;
&lt;td&gt;The meaning follows from its parts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The goal is to reward pattern recognition over memorizing.&lt;/p&gt;

&lt;p&gt;GuessWithAnki encourages this by minimizing the amount of memorization needed to grasp an underlying pattern in a vocabulary deck.&lt;/p&gt;

&lt;p&gt;This has the added effect of improving your memory, and giving you access to skills that are usually reserved for more advanced language learners.&lt;/p&gt;

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

&lt;p&gt;The video at the top walks through the different performance profiles of decks across languages. Below you'll see the potential gains in Chinese vocabulary decks, which are the best suited for this technique.&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%2Frbs3mgqsomgirgk2o4it.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%2Frbs3mgqsomgirgk2o4it.png" alt="The GuessWithAnki dashboard on an HSK deck, guessable on arrival 6 → 321" width="799" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With GuessWithAnki you are able to learn the equivalent of 500 Chinese words with less than 200 words. Just by changing the order you study them in.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/BlaiseLabs/GuessWithAnki" rel="noopener noreferrer"&gt;BlaiseLabs/GuessWithAnki&lt;/a&gt;&lt;/strong&gt; has the add-on, measurement tools, experimental results, and video source files, including Manim scenes, narration, and build scripts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/BlaiseLabs/GuessWithKanji" rel="noopener noreferrer"&gt;BlaiseLabs/GuessWithKanji&lt;/a&gt;&lt;/strong&gt; is the original Japanese-only version.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  1. How guessable is a word?
&lt;/h3&gt;

&lt;p&gt;I started by looking at how much overlap in kanji there was across words. The more unique kanji there were, the more difficult it would be to guess a word's meaning.&lt;/p&gt;

&lt;p&gt;Luckily for me that's not how Japanese works, and as it turns out there was a large overlap between the words and the kanji they shared.&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%2Fkqz35xsv9g3iazd5p3k4.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%2Fkqz35xsv9g3iazd5p3k4.png" alt="A piece is a kanji plus the reading it has in that word" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  The reading
&lt;/h4&gt;

&lt;p&gt;This part was surprisingly straightforward.&lt;/p&gt;

&lt;p&gt;Two free dictionaries, KANJIDIC2 and JMdict, provide kanji readings and tens of thousands of vocabulary entries.&lt;/p&gt;

&lt;p&gt;I wrote a small Python function to match each word's reading to its individual kanji. Compared against JmdictFurigana, it agreed on 99% of 17,854 common words.&lt;/p&gt;

&lt;p&gt;Once you have those matches, you can count how frequently each reading occurs.&lt;/p&gt;

&lt;p&gt;For example, 気 is read as き in 130 dictionary words, but as け in only 14.&lt;/p&gt;

&lt;p&gt;So if you've learned 気 as き, a new word using that same reading becomes much easier to guess.&lt;/p&gt;

&lt;h4&gt;
  
  
  The meaning
&lt;/h4&gt;

&lt;p&gt;Figuring out whether a word's meaning follows from its pieces is trickier.&lt;/p&gt;

&lt;p&gt;I tried two approaches, both using open models.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Embeddings. EmbeddingGemma represents each meaning as a point in a vector space. If a word's meaning is close to the meanings of its kanji, there's a good chance you can infer it. After tuning on labelled words, this approach achieved an AUC of 0.83, compared with 0.73 for simple word overlap.&lt;/li&gt;
&lt;li&gt;Asking a model directly. Gemma 4 runs locally through Ollama and labels words in batches. It judges whether the reading and meaning are predictable, partly predictable, or not predictable, using a JSON schema that specifies the exact words in each batch.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  My own deck
&lt;/h4&gt;

&lt;p&gt;I ran the analysis on my own deck of 2,038 words containing kanji.&lt;/p&gt;

&lt;p&gt;Here's what I found.&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%2Fuithr60m7u8581cs1xba.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%2Fuithr60m7u8581cs1xba.png" alt="Reading 96%, meaning 69% (95% at least a hint), no clue 5%" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For 67% of the words, both the reading and meaning were predictable.&lt;/p&gt;

&lt;p&gt;In other words, roughly two out of every three words I was about to study were, at least in theory, words I could have guessed on first sight.&lt;/p&gt;

&lt;p&gt;That was a much bigger share than I'd expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Finding the right order with a greedy algorithm
&lt;/h3&gt;

&lt;p&gt;There's a catch, though. You can only guess a word if you've already encountered the pieces it's made of. For example, you can't guess 天気 (てんき) from its kanji if you've never learned 天 read as てん.&lt;/p&gt;

&lt;p&gt;So this basically becomes a max/min problem. How do I maximize the number of guessable Anki cards while minimizing the amount of memorization needed?&lt;/p&gt;

&lt;p&gt;Trying every possible order is out of the question. For 2,000 cards there are about 3.3 × 10&lt;sup&gt;5735&lt;/sup&gt; possible orders.&lt;/p&gt;

&lt;p&gt;This basically turns into something a lot like the traveling salesman problem, and one of the simplest ways to approach this is using a greedy algorithm. A greedy algorithm builds a solution one step at a time. At each step, it chooses whatever looks most promising right now, without going back to reconsider earlier decisions.&lt;/p&gt;

&lt;p&gt;It doesn't guarantee the perfect solution, but it's fast, and can get pretty close.&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%2F9ztrok2ptvfjfvlo6ab1.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%2F9ztrok2ptvfjfvlo6ab1.png" alt="A greedy algorithm takes the best-looking branch at every step" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At every step, the algorithm asks which card should come next.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If a word is already guessable, it gets priority, especially if you've just encountered the pieces that make it up.&lt;/li&gt;
&lt;li&gt;If nothing is guessable yet, the algorithm looks for an &lt;em&gt;opener&lt;/em&gt;, a card that introduces just one new piece, preferably one that will help unlock other words.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, you might study 取る (&lt;em&gt;toru&lt;/em&gt;, to take), followed by 戻る (&lt;em&gt;modoru&lt;/em&gt;, to return).&lt;/p&gt;

&lt;p&gt;Once you've learned those pieces, 取り戻す (&lt;em&gt;torimodosu&lt;/em&gt;, to take back) becomes guessable.&lt;/p&gt;

&lt;p&gt;The algorithm tries to create as many of these little chains as possible.&lt;/p&gt;

&lt;p&gt;On my own deck, this changed the number of guessable words among the next 500 cards from 66 to 307.&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%2F2xr190401yt7ga5kes5x.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%2F2xr190401yt7ga5kes5x.png" alt="500 cards, 66 guessable in deck order and 307 on the guessable path" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's nearly five times as many words you might be able to figure out without first memorizing them.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Does it actually help?
&lt;/h3&gt;

&lt;p&gt;Of course, a word being &lt;em&gt;theoretically&lt;/em&gt; guessable doesn't mean you'll actually guess it correctly.&lt;/p&gt;

&lt;p&gt;And even if you do, will it help you remember more over time?&lt;/p&gt;

&lt;p&gt;To explore that, I built a simulation of someone studying with Anki for 100 days.&lt;/p&gt;

&lt;p&gt;The simulated learner studies 20 new cards per day and completes every scheduled review. Reviews follow FSRS-6, Anki's scheduling algorithm, which I reimplemented and checked against py-fsrs.&lt;/p&gt;

&lt;p&gt;Each piece of a word has its own memory state. That memory gradually fades, but gets reinforced whenever another word containing the same piece appears.&lt;/p&gt;

&lt;p&gt;A word can only be guessed if the learner still remembers its pieces.&lt;/p&gt;

&lt;p&gt;On a JLPT vocabulary deck, with perfect guessing, a learner would need to learn just 16 cards from scratch to know their first 100 words. The other 84 could be guessed.&lt;/p&gt;

&lt;p&gt;100% guessing isn't realistic though. This isn't magic, and as learners we're still going to get some words wrong.&lt;/p&gt;

&lt;p&gt;I checked my own Anki review history and found that when a word was guessable and I'd seen its kanji recently, I answered correctly about 73% of the time.&lt;/p&gt;

&lt;p&gt;So I also tested a more realistic 80% guessing rate.&lt;/p&gt;

&lt;p&gt;At that rate, reaching the first 100 words required learning just 35 cards from scratch, rather than 100.&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%2Fd5syjirwswjtrt9et3zl.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%2Fd5syjirwswjtrt9et3zl.png" alt="At 80% guessing, 35 learned and 65 guessed, 2.9×" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And there was another benefit I hadn't expected. Less forgetting.&lt;/p&gt;

&lt;p&gt;Every new word reinforces pieces you've already learned. So you're not just accumulating vocabulary. You're repeatedly practicing the patterns behind it.&lt;/p&gt;

&lt;p&gt;In the Core 2k simulation, forgotten reviews by day 30 fell from 189 to 72.&lt;/p&gt;

&lt;p&gt;The same ordering that made words easier to guess also helped keep their building blocks fresh in memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Does it work beyond Japanese?
&lt;/h3&gt;

&lt;p&gt;Japanese turned out to be a great fit for this idea. But I wanted to know whether it would work for other subjects too.&lt;br&gt;
Then I ran the same experiment on two decks each for Chinese learners, English learners, and medical students, and three decks for Korean learners.&lt;/p&gt;

&lt;p&gt;The underlying algorithm stays the same. The only thing that changes is what counts as a reusable piece.&lt;/p&gt;

&lt;p&gt;For speed, I used a cloud model to label the 21,624 words across these decks in parallel, processing about 2.6 million tokens. The add-on itself uses Gemma locally, processing one batch at a time.&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%2Feurxsv72joa06t1jtxad.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%2Feurxsv72joa06t1jtxad.png" alt="开学, 开 kāi (open) plus 学 xué (study), the start of term" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are the results at an 80% guessing rate.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Deck&lt;/th&gt;
&lt;th&gt;Guessable&lt;/th&gt;
&lt;th&gt;Cards to reach 500 words&lt;/th&gt;
&lt;th&gt;Speed-up&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;New HSK 3.0, levels 1–4 (Chinese)&lt;/td&gt;
&lt;td&gt;71%&lt;/td&gt;
&lt;td&gt;392 → 200&lt;/td&gt;
&lt;td&gt;2.0×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HSK 2012, levels 1–5 (Chinese)&lt;/td&gt;
&lt;td&gt;66%&lt;/td&gt;
&lt;td&gt;473 → 256&lt;/td&gt;
&lt;td&gt;1.8×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Core 2k (Japanese)&lt;/td&gt;
&lt;td&gt;60%&lt;/td&gt;
&lt;td&gt;481 → 265&lt;/td&gt;
&lt;td&gt;1.8×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kaishi 1.5k (Japanese)&lt;/td&gt;
&lt;td&gt;64%&lt;/td&gt;
&lt;td&gt;474 → 282&lt;/td&gt;
&lt;td&gt;1.7×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oxford 3000 (English)&lt;/td&gt;
&lt;td&gt;27%&lt;/td&gt;
&lt;td&gt;494 → 303&lt;/td&gt;
&lt;td&gt;1.6×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Korean Vocabulary by Evita (Korean)&lt;/td&gt;
&lt;td&gt;39%&lt;/td&gt;
&lt;td&gt;492 → 310&lt;/td&gt;
&lt;td&gt;1.6×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2k Essential Beginner Vocab (Korean)&lt;/td&gt;
&lt;td&gt;31%&lt;/td&gt;
&lt;td&gt;486 → 350&lt;/td&gt;
&lt;td&gt;1.4×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4000 Essential English Words&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;td&gt;494 → 356&lt;/td&gt;
&lt;td&gt;1.4×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Medical Terminology with Etymology&lt;/td&gt;
&lt;td&gt;27%&lt;/td&gt;
&lt;td&gt;482 → 474&lt;/td&gt;
&lt;td&gt;1.0×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TTMIK My First 500 Words (Korean)&lt;/td&gt;
&lt;td&gt;25%&lt;/td&gt;
&lt;td&gt;495 → 492&lt;/td&gt;
&lt;td&gt;1.0×&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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%2F5rnk6d012dviyr9r7pl4.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%2F5rnk6d012dviyr9r7pl4.png" alt="Speed-up at 500 words, Chinese 1.9×, Japanese 1.8×, English 1.5×, medical 1.1×" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Chinese did even better than Japanese
&lt;/h4&gt;

&lt;p&gt;Chinese turned out to be an even better fit than I'd expected.&lt;/p&gt;

&lt;p&gt;A character usually has one reading, so the pinyin of about 96% of words can be predicted from their characters.&lt;/p&gt;

&lt;p&gt;And 90% of HSK words share every character with at least one other word.&lt;/p&gt;

&lt;p&gt;That gives the algorithm plenty of reusable pieces to work with.&lt;/p&gt;

&lt;p&gt;The advantage also lasts. Even beyond a thousand words, the optimized order maintains a 1.6–1.8× lead.&lt;/p&gt;

&lt;h4&gt;
  
  
  Korean lands in the middle
&lt;/h4&gt;

&lt;p&gt;Korean was a late addition, after someone asked for it.&lt;/p&gt;

&lt;p&gt;Most Korean vocabulary is Sino-Korean, built from syllables that each come from a Chinese character (Hanja). So once you know 학생 (student) and 교실 (classroom), 학교 (school) gives itself away.&lt;/p&gt;

&lt;p&gt;The catch is that native Korean words and loanwords don't split into pieces like that, so only about a third of a beginner deck is guessable.&lt;/p&gt;

&lt;p&gt;Evita's deck still reached 1.6× at 500 words, and kept 1.5× past a thousand. The small TTMIK deck barely moved, since its pieces rarely come back.&lt;/p&gt;

&lt;h4&gt;
  
  
  English is more modest
&lt;/h4&gt;

&lt;p&gt;Most everyday English words don't break neatly into meaningful pieces. Knowing the spelling of &lt;em&gt;beach&lt;/em&gt;, for example, doesn't tell you what it means.&lt;/p&gt;

&lt;p&gt;But word families offer a useful shortcut.&lt;/p&gt;

&lt;p&gt;Once you know &lt;em&gt;employ&lt;/em&gt;, words like &lt;em&gt;employer&lt;/em&gt;, &lt;em&gt;employment&lt;/em&gt;, and &lt;em&gt;unemployed&lt;/em&gt; become much easier to figure out.&lt;/p&gt;

&lt;p&gt;The gains aren't as dramatic as in Chinese or Japanese, but they're still meaningful.&lt;/p&gt;

&lt;h4&gt;
  
  
  Medicine was the surprise
&lt;/h4&gt;

&lt;p&gt;I initially thought medical terminology would be the perfect use case.&lt;/p&gt;

&lt;p&gt;So many medical terms are built from Greek and Latin roots. So I figured they would especially benefit from greedy based sorting.&lt;/p&gt;

&lt;p&gt;But the medical terminology deck barely improved on its own.&lt;/p&gt;

&lt;p&gt;The problem was the deck itself. It was relatively small and mixed together technical terms, abbreviations, drug names, and everyday vocabulary. Many roots simply didn't appear often enough to be reused.&lt;/p&gt;

&lt;p&gt;Medical students are often advised to learn the roots first. But with a roots deck placed ahead of the terminology deck, the learner has to get through 982 root cards before seeing the first medical term, around day 50.&lt;/p&gt;

&lt;p&gt;GuessWithAnki takes a different approach.&lt;/p&gt;

&lt;p&gt;Instead of teaching every root up front, it introduces only the roots needed for the next terms, right before those terms appear.&lt;/p&gt;

&lt;p&gt;That means the learner can start guessing actual medical terminology within the first two weeks.&lt;/p&gt;

&lt;p&gt;So even when the raw speed-up looks small, changing the order can make the learning experience very different.&lt;/p&gt;

&lt;p&gt;Across all five profiles, the pattern became clear. What matters is how often meaningful pieces get reused, and how reliably they predict the words built from them.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Making the video with open models
&lt;/h3&gt;

&lt;p&gt;I also wanted to explain the project visually, so I made a 3Blue1Brown-style video using Manim.&lt;/p&gt;

&lt;p&gt;It features a little mascot named Gaku (学, meaning "study"), who reacts to the explanations as I talk.&lt;/p&gt;

&lt;p&gt;The narration uses a clone of my own voice, and the whole production pipeline runs locally on a Mac mini.&lt;/p&gt;

&lt;p&gt;Here's how I put it together.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The voice.&lt;/strong&gt; I used Qwen3-TTS (1.7B, open weights) through MLX, cloning my voice from just &lt;strong&gt;5.7 seconds&lt;/strong&gt; of recorded speech. I generate whole paragraphs at once to keep the delivery natural. Whisper then detects the pauses between sentences so I can cut the audio and align each animation with its narration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checking the narration.&lt;/strong&gt; Every generated take is transcribed with Whisper and compared word for word against the script. If something comes out wrong, the pipeline automatically generates another take.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixing Japanese pronunciation.&lt;/strong&gt; The cloned voice kept pronouncing とる (&lt;em&gt;toru&lt;/em&gt;) as "toh-ruh", and no amount of creative respelling helped. In the end, I recorded that paragraph and the intro myself, then used CosyVoice2 for voice conversion. That preserved my actual pronunciation and timing, including the laughs and stumbles, while giving it the cloned voice's sound.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catching layout bugs.&lt;/strong&gt; Animation overlaps are surprisingly hard to spot by eye. So I wrote a checker that runs after every animation and flags overlapping text, text escaping its box, anything covering Gaku, and objects falling outside the frame. It caught 30 problems, plus one particularly funny bug where Gaku's eyebrows collapsed into a single dot in the middle of the screen.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;None of this would have been possible without open-source work.&lt;/p&gt;

&lt;p&gt;The language data comes from open resources, KANJIDIC2 and JMdict from EDRDG, plus CC-CEDICT for Chinese.&lt;/p&gt;

&lt;p&gt;The scheduling algorithm is open too. It's FSRS, developed by the open-spaced-repetition project.&lt;/p&gt;

&lt;p&gt;And the AI models run on my own machines. GuessWithAnki uses Gemma 4 and EmbeddingGemma, while the video pipeline uses Qwen3-TTS, CosyVoice2, and Whisper.&lt;/p&gt;

&lt;p&gt;Put together, these tools let one language learner go from wondering, "How do advanced learners do that?" to actually measuring the phenomenon and building something useful from it.&lt;/p&gt;

&lt;p&gt;Just as importantly, &lt;strong&gt;other people can check the results and build on the work&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The add-on doesn't need a server. Even its built-in heuristics, without a language model, judged 68% of a 4,995-word HSK deck to be guessable, close to the model's estimate.&lt;/p&gt;

&lt;p&gt;Guessability labels are just data. You can share them, bundle them with a deck, or improve them together as a community.&lt;/p&gt;

&lt;p&gt;That means the idea doesn't have to stop with my experiments.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lazy Payoff
&lt;/h2&gt;

&lt;p&gt;With an 80% guessing rate, the simulation suggests you could reach your first 500 Chinese words while learning only about half as many cards from scratch. Japanese comes close.&lt;/p&gt;

&lt;p&gt;You get more words from less memorization, reinforce the pieces you already know, and spend more of your time recognizing patterns instead of treating every word as something completely new.&lt;/p&gt;

&lt;p&gt;And that's what brings me back to those advanced Japanese learners who seemed to know words they'd never studied.&lt;/p&gt;

&lt;p&gt;Now I understand they were able to do this by learning enough pieces to start seeing the patterns in kanji across words.&lt;/p&gt;

&lt;p&gt;GuessWithAnki is my attempt to help the rest of us get there sooner.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  Best Use of Gemma
&lt;/h4&gt;

&lt;p&gt;Gemma 4 labels word guessability locally through Ollama, processing batches of 20 words with a JSON schema that specifies the exact batch contents and a daily processing cap.&lt;/p&gt;

&lt;p&gt;EmbeddingGemma provides a second way to estimate guessability by measuring the semantic similarity between a word's meaning and the meanings of its pieces.&lt;/p&gt;

&lt;p&gt;On 1,839 words from my own deck, Gemma 4 12B agreed with a much larger cloud model on &lt;strong&gt;86% of reading labels and 79% of meaning labels&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sentry Agent Tracing
&lt;/h4&gt;

&lt;p&gt;Every labelling job is recorded in a self-hosted Sentry instance using Sentry's AI agent tracing format.&lt;/p&gt;

&lt;p&gt;Each batch gets its own transaction, recording token usage, timing, and unreadable words. Individual embedding calls are tracked as spans.&lt;/p&gt;

&lt;p&gt;This wasn't just instrumentation for its own sake. The traces helped me catch several real bugs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Empty responses with thinking enabled.&lt;/strong&gt; Gemma sometimes returned nothing at all. Setting &lt;code&gt;reasoning_effort&lt;/code&gt; to &lt;code&gt;none&lt;/code&gt; fixed it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context overflow.&lt;/strong&gt; Batches of 40 words exceeded Ollama's default 4,096-token context and crashed the parser. Reducing the batch size to 20 fixed the problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incomplete but valid JSON.&lt;/strong&gt; Gemma 4 E4B once returned a perfectly valid JSON response containing just 1 of the 20 requested words. I updated the schema to enforce the exact words and their count.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing traces on long jobs.&lt;/strong&gt; Some long-running jobs disappeared from the tracer. Splitting the work into separate transactions per batch solved that.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After those fixes, Gemma 12B successfully labelled all &lt;strong&gt;1,839 words in 2.3 hours, with no failures&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>gemma</category>
      <category>sentry</category>
    </item>
    <item>
      <title>OpenGameBuilder: Describe a game in one sentence and generate it using a local LLM like Gemma 4.</title>
      <dc:creator>Blaise Labs</dc:creator>
      <pubDate>Mon, 19 Oct 2026 07:20:25 +0000</pubDate>
      <link>https://dev.to/blaiselabs/opengamebuilder-describe-a-game-in-one-sentence-and-generate-it-using-a-local-llm-like-gemma-4-a6k</link>
      <guid>https://dev.to/blaiselabs/opengamebuilder-describe-a-game-in-one-sentence-and-generate-it-using-a-local-llm-like-gemma-4-a6k</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;&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%2Fs035rpwzlcmz122ezi87.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%2Fs035rpwzlcmz122ezi87.png" alt="A river town under cherry trees, drawn entirely by code" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every pixel above is drawn by code. The whole world file is 551 bytes of JSON: a cherry bank, then paddies, people who wander, and a village of ten with a stone lane, shops, a shrine and a temple. A model can write a file like that from one sentence, and then it is a game you can play and download.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;What it is.&lt;/strong&gt; A small game builder on top of a world engine. You pick a world and a kind of game (or describe a world in a sentence and let a model make it), press Play, and download the game as one HTML file that runs offline, drawn entirely in code with no image files. The demo comes with prebuilt worlds you can play in your browser right now (link under Demo).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who it is for.&lt;/strong&gt; People who would like a living little world or game but cannot draw or animate: small game makers, teachers, anyone making a toy for a friend. And people building with small local models, who need a model's output to become something visual that reliably works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The side hustle: games as a service, for many people, not just me.&lt;/strong&gt; It empowers solo game makers and enthusiasts to build simple games with open models like Gemma 4, at a quality comparable to a cloud model's. The point is that other people can make a living with it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a language teacher turns each week's word list into a quiz world for their students;&lt;/li&gt;
&lt;li&gt;a D&amp;amp;D game master builds their campaign's town so the table can walk it before the session;&lt;/li&gt;
&lt;li&gt;someone starts a small business making games for a community, a shop, a classroom or a Discord server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tools are free to use, and free to make and sell games with. When one game has earned US$500 in total, it owes a royalty of 5% of its revenue above that: Unreal Engine's model, at the scale of small games. So a teacher or a game master never pays anything, and the project earns only when the people building on it do.&lt;/p&gt;

&lt;p&gt;It is three open projects, each built on the one before:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/BlaiseLabs/procedural-almanac" rel="noopener noreferrer"&gt;procedural-almanac&lt;/a&gt;&lt;/strong&gt;: the techniques (noise, light, dithering, water, terrain, motion, genes), each with its sources and short tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/BlaiseLabs/OpenWorldBuilder" rel="noopener noreferrer"&gt;OpenWorldBuilder&lt;/a&gt;&lt;/strong&gt;: worlds as data, drawn by the almanac's techniques: a top-down pixel style, a 3D outdoors mode, and side and island views.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/BlaiseLabs/OpenGameBuilder" rel="noopener noreferrer"&gt;OpenGameBuilder&lt;/a&gt;&lt;/strong&gt;: a world plus a small rules file becomes a game.&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/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8doh1hhvvi8zer4n42jn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8doh1hhvvi8zer4n42jn.gif" alt="Villages: people in the lanes of a tea village, a fishing village, a river town, a hot-spring town and a snowy hamlet" width="480" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;a href="https://blaiselabs.github.io/OpenGameBuilder/builder/" rel="noopener noreferrer"&gt;Play the prebuilt worlds in your browser&lt;/a&gt;&lt;/strong&gt; (no account, nothing to install; making a world from a sentence needs a model, so that part runs where you set one up).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fufya81elymozazmdoml4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fufya81elymozazmdoml4.gif" alt="Six top-down worlds, all drawn by code" width="480" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pick a world, or describe one ("a foggy harbour town where crabs run the market").&lt;/li&gt;
&lt;li&gt;Pick a kind of game: explore and collect, endless runner, photo safari, hidden object, fishing, lane racer, quiz (from your own CSV), creature keeper, point and click, island explorer. Eight of them play on the top-down worlds.&lt;/li&gt;
&lt;li&gt;Turn a few knobs, press &lt;strong&gt;Play&lt;/strong&gt;, then &lt;strong&gt;Download&lt;/strong&gt;: one HTML file, about 330 KB, that runs offline. With the 3D mode on it is about 1 MB.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flvf8jfeob0rn5ua2yhok.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flvf8jfeob0rn5ua2yhok.gif" alt="The island explorer in the tea village: walking the lanes, finding the shrine" width="480" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From one sentence to a game: a model made this harbour, its knowledge base and its rules, then a bot played it and won.&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%2F6vyw2czlg2q65p1874s0.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%2F6vyw2czlg2q65p1874s0.png" alt="Lanterns of Clatterclaw, a game made from one sentence" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same worlds can stand up in 3D: an oblique camera that shows roofs and west walls, terraces and walls from the land's own heights, buildings with real roofs, sun shadows, windows lit at night.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxw0hf99w4n0ox58ikt6f.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxw0hf99w4n0ox58ikt6f.gif" alt="The tea village and the fishing village in 3D" width="576" height="300"&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%2Ftbbn4wk9jns474ifsmi3.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%2Ftbbn4wk9jns474ifsmi3.png" alt="The tea village in 3D: roofs, walls and terraces down to the water" width="800" height="417"&gt;&lt;/a&gt;&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/BlaiseLabs" rel="noopener noreferrer"&gt;
        BlaiseLabs
      &lt;/a&gt; / &lt;a href="https://github.com/BlaiseLabs/procedural-almanac" rel="noopener noreferrer"&gt;
        procedural-almanac
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Procedural drawing and motion techniques, each with its sources and short tests
    &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;procedural-almanac&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Procedural drawing and motion for the canvas: walk cycles, flocks, noise-made land, light and projection, where every
technique cites where it came from.&lt;/p&gt;
&lt;p&gt;Version 0.2 holds 72 techniques, 36 established and 36 original, citing 60 sources and held by 150 checks. The full
list, with every source and every test, is the &lt;a href="https://github.com/BlaiseLabs/procedural-almanac/CATALOG.md" rel="noopener noreferrer"&gt;catalog&lt;/a&gt;.&lt;/p&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;module&lt;/th&gt;
&lt;th&gt;techniques&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;numbers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;clamp, lerp, smoothstep, wrap, angleDiff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;random&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;hash32, fnv1a, hashString, indexRandom, SeededRandom, latticeHash, linearCongruential&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;noise&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;latticeRandom, valueNoise, fractalNoise, ridgedNoise, noiseLine, noiseTile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;colour&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;hexToRgb, rgbToHex, rgba, mixColour, shade, luma, rgbToHsl, hslToRgb, hueToward, gradeColour&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pixels&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;packRgb, mixPacked, packedHsl, packedToHsl, hueShiftTone, bayerThreshold, ditheredBorder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;light&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;dayCycle, aerialPerspective, twinkle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;water&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;waterTime, waterPixel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;land&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;hillLine, islandHeight, levelCut, heightWater, wanderingHeading&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;scatter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;scatterAlong, windowLit, blink&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;projection&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;parallax, turnedProjection, turnedDepth, faceShade&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;limbs&lt;/code&gt;, &lt;code&gt;gait&lt;/code&gt;, &lt;code&gt;genes&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;twoBoneLimb; footStep, strideRate, gaitTiming; genomeFrom, crossGenomes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;motion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;flockStep, gridWalk, pulseRise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;particles&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;particleField, fall, rise, hover, wrapAround&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;growth&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;branchingTree, swayingChain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;drawing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;partPath, fillInArt, drawRecipe, grain, vignette, glowSprite,&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/BlaiseLabs/procedural-almanac" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&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/BlaiseLabs" rel="noopener noreferrer"&gt;
        BlaiseLabs
      &lt;/a&gt; / &lt;a href="https://github.com/BlaiseLabs/OpenWorldBuilder" rel="noopener noreferrer"&gt;
        OpenWorldBuilder
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Living worlds drawn by code from a JSON recipe; an open model on a laptop can write one
    &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;OpenWorldBuilder&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Living worlds drawn by code, where a world is only data: a person can write that data by hand, and a language model
even a small open one running on a laptop, can write it from a description.&lt;/p&gt;
&lt;p&gt;Nothing here is a picture file. The ground and its hills, water you can see into, trees and stones standing with their
shadows, animals living their own lives, people by the trail, rain and snow and fireflies, day turning to night: all of
it is drawn by code, from a seed, by one engine (&lt;code&gt;engine/&lt;/code&gt;). A world is one JSON file (&lt;code&gt;worlds/*.json&lt;/code&gt;).&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The top view&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The main view is a world seen from above, drawn as pixel art. It is the engine of &lt;strong&gt;言の葉&lt;/strong&gt; (&lt;em&gt;Kotonoha&lt;/em&gt;, "leaves of
words"), the procedural journey that plays behind the flash cards of &lt;strong&gt;綴 Tsuzuri&lt;/strong&gt; (&lt;em&gt;Tsuzuri&lt;/em&gt;, "writing it…&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/BlaiseLabs/OpenWorldBuilder" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&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/BlaiseLabs" rel="noopener noreferrer"&gt;
        BlaiseLabs
      &lt;/a&gt; / &lt;a href="https://github.com/BlaiseLabs/OpenGameBuilder" rel="noopener noreferrer"&gt;
        OpenGameBuilder
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A small playable web game from a world, an idea or your own data
    &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;OpenGameBuilder&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A small playable web game from an idea, a few choices or some data. Pick a world and a genre (or describe one and let
a model make it), turn a few knobs, upload a file if you have one, press Play, and download the game as one HTML file
that runs anywhere, offline.&lt;/p&gt;
&lt;p&gt;It is a thin layer on two other projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/BlaiseLabs/OpenGameBuilder/../procedural-almanac" rel="noopener noreferrer"&gt;procedural-almanac&lt;/a&gt;: the techniques (noise, light, motion, drawing), each with its sources
and tests.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/BlaiseLabs/OpenGameBuilder/../OpenWorldBuilder-pruned" rel="noopener noreferrer"&gt;OpenWorldBuilder&lt;/a&gt;: living worlds drawn by code from a JSON recipe; a model, even a
small open one, can dream one up.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OpenGameBuilder adds what a world lacks to be a game: a player, a goal, a way to win, and a genre's rules.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Run it&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install
npm start            &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; builds the game script, serves the builder at http://127.0.0.1:8124/builder/&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Without a model, everything except "Describe" works (and the builder can be…&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/BlaiseLabs/OpenGameBuilder" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The almanac is MIT. OpenWorldBuilder and OpenGameBuilder are under a small community license: free to use, change and share, free to make and sell games with, and 5% of a game's revenue above US$500.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 1: the almanac
&lt;/h3&gt;

&lt;p&gt;Every procedural technique OpenWorldBuilder and OpenGameBuilder use lives in one library, each with its sources and a set of short tests that validate it: drawing pixels, bodies that walk, terrain and water from noise, weather, light, paths. Today it holds 162 entries, 106 references and 268 checks. Moving a technique there changes no picture: every move was proved by drawing the same worlds before and after, 0 pixels different.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 2: worlds as data
&lt;/h3&gt;

&lt;p&gt;A top-down world is a list of lands and a route across them. A land is generated from a rule set, not a map:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;rule&lt;/th&gt;
&lt;th&gt;what it says&lt;/th&gt;
&lt;th&gt;for example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ground&lt;/td&gt;
&lt;td&gt;the two tones of the ground and how they are textured&lt;/td&gt;
&lt;td&gt;snow, hatch, rows of tea&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;water&lt;/td&gt;
&lt;td&gt;how much of the land is water, and what kind&lt;/td&gt;
&lt;td&gt;sea, pond, river, hot spring, paddy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;flora&lt;/td&gt;
&lt;td&gt;which plants grow, how often, and where&lt;/td&gt;
&lt;td&gt;maples in groves, reeds on the shore&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fauna&lt;/td&gt;
&lt;td&gt;which animals live there, how many, and how they live&lt;/td&gt;
&lt;td&gt;deer that graze, gulls that flock, people who wander&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;places&lt;/td&gt;
&lt;td&gt;the wayside things&lt;/td&gt;
&lt;td&gt;a well, a shrine, a lighthouse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;village&lt;/td&gt;
&lt;td&gt;a cluster of buildings along a lane&lt;/td&gt;
&lt;td&gt;ten houses, two shops, a temple&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;motes&lt;/td&gt;
&lt;td&gt;what drifts in the air&lt;/td&gt;
&lt;td&gt;snow, petals, fireflies, steam&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Code turns the rules into an ecosystem with terrain, plants, animals, and weather. &lt;/p&gt;

&lt;p&gt;The vocabulary is small and closed: 27 built-in lands, 23 plants, 25 body plans (people among them), 26 kinds of wayside place, 9 kinds of building, 21 ways of living. A checker answers every mistake in words a model can act on, such as a fish living on dry land or a boathouse with no water. A world can also be bounded, so a game's map has an edge: the sea, mist or mountains.&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%2Fofr4y31ebz61kez4xahe.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%2Fofr4y31ebz61kez4xahe.png" alt="Seven hand-made top-down worlds" width="800" height="1000"&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/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcq7qz3jb3avspxa87i3s.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcq7qz3jb3avspxa87i3s.gif" alt="The wild lands: a maple valley, coral isles, a mangrove coast, a violet moor, a mushroom wood, a cherry forest" width="480" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 3: games as rules
&lt;/h3&gt;

&lt;p&gt;A game's rules are a small JSON file beside the world. They never draw anything: they name the world's own animals, places and people by id ("meet the seals of the drift-ice sea", "find the cairn"), so the checker can tell at once whether a goal exists in the world. Each genre also has a bot that plays it. The test plays every genre on every world it fits, and all 324 games are won.&lt;/p&gt;

&lt;h3&gt;
  
  
  An open model on a Mac
&lt;/h3&gt;

&lt;p&gt;The first version asked models to write whole worlds. Gemma 4 12B, on a Mac mini through Ollama, took up to 13 minutes a game world in the initial version of the builder.&lt;/p&gt;

&lt;p&gt;So for small models the code does most of the writing. It lays out one built-in land for each place in the world's knowledge base, the nearest fit, and the model answers one small design: each land's colours, what drifts in the air, and which word draws each thing in the knowledge base. Gemma 12B now makes a clean world in under three minutes, in two calls and about 4.3k tokens, drawing 90 to 100 percent of its knowledge base. A town with a harbour and a temple village took 3.1 to 3.4 minutes.&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%2F6g17yeigfmvqfzhokifu.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%2F6g17yeigfmvqfzhokifu.png" alt="Gemma 4 12B on a Mac mini: a mushroom wood, a drowned cherry forest, a maple valley" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Watching the agents with Sentry
&lt;/h3&gt;

&lt;p&gt;Sentry 26.10.0 runs self-hosted on a mini PC beside the Mac: no account, and the traces never leave my network. Each world is one trace, each stage an &lt;code&gt;invoke_agent&lt;/code&gt; span, each model call a &lt;code&gt;chat&lt;/code&gt; span with its tokens (and, for Gemma, Ollama's own seconds for reading against writing), each check and repair an &lt;code&gt;execute_tool&lt;/code&gt; span.&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%2F9fnkgwzkc6oyrsocuutw.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%2F9fnkgwzkc6oyrsocuutw.png" alt="A Gemma top world in Sentry: one trace, two model calls" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is a whole world from one sentence ("a lantern-lit tea village on terraced hills where foxes carry letters between the farms"), made today by Gemma 12B on the Mac: 3.15 minutes and 9 spans in all. The Lorekeeper writes the knowledge base in one call (2.28 minutes), a repair tool tidies it in a millisecond, and the World Author answers one small design in one call (51 seconds). Nothing failed, so nothing was asked twice.&lt;/p&gt;

&lt;p&gt;It did not start this lean. Two things the traces showed me. A 27-token answer took 56 seconds because Gemma was re-reading a 6.8k-token prompt on every call; a shorter prompt cut it to 33 seconds. And whole rewrites wasted most of the work: a draft from code with changes only drew the same knowledge base in 122 seconds instead of 369. Those two findings led to the design path above.&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%2F0wlzxqig5lsm4mroq4q1.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%2F0wlzxqig5lsm4mroq4q1.png" alt="Sentry's AI agents overview" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What it is not, yet
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The bots prove every game can be won. They win in seconds, so they say nothing about whether a game is fun; no person has played them all.&lt;/li&gt;
&lt;li&gt;There is no sound.&lt;/li&gt;
&lt;li&gt;The 3D buildings are simpler than hand-drawn art, and every building faces south.&lt;/li&gt;
&lt;li&gt;Runner and racer play only in the side view.&lt;/li&gt;
&lt;li&gt;Gemma's lands start from built-in ones, so its worlds are safe rather than surprising.&lt;/li&gt;
&lt;li&gt;The games' own words are thin: the lines a game says are made from templates, and my first user found them flat and in places wrong (see "My First User").&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Open innovation makes new economies possible.&lt;/strong&gt; A closed tool sells games to people. An open one lets people sell games to each other. With an open model on their own machine, a teacher, a game master or a small studio can make games as a service for their own customers: their students, their table, their community. Their cost for one more world is electricity, not an API bill, so even a small price leaves them a living, and the license asks for nothing until a game has really earned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The model lives where the worlds are made.&lt;/strong&gt; Gemma runs on a small computer on my desk: no fee per call, no rate limit, nothing leaves the machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I could build around the model.&lt;/strong&gt; With open weights I could measure where it spent its time, hold every answer to a schema made from the engine's own vocabulary, and shrink its job until it fit: three minutes instead of ten.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open all the way down.&lt;/strong&gt; Open weights, three plain JavaScript projects, worlds and rules as JSON a person can read and edit, and an open-source Sentry on my own machine. The art is code: no image model, nothing trained on anyone's paintings.&lt;/p&gt;

&lt;h2&gt;
  
  
  My First User
&lt;/h2&gt;

&lt;p&gt;My first user is a customer in every way but one: they have not paid, because nothing they made has earned money yet, so under the license nothing is owed. They came with a game in mind and typed it in:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a medieval sky city where Laputa meets Arlathan (island explorer, five kinds of creature to talk to, three places to find)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It came back as two playable versions: one from a cloud model in 49 seconds, and one free, from Gemma on my Mac, in 6.5 minutes. Gemma's has elven purple woods, named folk like the Cloud Monk and the Cloud Strider, and a citadel town with a temple and a bathhouse.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2v7e79cu25jdm0s9ba4e.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2v7e79cu25jdm0s9ba4e.gif" alt="The first user's sky city, made by Gemma, played as the island explorer" width="480" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is not yet the sky city they imagined: nothing reads as sky, and in Gemma's version the bot could not reach the bathhouse and the temple, so the checker's promise that every game can be won has a gap to close.&lt;/p&gt;

&lt;p&gt;They also played two games the night before the deadline, with nothing but the builder and its guide. They picked a world, a kind of game and a few settings, played, and wrote down what bothered them. I have left the code exactly as they found it until after the deadline, so this is their report, not a list of things already fixed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tea Hills in 3D, hidden object, 8 clues, no time limit, seed 1.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A wrong click names what you clicked, and the English is off: "That is the trees", "That is the tufts".&lt;/li&gt;
&lt;li&gt;Some things answer a click with a description (the trees) and others (the animals) say nothing at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Glowing Reef Drift (a side-view reef), quiz in a world, 15 right answers to win, six screens wide, no file uploaded.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The game asked the same few questions (four, by their count) over and over to reach fifteen. The cause is plain once you look: this world has no knowledge base and they uploaded no questions, so the quiz made its questions from the world's animals and plants alone, and there were only a handful to make.&lt;/li&gt;
&lt;li&gt;The score at the top right ("140") does not say out of what. "140/150" would.&lt;/li&gt;
&lt;li&gt;The win screen is too dry: "You won. You did it." Their words: "Be happy for the player's victory, thou must."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this would have shown up in my tests, and that is the point of a first user. All 324 bot games are won, and a bot does not mind a repeated question, a bare number or a flat "You did it." The checker proves a game can be won; it says nothing about whether its words read as if a person wrote them. The fixes are small and clear, and they are the first things I will do after the deadline: names that read as English ("Those are the trees"), every clickable thing answering, a quiz that never asks more questions than it has (and says so, suggesting you upload your own), the score as a share of the goal, and a win screen with some joy in it.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemma (Google):&lt;/strong&gt; Gemma 4 12B, run locally on a Mac mini through Ollama, makes top-down worlds and towns in under three and a half minutes each, and the framework (a draft from code, one small design, the checker) is built so a small open model can do it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sentry Agent Tracing:&lt;/strong&gt; every model run is traced in a self-hosted Sentry, and the traces led to the design path. Setup, spans and findings are in "Watching the agents with Sentry" above.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>gemma</category>
      <category>sentry</category>
    </item>
    <item>
      <title>OpenGameBuilder: Describe a game in one sentence and generate it using a local LLM like Gemma 4.</title>
      <dc:creator>Blaise Labs</dc:creator>
      <pubDate>Mon, 19 Oct 2026 07:01:01 +0000</pubDate>
      <link>https://dev.to/blaiselabs/opengamebuilder-describe-a-game-in-one-sentence-and-generate-it-using-a-local-llm-like-gemma-4-215m</link>
      <guid>https://dev.to/blaiselabs/opengamebuilder-describe-a-game-in-one-sentence-and-generate-it-using-a-local-llm-like-gemma-4-215m</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;&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%2Fs035rpwzlcmz122ezi87.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%2Fs035rpwzlcmz122ezi87.png" alt="A river town under cherry trees, drawn entirely by code" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every pixel above is drawn by code. The whole world file is 551 bytes of JSON: a cherry bank, then paddies, people who wander, and a village of ten with a stone lane, shops, a shrine and a temple. A model can write a file like that from one sentence, and then it is a game you can play and download.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;What it is.&lt;/strong&gt; A small game builder on top of a world engine. You pick a world and a kind of game (or describe a world in a sentence and let a model make it), press Play, and download the game as one HTML file that runs offline, drawn entirely in code with no image files. The demo comes with prebuilt worlds you can play in your browser right now (link under Demo).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who it is for.&lt;/strong&gt; People who would like a living little world or game but cannot draw or animate: small game makers, teachers, anyone making a toy for a friend. And people building with small local models, who need a model's output to become something visual that reliably works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The side hustle: games as a service, for many people, not just me.&lt;/strong&gt; It empowers solo game makers and enthusiasts to build simple games with open models like Gemma 4, at a quality comparable to a cloud model's. The point is that other people can make a living with it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a language teacher turns each week's word list into a quiz world for their students;&lt;/li&gt;
&lt;li&gt;a D&amp;amp;D game master builds their campaign's town so the table can walk it before the session;&lt;/li&gt;
&lt;li&gt;someone starts a small business making games for a community, a shop, a classroom or a Discord server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tools are free to use, and free to make and sell games with. When one game has earned US$500 in total, it owes a royalty of 5% of its revenue above that: Unreal Engine's model, at the scale of small games. So a teacher or a game master never pays anything, and the project earns only when the people building on it do.&lt;/p&gt;

&lt;p&gt;It is three open projects, each built on the one before:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/BlaiseLabs/procedural-almanac" rel="noopener noreferrer"&gt;procedural-almanac&lt;/a&gt;&lt;/strong&gt;: the techniques (noise, light, dithering, water, terrain, motion, genes), each with its sources and short tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/BlaiseLabs/OpenWorldBuilder" rel="noopener noreferrer"&gt;OpenWorldBuilder&lt;/a&gt;&lt;/strong&gt;: worlds as data, drawn by the almanac's techniques: a top-down pixel style, a 3D outdoors mode, and side and island views.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/BlaiseLabs/OpenGameBuilder" rel="noopener noreferrer"&gt;OpenGameBuilder&lt;/a&gt;&lt;/strong&gt;: a world plus a small rules file becomes a game.&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/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8doh1hhvvi8zer4n42jn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8doh1hhvvi8zer4n42jn.gif" alt="Villages: people in the lanes of a tea village, a fishing village, a river town, a hot-spring town and a snowy hamlet" width="480" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;a href="https://blaiselabs.github.io/OpenGameBuilder/builder/" rel="noopener noreferrer"&gt;Play the prebuilt worlds in your browser&lt;/a&gt;&lt;/strong&gt; (no account, nothing to install; making a world from a sentence needs a model, so that part runs where you set one up).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fufya81elymozazmdoml4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fufya81elymozazmdoml4.gif" alt="Six top-down worlds, all drawn by code" width="480" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pick a world, or describe one ("a foggy harbour town where crabs run the market").&lt;/li&gt;
&lt;li&gt;Pick a kind of game: explore and collect, endless runner, photo safari, hidden object, fishing, lane racer, quiz (from your own CSV), creature keeper, point and click, island explorer. Eight of them play on the top-down worlds.&lt;/li&gt;
&lt;li&gt;Turn a few knobs, press &lt;strong&gt;Play&lt;/strong&gt;, then &lt;strong&gt;Download&lt;/strong&gt;: one HTML file, about 330 KB, that runs offline. With the 3D mode on it is about 1 MB.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flvf8jfeob0rn5ua2yhok.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flvf8jfeob0rn5ua2yhok.gif" alt="The island explorer in the tea village: walking the lanes, finding the shrine" width="480" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From one sentence to a game: a model made this harbour, its knowledge base and its rules, then a bot played it and won.&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%2F6vyw2czlg2q65p1874s0.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%2F6vyw2czlg2q65p1874s0.png" alt="Lanterns of Clatterclaw, a game made from one sentence" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same worlds can stand up in 3D: an oblique camera that shows roofs and west walls, terraces and walls from the land's own heights, buildings with real roofs, sun shadows, windows lit at night.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxw0hf99w4n0ox58ikt6f.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxw0hf99w4n0ox58ikt6f.gif" alt="The tea village and the fishing village in 3D" width="576" height="300"&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%2Ftbbn4wk9jns474ifsmi3.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%2Ftbbn4wk9jns474ifsmi3.png" alt="The tea village in 3D: roofs, walls and terraces down to the water" width="800" height="417"&gt;&lt;/a&gt;&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/BlaiseLabs" rel="noopener noreferrer"&gt;
        BlaiseLabs
      &lt;/a&gt; / &lt;a href="https://github.com/BlaiseLabs/procedural-almanac" rel="noopener noreferrer"&gt;
        procedural-almanac
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Procedural drawing and motion techniques, each with its sources and short tests
    &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;procedural-almanac&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Procedural drawing and motion for the canvas and for pixel art: walk cycles, flocks, noise-made land, water
weather, light and projection, ways across a grid, where every technique cites where it came from.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/BlaiseLabs/procedural-almanac/examples/island/island.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2FBlaiseLabs%2Fprocedural-almanac%2FHEAD%2Fexamples%2Fisland%2Fisland.gif" alt="An island drawn with nothing but the almanac: noise becomes terraces, the sea comes in, a river, a forest, villages and roads appear, then a day, a night and a storm"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The island above is made with the almanac alone: &lt;a href="https://github.com/BlaiseLabs/procedural-almanac/examples/island/scene.js" rel="noopener noreferrer"&gt;one scene&lt;/a&gt; calls 85 of its functions
with no sprites or image files, and each caption names the functions on screen.
&lt;strong&gt;&lt;a href="https://blaiselabs.github.io/procedural-almanac/examples/island/" rel="nofollow noopener noreferrer"&gt;Run it in your browser&lt;/a&gt;&lt;/strong&gt;, with a seed of your own.&lt;/p&gt;
&lt;p&gt;The almanac holds 162 techniques, 77 established and 85 original, citing 106 sources and held by 267 checks. The full
list, with every source and every test, is the &lt;a href="https://github.com/BlaiseLabs/procedural-almanac/CATALOG.md" rel="noopener noreferrer"&gt;catalog&lt;/a&gt;.&lt;/p&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;module&lt;/th&gt;
&lt;th&gt;techniques&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;numbers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;clamp, lerp, smoothstep, wrap, angleDiff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;random&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;hash32, fnv1a, hashString, indexRandom, SeededRandom, latticeHash, linearCongruential&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;noise&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;latticeRandom, valueNoise, fractalNoise, ridgedNoise, noiseLine, noiseTile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pixels&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;packRgb, mixPacked, packedHsl, packedToHsl, hueShiftTone, bayerThreshold, ditheredBorder, scalePacked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;water&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;waterTime, waterPixel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;colour&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;hexToRgb, rgbToHex, rgba, mixColour, shade, luma, rgbToHsl,&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/BlaiseLabs/procedural-almanac" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&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/BlaiseLabs" rel="noopener noreferrer"&gt;
        BlaiseLabs
      &lt;/a&gt; / &lt;a href="https://github.com/BlaiseLabs/OpenWorldBuilder" rel="noopener noreferrer"&gt;
        OpenWorldBuilder
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Living worlds drawn by code from a JSON recipe; an open model on a laptop can write one
    &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;OpenWorldBuilder&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Living worlds drawn by code, where a world is only data: a person can write that data by hand, and a language model
even a small open one running on a laptop, can write it from a description.&lt;/p&gt;
&lt;p&gt;Nothing here is a picture file. The ground and its hills, water you can see into, trees and stones standing with their
shadows, animals living their own lives, people by the trail, rain and snow and fireflies, day turning to night: all of
it is drawn by code, from a seed, by one engine (&lt;code&gt;engine/&lt;/code&gt;). A world is one JSON file (&lt;code&gt;worlds/*.json&lt;/code&gt;).&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The top view&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The main view is a world seen from above, drawn as pixel art. It is the engine of &lt;strong&gt;言の葉&lt;/strong&gt; (&lt;em&gt;Kotonoha&lt;/em&gt;, "leaves of
words"), the procedural journey that plays behind the flash cards of &lt;strong&gt;綴 Tsuzuri&lt;/strong&gt; (&lt;em&gt;Tsuzuri&lt;/em&gt;, "writing it…&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/BlaiseLabs/OpenWorldBuilder" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&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/BlaiseLabs" rel="noopener noreferrer"&gt;
        BlaiseLabs
      &lt;/a&gt; / &lt;a href="https://github.com/BlaiseLabs/OpenGameBuilder" rel="noopener noreferrer"&gt;
        OpenGameBuilder
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A small playable web game from a world, an idea or your own data
    &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;OpenGameBuilder&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A small playable web game from an idea, a few choices or some data. Pick a world and a genre (or describe one and let
a model make it), turn a few knobs, upload a file if you have one, press Play, and download the game as one HTML file
that runs anywhere, offline.&lt;/p&gt;
&lt;p&gt;It is a thin layer on two other projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/BlaiseLabs/OpenGameBuilder/../procedural-almanac" rel="noopener noreferrer"&gt;procedural-almanac&lt;/a&gt;: the techniques (noise, light, motion, drawing), each with its sources
and tests.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/BlaiseLabs/OpenGameBuilder/../OpenWorldBuilder-pruned" rel="noopener noreferrer"&gt;OpenWorldBuilder&lt;/a&gt;: living worlds drawn by code from a JSON recipe; a model, even a
small open one, can dream one up.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OpenGameBuilder adds what a world lacks to be a game: a player, a goal, a way to win, and a genre's rules.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Run it&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install
npm start            &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; builds the game script, serves the builder at http://127.0.0.1:8124/builder/&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Without a model, everything except "Describe" works (and the builder can be…&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/BlaiseLabs/OpenGameBuilder" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The almanac is MIT. OpenWorldBuilder and OpenGameBuilder are under a small community license: free to use, change and share, free to make and sell games with, and 5% of a game's revenue above US$500.&lt;/p&gt;

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

&lt;p&gt;I built it with AI coding agents, several at a time, each on its own part, each held to tests and to films of what it drew. I set the direction and judged every result by looking at it: the first versions were flat side-on scenes, I called them what they were, and the top-down style, the villages and the 3D came from that. The open model is what the product itself runs on: Gemma 4 12B through Ollama, on a Mac mini on my desk.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 1: the almanac
&lt;/h3&gt;

&lt;p&gt;Every procedural technique OpenWorldBuilder and OpenGameBuilder use lives in one library, each with its sources and a set of short tests that validate it: drawing pixels, bodies that walk, terrain and water from noise, weather, light, paths. Today it holds 162 entries, 106 references and 268 checks. Moving a technique there changes no picture: every move was proved by drawing the same worlds before and after, 0 pixels different.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 2: worlds as data
&lt;/h3&gt;

&lt;p&gt;A top-down world is a list of lands and a route across them. A land is generated from a rule set, not a map:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;rule&lt;/th&gt;
&lt;th&gt;what it says&lt;/th&gt;
&lt;th&gt;for example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ground&lt;/td&gt;
&lt;td&gt;the two tones of the ground and how they are textured&lt;/td&gt;
&lt;td&gt;snow, hatch, rows of tea&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;water&lt;/td&gt;
&lt;td&gt;how much of the land is water, and what kind&lt;/td&gt;
&lt;td&gt;sea, pond, river, hot spring, paddy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;flora&lt;/td&gt;
&lt;td&gt;which plants grow, how often, and where&lt;/td&gt;
&lt;td&gt;maples in groves, reeds on the shore&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fauna&lt;/td&gt;
&lt;td&gt;which animals live there, how many, and how they live&lt;/td&gt;
&lt;td&gt;deer that graze, gulls that flock, people who wander&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;places&lt;/td&gt;
&lt;td&gt;the wayside things&lt;/td&gt;
&lt;td&gt;a well, a shrine, a lighthouse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;village&lt;/td&gt;
&lt;td&gt;a cluster of buildings along a lane&lt;/td&gt;
&lt;td&gt;ten houses, two shops, a temple&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;motes&lt;/td&gt;
&lt;td&gt;what drifts in the air&lt;/td&gt;
&lt;td&gt;snow, petals, fireflies, steam&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Code turns the rules into an ecosystem with terrain, plants, animals, and weather. &lt;/p&gt;

&lt;p&gt;The vocabulary is small and closed: 27 built-in lands, 23 plants, 25 body plans (people among them), 26 kinds of wayside place, 9 kinds of building, 21 ways of living. A checker answers every mistake in words a model can act on, such as a fish living on dry land or a boathouse with no water. A world can also be bounded, so a game's map has an edge: the sea, mist or mountains.&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%2Fofr4y31ebz61kez4xahe.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%2Fofr4y31ebz61kez4xahe.png" alt="Seven hand-made top-down worlds" width="800" height="1000"&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/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcq7qz3jb3avspxa87i3s.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcq7qz3jb3avspxa87i3s.gif" alt="The wild lands: a maple valley, coral isles, a mangrove coast, a violet moor, a mushroom wood, a cherry forest" width="480" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 3: games as rules
&lt;/h3&gt;

&lt;p&gt;A game's rules are a small JSON file beside the world. They never draw anything: they name the world's own animals, places and people by id ("meet the seals of the drift-ice sea", "find the cairn"), so the checker can tell at once whether a goal exists in the world. Each genre also has a bot that plays it. The test plays every genre on every world it fits, and all 324 games are won.&lt;/p&gt;

&lt;h3&gt;
  
  
  An open model on a Mac
&lt;/h3&gt;

&lt;p&gt;The first version asked models to write whole worlds. Gemma 4 12B, on a Mac mini through Ollama, took up to 13 minutes a game world in the initial version of the builder.&lt;/p&gt;

&lt;p&gt;So for small models the code does most of the writing. It lays out one built-in land for each place in the world's knowledge base, the nearest fit, and the model answers one small design: each land's colours, what drifts in the air, and which word draws each thing in the knowledge base. Gemma 12B now makes a clean world in under three minutes, in two calls and about 4.3k tokens, drawing 90 to 100 percent of its knowledge base. A town with a harbour and a temple village took 3.1 to 3.4 minutes.&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%2F6g17yeigfmvqfzhokifu.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%2F6g17yeigfmvqfzhokifu.png" alt="Gemma 4 12B on a Mac mini: a mushroom wood, a drowned cherry forest, a maple valley" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Watching the agents with Sentry
&lt;/h3&gt;

&lt;p&gt;Sentry 26.10.0 runs self-hosted on a mini PC beside the Mac: no account, and the traces never leave my network. Each world is one trace, each stage an &lt;code&gt;invoke_agent&lt;/code&gt; span, each model call a &lt;code&gt;chat&lt;/code&gt; span with its tokens (and, for Gemma, Ollama's own seconds for reading against writing), each check and repair an &lt;code&gt;execute_tool&lt;/code&gt; span.&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%2F9fnkgwzkc6oyrsocuutw.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%2F9fnkgwzkc6oyrsocuutw.png" alt="A Gemma top world in Sentry: one trace, two model calls" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is a whole world from one sentence ("a lantern-lit tea village on terraced hills where foxes carry letters between the farms"), made today by Gemma 12B on the Mac: 3.15 minutes and 9 spans in all. The Lorekeeper writes the knowledge base in one call (2.28 minutes), a repair tool tidies it in a millisecond, and the World Author answers one small design in one call (51 seconds). Nothing failed, so nothing was asked twice.&lt;/p&gt;

&lt;p&gt;It did not start this lean. Two things the traces showed me. A 27-token answer took 56 seconds because Gemma was re-reading a 6.8k-token prompt on every call; a shorter prompt cut it to 33 seconds. And whole rewrites wasted most of the work: a draft from code with changes only drew the same knowledge base in 122 seconds instead of 369. Those two findings led to the design path above.&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%2F0wlzxqig5lsm4mroq4q1.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%2F0wlzxqig5lsm4mroq4q1.png" alt="Sentry's AI agents overview" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What it is not, yet
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The bots prove every game can be won. They win in seconds, so they say nothing about whether a game is fun; no person has played them all.&lt;/li&gt;
&lt;li&gt;There is no sound.&lt;/li&gt;
&lt;li&gt;The 3D buildings are simpler than hand-drawn art, and every building faces south.&lt;/li&gt;
&lt;li&gt;Runner and racer play only in the side view.&lt;/li&gt;
&lt;li&gt;Gemma's lands start from built-in ones, so its worlds are safe rather than surprising.&lt;/li&gt;
&lt;li&gt;The games' own words are thin: the lines a game says are made from templates, and my first user found them flat and in places wrong (see "My First User").&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Open innovation makes new economies possible.&lt;/strong&gt; A closed tool sells games to people. An open one lets people sell games to each other. With an open model on their own machine, a teacher, a game master or a small studio can make games as a service for their own customers: their students, their table, their community. Their cost for one more world is electricity, not an API bill, so even a small price leaves them a living, and the license asks for nothing until a game has really earned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The model lives where the worlds are made.&lt;/strong&gt; Gemma runs on a small computer on my desk: no fee per call, no rate limit, nothing leaves the machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I could build around the model.&lt;/strong&gt; With open weights I could measure where it spent its time, hold every answer to a schema made from the engine's own vocabulary, and shrink its job until it fit: three minutes instead of ten.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open all the way down.&lt;/strong&gt; Open weights, three plain JavaScript projects, worlds and rules as JSON a person can read and edit, and an open-source Sentry on my own machine. The art is code: no image model, nothing trained on anyone's paintings.&lt;/p&gt;

&lt;h2&gt;
  
  
  My First User
&lt;/h2&gt;

&lt;p&gt;My first user is a customer in every way but one: they have not paid, because nothing they made has earned money yet, so under the license nothing is owed. They came with a game in mind and typed it in:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;a medieval sky city where Laputa meets Arlathan (island explorer, five kinds of creature to talk to, three places to find)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It came back as two playable versions: one from a cloud model in 49 seconds, and one free, from Gemma on my Mac, in 6.5 minutes. Gemma's has elven purple woods, named folk like the Cloud Monk and the Cloud Strider, and a citadel town with a temple and a bathhouse.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2v7e79cu25jdm0s9ba4e.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2v7e79cu25jdm0s9ba4e.gif" alt="The first user's sky city, made by Gemma, played as the island explorer" width="480" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is not yet the sky city they imagined: nothing reads as sky, and in Gemma's version the bot could not reach the bathhouse and the temple, so the checker's promise that every game can be won has a gap to close.&lt;/p&gt;

&lt;p&gt;They also played two games the night before the deadline, with nothing but the builder and its guide. They picked a world, a kind of game and a few settings, played, and wrote down what bothered them. I have left the code exactly as they found it until after the deadline, so this is their report, not a list of things already fixed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tea Hills in 3D, hidden object, 8 clues, no time limit, seed 1.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A wrong click names what you clicked, and the English is off: "That is the trees", "That is the tufts".&lt;/li&gt;
&lt;li&gt;Some things answer a click with a description (the trees) and others (the animals) say nothing at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Glowing Reef Drift (a side-view reef), quiz in a world, 15 right answers to win, six screens wide, no file uploaded.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The game asked the same few questions (four, by their count) over and over to reach fifteen. The cause is plain once you look: this world has no knowledge base and they uploaded no questions, so the quiz made its questions from the world's animals and plants alone, and there were only a handful to make.&lt;/li&gt;
&lt;li&gt;The score at the top right ("140") does not say out of what. "140/150" would.&lt;/li&gt;
&lt;li&gt;The win screen is too dry: "You won. You did it." Their words: "Be happy for the player's victory, thou must."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this would have shown up in my tests, and that is the point of a first user. All 324 bot games are won, and a bot does not mind a repeated question, a bare number or a flat "You did it." The checker proves a game can be won; it says nothing about whether its words read as if a person wrote them. The fixes are small and clear, and they are the first things I will do after the deadline: names that read as English ("Those are the trees"), every clickable thing answering, a quiz that never asks more questions than it has (and says so, suggesting you upload your own), the score as a share of the goal, and a win screen with some joy in it.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemma (Google):&lt;/strong&gt; Gemma 4 12B, run locally on a Mac mini through Ollama, makes top-down worlds and towns in under three and a half minutes each, and the framework (a draft from code, one small design, the checker) is built so a small open model can do it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sentry Agent Tracing:&lt;/strong&gt; every model run is traced in a self-hosted Sentry, and the traces led to the design path. Setup, spans and findings are in "Watching the agents with Sentry" above.&lt;/li&gt;
&lt;/ul&gt;

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