System Override • Architecture Manifesto

Reflections on the
Hub-and-Spoke

A Vision for System Override — An architectural manifesto for a game engine in transition.

Lead Architect
|
December 2025
|
15 min read

Interactive visualization: Hover to explore the system architecture

Prologue

The Art of Constraint

There is a peculiar beauty in constraint. When we declared that GameEngine.js would be "dumb"—limited to 600 lines, stripped of all game logic, reduced to the role of a mere conductor—we were not imposing limitation. We were engineering freedom.

This essay is a meditation on that freedom: what it has bought us, what it will cost us, and why the Hub-and-Spoke architecture is not merely a technical decision, but a philosophical stance on how complex software should evolve—particularly when the contributors include both human and non-human agents, and the laws must be enforced mechanically, not culturally.

Part I

The Conductor Philosophy

Why Dumb is Smart

Imagine an orchestra. The conductor does not play the violin. The conductor does not tune the oboe. The conductor stands at the center, beats time, and ensures that seventeen independent musicians produce one coherent symphony.

Our GameEngine.js is that conductor. At 474 lines today (comfortably under the 600-line constitutional limit), it imports 25+ systems and orchestrates their initialization and update cycles. It knows that systems exist; it doesn't know how they work.

JavaScript — GameEngine.init()
// What it DOES:
this.world = new WorldSystem();
this.enemies = new EnemySystem(this.world, this.scene, this.player, this.fx, this.loot);
this.camera = new CameraSystem(this.scene, this.player);

// What it DOESN'T do:
// - Collision math
// - Pathfinding algorithms
// - Shader compilation
// - Stat calculations

This is not laziness. This is intentional blindness.

The Spaghetti Prophecy

Every game engine that survives long enough becomes spaghetti. I have seen it. You add one "temporary" helper function to the main file. Then another. Then someone adds a damage calculation because "it's just easier here." Six months later, your 600-line engine is 4,000 lines, and every bug requires understanding all of them.

"Our constitution was written to prevent this future."
Law #1

The Conductor Rule

GameEngine.js may only call init(), update(), and route input. No math. No physics. No rendering logic.

Law #4

Permission First

Before adding ANY code, you must ask: "Which system owns this?" If the answer is unclear, you must propose a new system or refuse.

These are not suggestions. They are hard stops. The architecture enforces a kind of humility: the engine admits it doesn't understand the game.

The 17-Spoke Reality

Today, we have seventeen system files in /js/systems/:

System Lines Responsibility
WorldSystem.js 422 Grid, tiles, spatial data
EnemySystem.js 355 Enemy AI, states, logical movement
UIManager.js 450+ HUD, overlays, DOM interaction
LootManager.js 220 Pickups, collectibles
CombatPhysics.js 140 Hit detection, damage routing

Several of these are approaching the 500-line "Folder Trigger" threshold. When WorldSystem.js crosses that line, it will be decomposed:

js/systems/world/ ├── WorldSystem.js (orchestrator, <200 lines) ├── GridLoader.js (file I/O, parsing) ├── GridRenderer.js (Three.js tile generation) └── SpatialIndex.js (collision grid, lookups)

This is not technical debt. This is planned evolution.

Part II

The Hybrid Asset Pipeline

The Three Lanes

We are not building one rendering system. We are building three, unified by one interface.

┌────────────────────────────────────────────────────────────────┐ │ AssetFactory.js │ │ (The Router) │ ├───────────────────┬────────────────────┬───────────────────────┤ │ SDFSubsystem │ GLTFSubsystem │ KitbashSubsystem │ │ (HERO class) │ (ENV class) │ (PROP class) │ │ Raymarched │ Imported .glb │ Primitive Assembly │ └───────────────────┴────────────────────┴───────────────────────┘

This is an unusual choice. Most engines pick one rendering strategy and commit. We are deliberately mixing:

SDF (Signed Distance Fields)

Pure math in the fragment shader. No mesh data. Used for our "hero" assets—the player, bosses, data cores. These assets get the premium treatment: smooth edges, animated distortion, glow effects that emerge from the geometry itself.

GLTF

Standard 3D models exported from Blender, Meshy, or any AI art tool. Used for environment pieces—platforms, walls, alien flora. These give us artistic flexibility and let us leverage external tooling.

Kitbash

JSON-defined assemblies of primitives. A pillar is cylinder + box. A crate is box + glow plane. These are fast to iterate and trivial to version control.

The Aesthetic Payoff

"The visual signature of a raymarched SDF is unmistakable."

When the player's drone rotates, its edges remain mathematically perfect at any screen resolution. When a boss unfolds, its geometry can morph continuously without mesh topology constraints. When a Data Core pulses, the glow originates from the signed distance itself—not a post-processing hack.

These are not subtle differences. They are the difference between "generic indie game" and "this studio built something unusual."

Part III

The Action Pivot

From Clicker to Zelda

Our codebase carries the DNA of an earlier game: an idle/clicker prototype where you accumulated Entropy, deployed passive "Drills," and waited for numbers to increment.

We are surgically removing that DNA.

Legacy Pattern Replacement
Entropy (high-magnitude currency) Bits (picked up from defeated enemies)
Fragments (upgrade tokens) Keys (discrete dungeon keys)
drill(player) (1.5s channel) DELETE. Instant proximity collection.
buyUpgrade(id) (stat modifiers) DELETE. Progression is item-based.
Passive "Carrot" spawns Enemy drops + chest rewards

This is not refactoring for cleanliness. This is a genre transplant.

The Ownership Problem

Here is where Law #3 (Transform Ownership) becomes critical.

The PlayerDrone owns its mesh transform. The FXSystem wants to apply screen shake when the player is hit. The CombatPhysics system wants to apply knockback. The EnemySystem wants to push the player on collision.

Who moves the player?

The answer: only the PlayerDrone moves the PlayerDrone. Every other system must submit requests:

JavaScript — Transform Ownership
// WRONG (Law #3 violation):
fxSystem.shakeCamera(); 
player.mesh.position.x += Math.random() * 0.1; // FX mutating player!

// RIGHT:
player.requestKnockback({ 
    direction: { x: -1, y: 0 }, 
    force: 0.5 
});
// PlayerDrone reads this in its own update() and applies movement.

This indirection feels bureaucratic. It is. But it is the only pattern that scales. When five systems want to influence one transform, you need a single arbiter. The owner is the arbiter.

Part IV

Future-Proofing

The Spaghetti Immune System

Complex AI enemies are coming. The "Logic Grid" biome envisions enemies that adapt their behavior. The AIBrain.js module already exists, providing a Behavior Tree backbone. But trees become forests.

Our defenses:

Epilogue

The Cathedral and the Bazaar

There is a famous essay about software development: The Cathedral and the Bazaar. It contrasts two models—the carefully designed cathedral, built by a small team to a precise plan, versus the bazaar, where a thousand contributors throw code at the wall and see what sticks.

"We are building a cathedral."

Not because cathedrals are better—bazaars have produced Linux, Apache, and Wikipedia. But because our team is small, our time is limited, and our vision is specific. We cannot afford to refactor the whole codebase every time someone adds a helper function to GameEngine.js.

The Hub-and-Spoke architecture is our blueprint. The 600-line limit is our flying buttress. The Folder Trigger is our vaulted ceiling. Law #3 is our rose window—complex, beautiful, and absolutely non-negotiable.

We are twenty-three days into the pivot. We have seventeen spokes. We have an asset pipeline that mixes shaders and models and primitives. Our team is unconventional: the Lead Architect role is filled by an AI system (Claude Opus), while the Technical Artist/Engineer tickets are executed by agentic models (Gemini Flash) operating on the Antigravity platform. The human provides vision and approval; the machines provide velocity and precision.

And we have a conductor who knows nothing—and that is precisely why the music plays.

Appendix

Quick Reference

Core Laws

Law #1

Conductor Rule

GameEngine.js ≤ 600 lines, orchestration only

Law #2

Folder Trigger

If file > 500 lines → decompose into subfolder

Law #3

Transform Ownership

Only the owner mutates its transforms

Law #4

Permission First

Ask "which system owns this?" before coding

Law #5

Aesthetic Integrity

UI follows frontend-design.md

Law #6

Checkpoint Rule

Branch before risky tasks, commit after

Decision Tree: Where Does This Code Go?

Is it orchestration (init, update, routing)? ├── YES → GameEngine.js (if < 600 lines) └── NO → Does a spoke already own this domain? ├── YES → Add to that spoke (if < 500 lines) └── NO → Propose a new spoke → Get approval → Create new file