LastBall Finale: One Last Ball Thrown, One Still Buried in Viridian Forest
The last post ended with a promise: let the machine run one complete shiny hunt in the emulator first, and when it has drawn all eight thousand lottery tickets for me and that one wrong-looking screenshot pops up on my phone, I'll go throw the last ball.
Time to settle the account. One ball has been thrown. The other is still buried under the 95% of bug Pokémon in Viridian Forest.
1. The good life in the emulator
The emulator was only ever meant to be a stepping stone, but this phase was genuinely fun. I ran fourteen emulator instances in parallel on a Mac mini, batch-hunting at about twenty thousand encounters an hour, my phone buzzing from morning to night. And as the grind went on, a problem I never thought of at kickoff surfaced: the target species is not the only thing living in this patch of grass. If the machine, mid-hunt, runs into a shiny of some other species — under the old logic it would flee without blinking, personally releasing a 1-in-8192 miracle back into the wild.
So I gave it a sideline mode (sideline.py). The program doesn't know in advance which species live in this grass; it learns them as it farms. Every non-target Pokémon it meets is first matched by appearance against the species it has already seen; an unfamiliar one gets recorded as a new species. For the first few encounters with a newly met species, the program hasn't yet collected enough reference frames for what its normal coloring looks like, so it sends the screenshot to a multimodal LLM and asks one question: is this the shiny coloration? Two or three questions per species is all it ever takes; once the references are collected, it switches to local color comparison and never spends another cent. That closes both holes at once: a first-ever encounter that happens to be shiny won't be fled as a normal one, and a shiny frame won't be mis-recorded as that species' normal coloring.
The sideline mode paid off fast: one shiny Zigzagoon and one shiny Wurmple, both caught by the LLM in that early getting-acquainted stage. The game froze on the spot, all input stopped, and my phone got the push: "Come throw the last ball."

The fleet hit one snag of its own. At first every instance ran with a graphics window. A dozen or so was fine, but past that, some instances visibly stalled. I worked through whether the CPU or the GPU was falling behind — and it turned out the big cost wasn't the game's own computation at all, but a dozen-plus windows all rendering at once. So I moved every instance to the background, no windows — and both the instance count and each instance's speed went up.
Not seeing the screens is fine day to day. When a shiny does land and the game freezes, the project has a takeover tool (takeover.py): it opens a window mirroring that instance's live game picture, and my keyboard input passes straight into the game. The hunting program has fully stood down by then; every step from there on is my own.
2. Back to the real business: my shopping list was completely wrong
With the emulator itch scratched, I remembered the roadmap still had two steps left: P2, swap the hand; P3, swap the eye — destination, real hardware. The picture in my head had always been: buy servos, 3D-print a mechanical finger to rest on the controller's A button, point a camera at the Switch screen, then wrestle lighting, moiré, and perspective distortion deep into the night.
Talking the requirements through with Fable 5, I found nearly the whole list could be crossed out. The eye: the Switch dock already outputs HDMI to a TV — swap the "TV" for a video capture card, plug the other end into the Mac, and the 1080p picture flows into the program untouched. No camera, no lighting rig, and moiré simply doesn't exist. The hand: the Switch already accepts any Bluetooth Pro Controller — flash a Pico 2 W with open-source firmware (PokemonAutomation's PABotBase2, MIT-licensed), and to the console it simply is a wireless controller; the USB serial side plugs into the Mac mini, and when my program says "press A," it presses A.
The shopping list shrank from a servo kit to a capture card plus a board that costs a few dollars. And the boundary didn't move an inch: what the console sees is a "TV" and a "controller," both things it was born to recognize. The game itself, the save file, the RNG — not one byte touched. The shiny is still rolled entirely by the game itself.
"Simple," of course, is relative to servos. The night of protocol archaeology still charged full tuition, and the best lesson was the gyroscope: in a wireless controller's full state report, the sensor readings must not all be zero — a controller holding perfectly still gets ruled dead by the console and kicked offline. You have to feed it 1G of gravity and a faint tremor so it passes for being held by a living hand. Also, the capture card must be opened by device name, never by index: I tried by index three times, and all three times opened my iPhone's Continuity Camera instead — the program dutifully took photos of my desk.
3. Gold at 1:55 a.m.
The real-console starter hunt began. The procedure is exactly what a human shiny hunter does: restart the game, receive the Charmander, glance at its color, and go again if it's normal — about 65 seconds a round, odds 1/8192, median time to a shiny about four days. I set my alarms and braced for a long campaign.
It took 27 rounds. At 1:55 a.m. the phone went off. Judge score 0.826, seven times the threshold. In the photo, a Charmander in solid gold, a star tucked into the corner of its portrait frame. Counting early sampling and debugging, the machine had seen only 121 Charmander in total before one came up shiny — a cumulative probability of just 1.5%. Absurd luck.

At the moment of discovery, the Charmander is already in the party — one step short of a save. Without a save, a single reset erases it. And saving is precisely the step the machine refuses to perform: it just holds position and pushes a reminder — don't touch the Mac, don't close the game. Sealing this Pokémon's ownership is the one step that must be done by a human; that rule was written on day one. I got out of bed, picked up my own controller, and pressed save.
The first "last ball" has been thrown.
📹 Footage of that moment: the machine froze, and I walked over to take the controller (2 min 47 s, shot on a phone; also on Bilibili)
4. Viridian Forest: 95% bugs, 5% Pikachu
After the starter, the hunt moved to the wild. Target: shiny Pikachu. The re-release prints the species name right on the HP plate, so identifying a Pokémon no longer means guessing from its looks — just read the text. On my side, all I have to say is "hunt me a shiny Pikachu," and the rest takes care of itself.
For this hunt I turned on --main-only mode: freeze only for the target species' shiny. Eighty percent of Viridian Forest encounters are Caterpie and Weedle; if the machine froze for their shinies too and waited for me, the Pikachu hunt would never end. So in this mode, on a non-target shiny the machine takes one photo, sends one notification, then flees normally and keeps hunting Pikachu. In two days it has released two this way: encounter #2641 was a shiny Weedle, #5814 a shiny Caterpie.

The numbers are honest. This run started on the evening of August 28 and is still going as I type: 7,931 encounters — 3,189 Weedle, 3,177 Caterpie, 789 Metapod, 399 Pikachu, 380 Kakuna. Pikachu is 5.03% of the total, dead on the official encounter table's 5% — this machine grinds even the probabilities honestly. Which also means a shiny Pikachu is a 5% × 1/8192 ≈ 1-in-163,840 event per encounter; at twenty-odd seconds an encounter, the median wait is about a month. The 399 Pikachu met so far are a rounding error of a rounding error.
One counterintuitive fact worth stating: there is no progress bar in shiny hunting. Every encounter is an independent 1-in-163,840 draw, and nothing already ground brings the next shiny any closer. Ask the program "how much longer" at any moment, and the answer is always the same: starting from right now, the median is about a month.
Epilogue
All four steps of the roadmap are done, and the project finally feels whole: a Mac mini, a capture card, and a Pico sit quietly on the TV stand, pressing buttons for me, checking colors for me, staying up nights for me. My phone rings for exactly three things: a shiny, a stall that needs my hands, or the Bluetooth controller needing to re-pair.
Pikachu may come next week, or not until the leaves fall. But I have never been this certain that it will come — because the moment it steps out, the machine will stop everything, and I will walk over and pick up my own controller.
The last ball stays in my hands.