betterwithage commited on
Commit
76bbcfa
·
verified ·
1 Parent(s): 8fbd84a

fix hero: working Sovereign Lattice cathedral.js (restores 3D sphere + live Λ pill)

Browse files
Files changed (1) hide show
  1. static/a11oy_cathedral.js +190 -145
static/a11oy_cathedral.js CHANGED
@@ -1,166 +1,211 @@
1
  /* ============================================================================
2
- * a11oy_cathedral.js — a11oy front-door sovereign 3D hero (vendored Three.js).
3
- * Brain-sun (a11oy) + 3 internal capabilities orbiting + inspectable.
4
- * Honesty: locked proven = 5; experimental main 1304/22; Λ = Conjecture 1;
5
- * conformal (never 100%) not Hoeffding; SLSA L1 honest / L2 roadmap.
6
- * Live /healthz + /lambda (13-axis Trust Score). No fakery; honest fallback.
7
  * Signed-off-by: Stephen P. Lutar Jr. <stephenlutar2@gmail.com>
8
  * ========================================================================== */
9
  import * as THREE from 'three';
10
- import { OrbitControls } from 'three/addons/OrbitControls.js';
11
-
12
- const CAPABILITIES = [
13
- { id:'reasoning', title:'Reasoning & Provenance', color:0x5cc4bf, angle:0,
14
- plain:'Grounded reasoning, memory/recall and provenance over a signed knowledge base — an internal a11oy function.',
15
- functions:['grounded ask (cites its source, refuses to fabricate)','13-axis Trust Score (geometric-mean aggregate, floor 0.90)','knowledge ontology (axioms → theorems → formulas)','model router (5-tier, cost-aware)'],
16
- proof:['Trust-Score CI from CONFORMAL (W5-3 + W7-4) — distribution-free, anti-overconfidence floor (never 100%, NOT Hoeffding)','Model-Router stability C20 + PAC-Bayes/router envelope W7-5 (min ≤ avg ≤ max)','Ontology label-invariance: F-G2 / F-G4 / F-G6 / W7-1 (graph substrate)'] },
17
- { id:'policy', title:'Policy & Compliance', color:0xd7b96b, angle:2.094,
18
- plain:'Deny-by-default safety gates and full ALLOW/DENY verdicts with signed receipts — an internal a11oy function.',
19
- functions:['8 deny-by-default safety gates','full verdict (ALLOW / DENY) with signals + receipt hash','30-signature threat corpus (MITRE ATT&CK + CVSS)','readiness / compliance (NIST / STIG / ISO)'],
20
- proof:['Gate-soundness P2 — no action without BOTH policy AND kernel/doctrine check; a single DENY is absorbing','Agentic-loop P3 non-interference — poisoned input provably cannot flip a DENY into an ALLOW'] },
21
- { id:'operator', title:'Operator · Ask / Act / Approvals', color:0xe58e54, angle:4.189,
22
- plain:'The governed run loop: ask, act with approvals, and emit replayable signed receipts — an internal a11oy function.',
23
- functions:['governed run loop P1–P6 (sign → gate → chain → memory → replay)','human approvals gate for high-impact actions','replayable, hash-chained receipts (Khipu)','a11oy Code — governed agentic coder (P1–P6), open-weight models'],
24
- proof:['Agentic-loop P1–P6: 28 kernel-verified theorems — run is auditable, gate-sound, injection-resistant end-to-end','P5 replay-determinism gated only by declared hashFn_collision_resistant axiom (named, not a hardness proof)'] }
25
- ];
26
-
27
- const A11OY = {
28
- id:'a11oy', title:'a11oy — Command Platform (the brain)',
29
- plain:'The orchestrating governance substrate: one brain coordinating reasoning, policy and operator capabilities. Live: /healthz.',
30
- functions:['command center + five superpowers + 25-demo Warhacker board (5×5 live)','a11oy Code (governed agentic coder, P1–P6, open-weight router)','one governance substrate (capabilities are internal, no service split)','13-axis Trust Score aggregate (yuyay_v3, geometric mean, floor 0.90)','/proven: 9 wave 9/10 formula cards (5 with live runtime checks)','signed Khipu receipts for every governed action'],
31
- proof:['Locked proven kernel = 5 {F1,F11,F12,F18,F19} @ c7c0ba17 (749/14/163) — machine-enforced count','Experimental main: 1304 decl / 22 axioms, waves 3–10 CI-green (~36–44 theorems), excluded from locked count','Λ-Aggregator uniqueness (F23) = Conjecture 1 — NOT a theorem (unconditional uniqueness machine-checked FALSE)'],
32
- url:'/console'
33
- };
34
-
35
- const ENDPOINTS = { health:'/healthz', lambda:'/api/a11oy/v1/lambda' };
36
 
 
37
  const canvas = document.getElementById('scene');
38
- const renderer = new THREE.WebGLRenderer({ canvas, antialias:true, alpha:false });
39
- renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.8));
40
- renderer.setSize(window.innerWidth, window.innerHeight);
41
- renderer.toneMapping = THREE.ACESFilmicToneMapping; renderer.toneMappingExposure = 1.15;
 
42
 
43
  const scene = new THREE.Scene();
44
- scene.fog = new THREE.FogExp2(0x070815, 0.0019);
45
- const camera = new THREE.PerspectiveCamera(55, window.innerWidth/window.innerHeight, 0.1, 4000);
46
- camera.position.set(0, 70, 320);
47
- const controls = new OrbitControls(camera, renderer.domElement);
48
- controls.enableDamping = true; controls.dampingFactor = 0.06;
49
- controls.minDistance = 90; controls.maxDistance = 1000;
50
- controls.autoRotate = true; controls.autoRotateSpeed = 0.45;
51
-
52
- scene.add(new THREE.AmbientLight(0x33304a, 0.9));
53
- scene.add(new THREE.PointLight(0xffe6a8, 2.4, 1600, 1.4));
54
- const rim = new THREE.DirectionalLight(0x5c8fd1, 0.5); rim.position.set(-200,120,-150); scene.add(rim);
55
-
56
- (function backdrop(){
57
- const N=2600, pos=new Float32Array(N*3);
58
- for(let i=0;i<N;i++){ const r=1400+Math.random()*1600, t=Math.random()*Math.PI*2, p=Math.acos(2*Math.random()-1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  pos[i*3]=r*Math.sin(p)*Math.cos(t); pos[i*3+1]=r*Math.cos(p); pos[i*3+2]=r*Math.sin(p)*Math.sin(t); }
60
  const g=new THREE.BufferGeometry(); g.setAttribute('position', new THREE.BufferAttribute(pos,3));
61
- scene.add(new THREE.Points(g, new THREE.PointsMaterial({ color:0x8a90c0, size:1.4, sizeAttenuation:true, transparent:true, opacity:0.55 })));
62
- })();
63
-
64
- const interactables=[];
65
- function registerBody(mesh,data){ mesh.userData.inspect=data; interactables.push(mesh); }
66
-
67
- const sunGroup=new THREE.Group(); scene.add(sunGroup);
68
- const sunCore=new THREE.Mesh(new THREE.IcosahedronGeometry(36,4),
69
- new THREE.MeshStandardMaterial({ color:0xffce6e, emissive:0xd79a2e, emissiveIntensity:1.5, roughness:0.35, metalness:0.1 }));
70
- sunGroup.add(sunCore); registerBody(sunCore, A11OY);
71
- const sunGlow=new THREE.Mesh(new THREE.SphereGeometry(50,32,32),
72
- new THREE.MeshBasicMaterial({ color:0xffd98a, transparent:true, opacity:0.10, side:THREE.BackSide }));
73
- sunGroup.add(sunGlow);
74
- const brainLattice=new THREE.Mesh(new THREE.IcosahedronGeometry(42,2),
75
- new THREE.MeshBasicMaterial({ color:0xffe6a8, wireframe:true, transparent:true, opacity:0.22 }));
76
- sunGroup.add(brainLattice);
77
- sunGroup.add(makeLabel('a11oy', 0xffe6a8, 66));
78
-
79
- const ORBIT_R=150; const capBodies=[];
80
- CAPABILITIES.forEach((cap)=>{
81
- const grp=new THREE.Group();
82
- const mesh=new THREE.Mesh(new THREE.IcosahedronGeometry(15,2),
83
- new THREE.MeshStandardMaterial({ color:cap.color, emissive:cap.color, emissiveIntensity:0.55, roughness:0.5, metalness:0.2 }));
84
- grp.add(mesh);
85
- const ring=new THREE.Mesh(new THREE.TorusGeometry(22,0.7,8,64), new THREE.MeshBasicMaterial({ color:cap.color, transparent:true, opacity:0.35 }));
86
- ring.rotation.x=Math.PI/2; grp.add(ring);
87
- grp.add(makeLabel(cap.title.split(/[ &·]/)[0], cap.color, 30));
88
- scene.add(grp); registerBody(mesh, cap);
89
- const tether=new THREE.Line(new THREE.BufferGeometry().setFromPoints([new THREE.Vector3(),new THREE.Vector3()]),
90
- new THREE.LineBasicMaterial({ color:cap.color, transparent:true, opacity:0.28 }));
91
- scene.add(tether);
92
- capBodies.push({ grp, mesh, cap, baseAngle:cap.angle, tether });
93
- });
94
-
95
- function makeLabel(text,color,size){
96
- const c=document.createElement('canvas'); c.width=256; c.height=64; const ctx=c.getContext('2d');
97
- ctx.font='700 34px ui-monospace, Menlo, Consolas, monospace';
98
- ctx.fillStyle='#'+new THREE.Color(color).getHexString();
99
- ctx.textAlign='center'; ctx.textBaseline='middle'; ctx.shadowColor='rgba(0,0,0,0.8)'; ctx.shadowBlur=8;
100
- ctx.fillText(text,128,34);
101
- const tex=new THREE.CanvasTexture(c); tex.anisotropy=4;
102
- const spr=new THREE.Sprite(new THREE.SpriteMaterial({ map:tex, transparent:true, depthWrite:false }));
103
- spr.scale.set(size*2,size*0.5,1); spr.position.y=size*0.9; spr.userData.isLabel=true; return spr;
104
  }
 
 
 
105
 
106
- const ray=new THREE.Raycaster(); const ptr=new THREE.Vector2();
107
- canvas.addEventListener('click',(e)=>{
108
- const r=canvas.getBoundingClientRect();
109
- ptr.x=((e.clientX-r.left)/r.width)*2-1; ptr.y=-((e.clientY-r.top)/r.height)*2+1;
110
- ray.setFromCamera(ptr,camera);
111
- const hits=ray.intersectObjects(interactables,false);
112
- if(hits.length) openInspector(hits[0].object.userData.inspect);
113
- });
114
 
115
- const insp=document.getElementById('inspector');
116
- document.getElementById('insp-close').addEventListener('click',()=>insp.classList.remove('show'));
117
- function openInspector(d){
118
- if(!d) return;
119
- document.getElementById('insp-title').textContent=d.title;
120
- document.getElementById('insp-plain').textContent=d.plain;
121
- let html='<div class="ih">Functions</div><ul>'+d.functions.map(f=>`<li>${esc(f)}</li>`).join('')+'</ul>';
122
- if(d.proof) html+='<div class="ih">Proof support (honest)</div><ul>'+d.proof.map(p=>`<li class="proof">${esc(p)}</li>`).join('')+'</ul>';
123
- if(d.url) html+=`<div class="ih">Open</div><ul><li><a href="${d.url}" style="color:#5cc4bf">Enter the working app ↗</a></li></ul>`;
124
- document.getElementById('insp-body').innerHTML=html; insp.classList.add('show');
125
- }
126
- function esc(s){ return String(s).replace(/[&<>"]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c])); }
127
 
128
- let liveState={ a11oy:'…' }, feedSource='connecting…', liveLambda=null;
129
- async function getJSON(url,ms){
130
- const ctrl=new AbortController(); const t=setTimeout(()=>ctrl.abort(), ms||7000);
131
- try{ const r=await fetch(url,{ signal:ctrl.signal, headers:{accept:'application/json'} }); if(!r.ok) throw 0; return await r.json(); }
132
- finally{ clearTimeout(t); }
 
 
 
 
 
 
 
133
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  async function poll(){
135
- try{ const h=await getJSON(ENDPOINTS.health,7000); liveState.a11oy=(h&&(h.status==='ok'||h.ok))?'LIVE':'DEGRADED'; }
136
- catch(_){ liveState.a11oy='OFFLINE'; }
137
- try{ const lam=await getJSON(ENDPOINTS.lambda,7000); if(lam&&typeof lam.lambda==='number'){ liveLambda=lam.lambda; feedSource='LIVE a11oy Λ='+lam.lambda.toFixed(3)+' (13-axis Trust Score)'; } }
138
- catch(_){ if(liveLambda===null) feedSource='Λ feed reconnecting…'; }
139
- paintHUD();
140
  }
141
- function paintHUD(){
142
- const cls=liveState.a11oy==='LIVE'?'live':(liveState.a11oy==='OFFLINE'?'off':'seed');
143
- let rows=`<div class="row"><span class="dot ${cls}"></span><span>a11oy · brain</span><span class="meta">${liveState.a11oy}</span></div>`;
144
- if(liveLambda!==null){ const v=liveLambda>=0.9?'green':(liveLambda>=0.5?'amber':'red'); const col=v==='green'?'#4fd18b':(v==='amber'?'#d7b96b':'#c0392b');
145
- rows+=`<div class="row"><span class="dot" style="background:${col};box-shadow:0 0 9px ${col}"></span><span>Trust Score Λ</span><span class="meta">${liveLambda.toFixed(3)}</span></div>`; }
146
- document.getElementById('status-rows').innerHTML=rows;
147
- document.getElementById('feed-src').textContent=feedSource;
148
  }
 
 
 
 
 
 
 
 
149
 
150
- let tms=0;
 
 
 
 
 
151
  function animate(){
152
- requestAnimationFrame(animate); tms+=0.004;
153
- sunCore.rotation.y+=0.0015; brainLattice.rotation.y-=0.0011; brainLattice.rotation.x+=0.0006;
154
- sunGlow.material.opacity=0.08+0.04*Math.sin(tms*2);
155
- capBodies.forEach((cb,i)=>{ const a=cb.baseAngle+tms*0.6; const x=Math.cos(a)*ORBIT_R, z=Math.sin(a)*ORBIT_R, y=Math.sin(a*1.3+i)*22;
156
- cb.grp.position.set(x,y,z); cb.mesh.rotation.y+=0.01;
157
- cb.tether.geometry.setFromPoints([new THREE.Vector3(0,0,0), new THREE.Vector3(x,y,z)]); cb.tether.geometry.attributes.position.needsUpdate=true; });
158
- controls.update(); renderer.render(scene,camera);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  }
160
- window.addEventListener('resize',()=>{ camera.aspect=window.innerWidth/window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth,window.innerHeight); });
161
- paintHUD(); animate();
162
- (function(){ var b=document.getElementById('boot'); b.classList.add('hide');
163
- b.addEventListener('transitionend', function(){ b.style.display='none'; });
164
- setTimeout(function(){ b.style.display='none'; }, 1200); })();
165
- poll(); setInterval(poll, 8000);
166
- controls.addEventListener('start',()=>{ controls.autoRotate=false; });
 
 
 
 
 
 
 
 
 
 
1
  /* ============================================================================
2
+ * a11oy_cathedral.js — "The Sovereign Lattice" front-door hero (vendored Three.js).
3
+ * A luminous gold lattice-core (a11oy) with three governed faculties orbiting it,
4
+ * in deep sovereign space. Cinematic: layered additive bloom, multi-depth starfield,
5
+ * faint nebula, pointer parallax, scroll-driven camera. Live /healthz + Λ.
6
+ * Honesty: locked proven = 5; Λ = Conjecture 1. No fakery; honest fallback.
7
  * Signed-off-by: Stephen P. Lutar Jr. <stephenlutar2@gmail.com>
8
  * ========================================================================== */
9
  import * as THREE from 'three';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
+ const REDUCED = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
12
  const canvas = document.getElementById('scene');
13
+ const renderer = new THREE.WebGLRenderer({ canvas, antialias:true, alpha:false, powerPreference:'high-performance' });
14
+ renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.9));
15
+ renderer.setSize(innerWidth, innerHeight);
16
+ renderer.toneMapping = THREE.ACESFilmicToneMapping;
17
+ renderer.toneMappingExposure = 1.18;
18
 
19
  const scene = new THREE.Scene();
20
+ scene.fog = new THREE.FogExp2(0x05060f, 0.0016);
21
+ const camera = new THREE.PerspectiveCamera(46, innerWidth/innerHeight, 0.1, 6000);
22
+
23
+ // composition: core sits on the right; hero text breathes on the left
24
+ const HOME = new THREE.Vector3(46, 16, 250);
25
+ const LOOK = new THREE.Vector3(64, 6, 0);
26
+ camera.position.copy(HOME);
27
+
28
+ scene.add(new THREE.AmbientLight(0x2a2942, 0.85));
29
+ const keyLight = new THREE.PointLight(0xffe2a0, 2.7, 2200, 1.5); keyLight.position.set(70, 30, 40); scene.add(keyLight);
30
+ const rim = new THREE.DirectionalLight(0x6d8fd6, 0.55); rim.position.set(-220, 120, -120); scene.add(rim);
31
+ const fill = new THREE.DirectionalLight(0x7fd6d1, 0.18); fill.position.set(120, -80, 120); scene.add(fill);
32
+
33
+ /* ---- faint nebula: large additive gradient sprites ---- */
34
+ function radialSprite(c1, c2, sz, op){
35
+ const cv=document.createElement('canvas'); cv.width=cv.height=256; const g=cv.getContext('2d');
36
+ const grd=g.createRadialGradient(128,128,0,128,128,128);
37
+ grd.addColorStop(0,c1); grd.addColorStop(0.45,c2); grd.addColorStop(1,'rgba(0,0,0,0)');
38
+ g.fillStyle=grd; g.fillRect(0,0,256,256);
39
+ const tex=new THREE.CanvasTexture(cv);
40
+ const s=new THREE.Sprite(new THREE.SpriteMaterial({ map:tex, transparent:true, opacity:op, blending:THREE.AdditiveBlending, depthWrite:false }));
41
+ s.scale.set(sz,sz,1); return s;
42
+ }
43
+ const neb1=radialSprite('rgba(215,185,107,0.5)','rgba(120,90,30,0.18)',1500,0.5); neb1.position.set(160,40,-500); scene.add(neb1);
44
+ const neb2=radialSprite('rgba(60,80,150,0.5)','rgba(30,40,90,0.16)',1900,0.45); neb2.position.set(-380,-120,-820); scene.add(neb2);
45
+ const neb3=radialSprite('rgba(127,214,209,0.32)','rgba(20,90,90,0.1)',1000,0.4); neb3.position.set(-180,180,-360); scene.add(neb3);
46
+
47
+ /* ---- multi-depth starfield ---- */
48
+ function starLayer(n, rMin, rMax, size, col, op){
49
+ const pos=new Float32Array(n*3);
50
+ for(let i=0;i<n;i++){ const r=rMin+Math.random()*(rMax-rMin), t=Math.random()*Math.PI*2, p=Math.acos(2*Math.random()-1);
51
  pos[i*3]=r*Math.sin(p)*Math.cos(t); pos[i*3+1]=r*Math.cos(p); pos[i*3+2]=r*Math.sin(p)*Math.sin(t); }
52
  const g=new THREE.BufferGeometry(); g.setAttribute('position', new THREE.BufferAttribute(pos,3));
53
+ const pts=new THREE.Points(g, new THREE.PointsMaterial({ color:col, size, sizeAttenuation:true, transparent:true, opacity:op, depthWrite:false }));
54
+ scene.add(pts); return pts;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  }
56
+ const stars1=starLayer(1700, 700, 1500, 1.1, 0x9aa0d0, 0.55);
57
+ const stars2=starLayer(1100, 1400, 2800, 2.2, 0xcdbb8e, 0.5);
58
+ const stars3=starLayer(500, 380, 900, 1.5, 0x7fd6d1, 0.32);
59
 
60
+ /* ---- the sovereign lattice-core (a11oy) ---- */
61
+ const core=new THREE.Group(); core.position.copy(LOOK); scene.add(core);
 
 
 
 
 
 
62
 
63
+ const coreMesh=new THREE.Mesh(new THREE.IcosahedronGeometry(34,5),
64
+ new THREE.MeshStandardMaterial({ color:0xffcf73, emissive:0xe0a536, emissiveIntensity:1.55, roughness:0.34, metalness:0.12, flatShading:true }));
65
+ core.add(coreMesh);
 
 
 
 
 
 
 
 
 
66
 
67
+ const latticeA=new THREE.Mesh(new THREE.IcosahedronGeometry(44,2),
68
+ new THREE.MeshBasicMaterial({ color:0xffe6a8, wireframe:true, transparent:true, opacity:0.26 }));
69
+ core.add(latticeA);
70
+ const latticeB=new THREE.Mesh(new THREE.IcosahedronGeometry(56,1),
71
+ new THREE.MeshBasicMaterial({ color:0xd7b96b, wireframe:true, transparent:true, opacity:0.12 }));
72
+ core.add(latticeB);
73
+
74
+ // layered additive bloom halos
75
+ for(const [r,o] of [[64,0.16],[92,0.09],[140,0.05]]){
76
+ const h=new THREE.Mesh(new THREE.SphereGeometry(r,32,32),
77
+ new THREE.MeshBasicMaterial({ color:0xffd98a, transparent:true, opacity:o, side:THREE.BackSide, blending:THREE.AdditiveBlending, depthWrite:false }));
78
+ core.add(h);
79
  }
80
+ const flare=radialSprite('rgba(255,222,150,0.95)','rgba(224,165,54,0.35)',360,0.9); core.add(flare);
81
+
82
+ // inner sparks orbiting inside the core
83
+ const sparkN=80, sparkPos=new Float32Array(sparkN*3), sparkSeed=[];
84
+ for(let i=0;i<sparkN;i++){ sparkSeed.push({a:Math.random()*Math.PI*2,b:Math.random()*Math.PI,r:20+Math.random()*22,s:0.4+Math.random()}); }
85
+ const sparkGeo=new THREE.BufferGeometry(); sparkGeo.setAttribute('position',new THREE.BufferAttribute(sparkPos,3));
86
+ core.add(new THREE.Points(sparkGeo, new THREE.PointsMaterial({ color:0xfff0c8, size:1.7, transparent:true, opacity:0.85, blending:THREE.AdditiveBlending, depthWrite:false })));
87
+
88
+ /* ---- three orbiting faculties ---- */
89
+ const FAC=[
90
+ {color:0x7fd6d1, angle:0.2, rx:120, rz:120, tilt:0.12},
91
+ {color:0xd7b96b, angle:2.25, rx:138, rz:128, tilt:-0.22},
92
+ {color:0xe58e54, angle:4.2, rx:128, rz:140, tilt:0.30},
93
+ ];
94
+ const facBodies=[];
95
+ FAC.forEach((f)=>{
96
+ const g=new THREE.Group();
97
+ const m=new THREE.Mesh(new THREE.IcosahedronGeometry(11,2),
98
+ new THREE.MeshStandardMaterial({ color:f.color, emissive:f.color, emissiveIntensity:0.7, roughness:0.45, metalness:0.25 }));
99
+ g.add(m);
100
+ const ring=new THREE.Mesh(new THREE.TorusGeometry(17,0.5,8,72),
101
+ new THREE.MeshBasicMaterial({ color:f.color, transparent:true, opacity:0.4 })); ring.rotation.x=Math.PI/2; g.add(ring);
102
+ g.add(radialSprite(`rgba(${(f.color>>16)&255},${(f.color>>8)&255},${f.color&255},0.8)`,'rgba(0,0,0,0)',70,0.7));
103
+ scene.add(g);
104
+ // curved tether (core -> faculty) as a tube we rebuild each frame
105
+ const tetherMat=new THREE.MeshBasicMaterial({ color:f.color, transparent:true, opacity:0.16, blending:THREE.AdditiveBlending, depthWrite:false });
106
+ let tetherMesh=null;
107
+ facBodies.push({ f, g, m, tetherMat, get tether(){return tetherMesh;}, set tether(v){tetherMesh=v;} });
108
+ });
109
+
110
+ /* ---- live mesh: /healthz + Λ ---- */
111
+ const lamDot=document.getElementById('lam-dot'), lamText=document.getElementById('lam-text');
112
+ async function getJSON(url,ms){ const c=new AbortController(); const t=setTimeout(()=>c.abort(),ms||7000);
113
+ try{ const r=await fetch(url,{signal:c.signal,headers:{accept:'application/json'}}); if(!r.ok) throw 0; return await r.json(); } finally{ clearTimeout(t); } }
114
+ let lambda=null, alive=false;
115
  async function poll(){
116
+ try{ const h=await getJSON('/healthz',7000); alive=!!(h&&(h.status==='ok'||h.ok)); }catch(_){ alive=false; }
117
+ try{ const l=await getJSON('/api/a11oy/v1/lambda',7000); if(l&&typeof l.lambda==='number') lambda=l.lambda; }catch(_){}
118
+ paint();
 
 
119
  }
120
+ function paint(){
121
+ if(!lamDot) return;
122
+ if(alive){ lamDot.classList.add('live'); }else{ lamDot.classList.remove('live'); }
123
+ if(lambda!==null) lamText.innerHTML = `<b>Λ ${lambda.toFixed(3)}</b> · live trust score · 13-axis`;
124
+ else lamText.textContent = alive ? 'mesh live · Λ reconnecting…' : 'live mesh offline · honest fallback';
 
 
125
  }
126
+ paint(); poll(); setInterval(poll, 8000);
127
+
128
+ /* ---- pointer parallax + scroll ---- */
129
+ let px=0, py=0, tpx=0, tpy=0;
130
+ if(!REDUCED) addEventListener('pointermove',(e)=>{ tpx=(e.clientX/innerWidth-0.5); tpy=(e.clientY/innerHeight-0.5); }, {passive:true});
131
+ let scrollP=0;
132
+ function onScroll(){ const max=document.body.scrollHeight-innerHeight; scrollP = max>0 ? Math.min(1, scrollY/max) : 0; }
133
+ addEventListener('scroll', onScroll, {passive:true}); onScroll();
134
 
135
+ /* ---- intro dolly ---- */
136
+ let intro=REDUCED?1:0;
137
+
138
+ const _v=new THREE.Vector3();
139
+ const _look=new THREE.Vector3();
140
+ let t=0;
141
  function animate(){
142
+ requestAnimationFrame(animate);
143
+ t+=0.0045;
144
+ if(intro<1){ intro=Math.min(1, intro+0.012); }
145
+ const e=intro<1 ? 1-Math.pow(1-intro,3) : 1; // easeOutCubic
146
+
147
+ // core motion
148
+ coreMesh.rotation.y+=0.0016; coreMesh.rotation.x+=0.0005;
149
+ latticeA.rotation.y-=0.0012; latticeA.rotation.x+=0.0007;
150
+ latticeB.rotation.y+=0.0009; latticeB.rotation.z-=0.0006;
151
+ const pulse=1+0.012*Math.sin(t*2.0); core.scale.setScalar(pulse);
152
+ flare.material.opacity=0.78+0.12*Math.sin(t*1.7);
153
+
154
+ // inner sparks
155
+ for(let i=0;i<sparkN;i++){ const s=sparkSeed[i]; const a=s.a+t*s.s; const b=s.b+t*0.3*s.s; const r=s.r;
156
+ sparkPos[i*3]=r*Math.sin(b)*Math.cos(a); sparkPos[i*3+1]=r*Math.cos(b); sparkPos[i*3+2]=r*Math.sin(b)*Math.sin(a); }
157
+ sparkGeo.attributes.position.needsUpdate=true;
158
+
159
+ // faculties orbit + curved tethers
160
+ facBodies.forEach((fb,i)=>{
161
+ const f=fb.f; const a=f.angle + t*0.22*(i%2?-1:1);
162
+ const x=LOOK.x+Math.cos(a)*f.rx;
163
+ const z=LOOK.z+Math.sin(a)*f.rz;
164
+ const y=LOOK.y+Math.sin(a*1.4+i)*26 + f.tilt*40*Math.cos(a*0.7);
165
+ fb.g.position.set(x,y,z); fb.m.rotation.y+=0.012;
166
+ const mid=new THREE.Vector3((LOOK.x+x)/2,(LOOK.y+y)/2+24,(LOOK.z+z)/2);
167
+ const curve=new THREE.QuadraticBezierCurve3(new THREE.Vector3(LOOK.x,LOOK.y,LOOK.z), mid, new THREE.Vector3(x,y,z));
168
+ if(fb.tether){ fb.tether.geometry.dispose(); core.parent.remove(fb.tether); }
169
+ fb.tether=new THREE.Mesh(new THREE.TubeGeometry(curve,20,0.45,6,false), fb.tetherMat); scene.add(fb.tether);
170
+ });
171
+
172
+ // starfield drift
173
+ stars1.rotation.y+=0.00012; stars2.rotation.y-=0.00007; stars3.rotation.y+=0.0002;
174
+
175
+ // camera: parallax + gentle idle + scroll framing.
176
+ // We aim LEFT of the core so it sits in the right third (text breathes on the
177
+ // left). As you scroll we push the core toward the right edge (no zoom-in that
178
+ // would swamp the headlines) and pull back slightly so it reads as an accent.
179
+ px+=(tpx-px)*0.04; py+=(tpy-py)*0.04;
180
+ const frameX = 60 + 84*scrollP; // aim offset: larger -> core further right
181
+ const frameY = 4 + 14*scrollP;
182
+ const camHome=HOME.clone();
183
+ camHome.y += 24*scrollP; // gentle lift
184
+ camHome.z += 30*scrollP; // pull back (core smaller) instead of zoom-in
185
+ camHome.x += 14*scrollP;
186
+ const idleX=Math.sin(t*0.5)*5, idleY=Math.cos(t*0.4)*4;
187
+ _v.set(camHome.x + px*32 + idleX, camHome.y - py*22 + idleY, camHome.z);
188
+ camera.position.lerp(_v, e<1?0.06*e+0.02:0.06);
189
+ const look=_look.set(LOOK.x - frameX + px*12, LOOK.y + frameY - py*6, LOOK.z);
190
+ camera.lookAt(look);
191
+ renderer.toneMappingExposure = 1.2 - 0.16*scrollP;
192
+
193
+ renderer.render(scene,camera);
194
+ if(!_shown){ _shown=true; requestAnimationFrame(()=>canvas.classList.add('on')); }
195
  }
196
+ let _shown=false;
197
+ animate();
198
+
199
+ addEventListener('resize',()=>{ camera.aspect=innerWidth/innerHeight; camera.updateProjectionMatrix(); renderer.setSize(innerWidth,innerHeight); });
200
+
201
+ /* ---- nav stuck + scroll reveals + boot ---- */
202
+ const nav=document.getElementById('nav');
203
+ function navState(){ if(scrollY>24) nav.classList.add('stuck'); else nav.classList.remove('stuck'); }
204
+ addEventListener('scroll', navState, {passive:true}); navState();
205
+
206
+ const io=new IntersectionObserver((es)=>{ es.forEach(en=>{ if(en.isIntersecting){ en.target.classList.add('in'); io.unobserve(en.target); } }); }, {threshold:0.16});
207
+ document.querySelectorAll('.reveal').forEach((el,i)=>{ el.style.transitionDelay=(Math.min(i,6)*70)+'ms'; io.observe(el); });
208
+
209
+ /* boot overlay removed: editorial hero paints instantly; the 3D canvas fades in
210
+ on its first rendered frame (see #scene.on). Safety net if WebGL never starts: */
211
+ setTimeout(()=>canvas.classList.add('on'), 1800);