March 1, 2026 • Development

Tearing It All Down

How I destroyed a working Unity game to make it config-driven, fought with AI tooling all evening, and ended up in a better place. Probably.

The Honest Part

I'm going to be real: today felt like starting over. I had a game that worked. 15 scenes. Enemies that spawned. Videos that played. A build pipeline that shipped to production. Version 97 is live on the website right now.

And I tore all of it apart.

Not because it was broken. Because it wasn't scalable. Every time I wanted to add a level, I had to manually build a scene, drag in prefabs, wire up PlayableDirectors, configure Addressable groups by hand, copy-paste enemies, tweak positions in the editor. It was slow, error-prone, and completely dependent on me doing everything manually in the Unity Editor.

So I made the decision: make the game entirely data-driven. One config file defines everything. One button regenerates the whole project.

What I didn't anticipate was how painful the transition would be.

The Damage Report

15
Scenes deleted
0
PlayableDirectors remaining
30+
Editor tools removed
7
Hours of pain

Unity MCP: The Tool That Wasn't

Part of the vision was using Unity MCP — a bridge that lets AI agents control the Unity Editor remotely via WebSocket. Execute menu items, read console logs, modify scenes. In theory, it's incredible.

In practice? It disconnected constantly.

Every time we tried to execute a menu item — which is how you trigger editor scripts from outside Unity — the MCP connection would drop. We'd send the command, wait for results, and get nothing back. The operation might have succeeded, or it might have silently failed. No way to know without manually checking the Unity console.

Domain reloads killed it. Heavy operations killed it. Sometimes it just died for no reason. We had a monitor script that tried to auto-restart it every 5 seconds, and even that wasn't enough.

The result? Half the session was spent blind. The AI would write a script, try to execute it via MCP, get disconnected, write a different script, try again, get disconnected again. We went through at least 5 iterations of "fix and consolidate" scripts because we could never confirm what actually ran.

If your AI tooling can't reliably tell you whether it succeeded, you're not automating — you're gambling.

Before vs After

❌ Before
  • 15 individual scenes
  • PlayableDirectors for video playback
  • Manually placed enemies in each scene
  • 30+ context menu tools
  • Scene-specific code everywhere
  • Add a level = build a whole scene by hand
  • Enemies, cameras, UI wired per-scene
✅ After
  • 3 generated scenes (Video, Level, Death)
  • SpriteFramePlayer + GameClock for playback
  • All enemies defined in config with positions
  • 1 menu item: Generate Project
  • Config-driven everything
  • Add a level = add an entry to GameDefinition
  • UI/camera prefabs defined once in config

The New Architecture

Everything flows from one file: GameDefinition.asset

GameDefinition.asset
├── PlayerConfig (prefab, speed, health, upgrades)
├── LevelConfig[] (enemies, platforms, music, duration, barriers)
├── VideoConfig[] (sprite frames data, audio, flow)
├── DeathConfig[] (animation data, audio, reload delay)
├── EnemyTemplate[] (prefab, stats, sounds, drops)
└── Scene Prefabs (camera, UI for each scene type)

When you press Generate Project, the system reads this config and produces fully-wired Unity scenes. The generators use SerializedObject to connect every reference at edit-time — the Character prefab is instantiated and wired to LevelRuntime, the camera prefab is placed and wired to the canvas, the AudioSource is connected to the music clip.

At runtime, LevelRuntime reads the level number from PlayerPrefs, looks up the config, and spawns enemies, platforms, and barriers dynamically. VideoRuntime does the same for videos. DeathRuntime for deaths.

The scenes are output. The config is the game.

Why I Did This

Three days ago I built an AI pipeline that generates enemy characters from text prompts. Concept art → animation → sprite sheet → Unity prefab in about 3 minutes, $0.10 per character.

But the pipeline ended at the prefab. Getting that character into an actual level still required manual scene editing. Place the prefab, set the position, configure health, wire up the spawn timing. For every single instance.

Now? I add an entry to the enemies list in the config:

- type: Chaser
  position: {x: 3, y: -2}
  spawnTime: 5
  healthOverride: 10

That's it. The pipeline now goes all the way from text prompt to in-game enemy. No manual scene editing. No drag and drop. No "open Level3.unity and place the prefab at these coordinates."

This is what pipeline-ready means. Every piece of content — enemies, levels, videos, death animations — is just data. And data can be generated, modified, and deployed by scripts, AI agents, or a simple YAML edit.

The Rewind System Survived

One thing that came through the refactor intact: the rewind system. We replaced Unity's Timeline with a custom GameClock that can run time forward or backward. A StateRecorder takes snapshots of the entire game state — player position, enemy positions, health values, camera position — at regular intervals. When you hold the rewind button, the GameClock reverses, and snapshots are restored in reverse order.

This is one of the reasons we killed PlayableDirectors. Timeline only goes forward. GameClock goes both ways. Every system in the game — sprite playback, experience events, enemy spawning — reads from GameClock instead of Time.time. Rewind isn't a special mode. It's just time going the other direction.

What's Left

The game is "closer" — but it's also clearly broken in new ways. Video playback needs debugging. The SpriteFramePlayer loads chunks via Addressables but may not be advancing frames correctly. The project generator creates simple scenes but the individual generators create richer ones — those need to be reconciled.

But the foundation is right. The architecture is right. And for the first time, the game is truly data-driven.

Sometimes you have to tear everything down to build it back correctly.

I just wish it didn't take 6 hours and a slowly depleting credit balance to get here.

Bonus: Watching the AI Think

I don't know if I'm doing this right, but this is what I use to follow Claw's reasoning while it's deployed in a Docker container. It tails the latest session log, filters for assistant messages, and extracts the text and thinking content in real-time:

@echo off
docker exec -it claw-docker-openclaw-gateway-1 bash -c ^
  "tail -f $(ls -t /home/node/.openclaw/agents/main/sessions/*.jsonl | head -1) ^
  | grep --line-buffered '\"role\":\"assistant\"' ^
  | jq --unbuffered -r '.message.content[] ^
  | select(.type==\"text\" or .type==\"thinking\") | .text'"

Seems to work really well with Opus. You can watch it reason through problems, plan its approach, catch its own mistakes. It's genuinely fascinating to see the thought process unfold in real-time.

With Sonnet? Falls completely flat. The reasoning is shallow, it misses context, and it keeps making the same mistakes in circles. Tonight was a perfect example — switched from Sonnet to Opus mid-session and the difference was night and day.

If you're running OpenClaw in Docker and want to see what your AI is actually thinking, give that one-liner a try.