Notes from
the studio.
Game updates, what goes on behind them, and the occasional technical write-up — from the person building them.
What AdMob Unity mediation adapter status means
Three mediation adapters showed up NotReady in a project with no mediation installed. I installed one for real to find out which field actually tells you anything.
ReadUnity IL2CPP vs Mono on Android, measured
Same project, both scripting backends, Unity 6. IL2CPP came out 47% smaller and took twice as long to build — and the Mono APK would not install on the test device at all.
Readask-first: questions in a card, not a paragraph
A free Claude Code plugin that moves every question out of prose and into a card — one question at a time, with a recommended answer. Here is why I built it, how it works, and how to install it.
ReadAdMob Unity test IDs, and two error codes
I loaded the three AdMob test units in a real Unity build, then broke the ad unit ID two ways. The failures look nothing alike, and one gets mistaken for no fill.
ReadUnity 6 Android build errors that exit 0
Four times last week a headless Unity 6 Android build told me it had succeeded when it had not. Every one returned exit code 0, which is the only thing CI reads.
ReadThe AdMob Unity SDK check that stops nothing
The Google Mobile Ads plugin says it will not build without an App ID. I left the field empty and got an APK anyway — one that dies before the first frame.
ReadAdMob limited ad serving on the wrong app
I created a second AdMob app for a game that already had one. The listing link went to the empty app, the app I was shipping got limited ad serving, and only one of them could be fixed without a release.
ReadFour things break when CI posts to LinkedIn
The LinkedIn API call that publishes a post is six lines. The token that expires every 60 days with no refresh, the read scope you cannot have, and a filename that became a dead link took the rest of the afternoon.
ReadGradle build failed is not the error
Unity prints CommandInvokationFailure, then 67 environment variables. The line saying what broke is 235 lines up. Four failures I reproduced in Unity 6000.4.
ReadOne engine, many games
Six word puzzles built as six copies of one game. What it cost, and what an app directory looks like once the game moves out of it and only identity stays behind.
ReadGenerate levels offline, not at runtime
Runtime generation promises infinite levels for free. What it gives you is levels nobody has checked. The offline pipeline I use instead.
ReadRating puzzle difficulty by decisions
Grid size is the obvious difficulty proxy and it is wrong. Measuring the branching factor of the solve gives a rating that survives contact with players.
ReadDifficulty rates a stage, progression places it
Sorting a level library easiest-to-hardest gives a campaign that is flat for a hundred stages and then a wall. What replaced the sort.
ReadThe opening layout is part of the puzzle
Where the loose pieces sit is a packing problem, and its objective is how large the board can be drawn. Optimise that and you leak the answer.
ReadShipping a 4 MB level pack
392 levels of JSON, pretty-printed for review and minified for the store. The Vite plugin that does it, and the hook choice that hid a real error.
ReadTesting a level pack you did not write
Unit-testing the game does not tell you whether the 392 levels in this build are solvable. So the suite plays every one of them.
ReadPricing an economy off its difficulty model
Levels differ 13x in the thinking they demand, so a flat coin reward is wrong on nearly all of them. Tying payouts to the difficulty walk.
ReadCutting a Capacitor Android build in half
13.1 MB down to 5.9 MB delivered. R8 is off in the project Capacitor generates, and one library's consumer ProGuard rule was pinning 9,304 classes.
ReadA release pipeline you cannot forget
The Android project is generated, not committed — which reset the version code to 1 and nearly made the app un-updatable. Plus the checks worth failing on.
ReadCloudflare injects a beacon. My CSP said no.
A CSP error in production, from a script I never added. The usual fix is to allow the host — which would have made my privacy policy false.
ReadLighthouse's image budget is w × h ÷ 6
Improve image delivery" makes two complaints in one panel. Both have exact arithmetic behind them, readable straight out of the JSON report.
Readopacity 0 does not hide anything
My lightbox was invisible and still in the tab order. Fixing that broke focus handling silently, because focus() on a hidden element reports nothing.
ReadThe check that passed while broken
Two checks in my build were green for months while testing nothing. One was switched off by a guard clause, the other by a missing space in a regex.
ReadChanging a Google Play privacy policy URL
Five live listings pointed at my old Blogger URLs. How I moved them without ever serving a broken privacy policy link.
ReadThe blast radius rule for AI coding
How I decide what an AI agent may change on its own — sorted by what a mistake costs to undo, not by how hard the task is. Three zones, and the check for each.
ReadI don't review AI code. My build does.
Reading every diff at generation speed isn't review, it's skimming. Here is the 169-line verifier that gates this site, and the bug behind every check in it.
ReadI stopped writing prompts. I write the repo.
The best prompt I ever wrote was a README. What changed when I moved my conventions out of the chat window and into the files they describe.
ReadDeploying a static site to Cloudflare Workers
A build-verify-deploy pipeline on Cloudflare's free tier, and the five traps that cost me an evening — including one that silently takes your staging URL offline.
Read