From 6543d4f886c5e42735b5d68c8590e34c50902a5c Mon Sep 17 00:00:00 2001 From: amosblomqvist Date: Tue, 29 Sep 2026 02:40:07 +0300 Subject: [PATCH] =?UTF-8?q?supports-edges=20draw=20toggle=20=E2=80=94=20la?= =?UTF-8?q?st=20row=20of=20the=20graph=20settings'=20first=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Off hides supports edges from the canvas: the renderer skips them when building the shaft/head paths (draw-only — the physics sim still feels them and detail cards still list them; settings never shift the graph). Server-persisted with the rest (render-settings.json); sanitizer takes real booleans only, anything else (missing key, legacy file) loads ON — today's look. Toggle row styled as the Background-colors row; sanitiser pinned in render-settings.test. --- components/graph-canvas.ts | 5 ++++- components/graph-view.tsx | 18 +++++++++++++++++- src/core/render-settings.ts | 8 ++++++++ tests/render-settings.test.ts | 11 +++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/components/graph-canvas.ts b/components/graph-canvas.ts index 802c99e..d058059 100644 --- a/components/graph-canvas.ts +++ b/components/graph-canvas.ts @@ -1232,11 +1232,14 @@ export class GraphCanvasRenderer { // Edge shafts + arrowheads: tip lands on the target disc edge. Both // relation types draw the same arrow for now — the double-shaft // glyph was rejected (2026-09-15); differentiation is pending a new - // approach. CanvasEdge.type is plumbed for whatever comes next. + // approach. CanvasEdge.type is plumbed for whatever comes next — + // except the supports draw toggle (owner, 2026-09-29): off skips + // the paths entirely (a draw-only hide; the sim still feels them). const arrowLen = settings.arrowLength; const shafts = new Path2D(); const heads = new Path2D(); for (const e of data.edges) { + if (!settings.showSupports && e.type === "supports") continue; if (!isVisible(e.from) || !isVisible(e.to)) continue; const a = this.nodeById.get(e.from); const b = this.nodeById.get(e.to); diff --git a/components/graph-view.tsx b/components/graph-view.tsx index 77a4064..4e55601 100644 --- a/components/graph-view.tsx +++ b/components/graph-view.tsx @@ -51,7 +51,9 @@ * * Rendering settings (2026-09-13): the gear in the search panel reveals * five sliders (node size, edge width, arrowhead length, label size, the - * zoom threshold) plus the cluster-labels checkbox. SERVER-persisted + * zoom threshold), the supports-edges draw toggle (2026-09-29: off hides + * supports edges from the canvas — draw-only; physics and detail cards + * still see them), and the cluster-labels checkbox. SERVER-persisted * (data/render-settings.json via /api/graph/render-settings): loaded * once after mount, saved debounced on every user change — one source * of truth shared by every browser. The label-zoom slider is log-scaled @@ -528,6 +530,20 @@ function GraphSettingsControl({ onChange={(p) => changeSettings((cur) => ({ ...cur, labelZoom: fromLadderPosition(p, LABEL_ZOOM_LADDER) }))} /> + {/* Supports draw toggle (owner, 2026-09-29): hides the single-line + supports edges from the canvas — follows (⟹-meant) stay. Draw-only: + physics + detail cards still see them. Last row of the FIRST + section; the border-t below starts Regions. */} + {/* Regions: the blurred cluster tints. Sliders + a fixed-set dropdown for the bitmap resolution (it's a discrete choice, not a free number). Server-persisted like the diff --git a/src/core/render-settings.ts b/src/core/render-settings.ts index 7fa968a..3fc09a4 100644 --- a/src/core/render-settings.ts +++ b/src/core/render-settings.ts @@ -54,6 +54,11 @@ export interface GraphRenderSettings { labelZoom: number; /** Node + hover label font size, WORLD units (scales with camera). */ labelSize: number; + /** Draw `supports` edges at all (owner, 2026-09-29): off hides them + * from the canvas — a DRAW toggle only. The physics sim still feels + * them (settings never shift the graph: camera, one frame), and node + * detail cards still list them. */ + showSupports: boolean; /** Toggle for the cluster region labels (hulls always draw). */ clusterLabels: boolean; /** Cluster label font size, px on screen (camera-compensated — @@ -95,6 +100,8 @@ export function sanitizeRenderSettings(raw: unknown): GraphRenderSettings { arrowLength: legacySizes ? DEFAULT_RENDER_SETTINGS.arrowLength : ladd(r.arrowLength, ARROW_LENGTH_LADDER, DEFAULT_RENDER_SETTINGS.arrowLength), labelZoom: ladd(r.labelZoom, LABEL_ZOOM_LADDER, DEFAULT_RENDER_SETTINGS.labelZoom), labelSize: legacySizes ? DEFAULT_RENDER_SETTINGS.labelSize : ladd(r.labelSize, LABEL_SIZE_LADDER, DEFAULT_RENDER_SETTINGS.labelSize), + showSupports: + typeof r.showSupports === "boolean" ? r.showSupports : DEFAULT_RENDER_SETTINGS.showSupports, clusterLabels: typeof r.clusterLabels === "boolean" ? r.clusterLabels : DEFAULT_RENDER_SETTINGS.clusterLabels, clusterLabelSize: ladd( @@ -262,6 +269,7 @@ export const DEFAULT_RENDER_SETTINGS: GraphRenderSettings = { arrowLength: 2, labelZoom: 4, labelSize: 3, + showSupports: true, clusterLabels: true, clusterLabelSize: 14, regions: DEFAULT_REGION_TUNING, diff --git a/tests/render-settings.test.ts b/tests/render-settings.test.ts index af02080..011ca1a 100644 --- a/tests/render-settings.test.ts +++ b/tests/render-settings.test.ts @@ -118,6 +118,7 @@ describe("sanitizeRenderSettings", () => { arrowLength: 3, labelZoom: 2, labelSize: 4, + showSupports: false, clusterLabels: false, clusterLabelSize: 20, regions: DEFAULT_REGION_TUNING, @@ -126,6 +127,16 @@ describe("sanitizeRenderSettings", () => { assert.deepEqual(sanitizeRenderSettings(valid), valid); // every value a ladder member }); + test("showSupports (2026-09-29): boolean-only, default on — the draw toggle", () => { + // A render-only hide for supports edges: anything but a real boolean + // (missing key, legacy file, garbage) loads as ON (today's look); a + // real false round-trips untouched. + assert.equal(sanitizeRenderSettings({}).showSupports, true); + assert.equal(sanitizeRenderSettings({ showSupports: false }).showSupports, false); + assert.equal(sanitizeRenderSettings({ showSupports: "no" }).showSupports, true); + assert.equal(sanitizeRenderSettings({ showSupports: 0 }).showSupports, true); + }); + test("the pre-2026-09-13 stored shape (flat, no regions/physics) still loads", () => { // data/render-settings.json on disk predates the nested sections — // those loads must get defaults, not crash, not shift anything.