Give a monkey a typewriter and infinite time, and it will eventually type the works of Shakespeare. That's the infinite monkey theorem.
I got bored of a normal GitHub profile README. So I put the theorem on mine.
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.
The CLI the monkey pretends to run
$ monkey --type --keys=10M
# or, when someone feeds a banana:
$ monkey --type --banana=@you
Under the hood it's just:
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
How the typing works
27 keys (a–z + space), uniform, via crypto.randomBytes. Reject bytes ≥ 243 so every key stays equally likely:
const ALPHABET = "abcdefghijklmnopqrstuvwxyz ";
const DAILY_KEYSTROKES = 10_000_000;
function type(count) {
const chars = new Array(count);
let n = 0;
while (n < count) {
for (const byte of randomBytes(Math.min(65536, (count - n) * 2))) {
if (byte >= 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…
}
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.
Feed the monkey
Anyone can open a banana issue. Each one buys 1,000,000 extra keystrokes right away.
The Action replies with the snippet and your avatar lands on the donor wall.
🐒🍌 *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:
> To hell, allegiance! Vows, to the blackest devil!
No signup. GitHub Issues as a game controller.
The README is generated, not edited
// Generated by scripts/monkey.mjs. Edit the script, not this file.
writeFileSync(`${root}README.md`, readme(state));
Banners, stats, feed button and project cards are SVGs (light + dark), fonts embedded as base64 so every viewer sees the same type. Full source: scripts/monkey.mjs.
Why bother
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 — penciled.js, localhost, better-auth-localization — but this post is about the monkey, not a launch.
Try it
Profile: github.com/marcellosso
Drop a banana. Ruin (or slightly improve) the monkey's day.
If the monkey ever finishes Hamlet, I'll buy everyone a coffee. Don't hold your breath.

Top comments (0)