Library boundaries — platform layer stack
Policies that keep the org coherent
Authoritative dependency law for Novolis libraries. Numeric spine: novolis-math, novolis-physics, novolis-simulation. Product spine continues through novolis-gaming and novolis-avalonia into apps.
`novolis-raylib` is not part of this stack — no package reference between Raylib and Simulation (either direction). Apps that need both wire them at the product layer.
There are no “Kit” layers in the platform (no GameKit, CadKit, LabKit packages). Product repos and hosts compose the stack directly.
Stack (dependency direction)
Math
↓
Physics
↓
Simulation
↓
Gaming (Novolis.Game.*)
↓
Avalonia (Novolis.Avalonia.*)
↓
AppsLower layers must not reference higher layers. Same-layer / peer facet refs are fine. Apps compose any combination.
Avalonia isolation: only Novolis.Avalonia.* libraries may take Avalonia / Avalonia.* package references. Math, Physics, Simulation, Gaming, Economy, Astro, Rendering, Raylib, Agent, Cad, Audio, Markup, Blazor, etc. stay Avalonia-free. Product apps may reference Avalonia directly.
MAUI isolation: only Novolis.Maui.* libraries may take Microsoft.Maui.* package references (orthogonal island, not on the closed spine). Must not take Avalonia; Avalonia must not take MAUI. Product apps (Merglyph) may compose MAUI. Grandfathered adapter: Novolis.Audio.Voice.Platform.Maui.
Blazor isolation: only Novolis.Blazor.* libraries may take Microsoft.AspNetCore.Components* package or assembly references. Blazor is an independent UI island: Blazor libraries must not reference Avalonia or MAUI, and Avalonia/MAUI libraries must not reference Blazor. Product apps may compose Blazor directly.
Enforced by Novolis.Analyzers.StackBoundaries (NOV2006, NOV2007, NOV2010–NOV2013) and scripts/verify-layer-boundaries.ps1.
`novolis-raylib` remains a separate graphics/input host — orthogonal to the spine (never ↔ Simulation).
Simulation is not a game engine. It is neutral orchestration: worlds, objects, systems, time, observation, recording, and replay. HexGame-style game ticks belong in Simulation and apps — not in Physics (see hexgame-authoritative-core.md).
One-line rules
| Layer | Owns |
|---|---|
| Math | Numbers, transforms, geometry, topology — no time |
| Physics | Physical evolution over time (forces, motion, collision response) |
| Simulation | Orchestration over time (world, systems, clocks, all cameras) |
| Gaming | Authoring / shipping glue (Novolis.Game.*) — no Avalonia |
| Avalonia | UI controls and hosts (Novolis.Avalonia.*) — only layer that may depend on Avalonia UI packages |
| MAUI | UI controls and hosts (Novolis.Maui.*) — only library layer that may depend on Microsoft.Maui (orthogonal to Avalonia) |
| Executable hosts | Product composition in novolis-apps; package experiments in novolis-lab; MAUI hosts such as Merglyph (not under library apps/) |
Novolis.Math.* — space and numbers only
Repo: novolis-math
Math is one library family with facets (separate packages, same repo). Geometry and topology are parts of math, not separate platform layers or dependency tiers.
| Facet (current / planned) | Role |
|---|---|
Novolis.Math.Arrays | Dense grids, indices, packed voxel chunks (ChunkCoord3, VoxelChunk 16³) |
Novolis.Math.Geometry | BCL-backed primitives (Ray, Sphere, meshes), intersections, BVH |
Novolis.Math.Topology | Connectivity: polygon, face, edge, shape |
Novolis.Math.Measure | Scalar Length/Size/Thickness/Rect in points (page/print extents; no Vector2) |
BCL type first — always, no exception
When the BCL provides a type, use it. Do not add Novolis duplicates.
| Use (BCL) | Do not add |
|---|---|
System.Numerics.Vector3 | Vector3d, Vector3D, custom 3-vectors |
System.Numerics.Quaternion | Quaterniond, custom quaternions |
System.Numerics.Matrix4x4 | Matrix4x4d, custom 4×4 |
System.Numerics.Plane | custom plane types mirroring BCL |
Allowed Novolis types only where the BCL has no equivalent: Ray, Sphere, AxisAlignedBox, TriangleMesh, DenseGrid<T>, VoxelChunk / ChunkCoord3, topology records — composed from BCL primitives.
No dimension suffixes or 2D types in Math public APIs
- Forbidden:
*3/*2Dsuffixes on public Math types or members (Ray3,Sphere3,AxisAlignedBox3, …). - Forbidden:
System.Numerics.Vector2,Vector2D, or any Novolis 2D vector type. - Planar XZ:
System.Numerics.Vector3with `Y = 0` (optional extension helpers onVector3, not new vector types).
Owns:
- Pure spatial operations on BCL numerics
- Static helpers (e.g.
Matrix4x4.CreateLookAt) that do not imply a clock, tick, or observer lifecycle
Hard rule — no time in Math:
If a concept needs time, deltaTime, clocks, ticks, integration steps, or “what happens next frame”, it does not belong in Math. That is Physics (physical evolution) or Simulation (orchestration and observation).
Does not own:
- Cameras (any rig, pose, or controller) → Simulation
- Forces, bodies, integrators → Physics
- Worlds, scenarios, replay → Simulation
Novolis.Physics.* — physical rules over time
Repo: novolis-physics
Depends on: Math only (Novolis.Math.* facets as needed).
Owns:
RigidBody,MassProperties,Velocity,AccelerationForce,Torque,Material,Collider,Contact,ConstraintIntegrator,CollisionSolver, domain solvers (ballistics, orbits, gravity, aero)- Stepping state forward with
dt(physical time evolution)
Must not reference or know:
- Cameras, players, AI, networking, rendering, ECS, games
- Product occupancy conventions, maze generation
- Simulation-world tick ordering (orchestration is Simulation)
Novolis.Simulation.* — neutral runtime model
Repo: novolis-simulation
Depends on: Math, Physics only. Must not reference Novolis.Raylib.*, executable hosts, or SCR.
Owns:
SimulationWorld,SimulationClock,SimulationStepISimulationSystem,ISimulationState,ISimulationObject- Snapshots, determinism policy, unit-system policy, tick ordering
- Scenario loading, recording / replay
- All cameras — rigs, poses, controllers, and composition:
StaticCameraRig, OrbitCameraRig, TrackingCameraRig, FreeLookCameraRig
FirstPersonCameraRig, ThirdPersonCameraRig, CharacterCameraDirector, CharacterMotor
LookIntent / MoveIntent, YawPitchController, ViewPose, ObserverFrame- Tiles (
Novolis.Simulation.Tiles) — Prison Architect–style layered maps, edge walls/doors, room flood-fill, grid A* - Voxels (
Novolis.Simulation.Voxels+.Meshing) — chunked block worlds, streaming, terrain fill, face-culled / greedy mesh →Math.Geometry(no GPU)
Primitive third-person, orbit, first-person yaw/pitch, and CAD-style viewport cameras belong here. Product-only embellishments (e.g. run bobbing, weapon recoil shake, cinematic beats tied to a specific game) stay in apps, not platform Simulation.
Humanoid skeleton / mocap target: Novolis.Simulation.Humanoid — Mixamo/Unity-compatible bone ids, T-pose bind, FK/IK (including two-bone and FABRIK chain), animation clips. Physics ragdoll bridge: Novolis.Simulation.Humanoid.Physics. Import: Novolis.Simulation.Humanoid.Import (BVH / glTF joints). CPU skin: Novolis.Simulation.Humanoid.Skinning. Game clip banks: Novolis.Game.Humanoid (gaming repo).
Kinematics vs skeletal IK (do not confuse)
| Package | Owns | Does not own |
|---|---|---|
Novolis.Simulation.Humanoid | FK (HumanoidPoseSolver), two-bone IK, FABRIK chains, full-body multi-effector helpers, clip schema | Planar agent locomotion |
Novolis.Simulation.Kinematics | Planar XZ agent move (PlanarAgent) via occupancy / sphere sweep | Skeletal FK/IK, bone targets |
Novolis.Physics.Joints | Distance / swing / hinge dynamics (ragdolls) | Target-reaching IK |
Forbidden: IK solvers in Novolis.Math.*; putting TwoBoneIk / FABRIK into Simulation.Kinematics; treating joint constraint projection as IK.
Answers: How do multiple systems participate in one evolving world?
Naming: StarConflictsRevolt.Server.Simulation is product simulation. Novolis.Simulation.* is the platform library. Do not rename SCR projects.
Outside the stack
novolis-rendering
Separate repo and dependency island. Owns CPU framebuffer production (ray tracing, future software rasterizers). Does not open windows, call GPU APIs, or own platform cameras.
| Rule | Detail |
|---|---|
| Rendering → Raylib | Forbidden |
| Rendering → Simulation | Forbidden |
| Raylib → Rendering | Forbidden |
| Rendering → Raylib.Runtime | Only via Novolis.Rendering.Presentation.Raylib (blit adapter) |
| Rendering → Math | Allowed (Novolis.Math.Geometry for Rgba32, meshes, rays) |
| Wiring Simulation ↔ Rendering ↔ Raylib | Apps only — ViewPose → CameraSnapshot → IRayTracingBackend → host blit |
novolis-raylib
Separate repo and dependency island. Owns host loop, draw, input bindings, GPU types (e.g. Camera3D).
| Rule | Detail |
|---|---|
| Raylib → Simulation | Forbidden |
| Simulation → Raylib | Forbidden |
| Raylib → Math | Allowed when needed for types/interop (not Simulation) |
| Wiring Simulation ↔ Raylib | Apps only — adapt ViewPose / platform cameras to GPU at compose time |
Raylib does not own platform camera logic; apps bridge observers to the renderer.
Executable hosts (lab, SCR, …)
Product rules, HUD, networking, highly specific camera feel (run bobbing, recoil). May reference Math, Physics, Simulation, and Raylib independently.
Placement guide
| Concept | Home |
|---|---|
Vector3, Matrix4x4, mesh, BVH, Ray hit | Math (Geometry facet; BCL vectors) |
Matrix4x4.CreateLookAt (no camera record) | BCL / Math extension |
RigidBody + integrate with dt | Physics |
| Sphere sweep + restitution | Physics |
SimulationClock, tick order, replay | Simulation |
Any *Camera*, ViewPose, observer rig | Simulation |
| Run bobbing / recoil / game-specific camera juice | App |
Bridge Simulation camera → CameraSnapshot for trace | App (uses Rendering + Simulation; neither lib references the other) |
IMaterial, Scene, CompiledScene, IRayTracingBackend | Rendering (Novolis.Rendering.*) |
IFramePresenter, CPU/GPU blit adapters | Novolis.Rendering.Presentation.Raylib, Novolis.Rendering.Presentation.Silk |
Material compile → GpuMaterial | Novolis.Rendering.Materials |
| Scene compile → BVH + flat buffers | Novolis.Rendering.Compile (+ BVH structure in Novolis.Math.Geometry) |
Camera3D, draw loop | Raylib only |
| Planar occupancy, LOS on a world | Simulation |
| Edge-wall tile maps, room flood-fill, grid A* | Novolis.Simulation.Tiles |
| Chunked voxel world, dig/place, streamer | Novolis.Simulation.Voxels |
| Voxel → triangle mesh (face cull / greedy) | Novolis.Simulation.Voxels.Meshing |
| Packed 16³ block storage | Novolis.Math.Arrays (VoxelChunk) |
| Headless racing sim (tracks, sensors, tick loop) | Novolis.Simulation.Racing |
| NN evolution on racing (trainer, neural car controller) | Apps (e.g. novolis-lab NeuralRacing) — not Novolis.MachineLearning.* |
Package dependency graph
Spine (closed, low → high):
novolis-math (Arrays, Geometry, Topology, core numerics)
novolis-physics → math
novolis-simulation → math, physics
(facets: Abstractions, World, View, Tiles, Voxels, Voxels.Meshing, Kinematics, World.Builders, Racing, …)
novolis-gaming → math / physics / simulation as needed; never → Avalonia UI packages
novolis-avalonia → math…gaming + Avalonia.* ; never pull Avalonia into lower layers
novolis-lab / apps → compose freely (including Avalonia + Raylib + Simulation)Orthogonal (not on the spine ranks; still Avalonia-free libraries):
novolis-machinelearning (Core, Neural.*, AutoMl — building blocks only; no domain packages)novolis-chat → SecureText + Game.Identity; Hosting.AspNetCore may use ASP.NET Core/SignalR
no Avalonia, LiveKit, Duende, Raven, or product storage
novolis-security → PasswordHashing / Encryption / Secrets / Cryptography / WordLists / HaveIBeenPwned / SecureText
Authentication.* / OAuth.* / Authorization.*
OAuth and Authorization.AspNetCore may use ASP.NET Core.
Credential store is CredentialReference + hash only — never IdentityId, email, or username.
Authorization depends on Authentication.Abstractions only for IdentityId.
never Avalonia, Game.Identity, Duende, or OpenIddict
novolis-raylib → math only (if needed); never → simulation; never → Avalonia
novolis-rendering → math only; never → simulation or raylib; never → Avalonia
novolis-maui → Markup + Microsoft.Maui.*; never → Avalonia; never pull MAUI into Markup/Audio (except Voice.Platform.Maui)
novolis-3d → Math only; renderer-neutral scene documents and asset import
no Avalonia, rendering, Raylib, simulation, CAD, or app-host references
novolis-pdf → PDF reading (parse, text, page plans, Skia raster). Math.Geometry only.
never Avalonia or MAUI; hosts compose Novolis.Maui.PdfViewer
novolis-documents → one-column PDF writing. Math.Measure only. never Avalonia or MAUInovolis-cad → Math only (Cad.Primitives, Cad.Blueprint, Cad.Evaluation, Cad.SceneBridge)
Avalonia-free .cadjson interchange + Cad→3D bridge
Must not host mesh scene graphs (those are Novolis.3D.*)
novolis-avalonia → Novolis.Avalonia.* UI controls and shells only
including Novolis.Avalonia.ThreeD / Cad / Ship.Design
Novolis.Avalonia.Chat binds Chat DTOs; it does not host ChatHub
novolis-3d → Novolis.ThreeD.Scene / Novolis.ThreeD.Import.Assimp
(.nov3djson scene graph and Assimp import); no UI or renderer bridgeCad vs 3D cameras: document pose bags (CadCamera, CameraNode) may live in Cad/3D DTOs. Orbit / free-look controllers and ViewPose stay in Novolis.Simulation.View. Apps/Avalonia compose DTO poses → ViewPose. Do not put Rendering soft-bridges in Cad libraries — apps wire Cad/3D lights → Rendering.
Apps may reference any combination; they own cross-repo glue.
Transitional state (2026-05)
Wave 7–11 migrations may still place types in legacy packages. Prefer the boundaries above for new code.
| Legacy location | Target home |
|---|---|
Camera / camera controllers in Novolis.Math.Geometry | Novolis.Simulation.View |
Novolis.Math.Geometry.GridCollision2D | Novolis.Simulation.World |
Novolis.Physics.Collision.Simple.RoomMeshBuilder | Novolis.Simulation.World.Builders |
Novolis.Physics.Collision.Simple.GridPhysicsMovement | Novolis.Simulation.Kinematics |
Custom Vector3d / Novolis.Physics.Numerics (removed) | System.Numerics + Novolis.Math.Geometry primitives |
| BVH structure in Physics | Novolis.Math.Geometry; response stays Physics |
StaticTriangleMesh in Physics | deleted — use Novolis.Math.Geometry.TriangleMesh |
Related
- hexgame-authoritative-core.md — HexGame-shaped game loops: Tick in Simulation/apps; Physics is a callee only (no HexGame NuGet / no GameKit)
- workspace-snapshot-timeline.md — editor workspaces, save points, and branchable timelines (
novolis-workspaces) - gaming-layer-policy.md —
novolis-gamingauthoring lane (identity, menus, multiplayer glue, session protocol) - simulation-layer-policy.md — operational summary
- wave-7-gameengine-math.md
- wave-11-simulation-repo.md
- local-nuget-development.md
- gameengine-reference-policy.md