Architecture
51 packages and 218 declared dependencies, arranged so that no package can reach a system it did not ask for.
Foundry ships as a set of Unity packages, each with its own manifest, its own assembly definitions, and its own tests. A package declares what it depends on, and the architecture tests fail the build when an assembly reaches past that declaration. Every other property described here follows from that one rule.
Adoption is therefore incremental. You can take Inventory without Equipment, Armory without a player controller, and Persistence without Networking. A lower layer holds no reference to the layers above it, so a system you skip is absent from the build instead of sitting dormant in it.
Two packages sit underneath everything and depend on nothing at all. Messaging carries events and resolves services. Foundation carries the primitives, the definition registry, and the diagnostics gate. Two packages that need to talk without knowing about each other go through one of those two.
The shape
Six layers
Kernel
8 packagesCore
10 packagesGameplay
12 packagesPresentation
10 packagesPlatform
4 packagesTooling
7 packagesArrows read downward as “is built on”. A package may depend on anything in its own band or below it, and never on anything above.
Root packages
7 packages depend on nothing
These are the contracts. Everything above inherits their constraints, which is the argument for keeping them small.
com.zoa.diagnostics.contracts
Two types, no dependencies, so any package can publish a debug tab without depending on Nucleon.
com.zoa.foundation
Stable ids, the definition database, grid geometry, pooling, and the diagnostics gate every other package compiles against.
com.zoa.messaging
The publish/subscribe bus and service registry every other package talks through.
com.zoa.networking.abstractions
Dependency-free networking contracts: protocol DTOs, session policy, adapter seams, and the backend support matrix.
com.zoa.platform
One provider-neutral surface for auth, profiles, achievements, leaderboards, stats, friends, cloud saves, inventory, Workshop, DLC, overlay, and lobbies.
com.zoa.stats
Stat identifiers, modifiers, and the evaluation rule every gameplay package agrees on.
com.zoa.ui.theming
The design-token contract every ZOA surface renders through, owned by nobody and importable from anywhere.
Load bearing
Most depended upon
Change one of these and you change everything downstream. They are also the packages whose tests matter most.
| Package | Tier | Dependents |
|---|---|---|
| foundation | Kernel | 41 |
| messaging | Kernel | 27 |
| ui.theming | Kernel | 12 |
| inventory | Core | 10 |
| common | Kernel | 8 |
| interaction | Core | 8 |
| networking.abstractions | Kernel | 8 |
| weaponmodding | Core | 8 |
| persistence | Core | 7 |
| animation | Gameplay | 6 |
| combat | Kernel | 6 |
| stats | Kernel | 6 |
Rules
How packages talk
Something happened: publish it on the event bus. A weapon that finishes reloading does not know the HUD exists, and the HUD does not know which weapon fired the event. Both know the message type, which lives in whichever package owns the concept.
Something is needed: resolve it from the service registry. A HUD component that needs theme data resolves IHudTheme rather than importing Equipment, which is why UI Theming is contract-only and depends on nothing.
Something must be authored: define it as a ScriptableObject. Definitions are the seam between designers and code across the whole stack, and the definition registry in Foundation is how a runtime system finds one without holding a hard reference to it.