A Claude Code build diary

Train Masters: a cosy model railway for your TV, built with Claude Code

How a peaceful little railway game went from an idea to the Amazon Appstore, with an AI agent that wrote the code and also tested it on a real Fire TV Stick over Wi-Fi.

November 2026 · about a 10-minute read

A village and railway lines in golden evening light, with trains running between fields
Golden evening light on a randomly generated map. Every map is different: villages, farms, rivers and hills, all made fresh from a seed.

Train Masters is a cosy, peaceful railway game for the Amazon Fire TV Stick. You lay track across a randomly generated English countryside, build stations in the villages, buy steam and diesel trains, and then sit back and watch them run. There's a 2D map for building and a 3D view for watching, including a cab view so you can ride along with the driver.

Almost all of the code was written by Claude Code, Anthropic's coding agent, working in the terminal. All that was needed was direction on the style and feel: what the game should feel like, what was annoying, what was missing. This post is about how that worked in practice. It covers the setup that let Claude test on the real TV, how it was tested, and the features we're proudest of.

The shape of the thing

The whole game is one HTML file: an 812 KB page with a 2D canvas for the map and Three.js for the 3D view. It runs inside a tiny Android app, which is just a full-screen WebView, because Fire TV Sticks run Android underneath. GitHub Actions builds the app on every push, so nobody installs Android Studio.

We picked that shape on purpose. A single file is easy for an agent to read, test and change, and the same page runs in a desktop browser for fast automated tests. The hard part was that a Fire TV Stick is a very modest computer, and a game that's smooth on a laptop can crawl on the TV.

The 2D map view with stations, departure boards, coloured trains and the remote-friendly toolbar
The 2D map, built for the TV remote: arrows move, OK builds, and every station has a departure board.

Letting Claude drive the real TV

This is probably the most interesting part for Claude Code users. Claude didn't just write code and hope. It installed each build on a real Fire TV Stick, pressed buttons on the "remote", read the game's state, measured the frame rate and took screenshots, all over the home Wi-Fi. A typical loop looked like this:

  1. Change the game, run the Playwright tests locally, watch them pass.
  2. Run tools/tv/deploy.sh: commit and push, wait for the CI run of that exact commit, download the APK and adb install it on the TV.
  3. Connect to the game running on the TV through Chrome DevTools, and run JavaScript inside it: "how many trains are moving?", "what's the frame rate here?", "open the 3D cab view".
  4. Take a screenshot of the TV with adb exec-out screencap and look at it, because tests can't tell you a thing looks ugly.

Being able to look at the TV made a huge difference. Many fixes in this post started with Claude saying "that doesn't look right" on a screenshot it had just taken.

How to set it up yourself

All of this works with any WebView-based app on a Fire TV. The steps:

1. Turn on debugging on the Fire TV. Settings → My Fire TV → About, click the device name seven times to unlock Developer options, then turn on ADB debugging (and Apps from unknown sources for your own APKs). Note the TV's IP address from Settings → Network.

2. Connect over Wi-Fi from your computer and accept the prompt on the TV the first time:

adb connect 192.168.1.50:5555      # your TV's address
adb shell input keyevent 224       # wake it up
adb shell input keyevent 23        # press OK (19-22 arrows, 4 Back, 82 Menu)
adb exec-out screencap -p > tv.png # see what's on screen

3. Make the WebView debuggable in debug builds of your app:

if (BuildConfig.DEBUG) WebView.setWebContentsDebuggingEnabled(true);

4. Reach the page's DevTools. Each debuggable WebView exposes a socket named after its process. Forward it to your computer and ask for the page's websocket address:

PID=$(adb shell pidof com.example.yourgame)
adb forward tcp:9399 localabstract:webview_devtools_remote_$PID
curl -s localhost:9399/json       # -> "webSocketDebuggerUrl": "ws://localhost:9399/devtools/page/..."

5. Evaluate JavaScript in the running game. This four-line Node script is the whole "remote control" Claude used hundreds of times:

// cdp.mjs  — node --experimental-websocket cdp.mjs "$WS" 'trains.length'
const [,, url, expr] = process.argv;
const ws = new WebSocket(url);
ws.onopen = () => ws.send(JSON.stringify({id:1, method:'Runtime.evaluate',
  params:{expression:expr, returnByValue:true, awaitPromise:true}}));
ws.onmessage = m => { const d = JSON.parse(m.data); if (d.id===1) {
  console.log(JSON.stringify(d.result.result.value ?? d.result)); process.exit(0); } };

A few lessons from doing this daily:

Tests first, then the TV

Nearly every change started with a failing test. The suite now has about 50 Playwright test scripts, covering things like "trains keep a safe distance", "the whistle sounds when you ride in the cab" and "the passing loop is long enough for the longest train". Headless Chromium has quirks with WebGL: it stops drawing 3D frames after about half a second. So the tests step the 3D scene by hand, and Claude grabs the 3D canvas directly when it wants a picture.

Given a brief of "four hours of bug hunting on the TV", Claude also mashed random remote buttons at the game (about 4,500 presses), copied real saved railways off the TV and ran them for days of game time on the computer, and checked the TV's graphics memory for leaks. Then it sent back a table of fourteen fixes with before-and-after screenshots.

The features we love

Drive it yourself

In the cab or chase view you can take over any train. Up on the remote adds power (five notches), Down brakes (four notches), and OK blows the whistle. Signals still apply, so if you charge a red light you get an emergency stop. Pull into a platform and you're marked out of three stars:

★★★ Perfect stop!   ★★☆ Good stop   ★☆☆ Too fast! The passengers spilled their tea

Driving a Pannier tank from the cab, with the dashboard showing speed, power notches, the signal and the next station Coming into the station too fast earns one star and the message that the passengers spilled their tea
The driving dashboard: speed, power notches, the signal ahead and the distance to the next stop. Come in too hot and the tea goes everywhere.

Riding through the tunnels

Lay track into a hill and you get a tunnel. In the cab view you go in with the driver: the outside world disappears, it's just you, the rails and the tunnel walls until daylight appears at the far end. That took more work than it sounds. The camera has to fit inside the tunnel's bore, and anything outside the tunnel has to stay hidden, so the hillside doesn't poke through the walls.

The cab view inside a tunnel, looking along the rails towards the light at the end
In the cab, inside a tunnel. Daylight at the far end.

The rest of the timetable

A flyover where one railway line passes over another Display mode: a wide view of the railway with a clock and day caption
A flyover from above, and display mode turning the TV into a slow, peaceful picture.

Shipping it

Claude also handled the boring-but-scary parts: a signed release build, the privacy policy page, store art (including a photo-real render of a little engine, made in Blender from a script), the in-app purchase for the 99p Pro upgrade, tested end to end with Amazon's App Tester, and the store listing text. Train Masters is now on the Amazon Appstore for Fire TV. Updates go out through Amazon's App Submission API: Claude builds the new version, uploads it as a draft, and stops until it's told to "submit".

And finally: ducks

The latest addition is the most heart-warming one. With countryside life on, the world around the railway gets busy in a quiet sort of way. Villagers are out and about depending on the time of day, cars and lorries pootle between villages, and tractors work the fields. Then there's the water:

Ducks paddling on a pond right next to the railway line A little yacht sailing just off the coast
Yes, we added boats. And some ducks. (Ducks on a pond by the line; a yacht off the coast.)

None of it changes how you play. It just makes the little world feel lived in, which is the whole point of a cosy game. Put the kettle on, pick a train, and watch it go.