Rename vg-csg to CultGeometry CSG

This commit is contained in:
Meta Vens 2026-08-26 17:38:13 +02:00
commit b476a05eb5
15 changed files with 155 additions and 49 deletions

105
Cargo.lock generated
View file

@ -149,6 +149,15 @@ dependencies = [
"serde_core",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bumpalo"
version = "3.20.2"
@ -181,12 +190,31 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
dependencies = [
"libc",
]
[[package]]
name = "critical-section"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
[[package]]
name = "crypto-common"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "derive_more"
version = "2.1.1"
@ -208,6 +236,16 @@ dependencies = [
"syn",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "disqualified"
version = "1.0.0"
@ -288,6 +326,27 @@ dependencies = [
"slab",
]
[[package]]
name = "gamecult-geometry-csg"
version = "0.1.0"
dependencies = [
"approx",
"bevy_math",
"rmp-serde",
"serde",
"sha2",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.3.4"
@ -597,6 +656,25 @@ dependencies = [
"bitflags",
]
[[package]]
name = "rmp"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c"
dependencies = [
"num-traits",
]
[[package]]
name = "rmp-serde"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155"
dependencies = [
"rmp",
"serde",
]
[[package]]
name = "rustc_version"
version = "0.4.1"
@ -667,6 +745,17 @@ dependencies = [
"zmij",
]
[[package]]
name = "sha2"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "slab"
version = "0.4.12"
@ -764,6 +853,12 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
[[package]]
name = "typenum"
version = "1.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
[[package]]
name = "unicode-ident"
version = "1.0.24"
@ -800,12 +895,10 @@ dependencies = [
]
[[package]]
name = "vg_csg"
version = "0.1.0"
dependencies = [
"approx",
"bevy_math",
]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasip2"

View file

@ -1,10 +1,10 @@
[package]
name = "vg_csg"
name = "gamecult-geometry-csg"
version = "0.1.0"
edition = "2024"
description = "Lean Bevy-math constructive geometry assembler for VibeGeometry blockouts"
description = "CultGeometry constructive-solid-geometry kernel"
license = "MIT"
repository = "https://github.com/GameCult/vg-csg"
repository = "https://github.com/GameCult/GameCult.Geometry.Csg"
readme = "README.md"
[dependencies]

View file

@ -1,8 +1,11 @@
# vg-csg
# GameCult.Geometry.Csg
The project is known as **CultGeometry CSG**. Its Rust package is
`gamecult-geometry-csg`, exposed to Rust code as `gamecult_geometry_csg`.
Lean constructive geometry tooling for Rust/Bevy-math scene blockouts.
`vg-csg` is the extracted CSG kernel from VibeGeometry. It is not trying to be
CultGeometry CSG is the extracted CSG kernel from VibeGeometry. It is not trying to be
a full CAD kernel. It is a small, inspectable machine for agent-authored level
and habitat geometry:
@ -39,7 +42,7 @@ experiments/generated/
```rust
use bevy_math::{Quat, Vec3};
use vg_csg::{LevelDsl, MaterialId};
use gamecult_geometry_csg::{LevelDsl, MaterialId};
let mut level = LevelDsl::new();
level.solid_box(

View file

@ -8,7 +8,7 @@ Run our current kernel:
.\tools\run_csg_perf.ps1
```
The script builds `vg_csg` in release mode and writes JSONL to
The script builds `gamecult-geometry-csg` in release mode and writes JSONL to
`experiments/generated/csg-perf-latest.jsonl`. Each record carries:
- `kernel`
@ -19,7 +19,7 @@ The script builds `vg_csg` in release mode and writes JSONL to
- emitted triangle, fragment, and warning counts
- demand-frontier `candidate_pairs` and `rejected_pairs`
The `vg_csg` fixture measures:
The CultGeometry CSG fixture measures:
- `stable`: cached output after warmup
- `dirty`: full rebuild through the current ordered assembler
@ -47,7 +47,7 @@ still rebuild.
The same wrapper can append reference timings:
```powershell
$env:VIBEGEOMETRY_REFERENCE_CSG_PERF = "path\to\reference-perf.exe"
$env:GAMECULT_GEOMETRY_CSG_REFERENCE_PERF = "path\to\reference-perf.exe"
.\tools\run_csg_perf.ps1
```
@ -94,7 +94,7 @@ inside/outside/aligned/reverse-aligned categories, crossing polygon splits, and
logical routing tables. Use it as readable doctrine. Use the native bridge as
the performance target.
`vg_csg` now reports the first demand-frontier counters. These are not yet a
CultGeometry CSG reports the first demand-frontier counters. These are not yet a
new kernel path; they expose the ordered brush stream as affected source/operator
pairs and rejected bounds pairs so future router/index work can prove it is
refusing real work rather than merely rearranging it.

View file

@ -41,14 +41,14 @@ to Bevy render assets.
## Current Port Shape
`vg-csg` is the first lean Rust organ.
CultGeometry CSG is the lean Rust CSG organ.
It uses `bevy_math` for `Vec3`, `Vec2`, and Bevy-compatible spatial types while
keeping output as simple arrays:
```rust
use bevy_math::Vec3;
use vg_csg::{LevelDsl, MaterialId};
use gamecult_geometry_csg::{LevelDsl, MaterialId};
let mut level = LevelDsl::new();
level.solid_box(
@ -109,7 +109,7 @@ level script can mix hard architectural cuts with habitat-specific forms:
```rust
level.dome_cap_z(
"city dome",
vg_csg::DomeCapZSpec {
gamecult_geometry_csg::DomeCapZSpec {
center: Vec3::ZERO,
radius: 20.0,
height: 8.0,
@ -120,7 +120,7 @@ level.dome_cap_z(
);
level.floret_arm(
"radiator petal",
vg_csg::FloretArmSpec {
gamecult_geometry_csg::FloretArmSpec {
anchor: Vec3::new(20.0, 0.0, 0.2),
direction: Vec3::X,
length: 120.0,
@ -188,7 +188,7 @@ slot for a public-demo/reference harness when one is available.
## Limits
`vg_csg` is not yet a full RealtimeCSG replacement.
CultGeometry CSG is not yet a full RealtimeCSG replacement.
- subtractive convex support currently covers axis-aligned and oriented boxes
- non-box subtractors are reported and ignored

View file

@ -27,7 +27,7 @@ CSG tree, and emits the pieces that remain visible. It does not treat the final
mesh as the authority. The brush tree is the authority; the mesh is cache and
evidence.
The highest-value shift for `vg_csg` is therefore:
The highest-value shift for CultGeometry CSG is therefore:
```text
from: subtract cutter -> produce new convex fragments -> triangulate fragments
@ -63,7 +63,7 @@ A brush should be authored and cached as a set of planes, not merely as a
triangle soup. Brush mesh creation is the act of finding valid intersections
between those planes and linking the resulting topology.
Implication for `vg_csg`: add a `ConvexBrush` authored by planes, then derive
Implication for CultGeometry CSG: add a `ConvexBrush` authored by planes, then derive
polygons, half-edges, bounds, and render buffers from that. Boxes, cylinders,
wedges, stairs, panels, and dome approximations should become constructors for
plane sets where possible.
@ -120,7 +120,7 @@ Top-level output policy:
- overlapping coplanar surfaces are resolved by tree/order policy so duplicate
faces do not z-fight
Implication for `vg_csg`: material propagation should be natural if source
Implication for CultGeometry CSG: material propagation should be natural if source
polygons remain source polygons. Generated cut faces need explicit policy:
inherit cutter material, source material, or a domain material such as "raw
concrete cut." Do not leave that as accidental array order.
@ -138,7 +138,7 @@ allow early-outs before cutting:
The optimization post reports a major speedup from branch-specific bounds
checks alone. This is not a garnish. Bounds are semantic gates.
Implication for `vg_csg`: every brush, polygon batch, and branch needs cheap
Implication for CultGeometry CSG: every brush, polygon batch, and branch needs cheap
bounds. Later BVH, hashed grid, or sweep-and-prune should be measured against
the built-in tree culling instead of assumed superior by vibes in a lab coat.
@ -150,7 +150,7 @@ sampled many times. Dreams' prototype refined frustum cells, shortened object
lists as cells split, then switched to per-pixel sorted lists that could truncate
at the first solid hit.
For `vg_csg`, that translates to consumer-shaped query frontiers:
For CultGeometry CSG, that translates to consumer-shaped query frontiers:
- dirty brush movement asks for affected brush pairs, not a world rebuild;
- branch evaluation asks for left/right bounds gates before polygon tests;
@ -242,7 +242,7 @@ Use procedural fields and meshes for:
The level DSL should let these coexist. Boolean nodes cut space; procedural
nodes grow matter and detail around that space.
## Implementation Target For `vg_csg`
## Implementation Target For CultGeometry CSG
Near-term kernel shape:
@ -269,7 +269,7 @@ Process brush:
emit visible pieces into render mesh
```
`vg_csg` now exposes the first version of that public tree surface:
CultGeometry CSG exposes the first version of that public tree surface:
- `CsgOperationType::{Additive, Subtractive, Intersecting}` with parity-tested
ordinals matching the public API
@ -285,7 +285,7 @@ backend grows into the category router.
Algorithm migration steps:
1. Add polygon categories and visible/reversed flags to `vg_csg`.
1. Add polygon categories and visible/reversed flags to CultGeometry CSG.
2. Add plane-set brush construction independent of `Aabb`.
3. Add a topology arena with vertices, directed edges, polygons, and polygon
plane/material ids.
@ -303,7 +303,7 @@ Algorithm migration steps:
## Acceptance Tests To Add
- Where `vg_csg` exposes the same behavior as public RealtimeCSG/demo APIs,
- Where CultGeometry CSG exposes the same behavior as public RealtimeCSG/demo APIs,
maintain exact observable parity fixtures. These should compare public
behavior such as category vocabulary, brush plane/polygon counts, split
counts, visible/reversed semantics, bounds early-outs, and mesh output

View file

@ -4,7 +4,7 @@ use std::{
};
use bevy_math::{Quat, Vec3};
use vg_csg::{
use gamecult_geometry_csg::{
Aabb, Assembler, BrushOp, DomainQuery, MaterialId, Primitive, lower_selected_cut_chunks,
ragnarok_column_fixture, select_domain_cut,
};
@ -86,7 +86,11 @@ impl PerfMode {
}
}
fn build(self, assembler: &mut Assembler, iteration: usize) -> vg_csg::BuildOutput {
fn build(
self,
assembler: &mut Assembler,
iteration: usize,
) -> gamecult_geometry_csg::BuildOutput {
match self {
Self::Stable => assembler.build(),
Self::Dirty => {
@ -168,7 +172,7 @@ fn run_case(case: PerfCase, mode: PerfMode) {
let p95_ns = percentile_ns(&timings, 95);
println!(
"{{\"kernel\":\"vg_csg\",\"mode\":\"{}\",\"scenario\":\"{}\",\"brushes\":{},\"iterations\":{},\"warmup_iterations\":{},\"mean_ns\":{},\"min_ns\":{},\"p50_ns\":{},\"p95_ns\":{},\"max_ns\":{},\"triangles\":{},\"fragments\":{},\"warnings\":{},\"candidate_pairs\":{},\"rejected_pairs\":{},\"reused_mesh\":{},\"used_checkpoint\":{},\"checkpoint_rebuild_from\":{},\"direct_dirty_rebuild\":{}}}",
"{{\"kernel\":\"gamecult_geometry_csg\",\"mode\":\"{}\",\"scenario\":\"{}\",\"brushes\":{},\"iterations\":{},\"warmup_iterations\":{},\"mean_ns\":{},\"min_ns\":{},\"p50_ns\":{},\"p95_ns\":{},\"max_ns\":{},\"triangles\":{},\"fragments\":{},\"warnings\":{},\"candidate_pairs\":{},\"rejected_pairs\":{},\"reused_mesh\":{},\"used_checkpoint\":{},\"checkpoint_rebuild_from\":{},\"direct_dirty_rebuild\":{}}}",
mode.as_str(),
case.name,
case.brushes,
@ -314,7 +318,7 @@ fn run_lod_case(name: &'static str, query: DomainQuery) {
let p95_ns = percentile_ns(&timings, 95);
println!(
"{{\"kernel\":\"vg_csg\",\"mode\":\"lod_query\",\"scenario\":\"{}\",\"selected_nodes\":{},\"emitted_claims\":{},\"brushes\":{},\"iterations\":{},\"warmup_iterations\":{},\"mean_ns\":{},\"min_ns\":{},\"p50_ns\":{},\"p95_ns\":{},\"max_ns\":{},\"triangles\":{},\"collider_triangles\":{},\"candidate_pairs\":{},\"rejected_pairs\":{}}}",
"{{\"kernel\":\"gamecult_geometry_csg\",\"mode\":\"lod_query\",\"scenario\":\"{}\",\"selected_nodes\":{},\"emitted_claims\":{},\"brushes\":{},\"iterations\":{},\"warmup_iterations\":{},\"mean_ns\":{},\"min_ns\":{},\"p50_ns\":{},\"p95_ns\":{},\"max_ns\":{},\"triangles\":{},\"collider_triangles\":{},\"candidate_pairs\":{},\"rejected_pairs\":{}}}",
name,
selected_nodes,
emitted_claims,

View file

@ -1,5 +1,5 @@
use bevy_math::Vec3;
use vg_csg::{DomeCapZSpec, FloretArmSpec, LevelDsl, MaterialId};
use gamecult_geometry_csg::{DomeCapZSpec, FloretArmSpec, LevelDsl, MaterialId};
fn main() {
let mut level = LevelDsl::new();

View file

@ -5,7 +5,7 @@ use std::{
};
use bevy_math::{Quat, Vec3};
use vg_csg::{DomeCapZSpec, LevelDsl, MaterialId, TriangleMesh};
use gamecult_geometry_csg::{DomeCapZSpec, LevelDsl, MaterialId, TriangleMesh};
const FLOOR: MaterialId = MaterialId(1);
const WALL: MaterialId = MaterialId(2);

View file

@ -5,7 +5,7 @@ use std::{
};
use bevy_math::Vec3;
use vg_csg::{LevelDsl, MaterialId, TriangleMesh};
use gamecult_geometry_csg::{LevelDsl, MaterialId, TriangleMesh};
const DECK: MaterialId = MaterialId(21);
const SHELL: MaterialId = MaterialId(22);

View file

@ -4,7 +4,7 @@ use std::{
};
use bevy_math::Vec3;
use vg_csg::{
use gamecult_geometry_csg::{
Aabb, CultGeometryBuildRequest, CultGeometryChunkArtifact, CultGeometryDomainDocument,
CultGeometrySelectedCutManifest, DomainQuery, GEOMETRY_BUILD_REQUEST_SCHEMA,
GEOMETRY_CHUNK_ARTIFACT_SCHEMA, GEOMETRY_DOMAIN_SCHEMA, GEOMETRY_SELECTED_CUT_SCHEMA,
@ -21,8 +21,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let spec = ragnarok_column_spec();
let root = spec.compile_root();
let query = high_lod_query();
let domain =
CultGeometryDomainDocument::from_spec(&spec, "vg-csg", "2026-05-29T00:00:00.0000000Z");
let domain = CultGeometryDomainDocument::from_spec(
&spec,
"gamecult.geometry.csg",
"2026-05-29T00:00:00.0000000Z",
);
let domain_key = domain.record_key();
let request = CultGeometryBuildRequest::from_query(
"ragnarok-column-high",

View file

@ -535,8 +535,11 @@ mod tests {
#[test]
fn domain_document_emits_msgpack_payload_and_stable_key() {
let spec = ragnarok_column_spec();
let document =
CultGeometryDomainDocument::from_spec(&spec, "vg-csg", "2026-05-29T00:00:00Z");
let document = CultGeometryDomainDocument::from_spec(
&spec,
"gamecult.geometry.csg",
"2026-05-29T00:00:00Z",
);
let payload = document.to_msgpack().unwrap();
let decoded = CultGeometryDomainDocument::from_msgpack(&payload).unwrap();
assert_eq!(document.record_key(), decoded.record_key());

View file

@ -1,4 +1,4 @@
//! Lean constructive geometry tools for VibeGeometry.
//! Constructive-solid-geometry tools for CultGeometry.
//!
//! This crate borrows RealtimeCSG's useful public shape: ordered brushes,
//! operation types, dirtied generations, prefix checkpoints, and rebuildable

View file

@ -1,5 +1,5 @@
use bevy_math::{Quat, Vec3};
use vg_csg::{
use gamecult_geometry_csg::{
Aabb, Assembler, ConvexSolid, CsgBranchOp, CsgOperationType, CsgTreeArena, MaterialId,
PolygonCategory, Primitive,
};

View file

@ -1,6 +1,6 @@
param(
[string]$OutputPath = ".\experiments\generated\csg-perf-latest.jsonl",
[string]$ReferenceCommand = $env:VIBEGEOMETRY_REFERENCE_CSG_PERF,
[string]$ReferenceCommand = $env:GAMECULT_GEOMETRY_CSG_REFERENCE_PERF,
[switch]$UseRealtimeCsgCpp
)
@ -15,17 +15,17 @@ Push-Location $root
try {
cargo build --release --example csg_perf_fixture | Out-Host
if ($LASTEXITCODE -ne 0) {
throw "vg_csg perf fixture build failed with exit code $LASTEXITCODE"
throw "CultGeometry CSG perf fixture build failed with exit code $LASTEXITCODE"
}
$exe = Join-Path $root "target\release\examples\csg_perf_fixture.exe"
if (!(Test-Path $exe)) {
throw "Missing vg_csg perf fixture executable: $exe"
throw "Missing CultGeometry CSG perf fixture executable: $exe"
}
& $exe | Set-Content -Path $resolvedOutput -Encoding utf8
if ($LASTEXITCODE -ne 0) {
throw "vg_csg perf fixture failed with exit code $LASTEXITCODE"
throw "CultGeometry CSG perf fixture failed with exit code $LASTEXITCODE"
}
if ($UseRealtimeCsgCpp) {
@ -44,7 +44,7 @@ try {
$missing = @{
kernel = "reference"
status = "missing"
reason = "Set VIBEGEOMETRY_REFERENCE_CSG_PERF or pass -ReferenceCommand with an executable that emits the same JSONL scenario records."
reason = "Set GAMECULT_GEOMETRY_CSG_REFERENCE_PERF or pass -ReferenceCommand with an executable that emits the same JSONL scenario records."
} | ConvertTo-Json -Compress
Add-Content -Path $resolvedOutput -Value $missing -Encoding utf8
}