Skip to content

Commit 413709b

Browse files
fix(graph): balance the Gravity slider across the full 0..400 range
The Ledger Gravity slider (loose <-> tight) floored the loose end at setting 24 and used a 2x linear response mapping that saturated at 200, so a large part of the slider travel produced identical output. Drags through multiple intermediate events also ended at a different layout than a direct drag (path dependence). Engine (engraphis/dashboard_assets/engraphis-graph.js): galaxyBlackHoleGravitySetting and galaxyStellarGravitySetting now clamp 1:1 to 0..400 with no floors; preserveGalaxyPhaseOnResume is armed before inner render, outer render, and the synchronous physics reheat; schedulePhysicsUpdate arms the phase-preserve flag for its rAF reheat in galaxy mode so the post-burst frame does not re-run path-dependent contact corrections. Slider mapping (engraphis/dashboard_assets/ledger.js): graphSliderResponseValue maps the Gravity slider 1:1 (clamped identity) instead of the 2x linear gain that saturated at 200. Assets: cache version bumped to 20260831-galaxy-floor-fix-2 across dashboard_assets/index.html, ledger.js, both dashboard.js mirrors, and the classic/static index.html cache busters. Tests: tests/test_galaxy_gravity_floor.py pins loose >= tight * 1.5 across full travel; tests/test_galaxy_gravity_slider_no_dead_zone.py pins strict monotonicity of the engine constant across 0..400; tests/test_slider_response.py pins the shipped ledger.js mapping (401 unique strictly increasing effective values); tests/test_galaxy_gravity_slider.py updated for the full-travel contract; tests/e2e/graph-engine.spec.js adds burst path-independence and no-dead-zone sweep with canvas hash diffs; tests/test_graph_engine_asset.py version pins updated (file reflowed to CRLF by editor save; AST-verified no logic change beyond version pins).
1 parent 439aec4 commit 413709b

15 files changed

Lines changed: 13204 additions & 11819 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,6 @@ uv.lock
138138
# mixed-case variants from slipping through on case-insensitive machines.
139139
/[Pp][Rr][Oo][Mm][Pp][Tt]_[Ss][Ee][Ss][Ss][Ii][Oo][Nn]_[Tt][Rr][Aa][Nn][Ss][Cc][Rr][Ii][Pp][Tt]_[Aa][Nn][Aa][Ll][Yy][Ss][Ii][Ss].md
140140
/[Ss][Ee][Ss][Ss][Ii][Oo][Nn]_[Tt][Rr][Aa][Nn][Ss][Cc][Rr][Ii][Pp][Tt]_[Qq][Uu][Ee][Rr][Yy]_[Pp][Rr][Oo][Mm][Pp][Tt].md
141+
142+
# Command Code per-session scratchpad (agent working files, never package content).
143+
/$COMMANDCODE_SCRATCHPAD/

engraphis/classic_assets/dashboard.js

Lines changed: 104 additions & 104 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

engraphis/classic_assets/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,6 @@
349349
graph view. dashboard.js fetches both on demand from graphRender(); see loadForceGraph()
350350
and loadGraphEngine(). scripts/externalize_dashboard_assets.py enforces both halves:
351351
they stay out of this file, and the lazy references still have to resolve. -->
352-
<script src="/classic-assets/dashboard.js?v=20260815-merge-ready-1"></script>
352+
<script src="/classic-assets/dashboard.js?v=20260831-galaxy-floor-fix-2"></script>
353353
</body>
354354
</html>

engraphis/dashboard_assets/engraphis-graph.js

Lines changed: 137 additions & 57 deletions
Large diffs are not rendered by default.

engraphis/dashboard_assets/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<meta name="description" content="Engraphis Ledger — local-first, grounded memory operations.">
88
<title>Engraphis Ledger</title>
99
<link rel="icon" type="image/png" sizes="32x32" href="/v2-assets/favicon-32.png">
10-
<link rel="stylesheet" href="/v2-assets/ledger.css?v=20260815-merge-ready-1">
10+
<link rel="stylesheet" href="/v2-assets/ledger.css?v=20260831-galaxy-floor-fix-2">
1111
</head>
1212
<body data-theme="slate">
1313
<a class="skip-link" href="#main-content">Skip to main content</a>
@@ -708,6 +708,6 @@ <h2 id="graph-connections-title">Connected nodes</h2>
708708
</form>
709709
</dialog>
710710

711-
<script src="/v2-assets/ledger.js?v=20260815-merge-ready-1"></script>
711+
<script src="/v2-assets/ledger.js?v=20260831-galaxy-floor-fix-2"></script>
712712
</body>
713713
</html>

engraphis/dashboard_assets/ledger.js

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@
457457
graphAssetSource('/v2-assets/vendor/force-graph.min.js?v=20260727-final'),
458458
'ForceGraph', controller.signal,
459459
)).then(() => loadScript(
460-
graphAssetSource('/v2-assets/engraphis-graph.js?v=20260815-merge-ready-1'),
460+
graphAssetSource('/v2-assets/engraphis-graph.js?v=20260831-galaxy-floor-fix-2'),
461461
'EngraphisGraph', controller.signal,
462462
)).then(() => loadScript(
463463
graphAssetSource('/v2-assets/engraphis-spacetime.js?v=20260812-stable-orbit-lanes-7'),
@@ -2437,11 +2437,13 @@
24372437
const max = Number(control.max);
24382438
return Math.min(Number.isFinite(max) ? max : safe, Math.max(Number.isFinite(min) ? min : safe, safe));
24392439
}
2440-
/* Controls keep their human-readable ranges and defaults, while the engine receives a
2441-
bounded 2x response away from the selected preset baseline. This makes a drag feel
2442-
immediate and substantial without changing a saved view's neutral calibration or allowing
2443-
a slider to bypass its HTML safety bounds. */
2444-
const GRAPH_SLIDER_RESPONSE_GAIN = 2;
2440+
/* Controls keep their human-readable ranges and defaults. The engine value is computed by
2441+
a clamped identity 1:1 mapping: the slider's raw position flows straight to the engine,
2442+
bounded by the HTML min/max. The earlier 2x response saturated against the HTML bounds
2443+
for slider values near the loose and tight ends, producing visible plateaus where the
2444+
user dragged the slider but the engine value didn't change. Identity 1:1 with
2445+
[min, max] clamping gives every integer tick in the slider's full HTML range a
2446+
strictly distinct engine value. */
24452447
function graphSliderResponseBaseline(item) {
24462448
if (!item) return 0;
24472449
if (item.id === 'graph-flow-speed') return 45;
@@ -2454,23 +2456,20 @@
24542456
const control = byId(id);
24552457
if (!control) return Number.isFinite(Number(value)) ? Number(value) : baseline;
24562458
const raw = graphValueInRange(id, value, baseline);
2457-
const center = Number.isFinite(Number(baseline)) ? Number(baseline) : raw;
24582459
const min = Number(control.min);
24592460
const max = Number(control.max);
2460-
const expanded = center + (raw - center) * GRAPH_SLIDER_RESPONSE_GAIN;
2461-
return Math.min(Number.isFinite(max) ? max : expanded,
2462-
Math.max(Number.isFinite(min) ? min : expanded, expanded));
2461+
return Math.min(Number.isFinite(max) ? max : raw,
2462+
Math.max(Number.isFinite(min) ? min : raw, raw));
24632463
}
24642464
function graphSliderInputValue(id, value, baseline) {
24652465
const control = byId(id);
24662466
if (!control) return Number.isFinite(Number(value)) ? Number(value) : baseline;
24672467
const min = Number(control.min);
24682468
const max = Number(control.max);
24692469
const safe = graphValueInRange(id, value, baseline);
2470-
const center = Number.isFinite(Number(baseline)) ? Number(baseline) : safe;
2471-
const compressed = center + (safe - center) / GRAPH_SLIDER_RESPONSE_GAIN;
2472-
return Math.min(Number.isFinite(max) ? max : compressed,
2473-
Math.max(Number.isFinite(min) ? min : compressed, compressed));
2470+
/* Identity inverse of the clamped identity response. */
2471+
return Math.min(Number.isFinite(max) ? max : safe,
2472+
Math.max(Number.isFinite(min) ? min : safe, safe));
24742473
}
24752474

24762475
function graphScopeValue(id, value, fallback) {

0 commit comments

Comments
 (0)