From c920f93b10a866ad32bd1a00233e353e8d789379 Mon Sep 17 00:00:00 2001 From: Sam Valladares Date: Wed, 8 Jul 2026 12:06:01 -0700 Subject: [PATCH] feat(graph): raw-WebGPU living field is now the main dashboard renderer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The main graph page defaults to the Observatory engine — GPU force sim, HDR bloom, and the recall wavefront sweeping the REAL memory graph on a 12s loop — instead of the flat Three.js view. Visuals to the max, per the locked ALIVE-field direction. - ObservatoryStage gains embedded (fills parent, not viewport) and chrome ('full' | 'none') props; chrome='none' is a pure living canvas plus loading/error text, so the page's own DOM chrome stays in charge. - New Field | Classic renderer toggle in the control bar. Field is the default wherever WebGPU exists; no WebGPU forces classic. Choice persists in localStorage. - Classic (Three.js) remains one click away and untouched: node picking, colour modes, node count, brightness, temporal scrubbing and legends are classic-renderer features and now only render there. Dream, Observatory takeover, Memory Cinema (protected) and Reload work in both modes. Verified live: fresh load defaults to Field (148 real nodes, 2865 real edges, recall ribbon igniting on camera, zero console errors); Classic toggle restores search/colour/brightness with a single canvas; the choice round-trips through localStorage. svelte-check 940 files 0 errors 0 warnings. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../lib/observatory/ObservatoryStage.svelte | 41 ++++++-- .../src/routes/(app)/graph/+page.svelte | 96 ++++++++++++++++--- 2 files changed, 113 insertions(+), 24 deletions(-) diff --git a/apps/dashboard/src/lib/observatory/ObservatoryStage.svelte b/apps/dashboard/src/lib/observatory/ObservatoryStage.svelte index 8ad5d0f..d7ea608 100644 --- a/apps/dashboard/src/lib/observatory/ObservatoryStage.svelte +++ b/apps/dashboard/src/lib/observatory/ObservatoryStage.svelte @@ -44,6 +44,19 @@ ondemochange?: (demo: DemoMode) => void; /** When provided, renders the exit control (× back to the dashboard). */ onexit?: () => void; + /** + * Embedded mode — the stage fills its PARENT (absolute) instead of the + * viewport (fixed). Used by the main graph page, where the field is the + * default renderer living under the page's own chrome. + */ + embedded?: boolean; + /** + * 'full' — telemetry strip, spine, verdicts, switcher, exit (the route + * and the takeover overlay). + * 'none' — pure living canvas + loading/error text only; the host page + * provides all chrome (the main graph's field renderer). + */ + chrome?: 'full' | 'none'; } let { @@ -53,7 +66,9 @@ capture = false, showSwitcher = true, ondemochange, - onexit + onexit, + embedded = false, + chrome = 'full' }: Props = $props(); // Human labels for the switcher chips — short, mono, uppercase (visual DNA §7.3). @@ -246,8 +261,11 @@ - -
+ +
+ capture hides it all (pure canvas for recording); H toggles; + chrome='none' leaves only loading/error (host page owns the chrome). --> {#if showHud}
+ {#if chrome === 'full'} + {/if} - {#if onexit} + {#if chrome === 'full' && onexit}
{:else if graphData} - + {#if renderMode === 'field'} + +
+ +
+ {:else} + + {/if} {/if} @@ -304,7 +340,8 @@ disown [padding-top:max(0.75rem,env(safe-area-inset-top))] [padding-left:max(0.75rem,env(safe-area-inset-left))] [padding-right:max(0.75rem,env(safe-area-inset-right))] sm:[padding-top:0] sm:[padding-left:0] sm:[padding-right:0]" > - + + {#if renderMode === 'classic'}
Focus
+ {/if}
+ +
+ + +
+ + {#if renderMode === 'classic'} @@ -386,6 +451,7 @@ disown {graphState.brightness.toFixed(1)}x + {/if}