Blog

Notes from
the studio.

Game updates, what goes on behind them, and the occasional technical write-up — from the person building them.

RSS feed

·5 min read

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.

unityandroidadmobgamedev
Read
·4 min read

Unity 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.

unityandroidil2cppgamedev
Read
·11 min read

ask-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.

claude-codeaiworkflowcode
Read
·4 min read

AdMob 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.

unityandroidadmobgamedev
Read
·5 min read

Unity 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.

unityandroidci-cdgradlegamedev
Read
·8 min read

The 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.

unityandroidadmobgamedev
Read
·6 min read

AdMob 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.

google-playadmobandroidrelease
Read
·11 min read

Four 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.

ci-cdgithub-actionslinkedin
Read
·9 min read

Gradle 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.

unityandroidgradlegamedev
Read
·7 min read

One 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.

gamedevarchitecturemonorepocapacitor
Read
·7 min read

Generate 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.

gamedevprocedural-generationpuzzlearchitecture
Read
·7 min read

Rating 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.

gamedevdifficultypuzzleprocedural-generationgist
Read
·7 min read

Difficulty 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.

gamedevdifficultylevel-designpuzzlegist
Read
·7 min read

The 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.

gamedevpuzzlelevel-design
Read
·5 min read

Shipping 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.

gamedevcapacitorviteperformancegist
Read
·5 min read

Testing 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.

testinggamedevpuzzlearchitecturegist
Read
·5 min read

Pricing 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.

gamedevgame-economyfree-to-playdifficultygist
Read
·7 min read

Cutting 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.

gamedevcapacitorandroidapkr8gist
Read
·6 min read

A 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.

gamedevcapacitorandroidreleasegradle
Read
·4 min read

Cloudflare 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.

cloudflaresecurityprivacyperformancegist
Read
·4 min read

Lighthouse'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.

performancelighthouseimageswebgist
Read
·4 min read

opacity 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.

accessibilitycssjavascriptwebgist
Read
·4 min read

The 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.

ci-cdtestingworkflowaigist
Read
·6 min read

Changing 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.

google-playprivacyhostingseo
Read
·8 min read

The 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.

aiclaude-codeworkflowgoogle-play
Read
·6 min read

I 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.

aiclaude-codeci-cdworkflowgist
Read
·7 min read

I 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.

aiclaude-codecontext-engineeringworkflow
Read
·7 min read

Deploying 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.

cloudflareci-cdgithub-actionshostinggist
Read