vestige/apps/dashboard/build/_app/immutable/chunks/BMB5u1EX.js
Sam Valladares 844b91a804 feat(dashboard): every organ is a living WebGPU field (LivingFieldPass)
Turn all 17 sparse organs from text-on-black voids into full-bleed, moving,
bioluminescent WebGPU fields. Each cell maps to a real backend fact; verified
live on the real brain with a decoded fill% + motion + zero-error probe.

Foundation: one reusable LivingFieldPass (src/lib/observatory/field/) does
splat -> separable-blur (render passes) -> membrane base coat -> HDR cells with
orbital drift and a CPU pick-mirror. Each organ writes a ~20-line data->cells
mapper (cell-layout.ts: layoutGalaxy / layoutRings / FIELD_HUE).

Organs brought alive (fill% before -> after, all zero WebGPU errors):
stats 0.8->80.9, observatory 10.8->81.4, graph 12.3->82.4, memories ->78.4,
blackbox 18.2->83.3, contradictions 1.6->69.6, dreams 0.3->64.5,
settings 2.7->76.4, reasoning 2.7->39.2, patterns 7.1->45.6,
activation 10->64.9, feed ->89, explore ->83.3, intentions ->66.6,
importance ->73.7, memory-prs ->74.4, schedule ->37.1.

Backend surfaces: add api.memoryChangelog() + ChangelogResponse; surface
suppress/unsuppress on the memories field (shift/alt-click -> scar).

Tests: palace-launch-gate now asserts fillPct>30 + isAnimating (not just
non-black), with a longer settle for reasoning's deep_reference and a raised
timeout for the curated tour. all-routes-smoke treats settings as the WebGPU
field it now is. Gates green: check 0/0, build ok, palace-launch-gate 22/22 +
tour, all-routes-smoke 20/20.

Protected work untouched: MemoryCinema, graph/cinema, observatory scene
shaders, node-renderer, palace-map.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 06:20:35 +07:00

235 lines
27 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var k=Object.defineProperty;var G=(a,e,t)=>e in a?k(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var s=(a,e,t)=>G(a,typeof e!="symbol"?e+"":e,t);import"./Bzak7iHL.js";import{o as V,a as U,s as z}from"./DAau0uzT.js";import{p as H,d as q,e as X,aH as W,a as T,b as Y,f as B,s as K,X as E,g as S,c as P,r as A,af as j,Y as J}from"./CGq8RnJq.js";import{b as Z,i as Q}from"./Ccqjq5DS.js";import{p as $}from"./DV6OI5iy.js";function D(a){let e=1779033703^a.length;for(let t=0;t<a.length;t++)e=Math.imul(e^a.charCodeAt(t),2654435761),e=e<<13|e>>>19;return function(){let t=e+=1831565813;return t=Math.imul(t^t>>>15,t|1),t^=Math.imul(t^t>>>7,t|61),((t^t>>>14)>>>0)/4294967296}}function R(a){return function(){let e=a+=1831565813;return e=Math.imul(e^e>>>15,e|1),e^=Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296}}class ee{constructor(e){s(this,"fps");s(this,"loopFrames");s(this,"seedStr");s(this,"_frame");s(this,"_totalFrames");s(this,"_rng");this.fps=e.fps??60,this.loopFrames=e.loopFrames??720,this.seedStr=e.seed,this._frame=0,this._totalFrames=0;const t=D(this.seedStr)();this._rng=R(Math.floor(t*2**32))}tick(){return this._frame=(this._frame+1)%this.loopFrames,this._totalFrames++,this.state}get state(){return{frame:this._frame,phase:this._frame/this.loopFrames,rng:this._rng,totalFrames:this._totalFrames}}reset(){this._frame=0,this._totalFrames=0;const e=D(this.seedStr)();this._rng=R(Math.floor(e*2**32))}get loopDuration(){return this.loopFrames/this.fps}get framesPerLoop(){return this.loopFrames}}function Fe(a,e,t,i){const r=Math.PI*(3-Math.sqrt(5)),o=1-a/(e-1||1)*2,n=Math.sqrt(1-o*o),l=r*a,h=Math.cos(l)*n,m=Math.sin(l)*n,u=(i()-.5)*.1*t,p=(i()-.5)*.1*t,c=(i()-.5)*.1*t;return[h*t+u,o*t+p,m*t+c]}const C=["recall-path","engram-birth","salience-rescue","forgetting-horizon","firewall"];function Se(a){return C.includes(a)}const Le=16,Me={posRadius:0,velRetention:4,colorFlags:8},Te={isCenter:1,suppressed:2,isAha:4,isFailure:8,isConfusion:16},Ee=2,Pe=4,Ae={recall:0,backwardCause:1,probe:2},te=20,De={none:0,firewall:1,dreamStorm:2,causalRecall:3,birth:4},y={liveKind:12,liveFrame:13,liveEnergy:14,projectionDays:15,cursorX:16,cursorY:17,cursorVx:18,cursorVy:19};function se(a){const e=C.indexOf(a);return e<0?0:e}function Re(a,e){return{id:a.id,index:e,label:a.label,type:a.type,retention:typeof a.retention=="number"?a.retention:0,tags:Array.isArray(a.tags)?a.tags:[],isCenter:!!a.isCenter,suppressed:(a.suppression_count??0)>0,stability:typeof a.stability=="number"?a.stability:void 0,lastAccessed:typeof a.lastAccessed=="string"?a.lastAccessed:void 0}}function re(a,e){const t=Math.max(1,a>>1),i=Math.max(1,e>>1),r=Math.min(6,Math.max(1,1+Math.floor(Math.log2(Math.min(t,i)/8)))),o=Array.from({length:r},(n,l)=>[Math.max(1,t>>l),Math.max(1,i>>l)]);return{baseW:t,baseH:i,mipCount:r,sizes:o}}const F=.18,ae=0,ie=2/255,oe=.85,ne=.62,le=`
// Tuning constants — interpolated from post.wgsl.ts (TS single source of truth).
const BLOOM_STRENGTH: f32 = ${F};
const BLOOM_CHROMATIC_TEXELS: f32 = ${ae};
const GRAIN_AMP: f32 = ${ie};
const VIGNETTE_LIFT: f32 = ${oe};
const VIGNETTE_TAN: f32 = ${ne};
// Params layout — VERBATIM from render-nodes.wgsl.ts (types.PARAMS_FLOATS).
struct Params {
frame: f32,
loop_phase: f32,
node_count: f32,
edge_count: f32,
path_count: f32,
pulse: f32,
viewport_w: f32,
viewport_h: f32,
brightness: f32,
demo_id: f32,
time: f32,
_pad: f32,
};
// Globally unique bindings — each entry point statically uses a subset; the
// explicit bind group layouts in post-chain.ts carry exactly what each
// pipeline needs (blur: 1+2, composite: 0+2+3+4).
@group(0) @binding(0) var<uniform> params: Params; // composite only
@group(0) @binding(1) var src: texture_2d<f32>; // blur chain input
@group(0) @binding(2) var samp: sampler; // shared
@group(0) @binding(3) var scene_tex: texture_2d<f32>; // composite only
@group(0) @binding(4) var bloom_tex: texture_2d<f32>; // composite only (FULL-mip view)
struct FSOut {
@builtin(position) pos: vec4f,
@location(0) uv: vec2f,
};
// Fullscreen triangle from bit math — no vertex buffer, no arrays.
// vi 0/1/2 → clip (-1,-1) (3,-1) (-1,3); uv y flipped so uv(0,0) = top-left.
@vertex
fn vs_fullscreen(@builtin(vertex_index) vi: u32) -> FSOut {
let xy = vec2f(f32((vi << 1u) & 2u), f32(vi & 2u)) * 2.0 - 1.0;
var out: FSOut;
out.pos = vec4f(xy, 0.0, 1.0);
out.uv = vec2f(xy.x, -xy.y) * 0.5 + 0.5;
return out;
}
fn luma(c: vec3f) -> f32 {
return dot(c, vec3f(0.2126, 0.7152, 0.0722));
}
// ---------------------------------------------------------------------------
// Bloom downsample — 13-tap Jimenez (SIGGRAPH 2014 "Next Generation Post
// Processing in Call of Duty: Advanced Warfare"), taps fully unrolled.
//
// a b c outer ring at ±2 texels
// j k inner ring at ±1 texels
// d e f e = center
// l m
// g h i
//
// Grouped as 5 overlapping 4-tap boxes: center box (the four inner taps)
// weight 0.5, four corner boxes weight 0.125 each. A flat field reproduces
// itself EXACTLY (0.5 + 4·0.125 = 1) — that exactness is what the void
// preimage in tone-reference.ts depends on.
// ---------------------------------------------------------------------------
@fragment
fn fs_downsample_karis(in: FSOut) -> @location(0) vec4f {
let ts = 1.0 / vec2f(textureDimensions(src));
let a = textureSampleLevel(src, samp, in.uv + vec2f(-2.0, -2.0) * ts, 0.0).rgb;
let b = textureSampleLevel(src, samp, in.uv + vec2f( 0.0, -2.0) * ts, 0.0).rgb;
let c = textureSampleLevel(src, samp, in.uv + vec2f( 2.0, -2.0) * ts, 0.0).rgb;
let d = textureSampleLevel(src, samp, in.uv + vec2f(-2.0, 0.0) * ts, 0.0).rgb;
let e = textureSampleLevel(src, samp, in.uv, 0.0).rgb;
let f = textureSampleLevel(src, samp, in.uv + vec2f( 2.0, 0.0) * ts, 0.0).rgb;
let g = textureSampleLevel(src, samp, in.uv + vec2f(-2.0, 2.0) * ts, 0.0).rgb;
let h = textureSampleLevel(src, samp, in.uv + vec2f( 0.0, 2.0) * ts, 0.0).rgb;
let i = textureSampleLevel(src, samp, in.uv + vec2f( 2.0, 2.0) * ts, 0.0).rgb;
let j = textureSampleLevel(src, samp, in.uv + vec2f(-1.0, -1.0) * ts, 0.0).rgb;
let k = textureSampleLevel(src, samp, in.uv + vec2f( 1.0, -1.0) * ts, 0.0).rgb;
let l = textureSampleLevel(src, samp, in.uv + vec2f(-1.0, 1.0) * ts, 0.0).rgb;
let m = textureSampleLevel(src, samp, in.uv + vec2f( 1.0, 1.0) * ts, 0.0).rgb;
let box_c = (j + k + l + m) * 0.25;
let box_tl = (a + b + d + e) * 0.25;
let box_tr = (b + c + e + f) * 0.25;
let box_bl = (d + e + g + h) * 0.25;
let box_br = (e + f + h + i) * 0.25;
// Karis average (fireflies killer) — used ONLY on the full→mip0 hop.
// Each box is additionally weighted 1/(1 + luma) and the sum RENORMALIZED:
// on a flat field every Karis factor is equal, so the result is exact.
let w_c = 0.5 / (1.0 + luma(box_c));
let w_tl = 0.125 / (1.0 + luma(box_tl));
let w_tr = 0.125 / (1.0 + luma(box_tr));
let w_bl = 0.125 / (1.0 + luma(box_bl));
let w_br = 0.125 / (1.0 + luma(box_br));
let sum = w_c * box_c + w_tl * box_tl + w_tr * box_tr + w_bl * box_bl + w_br * box_br;
return vec4f(sum / (w_c + w_tl + w_tr + w_bl + w_br), 1.0);
}
@fragment
fn fs_downsample(in: FSOut) -> @location(0) vec4f {
let ts = 1.0 / vec2f(textureDimensions(src));
let a = textureSampleLevel(src, samp, in.uv + vec2f(-2.0, -2.0) * ts, 0.0).rgb;
let b = textureSampleLevel(src, samp, in.uv + vec2f( 0.0, -2.0) * ts, 0.0).rgb;
let c = textureSampleLevel(src, samp, in.uv + vec2f( 2.0, -2.0) * ts, 0.0).rgb;
let d = textureSampleLevel(src, samp, in.uv + vec2f(-2.0, 0.0) * ts, 0.0).rgb;
let e = textureSampleLevel(src, samp, in.uv, 0.0).rgb;
let f = textureSampleLevel(src, samp, in.uv + vec2f( 2.0, 0.0) * ts, 0.0).rgb;
let g = textureSampleLevel(src, samp, in.uv + vec2f(-2.0, 2.0) * ts, 0.0).rgb;
let h = textureSampleLevel(src, samp, in.uv + vec2f( 0.0, 2.0) * ts, 0.0).rgb;
let i = textureSampleLevel(src, samp, in.uv + vec2f( 2.0, 2.0) * ts, 0.0).rgb;
let j = textureSampleLevel(src, samp, in.uv + vec2f(-1.0, -1.0) * ts, 0.0).rgb;
let k = textureSampleLevel(src, samp, in.uv + vec2f( 1.0, -1.0) * ts, 0.0).rgb;
let l = textureSampleLevel(src, samp, in.uv + vec2f(-1.0, 1.0) * ts, 0.0).rgb;
let m = textureSampleLevel(src, samp, in.uv + vec2f( 1.0, 1.0) * ts, 0.0).rgb;
let box_c = (j + k + l + m) * 0.25;
let box_tl = (a + b + d + e) * 0.25;
let box_tr = (b + c + e + f) * 0.25;
let box_bl = (d + e + g + h) * 0.25;
let box_br = (e + f + h + i) * 0.25;
return vec4f(box_c * 0.5 + (box_tl + box_tr + box_bl + box_br) * 0.125, 1.0);
}
// ---------------------------------------------------------------------------
// Bloom upsample — 9-tap 3×3 tent, 1/16·[1 2 1; 2 4 2; 1 2 1], radius = one
// SOURCE-mip texel. Rendered with additive one/one blending onto the stored
// downsample of the destination mip (accumulate-up-the-chain). The resulting
// DC gain of exactly mipCount is normalized in fs_composite.
// ---------------------------------------------------------------------------
@fragment
fn fs_upsample_tent(in: FSOut) -> @location(0) vec4f {
let ts = 1.0 / vec2f(textureDimensions(src));
let a = textureSampleLevel(src, samp, in.uv + vec2f(-1.0, -1.0) * ts, 0.0).rgb;
let b = textureSampleLevel(src, samp, in.uv + vec2f( 0.0, -1.0) * ts, 0.0).rgb;
let c = textureSampleLevel(src, samp, in.uv + vec2f( 1.0, -1.0) * ts, 0.0).rgb;
let d = textureSampleLevel(src, samp, in.uv + vec2f(-1.0, 0.0) * ts, 0.0).rgb;
let e = textureSampleLevel(src, samp, in.uv, 0.0).rgb;
let f = textureSampleLevel(src, samp, in.uv + vec2f( 1.0, 0.0) * ts, 0.0).rgb;
let g = textureSampleLevel(src, samp, in.uv + vec2f(-1.0, 1.0) * ts, 0.0).rgb;
let h = textureSampleLevel(src, samp, in.uv + vec2f( 0.0, 1.0) * ts, 0.0).rgb;
let i = textureSampleLevel(src, samp, in.uv + vec2f( 1.0, 1.0) * ts, 0.0).rgb;
let sum = (a + c + g + i) + (b + d + f + h) * 2.0 + e * 4.0;
return vec4f(sum * (1.0 / 16.0), 1.0);
}
// ---------------------------------------------------------------------------
// Composite — bloom-add → PBR Neutral → grain → vignette (order is mandated).
// ---------------------------------------------------------------------------
// Khronos PBR Neutral — EXACT port of the Khronos reference implementation.
// Hue-preserving; the FSRS palette keeps its channel ordering. Pinned to the
// CPU mirror in post/tone-reference.ts (pbrNeutralReference) — keep in
// lockstep, the void-preimage tests run against the mirror.
fn pbr_neutral(color_in: vec3f) -> vec3f {
let start_compression = 0.8 - 0.04;
let desaturation = 0.15;
var color = color_in;
let x = min(color.r, min(color.g, color.b));
// WGSL select(false_value, true_value, condition) — argument order trap.
let offset = select(0.04, x - 6.25 * x * x, x < 0.08);
color = color - vec3f(offset);
let peak = max(color.r, max(color.g, color.b));
if (peak < start_compression) {
return color;
}
let d = 1.0 - start_compression;
let new_peak = 1.0 - d * d / (peak + d - start_compression);
color = color * (new_peak / peak);
let g = 1.0 / (desaturation * (peak - new_peak) + 1.0);
// mix weight = 1 - g per the Khronos spec.
return mix(color, vec3f(new_peak), 1.0 - g);
}
// PCG hash — integers only, 24-bit-exact output in [0, 1). Deterministic.
fn pcg(v: u32) -> u32 {
var s = v * 747796405u + 2891336453u;
let t = ((s >> ((s >> 28u) + 4u)) ^ s) * 277803737u;
return (t >> 22u) ^ t;
}
fn hashf(p: vec2u, f: u32) -> f32 {
return f32(pcg(p.x ^ pcg(p.y ^ pcg(f))) >> 8u) / 16777216.0;
}
@fragment
fn fs_composite(in: FSOut) -> @location(0) vec4f {
let pix = vec2u(in.pos.xy);
// Exact 1:1 fetch (alpha discarded — see module header).
let scene = textureLoad(scene_tex, pix, 0).rgb;
// Bloom, normalized by the mip count: the additive up-chain has DC gain
// exactly mipCount, so /mips makes flat-field gain exactly 1 — the void
// preimage holds and brightness is viewport-stable. Chromatic dispersion
// rides the bloom term ONLY (BLOOM_CHROMATIC_TEXELS = 0.0 kills it).
let mips = f32(textureNumLevels(bloom_tex));
let dims = vec2f(textureDimensions(bloom_tex));
let dvec = in.uv - vec2f(0.5);
let off = dvec * (BLOOM_CHROMATIC_TEXELS * dot(dvec, dvec) * 4.0) / dims;
let bloom = vec3f(
textureSampleLevel(bloom_tex, samp, in.uv - off, 0.0).r,
textureSampleLevel(bloom_tex, samp, in.uv, 0.0).g,
textureSampleLevel(bloom_tex, samp, in.uv + off, 0.0).b
) / mips;
var c = pbr_neutral(scene + BLOOM_STRENGTH * bloom);
// Seeded TPDF film grain (post-tonemap dither): keyed to the WRAPPED loop
// frame → 720-periodic and capture-pinned. Full strength in the shadows
// (kills #05060a banding), fades out of highlights.
let f = u32(params.frame + 0.5);
let n = hashf(pix, f) + hashf(pix ^ vec2u(0x9E3779B9u, 0x85EBCA6Bu), f) - 1.0;
let w = 1.0 - smoothstep(0.0, 0.8, luma(c));
c += GRAIN_AMP * n * w;
// cos⁴ vignette: cos⁴θ = (1 + r²·tan²)⁻², aspect-normalized so rn = 1.0
// exactly at the corners regardless of viewport shape. Lifted floor keeps
// it an observatory, not a tunnel.
let ar = vec2f(params.viewport_w / max(params.viewport_h, 1.0), 1.0);
let rn = length((in.uv * 2.0 - 1.0) * ar) / length(ar);
let k = rn * rn * VIGNETTE_TAN * VIGNETTE_TAN;
c *= mix(VIGNETTE_LIFT, 1.0, 1.0 / ((1.0 + k) * (1.0 + k)));
// NO gamma encode — display-referred pass-through, matching the pre-post
// look where shader outputs went straight to the swapchain.
return vec4f(c, 1.0);
}
`,x="rgba16float",ce={color:{srcFactor:"one",dstFactor:"one",operation:"add"},alpha:{srcFactor:"one",dstFactor:"one",operation:"add"}};class ue{constructor(e,t,i){s(this,"device");s(this,"paramsBuffer");s(this,"samp");s(this,"blurLayout");s(this,"compositeLayout");s(this,"pipeDownFirst");s(this,"pipeDown");s(this,"pipeUp");s(this,"pipeComposite");s(this,"width",0);s(this,"height",0);s(this,"plan",null);s(this,"sceneTex",null);s(this,"_sceneView",null);s(this,"bloomTex",null);s(this,"mipViews",[]);s(this,"bloomFullView",null);s(this,"downBind",[]);s(this,"upBind",[]);s(this,"compositeBind",null);this.device=e,this.paramsBuffer=t,this.samp=e.createSampler({label:"observatory-post-sampler",minFilter:"linear",magFilter:"linear",addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge"});const r=e.createShaderModule({label:"observatory-post",code:le});this.blurLayout=e.createBindGroupLayout({label:"observatory-post-blur-layout",entries:[{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{sampleType:"float",viewDimension:"2d"}},{binding:2,visibility:GPUShaderStage.FRAGMENT,sampler:{type:"filtering"}}]}),this.compositeLayout=e.createBindGroupLayout({label:"observatory-post-composite-layout",entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}},{binding:2,visibility:GPUShaderStage.FRAGMENT,sampler:{type:"filtering"}},{binding:3,visibility:GPUShaderStage.FRAGMENT,texture:{sampleType:"float",viewDimension:"2d"}},{binding:4,visibility:GPUShaderStage.FRAGMENT,texture:{sampleType:"float",viewDimension:"2d"}}]});const o=e.createPipelineLayout({label:"observatory-post-blur-pipe-layout",bindGroupLayouts:[this.blurLayout]}),n=e.createPipelineLayout({label:"observatory-post-composite-pipe-layout",bindGroupLayouts:[this.compositeLayout]}),l=(h,m,u,p,c)=>e.createRenderPipeline({label:h,layout:m,vertex:{module:r,entryPoint:"vs_fullscreen"},fragment:{module:r,entryPoint:u,targets:[{format:p,blend:c}]},primitive:{topology:"triangle-list"}});this.pipeDownFirst=l("observatory-post-down-karis",o,"fs_downsample_karis",x),this.pipeDown=l("observatory-post-down",o,"fs_downsample",x),this.pipeUp=l("observatory-post-up",o,"fs_upsample_tent",x,ce),this.pipeComposite=l("observatory-post-composite",n,"fs_composite",i)}get sceneView(){if(!this._sceneView)throw new Error("PostChain.ensure() must run before sceneView is used");return this._sceneView}ensure(e,t){var h,m;const i=Math.max(1,Math.floor(e)),r=Math.max(1,Math.floor(t));if(i===this.width&&r===this.height&&this.sceneTex!==null)return;this.width=i,this.height=r,(h=this.sceneTex)==null||h.destroy(),(m=this.bloomTex)==null||m.destroy(),this.sceneTex=this.device.createTexture({label:"observatory-scene-hdr",size:[i,r],format:x,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING}),this._sceneView=this.sceneTex.createView({label:"observatory-scene-hdr-view"});const o=re(i,r);this.plan=o,this.bloomTex=this.device.createTexture({label:"observatory-bloom-mips",size:[o.baseW,o.baseH],format:x,mipLevelCount:o.mipCount,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING});const n=this.bloomTex;this.mipViews=Array.from({length:o.mipCount},(u,p)=>n.createView({label:`observatory-bloom-mip-${p}`,baseMipLevel:p,mipLevelCount:1})),this.bloomFullView=n.createView({label:"observatory-bloom-full"});const l=this._sceneView;this.downBind=this.mipViews.map((u,p)=>this.device.createBindGroup({label:`observatory-bloom-down-bind-${p}`,layout:this.blurLayout,entries:[{binding:1,resource:p===0?l:this.mipViews[p-1]},{binding:2,resource:this.samp}]})),this.upBind=[];for(let u=0;u+1<o.mipCount;u++)this.upBind.push(this.device.createBindGroup({label:`observatory-bloom-up-bind-${u}`,layout:this.blurLayout,entries:[{binding:1,resource:this.mipViews[u+1]},{binding:2,resource:this.samp}]}));this.compositeBind=this.device.createBindGroup({label:"observatory-post-composite-bind",layout:this.compositeLayout,entries:[{binding:0,resource:{buffer:this.paramsBuffer}},{binding:2,resource:this.samp},{binding:3,resource:l},{binding:4,resource:this.bloomFullView}]})}encode(e,t){const i=this.plan;if(!i||!this.compositeBind)return;const r=i.mipCount;for(let n=0;n<r;n++){const l=e.beginRenderPass({label:`observatory-bloom-down-${n}`,colorAttachments:[{view:this.mipViews[n],loadOp:"clear",storeOp:"store"}]});l.setPipeline(n===0?this.pipeDownFirst:this.pipeDown),l.setBindGroup(0,this.downBind[n]),l.draw(3),l.end()}for(let n=r-2;n>=0;n--){const l=e.beginRenderPass({label:`observatory-bloom-up-${n}`,colorAttachments:[{view:this.mipViews[n],loadOp:"load",storeOp:"store"}]});l.setPipeline(this.pipeUp),l.setBindGroup(0,this.upBind[n]),l.draw(3),l.end()}const o=e.beginRenderPass({label:"observatory-post-composite",colorAttachments:[{view:t,loadOp:"clear",storeOp:"store"}]});o.setPipeline(this.pipeComposite),o.setBindGroup(0,this.compositeBind),o.draw(3),o.end()}dispose(){var e,t;(e=this.sceneTex)==null||e.destroy(),(t=this.bloomTex)==null||t.destroy(),this.sceneTex=null,this.bloomTex=null,this._sceneView=null,this.bloomFullView=null,this.mipViews=[],this.downBind=[],this.upBind=[],this.compositeBind=null,this.plan=null,this.width=0,this.height=0}}const I=Math.sqrt(5/255/6.25),N=I-5/255,pe={r:I/(1+F),g:(6/255+N)/(1+F),b:(10/255+N)/(1+F),a:1},w=class w{constructor(e){s(this,"canvas");s(this,"device",null);s(this,"context",null);s(this,"format","bgra8unorm");s(this,"clock");s(this,"demo");s(this,"freezeFrame");s(this,"rafId",0);s(this,"running",!1);s(this,"disposed",!1);s(this,"maxDpr");s(this,"onFrame");s(this,"params",new Float32Array(te));s(this,"paramsBuffer",null);s(this,"passes",[]);s(this,"post",null);s(this,"_status",{state:"booting"});s(this,"statusListeners",new Set);s(this,"preFrameHook",null);s(this,"lastRafTs",0);s(this,"fpsEstimate",0);s(this,"accumulatorMs",0);s(this,"paused",!1);s(this,"frame",e=>{var p,c,d,b;if(!this.running||!this.device||!this.context||!this.paramsBuffer||!this.post)return;let t=0;for(this.lastRafTs>0&&(t=e-this.lastRafTs,t>0&&(this.fpsEstimate=Math.round(1e3/t))),this.lastRafTs=e,this.accumulatorMs+=Math.min(t,250);this.accumulatorMs>=w.FIXED_DT_MS;)this.paused||this.clock.tick(),this.accumulatorMs-=w.FIXED_DT_MS;const i=this.clock.state,r=this.freezeFrame??i.frame,o=r/this.clock.framesPerLoop,n=this.params;n[0]=r,n[1]=o,n[5]=.5+.5*Math.sin(2*Math.PI*4*o),n[6]=this.canvas.width,n[7]=this.canvas.height,n[9]=se(this.demo),n[10]=r/60,n[11]=this.freezeFrame!==null?1:0,(p=this.preFrameHook)==null||p.call(this,i.totalFrames),this.device.queue.writeBuffer(this.paramsBuffer,0,n);let l;try{l=this.context.getCurrentTexture()}catch{this.rafId=requestAnimationFrame(this.frame);return}this.post.ensure(l.width,l.height);const h=l.createView(),m=this.device.createCommandEncoder({label:"observatory-frame"});for(const v of this.passes)(c=v.compute)==null||c.call(v,m,r);const u=m.beginRenderPass({label:"observatory-main",colorAttachments:[{view:this.post.sceneView,clearValue:pe,loadOp:"clear",storeOp:"store"}]});for(const v of this.passes)(d=v.render)==null||d.call(v,u,r);u.end(),this.post.encode(m,h),this.device.queue.submit([m.finish()]),(b=this.onFrame)==null||b.call(this,r,this.fpsEstimate),this.rafId=requestAnimationFrame(this.frame)});this.canvas=e.canvas,this.demo=e.demo,this.maxDpr=e.maxDpr??2,this.onFrame=e.onFrame,this.clock=new ee({seed:e.seed}),this.freezeFrame=typeof e.freezeFrame=="number"&&Number.isFinite(e.freezeFrame)?(Math.floor(e.freezeFrame)%this.clock.framesPerLoop+this.clock.framesPerLoop)%this.clock.framesPerLoop:null,this.params[8]=1,this.setCursorPreNdc(999,999,0,0)}get status(){return this._status}get gpuDevice(){return this.device}get presentationFormat(){return this.format}get sceneFormat(){return x}get demoClock(){return this.clock}onStatus(e){return this.statusListeners.add(e),e(this._status),()=>this.statusListeners.delete(e)}setStatus(e){this._status=e;for(const t of this.statusListeners)t(e)}addPass(e){this.passes.push(e)}removePass(e){var i;const t=this.passes.indexOf(e);t!==-1&&(this.passes.splice(t,1),(i=e.dispose)==null||i.call(e))}clearPasses(){var e;for(const t of this.passes)(e=t.dispose)==null||e.call(t);this.passes.length=0}setPreFrameHook(e){this.preFrameHook=e}get totalFrames(){return this.clock.state.totalFrames}setCursorPreNdc(e,t,i=0,r=0){this.params[y.cursorX]=Number.isFinite(e)?e:999,this.params[y.cursorY]=Number.isFinite(t)?t:999,this.params[y.cursorVx]=Number.isFinite(i)?i:0,this.params[y.cursorVy]=Number.isFinite(r)?r:0}setPaused(e){this.paused=e}get isPaused(){return this.paused}get wallNowMs(){return Date.now()}async start(){var r;if(this.disposed)return!1;const e=navigator.gpu;if(!e)return this.setStatus({state:"unsupported",reason:"WebGPU is not available in this browser."}),!1;let t=null;try{t=await e.requestAdapter()}catch(o){return this.setStatus({state:"error",reason:o instanceof Error?o.message:"requestAdapter failed"}),!1}if(!t)return this.setStatus({state:"unsupported",reason:"No suitable GPU adapter found."}),!1;try{this.device=await t.requestDevice()}catch(o){return this.setStatus({state:"error",reason:o instanceof Error?o.message:"requestDevice failed"}),!1}if(this.disposed)return(r=this.device)==null||r.destroy(),this.device=null,!1;this.device.lost.then(o=>{this.disposed||o.reason==="destroyed"||(this.setStatus({state:"error",reason:`GPU device lost: ${o.message}`}),this.stopLoop())}),this.device.onuncapturederror=o=>{console.error("[observatory] WebGPU error:",o.error.message)};const i=this.canvas.getContext("webgpu");return i?(this.context=i,this.format=e.getPreferredCanvasFormat(),this.configureContext(),this.paramsBuffer=this.device.createBuffer({label:"observatory-params",size:this.params.byteLength,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.post=new ue(this.device,this.paramsBuffer,this.format),this.setStatus({state:"running"}),this.running=!0,this.rafId=requestAnimationFrame(this.frame),!0):(this.setStatus({state:"error",reason:"Could not get webgpu canvas context."}),!1)}resize(){var r;if(!this.device||!this.context)return;const e=Math.min(window.devicePixelRatio||1,this.maxDpr),t=Math.max(1,Math.floor(this.canvas.clientWidth*e)),i=Math.max(1,Math.floor(this.canvas.clientHeight*e));(this.canvas.width!==t||this.canvas.height!==i)&&(this.canvas.width=t,this.canvas.height=i,this.configureContext(),(r=this.post)==null||r.ensure(t,i))}configureContext(){!this.device||!this.context||this.context.configure({device:this.device,format:this.format,alphaMode:"opaque"})}stopLoop(){this.running=!1,this.rafId!==0&&(cancelAnimationFrame(this.rafId),this.rafId=0)}dispose(){var e,t,i;this.disposed||(this.disposed=!0,this.stopLoop(),(e=this.paramsBuffer)==null||e.destroy(),this.paramsBuffer=null,(t=this.post)==null||t.dispose(),this.post=null,(i=this.device)==null||i.destroy(),this.device=null,this.context=null,this.passes=[],this.setStatus({state:"disposed"}),this.statusListeners.clear())}};s(w,"FIXED_DT_MS",1e3/60);let M=w;var me=B(`<div class="fallback svelte-16248mg" role="alert"><div class="fallback-title svelte-16248mg">MEMORY FIELD OFFLINE</div> <div class="fallback-reason svelte-16248mg"> </div> <div class="fallback-hint svelte-16248mg">WebGPU is required for the Observatory. Chrome 113+, Edge 113+, or Safari 18+ —
the classic <a href="./graph" class="svelte-16248mg">Graph view</a> works everywhere.</div></div>`),he=B('<canvas class="observatory-canvas svelte-16248mg" aria-label="Vestige memory field"></canvas> <!>',1);function Ne(a,e){H(e,!0);let t=$(e,"freezeFrame",3,null),i,r=null,o=q(X({state:"booting"})),n=null,l=null;V(()=>{r=new M({canvas:i,demo:e.demo,seed:e.seed,freezeFrame:t(),maxDpr:2,onFrame:(c,d)=>{var b;return(b=e.onframe)==null?void 0:b.call(e,c,d)}}),n=r.onStatus(c=>K(o,c,!0)),l=new ResizeObserver(()=>r==null?void 0:r.resize()),l.observe(i),r.start().then(c=>{var d;c&&r&&(r.resize(),(d=e.onready)==null||d.call(e,r))})}),U(()=>{n==null||n(),l==null||l.disconnect(),r==null||r.dispose(),r=null});var h=he(),m=W(h);Z(m,c=>i=c,()=>i);var u=E(m,2);{var p=c=>{var d=me(),b=E(P(d),2),v=P(b,!0);A(b),j(2),A(d),J(()=>z(v,S(o).reason)),T(c,d)};Q(u,c=>{(S(o).state==="unsupported"||S(o).state==="error")&&c(p)})}T(a,h),Y()}function O(a){const e=/^#?([0-9a-fA-F]{6})$/.exec(a.trim());if(!e)return[2/255,3/255,7/255];const t=parseInt(e[1],16);return[(t>>16&255)/255,(t>>8&255)/255,(t&255)/255]}const de={blackwater:"#020307"},f={luciferin:"#E9FFB7",healthy:"#A8FF5E",recall:"#29F2A9",bridge:"#1BD6FF",debt:"#8A4B18",extinction:"#2A160B"},fe=[f.extinction,f.debt,f.healthy,f.luciferin],g={trustMembrane:"#F4F1D0",caution:"#FFD166",veto:"#FF3B30",suppressionScar:"#B90D2B",labile:"#FF7A1A"},_={forward:"#00F5D4",retrograde:"#FF2DF7"},L={validRing:"#6BFFB8",txShadow:"#7C6CFF",supersession:"#FFB000"},Be={throughput:"#9DFFEB"};function Ce(a){const e=Math.max(0,Math.min(1,a)),t=fe.map(O),i=e*(t.length-1),r=Math.min(t.length-2,Math.floor(i)),o=i-r,n=t[r],l=t[r+1];return[n[0]+(l[0]-n[0])*o,n[1]+(l[1]-n[1])*o,n[2]+(l[2]-n[2])*o]}const ve={MemoryCreated:f.healthy,SearchPerformed:_.forward,ActivationSpread:f.recall,ImportanceScored:L.supersession,RetentionDecayed:f.debt,ConnectionDiscovered:_.forward,DeepReferenceCompleted:f.luciferin,BackfillFired:_.retrograde,CausalReceipt:_.retrograde,MemorySuppressed:g.suppressionScar,MemoryUnsuppressed:g.labile,MemoryPromoted:f.luciferin,MemoryDemoted:f.debt,MemoryPrOpened:g.caution,MemoryPrDecided:g.trustMembrane,HookVerdictRecorded:g.veto,TraceEvent:_.forward,DreamStarted:L.txShadow,DreamCompleted:L.validRing,Rac1CascadeSwept:g.suppressionScar};function Ie(a){return O(ve[a]??de.blackwater)}function Oe(a){const e=Math.max(0,Math.min(1,a));return .003+(.018-.003)*e}export{_ as C,C as D,Le as F,g as I,De as L,de as M,Me as N,Ne as O,Ae as P,f as R,Ee as U,Be as V,Ce as a,Te as b,Pe as c,Fe as d,Ie as e,ee as f,y as g,Se as i,Oe as m,O as r,Re as t};