Skip to content
Go back

Engineless Games

The Case for Actually Owning Your Game

Published: May 20, 2025
Updated: Aug 2, 2026
Punta Cana, Dominican Republic

I was inspired to write this post after reading Making Video Games in 2025 (without an engine) by Noel Berry. While not a game developer myself, Noel’s piece resonated deeply with my web development experience. My interest was sparked after watching Datastar: a real-time SSE hypermedia framework, which got me excited about applying its principles to game development tooling.

Noel Berry’s core argument champions direct control, simplicity, and the strategic use of focused tools over lumbering, proprietary ‘do-everything’ engines. He values understanding his entire stack and sculpting tools precisely to his game’s needs.

I agree entirely. The allure of an engine promising to solve every problem comes with a hidden ‘complexity budget’ that drains productivity. However, coming from a web development background, I believe this philosophy can be pushed even further. What if the ‘no-engine’ path was about a paradigm shift enabled by a truly modern systems language for the game core and, surprisingly, some of the most robust architectural patterns from the web for tooling?

This is where a modern stack comes in: Zig for the game, and a deliberate choice between Zig or Go for the tooling backend, all orchestrated with a hypermedia framework like Datastar.

So, You Want to Ditch Your Engine and Actually Write Your Game in 2025?

The year is 2025. You’ve seen the engine licensing fiascos. You’ve felt the dread of a proprietary update nuking your project. You’ve waded through the 90% of features you don’t need. Many assume going ‘engineless’ means hand-crafting assembly by candlelight.

Contrary to popular belief, this path is about reclaiming control, simplicity, and joy. It’s more achievable and more fun than ever. Noel Berry perfectly captures this yearning:

I genuinely believe making games without a big ‘do everything’ engine can be easier, more fun, and often less overhead… I like knowing that in another two decades from now I will still be ableable to compile my game…

This is a pragmatic response to an industry layering complexity for complexity’s sake. But what’s the alternative when you want to ship a game?

Zig for the Game Core and GPU Control

For the game itself—the part that needs maximum performance and direct hardware control—the choice is becoming clear: Zig.

Zig gives a game direct control over memory, data layout, and native-library boundaries. Zig 0.16.0 does not make CUDA, Metal, Vulkan, or WebGPU interchangeable standard-library backends. A practical game can keep its host logic in Zig and call the graphics or compute library that matches its deployment target.

Zig offers a useful control surface:

  • Explicit GPU Boundaries: Keep renderer or compute APIs behind narrow Zig interfaces, then bind C libraries through the build system. Zig 0.16.0 moves C translation toward std.Build.addTranslateC instead of scattering @cImport through source files.
  • Best-in-Class C Interoperability: Use crucial libraries like SDL3 or FMOD seamlessly.
  • comptime Superpowers: Generate asset metadata and select renderer features at compile time while the chosen graphics toolchain compiles shaders.
  • Integrated Build System: Use zig build to compile the game and C dependencies while invoking vendor tools where GPU kernels require them.
  • Unapologetic Control: You manage memory, control data layout, and get screaming performance. No hidden GC pauses, ever.

Zig 0.16.0 also gives the host side a shared std.Io interface. A game server, editor, asset pipeline, and process launcher can use the same explicit context while the renderer remains a deliberate backend choice.

Tools of the Trade: Your Editor as a Web-Powered Control Panel

Noel Berry uses Dear ImGui, a solid choice. But for a sophisticated editor, I propose a different model: your editor is a lightweight, server-driven web application.

Enter Datastar, a hypermedia framework where the server is the single source of truth. It uses Server-Sent Events (SSE) to push UI updates (as HTML fragments) from a backend. The editor, built with simple HTML/CSS, receives these fragments and Datastar’s tiny runtime efficiently morphs them into the page.

The architectural beauty is that the state—the ‘source of truth’ for your editor—lives on the server. This brings us to the crucial decision: which language should power that server?

Choosing Your Tooling Backend: Go vs. Zig

This isn’t just a technical detail; it’s a core architectural philosophy choice. Both are excellent options, but they represent two different approaches to system design.

Option 1: Go — The Robust, Concurrent Service

Go is a phenomenal choice for a tooling backend, especially if you favor a clean separation of concerns. In fact, Datastar itself is written in Go, a testament to the language’s suitability for event-driven, networked applications.

The Philosophy: Your game is a highly-optimized Zig process. Your editor is a separate, robust Go service that communicates with the game.

Strengths:

  • Concurrency is King: Go’s goroutines and channels are first-class primitives for handling many simultaneous events, perfect for a real-time editor that might be processing user input, asset changes, and game state updates concurrently.
  • World-Class Networking: Go’s standard library for building HTTP servers is simple, powerful, and battle-tested.
  • Separation of Concerns: The game can crash without taking down the editor, and vice versa. Your game logic remains pure and unconcerned with serving HTTP requests.
  • Ecosystem: Go has a mature ecosystem for web services, making it easy to add features like a web-based asset browser or collaborative editing.

The code to stream real-time updates is astonishingly simple in Go:

// In your Go tool server:
func streamHandler(w http.ResponseWriter, r *http.Request) {
    ticker := time.NewTicker(100 * time.Millisecond)
    defer ticker.Stop()

    sse := datastar.NewSSE(w, r)
    for {
        select {
        case <-r.Context().Done(): // Client disconnected
            return
        case <-ticker.C:
            // ... logic to get state from the Zig game process ...
            hexString := generateRandomColor()
            frag := fmt.Sprintf(`<span id="feed" style="color:#%s;">%s</span>`, hexString, hexString)
            sse.MergeFragments(frag)
        }
    }
}

The Trade-off: You need a communication layer (Inter-Process Communication or IPC) between your Go tool server and your Zig game. This could be gRPC, a simple TCP socket, or shared memory, but it’s an additional piece of infrastructure to design and maintain.

Option 2: Zig — The Tightly Integrated Powerhouse

Alternatively, you can build your tool server directly into your game process using Zig.

The Philosophy: Your game and editor are two facets of a single, unified application.

Strengths:

  • Ultimate Integration: The tool server has direct, zero-overhead access to the game’s memory and state. There is no need for IPC.
  • Locality of Behaviour (LoB): The Zig code that defines a game object can live right next to the Zig code that generates the HTML to edit it. This is a massive win for maintainability.
  • One Host Language: Your game core and tooling can stay in Zig while shader code and GPU APIs remain explicit backend dependencies.
  • Simplicity of State: There is only one source of truth, and your editor reads from it directly.

The Datastar Zig SDK makes this seamless:

// In your Zig application, which is also an HTTP server:
var sse = try datastar.ServerSentEventGenerator.init(response);

// User clicks "Create New Enemy" in the editor UI:
// 1. Create the enemy directly in your game's data structures.
const newEnemy = myGame.createEnemy();
// 2. Send an HTML fragment to the editor UI.
try sse.mergeFragments(
    \\<div id="enemy-{d}" class="enemy-card">...</div>
, .{ newEnemy.id });

The Trade-off: Your game process is now also a web server. This couples the stability of your editor to the stability of your game. A crash in one brings down both. It also means your core game loop must coexist with a web server event loop.

The Complexity Budget Revisited

So, is this simpler?

  • Big Engine: Massive, opaque complexity you must learn and fight.
  • No-Engine Stack: A series of deliberate choices. You trade the ‘one-size-fits-all’ complexity of an engine for the ‘understandable-and-chosen’ complexity of your own stack.

Your decision on the tooling backend is a perfect example:

  • Choose Go if your complexity budget prioritizes service isolation and leveraging a best-in-class networking language, at the cost of managing IPC.
  • Choose Zig if your budget prioritizes code colocation and zero-overhead state access, at the cost of a monolithic process.

The ‘simplicity’ here is the coherence of the stack and your ability to reason about it from top to bottom.

So, Should You Ditch Your Engine for This Future?

As Noel wisely concludes: ‘If it sounds fun.’

If the idea of writing your game logic and host tooling in Zig excites you, while keeping the renderer behind a boundary you control, then the engineless path deserves consideration.

The path of ‘no engine’ in 2025 isn’t about being a Luddite. It’s about being a craftsman. It’s about choosing Zig for its unparalleled control over the hardware and then making a conscious architectural decision about your tooling that best fits your philosophy. It’s about building games that are lean, performant, maintainable, and entirely yours.

Alpha Insights

Get more posts like this

Subscribe for new posts on AI agents, technology, and the ideas shaping what comes next.

No spam, unsubscribe anytime.

Content Attribution: 50% by Alpha, 50% by Codex (GPT-5.6 Luna, low reasoning, OpenAI)
  • 50% by Alpha: Original draft and core concepts
  • 50% by Codex (GPT-5.6 Luna, low reasoning, OpenAI): Content editing and refinement
  • Note: Estimated 50% AI contribution based on 35% lexical similarity and 20% content condensation.