After Monday’s comprehensive parity testing confirmed that simulation data was correct, Tuesday revealed a new set of challenges: while the numbers lined up perfectly, the visuals didn’t. Stars were rendering with the wrong colors, planets were losing their visual properties, and entity names were disappearing entirely.
Fixing the Star Rendering Bug
The day began by finishing the star rendering investigation I started Monday night. The issue came down to a type serialization mismatch.
In Godot, star types are represented as integer enum values — zero for red dwarfs, one for yellow stars, two for blue giants, and so on. But when serializing that data to JSON for the Zig engine, those enum values weren’t being preserved correctly.
Zig expected string representations such as “red dwarf” or “yellow star,” but it was receiving integers instead. When the Zig deserializer tried to interpret those integers as strings, the type information became corrupted, resulting in invalid or default star types and incorrect colors.
The solution was to add proper enum-to-string conversion in the Godot serialization layer. Now, when star data flows between the two engines, it converts integer enums into readable strings and back again as needed. With this fix in place, stars once again display with the correct colors and visual properties.
Preserving Planet Visual Data
Fixing the stars revealed another issue — planets were losing their visual properties after each turn.
Each planet has an orbital angle, orbital speed, and visual size that define how it appears in the star system view. After running a turn through the Zig simulation, all planets reset to default positions and sizes.
The cause was simple: the Zig layer doesn’t use visual data, so those cosmetic fields weren’t being serialized. To fix it, I extended the planet serialization to include the orbital fields.
Now, when planet data round-trips through Zig, it preserves its orbital angle, orbital speed, and size. Zig doesn’t calculate or modify these fields — it just passes them through unchanged so the Godot rendering layer can display planets exactly as the player left them.
Restoring Entity Names
A more fundamental problem appeared next: entity names were disappearing. Stars, planets, empires, and fleets were all showing up as “unnamed” or “unknown” after simulation turns.
This was another serialization gap. The name fields existed in Godot’s data structures and were sent to Zig correctly, but the Zig structs weren’t including them in their serialized output. As a result, when the game state returned to Godot, the name fields were missing.
The fix was straightforward: ensure every relevant Zig struct explicitly includes name serialization in its output. Star names, planet names, empire names, and fleet names are now preserved completely when the game state returns from the Zig engine.
Fixing Fleet Composition and Movement
The next discovery was serious: fleets were losing their ship composition data.
In Stellar Throne, fleets aren’t just a single number — they’re made up of multiple ship types, each with unique stats. For example, a fleet might include five destroyers, three cruisers, and two carriers, each with its own health and combat attributes.
While fleet data was being serialized to Zig correctly, the simulation layer only tracked total ship count. The specific ship types and their stats were discarded during processing, meaning fleets lost their internal structure by the time they returned to Godot.
I fixed this by expanding the Zig fleet struct to include a ship composition array, storing each ship group’s type, count, and health percentage. The Zig simulation now preserves these details throughout turn processing, and the data returns intact to the UI layer.
While testing this fix, I found another visual bug: fleets were parking themselves at the exact center of stars after arriving at their destinations. The arrival logic was setting fleet positions to the star’s coordinates instead of assigning proper orbital positions.
I added arrival positioning logic so fleets calculate and occupy realistic orbits around stars upon arrival. The result looks much more natural — fleets now glide into orbit rather than clustering in the star’s core.
Cleaning Up Unit Tests
Finally, I addressed a series of failing Zig unit tests. They were breaking because they tried to import Godot-specific modules that don’t exist in the standalone Zig build.
I made the imports conditional so that they only load when building the shared library for Godot. In standalone mode, the pure Zig tests now run cleanly without external dependencies.
Technical Breakdown
- 8 commits total
- Star type serialization: 3 files, 47 lines changed
- Planet visual preservation: 2 modules, 32 lines
- Entity name serialization: 4 structs, 69 lines
- Fleet composition fix: 5 files, 143 lines
- Fleet orbital positioning: 27 lines
- Unit test cleanup: 12 lines of conditional imports
The parity framework now preserves all visual data through simulation round-trips.
✔ Stars render correctly
✔ Planets maintain their orbits and sizes
✔ Entity names persist
✔ Fleets retain full ship composition
✔ Unit tests pass cleanly in both build modes
Why This Matters
This work ensures that Stellar Throne’s dual-engine architecture isn’t just mathematically correct, but visually consistent. Players don’t care that the simulation runs fifty-two times faster if their stars are the wrong color or their fleet names vanish.
These fixes make the performance improvements completely invisible to the player — everything feels smooth, stable, and accurate.
Next Steps
Stress test visual data preservation across long playthroughs
Add automated tests to confirm that cosmetic data survives multiple turn cycles
Profile the Zig engine for serialization performance
Begin designing new simulation systems — including diplomacy and trade routes — that take advantage of the validated, high-speed backend
Thanks for reading this week’s update.
Follow along with development progress and technical insights at MrPhilGames.com.