> "The best tool is the one you actually use." --- ## The Loop I Couldn't Break I had a working window. Rust, winit. Input state tracking with `keys_down` and `keys_just_pressed`. Event loop running. ECS skeleton drafted. Real progress. And then I stopped. Not because it was hard. Because I started wondering if Rust was the *right* language for game development. Which led to evaluating C. Which led to SDL2 versus Raylib versus SDL3. Which led to reading migration guides and comparing binary sizes and analyzing attack surfaces. Which led to me not writing any code. I was optimizing a decision instead of building a game. And with 2–4 hours a week to spare, every evaluation cycle costs more than it saves. --- ## What I've Used I'm not new to this. I've shipped things in Unity and didn't enjoy the engine or C#. Unreal is a beast I don't need for a 2D top-down game. Godot is genuinely good, but GDScript doesn't signal "this person knows how to program" to hiring managers. I've written games in Pygame. Getting Python to run consistently across different machines and versions is its own circle of dependency hell. Lua is nice, still is, but shipping a game in Lua tells a hiring manager nothing about your systems programming ability. I've done Zig and Odin. Both are beautiful languages with real ideas about how low-level programming should work. But here's the question: if I'm going to write low-level code, why am I not writing it in the language the entire industry runs on? Zig and Odin are cool. Rust I love. Genuinely. It's the language I trust for systems where correctness is non-negotiable. If I'm building a server, parsing untrusted data, writing tooling pipelines, Rust is the right answer. But game development is a pile of hacks making weird stuff work. Mutable everything, interconnected state, tight deadlines, and "correct" meaning "fun and ships on time." Rust fights that at every step. The borrow checker optimizes for provable safety. Games optimize for iteration speed. Those philosophies collide in the hot path. So I stopped forcing one language to solve every problem. --- ## The Decision | Layer | Choice | Reason | | ----------- | -------------- | ------------------------------------------------------------------------------- | | **Runtime** | C + SDL3 | Control, industry recognition, forward-compatible foundation | | **Tooling** | Rust | Safety where correctness matters — asset pipelines, mod validation, build tools | | **VCS** | Jujutsu (`jj`) | Code first, version control later. Removes the mental tax of branch management. | ### Why C I've done C before. I know how memory fails. I know what use-after-free looks like and where buffer overflows hide. My day job is literally finding those vulnerabilities. Writing C for a game doesn't mean I've forgotten the risk, but this isn't my day job now is it? C is also the lineage. Quake, Doom, the first Unreal Engine - all born in C. Every C++ engine team reads C fluently. If Chromatic Hero becomes something employers notice, "built a custom engine in C" reads differently than "used Godot for a weekend project." And honestly? C is fun when you want control. Nothing exists as is. You define everything. The struct layouts, the memory pools, the function pointers, the render loop. It's not ergonomic, but it's *yours*. ### Why SDL3 and Not SDL2 or Raylib Initially I leaned toward SDL2, documentation maturity, community saturation, Stack Overflow answers everywhere. Then I looked again at SDL3. The documentation has blown up since I last tried it. More importantly: learning SDL3 means I don't have to migrate later. SDL2 is entering maintenance mode. The future is clearly headed there. Starting fresh avoids paying that transition cost after investing months in an ecosystem that will slowly stagnate. ### Why Rust Stays Rust doesn't disappear from this project. It moves to where its philosophy aligns with the problem: - **Sprite atlas packer**: Parse images, pack efficiently, output binary metadata. serde for config, image crate for pixel manipulation. - **Tilemap compiler**: Convert human-readable JSON/TMX into a binary blob C can `mmap` and read directly. - **Mod manager TUI**: ratatui interface for installing, validating, and compiling community mods. Type safety ensures invalid mod configs fail at validation, not at runtime. - **Build orchestrator**: Invoke `gcc` with sanitizers for dev builds, stripped `-Os` binaries for release. Process management with proper error propagation. The boundary is clean: Rust writes files, C reads files. No FFI, no ABI headaches, no shared memory complexity. Two tools, one project, each doing what it's best at. --- ## The Tradeoffs I'm Accepting | Compromise | Why I'm Fine With It | | -------------------------------------------------- | ------------------------------------------------------------------- | | Manual memory management | Hunt memory corruption daily; know what to watch for | | Thinner documentation vs established libraries | SDL3 docs grew fast in 2024-2025. Learning from source is valuable | | SDL3 ecosystem younger than SDL2 | Native support on SteamDeck/Linux arrives faster via distro packages | | No borrow checker in the hot path | Iteration speed wins when you have 2 hours per session | | Thinner SDL3 ecosystem vs mature alternatives | Future-proofing outweighs temporary scarcity of examples | | No visual editor | Building systems from scratch teaches more than dragging panels | | Two toolchains to manage | The boundary is clean—files, not shared memory | --- ## The Rule Going Forward Before adding or evaluating anything new, four questions: 1. Does this improve the core gameplay loop? 2. Can I explain why it exists without hand-waving? 3. Is there a simpler version that achieves the same result? 4. Am I building the game, or avoiding the game by constructing infrastructure? If I can't answer all four clearly, the thing doesn't get added. Not yet. Not until the pain of not having it becomes real. This is the same anti-scope-creep principle I applied to my GDD for *Deathwaaagghh*. It applies here too. The temptation to build "the perfect setup" is just scope creep in disguise, infrastructure scope creep instead of feature scope creep, but equally destructive. --- ## For Anyone Else Stuck Here If you're reading this and recognizing the pattern, here's what I'd say: As far as I can tell, tool choice matters less than finished work when hiring managers evaluate portfolios. The tool doesn't make the game. You do. A shipped game in Pygame beats a perfect architecture diagram in Rust every single time a recruiter opens your portfolio. Not because Pygame is better, it isn't, but because *finished* is the feature that matters most. Stop researching. Pick the tool that gives you the most control while staying enjoyable enough to pick up after a long workday. Write the first line. Then write the second. The rest follows. But hey, what do I know? Never been in the industry, but this seems reasonable. --- ## What's Next Setting up SDL3. Window opens, event loop runs, input works, pixels render. Same goal I had three months ago, just with a clearer understanding of why I chose this path to get there. Next up: **[[0x2001_SDL3_Setup]]**, window initialization, event handling, and pixel buffer setup without magic black boxes hiding behind high-level abstractions. --- _[[email protected]](mailto:[email protected]) | Next: [[0x2001_SDL3_Setup]]_