novolis-simulation + local NuGet platform plan
Policies that keep the org coherent
name: Simulation repo and local NuGet
overview: Introduce novolis-simulation as the composition layer (worlds, view controllers, kinematics orchestration), keep novolis-physics as textbook-grade mechanics/collision, keep novolis-math as pure geometry—and standardize all repos (including StarConflictsRevolt) on a shared local NuGet feed with no cross-repo ProjectReference.
todos:
- id: gov-local-nuget
content: "Add governance: local-nuget-development.md, simulation-layer-policy.md, wave-11 brief; root d:/novolis/nuget.config + pack-novolis-local.ps1" status: completed
- id: template-pack-local
content: Add standard pack-local.ps1 + Directory.Build.props NovolisLocalFeed to novolis-template-dotnet and each packable repo status: completed
- id: repo-simulation-skeleton
content: Create novolis-simulation repo with Simulation.View/World/Kinematics/World.Builders packages + TUnit tests status: completed
- id: migrate-apis
content: Move GridCollision2D, FirstPersonCamera, RoomMeshBuilder, GridPhysicsMovement to simulation with obsolete shims in math/physics status: completed
- id: dogfood-nuget-only
content: Migrate novolis-dogfooding apps to PackageReference + local feed; update design.md and CI pack step status: completed
- id: scr-nuget-only
content: Migrate StarConflictsRevolt to local feed only; remove ProjectReference overrides; align Directory.Packages.props versions status: completed
- id: doomlite-kinematics
content: Unify DoomLite3D movement on Simulation.Kinematics; adopt Simulation.View for player camera status: completed isProject: false
Goals
- Clear layering: math = geometry/topology; physics = forces, collision, materials (textbook); simulation = composed worlds + cameras + motion policies for CAD / games / artillery / RTS.
- New repo: `novolis-simulation` (to be created) with packages
Novolis.Simulation.*. - Local dev standard: local NuGet feed only across Novolis library repos, `novolis-dogfooding`, and `StarConflictsRevolt` — no cross-repo
ProjectReference(per your choice). - Patterns first: governance + MSBuild templates before mass migration; breakages acceptable short-term.
Layer model (locked responsibilities)
flowchart TB
subgraph math [novolis-math]
Arrays[DenseGrid GridIndex]
Geo[Meshes Transforms Topology]
CamMath[Camera view/projection record]
MatExt[Matrix extensions]
end
subgraph physics [novolis-physics]
Num[Numerics Vector3d Sphere3d]
Abs[IStaticWorld contacts]
Col[BVH sweeps triangles]
Dom[Gravity Ballistics Orbits Aero Motion]
MatPhys[materials restitution drag - grow here]
end
subgraph simulation [novolis-simulation NEW]
World[Occupancy grids LOS planar queries]
Kin[Kinematics grid plus BVH policy]
View[View controllers all variants]
Bridge[World to static mesh builders]
end
subgraph render [novolis-raylib]
RL[Draw input HUD matrices from host]
end
subgraph consumers [apps]
Dogfood[DoomLite3D WireFish]
SCR[StarConflictsRevolt]
end
Arrays --> World
Geo --> Col
Geo --> Bridge
physics --> Kin
World --> Kin
Bridge --> Col
View --> CamMath
CamMath --> RL
simulation --> Dogfood
simulation --> SCR
physics --> SCR
math --> SCR
render --> Dogfood
render --> SCR| Layer | Owns | Does not own |
|---|---|---|
| Math | DenseGrid, meshes, transforms, lattices, `Camera` (position, target, FOV, aspect) + `GetViewMatrix` / `GetProjectionMatrix` (`Camera.cs`, `CameraExtensions`) | Input, game rules, occupancy semantics, controller behaviors |
| Physics | Forces, integration, collision mathematics (BVH, sphere sweep, restitution in `SphereContactKinematics`), domain solvers (ballistics, orbits, aero) | “Walkable cell = 0”, maze generation, third-person shoulder offset |
| Simulation | World models, composed motion, view controllers, bridges from grids → physics worlds | GPU draw, networking, product UI |
| Raylib | Host loop, textures, Camera3D interop | Simulation rules |
| Apps | Product logic (Doom packs, SCR server events) | Reusable textbook physics |
Naming collision: SCR already has `StarConflictsRevolt.Server.Simulation` (product event loop). Governance must state: `Novolis.Simulation` = platform library; SCR keeps its namespace; prefer PackageReference to Novolis.Simulation.* without renaming SCR projects.
Camera judgment call (math vs simulation)
| Concept | Home | Rationale |
|---|---|---|
| View/projection parameters (pose → matrices) | Math Camera + extensions | GPU and render APIs need matrices; this is geometry, not gameplay |
| `ViewPose` / `Orientation` (position + yaw/pitch or quaternion) | Simulation Novolis.Simulation.View | Neutral state produced by controllers |
Controllers (FirstPerson, ThirdPerson, ThirdPersonOverShoulder, Cockpit, Orbit, FreeForm, God, MapProjection) | Simulation | Convenience policies; each implements IViewController.Tick(...) → ViewPose |
Adapter ViewPose.ToMathCamera() / ToViewMatrix() | Simulation (thin) or Math (if matrix pure) | Keeps math unaware of “shoulder offset” |
| Minimap / RTS map | Simulation MapProjection (world XZ → 2D map coords) | Not a 3D camera; today in `MinimapHud` — candidate extract later |
Migrate: `FirstPersonCamera` → Novolis.Simulation.View.FirstPersonController (or YawPitchController base). Leave one-release obsolete type forwarder in math if needed.
Do not put ThirdPersonOverShoulder in math — only the matrix math it uses stays in math.
novolis-simulation package layout (initial)
| Package | Responsibility | Migrated from |
|---|---|---|
| `Novolis.Simulation.View` | IViewController, ViewPose, camera variants listed above | FirstPersonCamera (math) |
| `Novolis.Simulation.World` | Planar occupancy on XZ (+Y up): move, LOS, raycast, push-out; axis convention doc | `GridCollision2D` (rename e.g. PlanarOccupancy) |
| `Novolis.Simulation.Kinematics` | Single PlanarAgent.Move(...) choosing grid vs IStaticWorld sweep | `GridPhysicsMovement`, DoomLite dual-path |
| `Novolis.Simulation.World.Builders` | Occupancy grid → BvhStaticWorld (extruded columns) | `RoomMeshBuilder` (rename OccupancyColumnMeshBuilder) |
| `Novolis.Simulation` (meta, optional) | Aggregator package like `Novolis.Physics` | — |
Dependencies: Novolis.Simulation.* → Novolis.Math.*, Novolis.Physics.*; never raylib, never dogfooding/SCR.
Tests: port `GridCollision2DTests` → Novolis.Simulation.World.Tests; add View tests for forward/right axes.
Physics stays for textbook expansion: material hardness, friction tensors, contact manifolds — future Novolis.Physics.Materials / contact models, not simulation.
Local NuGet-only workflow (platform standard)
You selected local NuGet feed only (no cross-repo ProjectReference). This replaces today’s split patterns:
- Dogfooding: submodule junctions +
ProjectReference(`design.md`) - SCR: pinned
PackageVersionin `Directory.Packages.props` + ad-hocUseLocalNovolisTesting+ProjectReferencein tests
Canonical layout (monorepo root d:\novolis)
| Path | Purpose |
|---|---|
| `d:\novolis\nuget.config` (new) | Adds local source → d:\novolis\artifacts\nuget-local |
d:\novolis\artifacts\nuget-local\ | Shared feed; all dotnet pack outputs land here |
d:\novolis\scripts\pack-novolis-local.ps1 (new) | Packs listed repos in dependency order (math → physics → simulation → raylib → …) |
Per-repo scripts/pack-local.ps1 | Thin wrapper calling shared script or dotnet pack -o ... |
MSBuild contract (every packable library repo)
Add to governance + template `novolis-template-dotnet`:
<!-- Directory.Build.props -->
<PropertyGroup>
<NovolisLocalFeed Condition="'$(NovolisLocalFeed)'==''">$(NOVOLIS_LOCAL_FEED)</NovolisLocalFeed>
<NovolisLocalFeed Condition="'$(NovolisLocalFeed)'==''">D:\novolis\artifacts\nuget-local</NovolisLocalFeed>
</PropertyGroup><!-- scripts/pack-local.ps1 standard -->
dotnet pack -c Release -o "$(NovolisLocalFeed)" /p:ContinuousIntegrationBuild=falseConsumers (dogfooding, SCR):
PackageReferenceonly in.csproj- Versions in
Directory.Packages.props(e.g.0.3.0-localor dated0.3.0-g$(git sha)) - Repo-level or user-level
nuget.configpointing atNovolisLocalFeed - Remove
ProjectReferencetod:\novolis\novolis-*and dogfooding submodule build paths for compile (submodules may remain for source browsing only, optional)
Versioning convention for local feed
| Environment | Version pattern |
|---|---|
| Local iterative | 0.3.0-local bumped in central props when breaking API, or 0.3.0-* with --force repack |
| CI / nuget.org | Semver from tag (`package-policy.md`) |
Document: after changing a library, run `pack-novolis-local.ps1` before building consumers.
StarConflictsRevolt integration
- Add
nuget.config(or document machine-wide) withD:\novolis\artifacts\nuget-local - Align `Directory.Packages.props` with locally packed versions (physics
0.2.0-alpha→ local; raylib0.1.1-alpha→ local) - Remove `tests/Directory.Build.props`
ProjectReferenceoverride path for raylib testing onceNovolis.Raylib.Testingis packed locally - Later: add
Novolis.Simulation.*when SCR adopts platform view/world APIs (not required for phase 1)
Dogfooding migration
- Update `DoomLite3D.csproj`:
PackageReferencetoNovolis.Raylib,Novolis.Math.*,Novolis.Physics.*, thenNovolis.Simulation.* - Revise `docs/design.md`: consumer-of-local-NuGet, not ProjectReference integrator
- CI: pack dependencies in workflow or use cached
nuget-localartifact between jobs (phase 2)
Governance deliverables (wave 11)
New docs under `novolis-governance/docs/`:
| Document | Contents |
|---|---|
| `simulation-layer-policy.md` | Math / physics / simulation / raylib boundaries; SCR naming note |
| `local-nuget-development.md` | Feed path, nuget.config, pack order, version rules, troubleshooting |
| `extraction-briefs/wave-11-simulation-repo.md` | Scope, migrations, done-when |
| Update `gameengine-reference-policy.md` | Point dogfood-grown APIs to simulation, not math |
| Update `naming.md` | novolis-simulation, Novolis.Simulation.View, etc. |
Phased execution
Phase 0 — Platform plumbing (no API moves yet)
- Add root
d:\novolis\nuget.config+artifacts/nuget-local+pack-novolis-local.ps1 - Add
local-nuget-development.md+ templatepack-local.ps1snippet for all packable repos - Pilot: pack `novolis-math`, `novolis-physics`, `novolis-raylib`; verify SCR/dogfood can restore from feed
Phase 1 — Create novolis-simulation skeleton
- New repo: solution,
Directory.Packages.props, TUnit tests, packaging props mirroring physics - Empty packages:
View,World,Kinematics,World.Builders - Register in `.novolis/repos.json` for discoverability (even if dogfood uses NuGet only)
Phase 2 — Move APIs (with obsolete shims)
- Move
GridCollision2D→Simulation.World(rename type; obsolete alias in math one release) - Move
FirstPersonCamera→Simulation.View - Move
RoomMeshBuilder,GridPhysicsMovement→ simulation (World.Builders,Kinematics) - Unify DoomLite `PlayerController` on
Kinematics.PlanarAgent.Move
Phase 3 — Consumers on local NuGet only
- Migrate dogfooding apps to
PackageReference+ local feed - Migrate SCR to local feed for all Novolis packages; drop test
ProjectReferencehacks - Bump central package versions; document pack-before-build in README
Phase 4 — Expand simulation (incremental)
- Stub remaining view controllers (orbit, third-person, god) as needed by SCR / CAD
MapProjectionextract from MinimapHud (optional)- Physics: flesh out materials package surface (hardness, friction) without moving to simulation
What stays in physics (textbook checklist)
Keep and document as fundamental (extend here, not in simulation):
Novolis.Physics.Numerics,Abstractions,Collision.Simple(BVH, mesh, sweep, restitution)Motion,Gravity,Ballistics,Orbits,Aerodynamics- Future: explicit material models (hardness, friction, combine rules), constraint solvers
Remove from physics after migration: grid-specific policy (GridPhysicsMovement, RoomMeshBuilder).
Risk notes
| Risk | Mitigation |
|---|---|
| Local feed stale vs source | pack-novolis-local.ps1 in dev loop; README “always pack after pull” |
| Dogfooding CI without submodules | CI job packs libs to artifact feed, then builds dogfood |
| SCR / Novolis.Simulation name clash | Document; no rename of SCR projects |
| Breaking consumers during moves | Obsolete type forwards; local 0.x-local version bumps |
Done when (wave 11)
novolis-simulationbuilds, tests pass, packs toartifacts/nuget-local- Governance policies published
- DoomLite3D builds via PackageReference only against local feed
- SCR builds via PackageReference only against local feed (versions documented)
- Math/physics no longer contain dogfood-grown occupancy/view policy (or only obsolete aliases)
- Physics repo README states textbook scope explicitly