Skip to content

Commit 6ebe9fb

Browse files
fix(graph): keep local orbits at zero global gravity
1 parent d63304b commit 6ebe9fb

2 files changed

Lines changed: 54 additions & 2 deletions

File tree

engraphis/dashboard_assets/engraphis-graph.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2973,7 +2973,8 @@
29732973
Number(opts.localSoftening) || opts.softening || 40);
29742974
const field = galaxyBlackHoleField(bodies, Object.assign({}, opts, { softening: centralSoftening }));
29752975
const anchor = field.anchor && field.anchor.anchor_role === 'global' ? field.anchor : null;
2976-
if (!anchor || !(field.gravitationalConstant > 0)) return empty;
2976+
if (!anchor) return empty;
2977+
const globalFieldActive = field.gravitationalConstant > 0;
29772978
const timestep = Math.max(0.001, Math.min(2, Number(opts.timestep) || 1));
29782979
const orbitalRadius = galaxyOrbitalRadiusMultiplier(opts.orbitalSpeed);
29792980
const absoluteSpeedLimit = Math.max(0.01, Number(opts.speedLimit) || MAX_NODE_SPEED);
@@ -3039,7 +3040,12 @@
30393040
if (!(Number.isFinite(Number(orbit.baseRadius)) && Number(orbit.baseRadius) > 0)) {
30403041
orbit.baseRadius = Number(orbit.radius) || starRadius;
30413042
}
3042-
orbit.radius = boundedRadius(orbit.baseRadius * orbitalRadius, extent * orbitalRadius);
3043+
/* At the zero global-gravity endpoint the black-hole carrier is stationary. Preserve its
3044+
current radius so local stellar members can keep orbiting that fixed carrier instead of
3045+
receiving a one-time radial resize from the orbital-speed presentation multiplier. */
3046+
orbit.radius = globalFieldActive
3047+
? boundedRadius(orbit.baseRadius * orbitalRadius, extent * orbitalRadius)
3048+
: boundedRadius(Number(orbit.radius) || starRadius, extent);
30433049
if (!Number.isFinite(orbit.angle)) {
30443050
orbit.angle = seededHash(opts.layoutSeed, 'kinematic-system:' + item.id)
30453051
/ 0x100000000 * Math.PI * 2;

tests/test_graph_engine_asset.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11858,6 +11858,52 @@ def test_kinematic_local_velocity_budget_uses_one_phase_speed() -> None:
1185811858
assert report["phaseSpeed"] == pytest.approx(report["relativeSpeed"], rel=1e-9), report
1185911859

1186011860

11861+
@requires_node
11862+
def test_kinematic_local_orbits_continue_when_global_gravity_is_zero() -> None:
11863+
"""Zero global gravity must not disable the independent local stellar clock."""
11864+
report = _run_node(
11865+
"""
11866+
const nodes = [
11867+
{ id: 'black-hole', anchor_role: 'global', community_id: 'core',
11868+
system_anchor_id: 'black-hole', gravity_mass: 8, radius: 8,
11869+
x: 0, y: 0, vx: 0, vy: 0 },
11870+
{ id: 'star', anchor_role: 'community', community_id: 'solar',
11871+
system_anchor_id: 'star', gravity_mass: 4, radius: 5,
11872+
x: 120, y: 0, vx: 0, vy: 0 },
11873+
{ id: 'planet', community_id: 'solar', system_anchor_id: 'star',
11874+
orbit_tier: 1, gravity_mass: 1, radius: 2,
11875+
x: 150, y: 0, vx: 0, vy: 0 },
11876+
];
11877+
const options = {
11878+
gravity: 0, softening: 32, centralSoftening: 40, localSoftening: 12,
11879+
localGravitySetting: 48, orbitalSpeed: 400, layoutSeed: 19,
11880+
timestep: .032, speedLimit: 48,
11881+
};
11882+
const angle = () => Math.atan2(nodes[2].y - nodes[1].y,
11883+
nodes[2].x - nodes[1].x);
11884+
const before = angle();
11885+
const first = I.advanceGalaxyKinematicOrbits(nodes, options);
11886+
const afterFirst = angle();
11887+
const second = I.advanceGalaxyKinematicOrbits(nodes, options);
11888+
const afterSecond = angle();
11889+
emit({ first, second,
11890+
localTravel: Math.atan2(Math.sin(afterSecond - before),
11891+
Math.cos(afterSecond - before)),
11892+
carrierTravel: Math.hypot(nodes[1].x - 120, nodes[1].y),
11893+
finite: nodes.every(node =>
11894+
[node.x, node.y, node.vx, node.vy].every(Number.isFinite)),
11895+
firstStepMoved: Math.abs(afterFirst - before) > 1e-8,
11896+
});
11897+
"""
11898+
)
11899+
assert report["finite"] is True
11900+
assert report["first"]["satellites"] > 0
11901+
assert report["second"]["satellites"] > 0
11902+
assert report["firstStepMoved"] is True
11903+
assert abs(report["localTravel"]) > 1e-5
11904+
assert report["carrierTravel"] <= 1e-9
11905+
11906+
1186111907
@requires_node
1186211908
def test_live_carrier_is_capped_before_local_motion_budgeting() -> None:
1186311909
report = _run_node(

0 commit comments

Comments
 (0)