<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Marcel Losso]]></title><description><![CDATA[Marcel Losso]]></description><link>https://marcellosso.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 04 Nov 2026 14:04:30 GMT</lastBuildDate><atom:link href="https://marcellosso.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[I Gave a Monkey 10 Million Keystrokes a Day on My GitHub Profile (It's Trying to Write Hamlet)]]></title><description><![CDATA[A GitHub Action gives a pixel monkey 10M random keystrokes daily and checks for Hamlet. Feed it a banana via Issues — live on my profile.]]></description><link>https://marcellosso.hashnode.dev/i-gave-a-monkey-10-million-keystrokes-a-day-on-my-github-profile-it-s-trying-to-write-hamlet</link><guid isPermaLink="true">https://marcellosso.hashnode.dev/i-gave-a-monkey-10-million-keystrokes-a-day-on-my-github-profile-it-s-trying-to-write-hamlet</guid><category><![CDATA[GitHub]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[fun]]></category><category><![CDATA[README]]></category><category><![CDATA[github readme]]></category><category><![CDATA[monkey type]]></category><category><![CDATA[Infinite monkey theorem]]></category><dc:creator><![CDATA[Marcel Losso Forte]]></dc:creator><pubDate>Tue, 27 Oct 2026 01:41:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adff5e1943e682eec05f9f7/8d62676e-31c1-43e7-98f1-2f80126164bd.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Give a monkey a typewriter and infinite time, and it will eventually type the works of Shakespeare. That's the <a href="https://en.wikipedia.org/wiki/Infinite_monkey_theorem">infinite monkey theorem</a>.</p>
<p>I got bored of a normal GitHub profile README. So I put the theorem on mine.</p>
<p>Every day a GitHub Action hands my pixel monkey 10,000,000 random keystrokes and checks whether any of them landed on Hamlet. The stats update on the README. The longest match so far is "o the bla" — nine characters, somewhere in Act IV. At this pace, finishing the play takes about 10^237421 years. Cool.</p>
<p><strong>The CLI the monkey pretends to run</strong></p>
<pre><code class="language-shell">$ monkey --type --keys=10M
# or, when someone feeds a banana:
$ monkey --type --banana=@you
</code></pre>
<p>Under the hood it's just:</p>
<pre><code class="language-shell">node scripts/monkey.mjs type    # daily: 10M random keystrokes
node scripts/monkey.mjs feed    # banana issue: +1M keys + reply
node scripts/monkey.mjs render  # redraw SVGs + README from state
</code></pre>
<p><strong>How the typing works</strong> 27 keys (a–z + space), uniform, via crypto.randomBytes. Reject bytes ≥ 243 so every key stays equally likely:</p>
<pre><code class="language-javascript">const ALPHABET = "abcdefghijklmnopqrstuvwxyz ";
const DAILY_KEYSTROKES = 10_000_000;
function type(count) {
  const chars = new Array(count);
  let n = 0;
  while (n &lt; count) {
    for (const byte of randomBytes(Math.min(65536, (count - n) * 2))) {
      if (byte &gt;= 243) continue; // 243 = 9 * 27
      chars[n++] = ALPHABET[byte % 27];
      if (n === count) break;
    }
  }
  const stream = chars.join("");
  // then find the longest substring that also appears in Hamlet…
}
</code></pre>
<p>Hamlet is normalized (lowercase letters, runs of junk → one space). Matches are looked up in length-keyed Sets, then mapped back to Act / Scene / line for the SVG quote.</p>
<p><strong>Feed the monkey</strong> Anyone can open a banana issue. Each one buys 1,000,000 extra keystrokes right away.</p>
<img src="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/zq3lkgt3pdl25yfg0x51.png" alt="A button with &quot;Feed the monkey&quot; written on it in yellow. Underneath a text that says &quot;Each banana buys 1,000,000 extra keystrokes right away. The monkey replies with what it typed, and you join the wall below.&quot; and then avatar images from &quot;Banana Donors&quot;" style="display:block;margin:0 auto" />

<p>The Action replies with the snippet and your avatar lands on the donor wall.</p>
<pre><code class="language-markdown">🐒🍌 *nom.* Thanks @you! That banana bought 1,000,000 keystrokes. Somewhere in the mess:
to hell allegiance vows to the bla…
                    ^^^^^^^^^
**"o the bla"** (9 characters) appears in Hamlet, Act IV, Scene I:
&gt; To hell, allegiance! Vows, to the blackest devil!
</code></pre>
<p>No signup. GitHub Issues as a game controller.</p>
<p>The README is generated, not edited</p>
<pre><code class="language-javascript">// Generated by scripts/monkey.mjs. Edit the script, not this file.
writeFileSync(`${root}README.md`, readme(state));
</code></pre>
<p>Banners, stats, feed button and project cards are SVGs (light + dark), fonts embedded as base64 so every viewer sees the same type. Full source: <a href="https://github.com/marcellosso/marcellosso/blob/main/scripts/monkey.mjs">scripts/monkey.mjs</a>.</p>
<p><strong>Why bother</strong> Profile READMEs are usually a skill grid and a wavy “Hi I'm…”. This one is an experiment you can poke. The cards under the monkey point at things I ship — <a href="https://www.penciled.org/">penciled.js</a>, <a href="https://www.getlocalhost.app/">localhost</a>, <a href="https://www.npmjs.com/package/better-auth-localization">better-auth-localization</a> — but this post is about the monkey, not a launch.</p>
<p><strong>Try it</strong> Profile: <a href="https://github.com/marcellosso">github.com/marcellosso</a></p>
<p>Drop a banana. Ruin (or slightly improve) the monkey's day.</p>
<p>If the monkey ever finishes Hamlet, I'll buy everyone a coffee. Don't hold your breath.</p>
]]></content:encoded></item></channel></rss>