OpenZT2 is a big graphics and simulation program. A piece of game data might start in an original Zoo Tycoon 2 file and pass through a parser before Bevy turns it into something the renderer can use. When the result on screen is wrong, we need to follow that path without spending half the investigation unpacking the project’s architecture.
That’s the reason for most of the contributing guide. We use long, specific names and give mutable data one clear owner. Struct fields stay together and aligned, while the code that works on them sits in plainly named files. Wrappers and intermediate models only get added when there’s a real job for them.
The style fits graphics programming
The style is closer to what you’ll find in established C codebases and newer systems languages such as Jai and Odin than in many current Rust projects. That’s a good fit for us. Graphics code is full of work that looks cheap from the outside while hiding copies, conversions or GPU synchronization. A fairly direct layout makes those costs easier to spot.
Long names are useful for the same reason. Render code has plenty of operations that look alike while doing very different jobs. A function called prepare tells you almost nothing in a call stack. compile_d3d9_effects_to_wgsl_and_pipeline_structs is long, but you know what went in and what came out without opening another file.
We approach data layout in the same practical way. A record should be easy to scan, with short comments where a field needs explaining:
// Font, font texture and glyph-array data
Font :: struct {
base_size: i32, // Default character height
glyph_count: i32, // Number of glyphs
glyph_padding: i32, // Padding in the texture atlas
texture: Texture2D, // Texture atlas
rectangles: [^]Rectangle, // Glyph rectangles
glyphs: [^]GlyphInfo, // Glyph records
}
This is common in Odin and will feel familiar to anyone who has worked with a tidy C header. You can understand the shape of the record first, then move on to the code that uses it.
The ownership rules apply that idea across the game. Bevy already owns the live world. If another module copies the same game data into a model of its own, we then have two versions to keep in sync. One owner is easier to reason about and usually means less memory traffic.
The guide also reduces review work
There’s also a less technical reason for writing all of this down. Public repositories get a lot of proposed code now, and a polished pull request can still be careless underneath. We’re a small team with limited review time. We can’t spend the start of every large review arguing from scratch about basic project conventions.
Following the guide is a fairly low bar: it shows that someone has read the project material and looked at how the existing code fits together. We still need to review the patch itself, but we can spend that time checking its behaviour.
Reviewing a patch can mean checking clean-room evidence or the exact behaviour of a render state. We may also need to check the memory cost of an asset path. If a submission ignores the simple rules that are easy to see, we’re unlikely to trust it on details that take hours to verify.
Sometimes a rule will be awkward for a particular change. Bringing up the concrete case early is fine, and we can change a rule when the code gives us a good reason. The problem is finding a second architecture halfway through review because the contributor never checked how the project was already put together.