The Boss Still Knew Where the Middle Was
Written later and filed to this date, as part of filling in every day of the year.
On a phone held upright, my survivor shooter was a letterbox. The canvas was 1280 by 720, the engine’s FIT mode shrank it until it fit the width, and the play area was a strip across the middle of the screen with black above and below it. The enemies had the strip. The thumb had the black.
A pull request on a Saturday morning in March changed one word in the config, FIT to EXPAND, and the canvas filled whatever screen it was on. Taller in portrait, wider in landscape, no bars. The session that opened it worked from the cloud, and its commit body is the kind I would like every contributor to write: what changed, why, and a list.
All 12 files using GAME_WIDTH/GAME_HEIGHT constants now use dynamic this.scale.width/height so game elements adapt to actual screen size
Thirteen files, 297 lines in, 207 out. In the enemy module it did the careful thing: the two constants were replaced by a pair of module-level bounds and a setter the scene calls on creation and again on every resize, and each use was swapped. The teleporter keeps itself on screen against the live bounds. The charger ends its charge at the live edge. The scene got a resize handler that moves every HUD element anchored to an edge or the center. I merged it at 11:22.
Four lines in the same file
The third boss in the game is called The Machine. Its opening state, in the module the pull request had just rewritten, reads like this:
// Move toward center-ish position, fire constantly
const targetX = 640; // Center of screen
const targetY = 360;
A few dozen lines down, the turrets it spawns are clamped between 80 and 1200 on one axis and 80 and 640 on the other, which is 80 pixels inside a frame that no longer existed. Four lines, two numbers each. None of them used the constants. They used what the constants stood for.
So the sentence in the commit body was true. Every file that used the constants had been changed. A search for a constant’s name finds every place that admitted it depended on the screen. It cannot find a place that only knew the answer, and 640 is the answer to a question nobody wrote down.
On a phone held upright the play area was narrower than 640. The boss’s first move was to steer for a point past the right edge, and to park its turrets around a frame the player could not see. An hour and four minutes after the merge, my own commit, titled “game scene size improvements”, replaced the four lines with halves of the live bounds. The comment went with them. Nothing needs to say it is the center once the code can work it out.
The same commit found three weapons that culled their projectiles at 1330 and 770, fifty pixels past the old frame. Ten numbers in five files, all of them the dimensions of a screen, none of them spelled as the dimensions of a screen. The pull request had done everything a search can do. These were outside the search.
What the afternoon was for
Filling the screen exposed the next thing. A HUD drawn for a 1280-wide canvas on a desk is drawn in pixels that are physically tiny on a phone, and the two commits at the end of the day added a scale utility whose header says what it is for: it accounts for the device pixel ratio “so high-PPI phones get readable text sizes”. Phones get the largest boost, tablets a moderate one, a high-density monitor none. Settings gained a slider, 0.5 to 2.0, because a formula about physical pixels is still a guess about a reader’s eyes.
The next morning a second cloud session rewrote the instruction file: the scene count went from nine to ten, the scale mode line was corrected, and the new utility got a paragraph. The documentation caught up with the code one day late, which for that file is a good week.
Why a constant is a confession
A named constant is a dependency that admits it is one. GAME_WIDTH says: this value is the width of the game, and if the width changes, so should I. A literal is the same dependency with the admission removed. The pull request’s author, reading a module of nearly two thousand lines under a deadline, did the right search and trusted its completeness, which is also what I would have done, and what I did when I merged on the strength of the list.
The lesson is not “agents miss things”. It is that a refactor that changes what a value means has to search for the value as well as the name, because the codebase is full of places that typed the answer instead of the question, and most of them were typed by me. The boss knew the middle was 640 across because, on the day I wrote it, it was.