Novolis Docs
novolis-governance / library-boundaries.md

Library boundaries — platform layer stack

dotnetgovernancenovolis

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.*)
  ↓
Apps

Lower 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

LayerOwns
MathNumbers, transforms, geometry, topology — no time
PhysicsPhysical evolution over time (forces, motion, collision response)
SimulationOrchestration over time (world, systems, clocks, all cameras)
GamingAuthoring / shipping glue (Novolis.Game.*) — no Avalonia
AvaloniaUI controls and hosts (Novolis.Avalonia.*) — only layer that may depend on Avalonia UI packages
MAUIUI controls and hosts (Novolis.Maui.*) — only library layer that may depend on Microsoft.Maui (orthogonal to Avalonia)
Executable hostsProduct 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.ArraysDense grids, indices, packed voxel chunks (ChunkCoord3, VoxelChunk 16³)
Novolis.Math.GeometryBCL-backed primitives (Ray, Sphere, meshes), intersections, BVH
Novolis.Math.TopologyConnectivity: polygon, face, edge, shape
Novolis.Math.MeasureScalar 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.Vector3Vector3d, Vector3D, custom 3-vectors
System.Numerics.QuaternionQuaterniond, custom quaternions
System.Numerics.Matrix4x4Matrix4x4d, custom 4×4
System.Numerics.Planecustom 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 / *2D suffixes on public Math types or members (Ray3, Sphere3, AxisAlignedBox3, …).
  • Forbidden: System.Numerics.Vector2, Vector2D, or any Novolis 2D vector type.
  • Planar XZ: System.Numerics.Vector3 with `Y = 0` (optional extension helpers on Vector3, 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, Acceleration
  • Force, Torque, Material, Collider, Contact, Constraint
  • Integrator, 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, SimulationStep
  • ISimulationSystem, 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)

PackageOwnsDoes not own
Novolis.Simulation.HumanoidFK (HumanoidPoseSolver), two-bone IK, FABRIK chains, full-body multi-effector helpers, clip schemaPlanar agent locomotion
Novolis.Simulation.KinematicsPlanar XZ agent move (PlanarAgent) via occupancy / sphere sweepSkeletal FK/IK, bone targets
Novolis.Physics.JointsDistance / 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.

RuleDetail
Rendering → RaylibForbidden
Rendering → SimulationForbidden
Raylib → RenderingForbidden
Rendering → Raylib.RuntimeOnly via Novolis.Rendering.Presentation.Raylib (blit adapter)
Rendering → MathAllowed (Novolis.Math.Geometry for Rgba32, meshes, rays)
Wiring Simulation ↔ Rendering ↔ RaylibApps only — ViewPose → CameraSnapshot → IRayTracingBackend → host blit

novolis-raylib

Separate repo and dependency island. Owns host loop, draw, input bindings, GPU types (e.g. Camera3D).

RuleDetail
Raylib → SimulationForbidden
Simulation → RaylibForbidden
Raylib → MathAllowed when needed for types/interop (not Simulation)
Wiring Simulation ↔ RaylibApps 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

ConceptHome
Vector3, Matrix4x4, mesh, BVH, Ray hitMath (Geometry facet; BCL vectors)
Matrix4x4.CreateLookAt (no camera record)BCL / Math extension
RigidBody + integrate with dtPhysics
Sphere sweep + restitutionPhysics
SimulationClock, tick order, replaySimulation
Any *Camera*, ViewPose, observer rigSimulation
Run bobbing / recoil / game-specific camera juiceApp
Bridge Simulation camera → CameraSnapshot for traceApp (uses Rendering + Simulation; neither lib references the other)
IMaterial, Scene, CompiledScene, IRayTracingBackendRendering (Novolis.Rendering.*)
IFramePresenter, CPU/GPU blit adaptersNovolis.Rendering.Presentation.Raylib, Novolis.Rendering.Presentation.Silk
Material compile → GpuMaterialNovolis.Rendering.Materials
Scene compile → BVH + flat buffersNovolis.Rendering.Compile (+ BVH structure in Novolis.Math.Geometry)
Camera3D, draw loopRaylib only
Planar occupancy, LOS on a worldSimulation
Edge-wall tile maps, room flood-fill, grid A*Novolis.Simulation.Tiles
Chunked voxel world, dig/place, streamerNovolis.Simulation.Voxels
Voxel → triangle mesh (face cull / greedy)Novolis.Simulation.Voxels.Meshing
Packed 16³ block storageNovolis.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 MAUI
novolis-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 bridge

Cad 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 locationTarget home
Camera / camera controllers in Novolis.Math.GeometryNovolis.Simulation.View
Novolis.Math.Geometry.GridCollision2DNovolis.Simulation.World
Novolis.Physics.Collision.Simple.RoomMeshBuilderNovolis.Simulation.World.Builders
Novolis.Physics.Collision.Simple.GridPhysicsMovementNovolis.Simulation.Kinematics
Custom Vector3d / Novolis.Physics.Numerics (removed)System.Numerics + Novolis.Math.Geometry primitives
BVH structure in PhysicsNovolis.Math.Geometry; response stays Physics
StaticTriangleMesh in Physicsdeleted — use Novolis.Math.Geometry.TriangleMesh

Related