m05 · Baking · reading · 9 min
Entity scenes — why baked data loads as bytes, not as calls
What the bakers actually produced
Every baker in a scene runs, and the result is a World — populated with
entities, in archetypes, laid out in GameObject world.
The naive serialization would be a recipe: a list saying “create an entity with these components and these values,” repeated per entity, replayed at load time. It would work. It would also throw away most of what baking bought you, because replaying that recipe means running the entire structural-change machinery from Module 1 — compute archetype, find or allocate a chunk, write each component — 50,000 times, on the main thread, at load.
The actual design skips it. Since baking already produced chunks, and a chunk
is a flat 16 KB block of unmanaged memory with a known layout, the serializer
writes the chunks themselves. Loading is then reading bytes off disk into
memory that is already in final form. No archetype computation, no
per-entity component writes, no
That is the payoff sentence of the whole module. Baking doesn’t just precompute values; it precomputes memory layout. The reason load is fast isn’t that conversion was skipped — it’s that the expensive part of conversion was the structural work, and structural work is exactly what a byte-for-byte chunk image eliminates.
Instantiate versus stream, priced
This reframes a decision you’ll make constantly, so price it explicitly.
Instantiating a prefab at runtime does real work per entity: allocate into a chunk, copy component values, possibly trigger a chunk allocation, and — if done via a command buffer — participate in a sync point (Module 2). Cost scales with entity count and with archetype complexity, and it lands on the main thread at the moment of the call.
Streaming a scene section loads a contiguous block. Cost scales with bytes and with I/O bandwidth, and the read can happen off the main thread; the main thread’s share is close to a pointer handoff. Ten thousand static props cost roughly what their bytes cost, not what ten thousand structural changes cost.
The design consequence follows directly: content that exists in the authored world should be baked and streamed, not instantiated. Reach for instantiation when entities are genuinely dynamic — spawned by gameplay, count unknown at build time. Using instantiation for authored content converts a byte copy into fifty thousand structural changes, which is the same category of mistake as doing structural changes inside a per-frame loop.
Sections make this granular. A scene divides into sections that load and unload independently, which is how open-world streaming works here: section 0 holds the always-resident content, and distant sections arrive as bytes when needed and are dropped by freeing their chunks. Unloading is as cheap as loading for the same reason — you’re releasing memory, not destroying 50,000 entities one at a time.
The one thing bytes can’t survive: references
There is a genuine complication, and it falls out of a fact from Module 1 rather than from any baking decision.
An Entity is not a pointer. It’s an index plus a version — a handle whose
meaning depends on which World it lives in. At bake time, entity 412 in the
baked world referred to a specific thing. At load time, that world already has
its own entities occupying low indices, and index 412 means something else
entirely, or nothing.
So any baked component holding an Entity field — a turret referencing its
target, a spawner referencing a prefab — contains an index that is wrong the
moment it’s loaded into a different world. Left alone, it silently refers to
an unrelated entity. That is a correctness bug, not a performance one.
The fix is remapping: the serialized scene carries a table of which entity references live where, and on load the streaming system patches each stored handle to the new world’s index. It’s a fixup pass over a known list, so it costs proportional to the number of references, not the number of entities.
Why baked scenes make iteration feel strange
One practical consequence worth stating, because it produces a confusing first experience. Because the runtime consumes baked output rather than the authored objects, editing an authoring value doesn’t change a running game until that value is re-baked and the section reloaded. The editor works hard to make this feel immediate — it re-bakes in the background and swaps the result in — but the indirection is real, and it’s the reason a baking change can appear not to apply.
When that happens, the diagnosis order follows straight from the last lesson: did the value get read through the Baker (tracked), or around it (untracked and therefore never re-baked)? The stale-value symptom and the untracked-read bug are the same event seen from two ends.
What this buys you
You can now explain why baked scenes serialize memory instead of instructions, why streaming authored content beats instantiating it by an order that scales with entity count, and why entity references need remapping while raw values don’t. Next: prefabs and blob assets — how baking handles the two things that must be shared across many entities rather than copied into each one.