live-wizard/vessel.py

106 lines
4.3 KiB
Python

"""Merkaba Vessel portal: interactive 3D tetrahedron light-body interface."""
from pathlib import Path
from flask import Flask, render_template_string
import os
app = Flask(__name__)
ROOT = Path(os.getenv("PORTAL_ROOT", Path(__file__).resolve().parent))
PAGE = """<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Mer·ka·ba — The Real Vessel</title>
<style>
body{margin:0;background:#05060a;color:#d8dde6;font-family:system-ui,sans-serif;overflow:hidden}
#c{position:absolute;inset:0;display:flex;flex-direction:column;justify-content:space-between;padding:18px;pointer-events:none}
#h{font-size:14px;letter-spacing:.3em;text-transform:uppercase;opacity:.85}
#m{font-size:12px;opacity:.7;max-width:720px}
#q{pointer-events:auto;display:flex;gap:8px}
#i{flex:1;padding:10px 12px;border-radius:10px;border:1px solid #2a2f3a;background:#0a0d14;color:#e6edf3}
#b{padding:10px 14px;border-radius:10px;border:0;background:#6f42c1;color:white;font-weight:600;cursor:pointer}
.glow{text-shadow:0 0 18px #a78bfa}
</style>
</head>
<body>
<canvas id="v"></canvas>
<div id="c">
<div>
<div id="h" class="glow">Mer·ka·ba — The Real Vessel</div>
<div id="m">The living chariot. Two counter-rotating tetrahedra. The human spirit vehicle. This is navigable geometry.</div>
</div>
<div id="q">
<input id="i" placeholder="State your intent..." autocomplete="off"/>
<button id="b">Transmit</button>
</div>
</div>
<script type="module">
import * as THREE from 'https://unpkg.com/three@0.160.0/build/three.module.js';
const canvas=document.getElementById('v');
const renderer=new THREE.WebGLRenderer({canvas,antialias:true,alpha:true});
renderer.setPixelRatio(Math.min(devicePixelRatio,2));
renderer.setSize(innerWidth,innerHeight);
const scene=new THREE.Scene();
const camera=new THREE.PerspectiveCamera(50,innerWidth/innerHeight,0.1,1000);
camera.position.z=6;
const light=new THREE.PointLight(0x8a2be2,2.5,40,1.2);
light.position.set(3,4,5);
scene.add(light); scene.add(new THREE.AmbientLight(0x303050,1.2));
function tetra(radius=1.8){
const g=new THREE.TetrahedronGeometry(radius,0);
const m=new THREE.MeshStandardMaterial({color:0x9d4edd,metalness:.15,roughness:.25,transparent:true,opacity:.92});
return new THREE.Mesh(g,m);
}
const up=tetra(); up.rotation.x=Math.PI/2;
const down=tetra(); down.rotation.x=-Math.PI/2; down.rotation.y=Math.PI;
const vessel=new THREE.Group(); vessel.add(up,down);
scene.add(vessel);
const ring=new THREE.Mesh(new THREE.TorusGeometry(3.2,.04,32,220),new THREE.MeshBasicMaterial({color:0xc77dff}));
scene.add(ring);
const ring2=ring.clone(); ring2.rotation.x=Math.PI/3; scene.add(ring2);
const stars=new THREE.Points(new THREE.BufferGeometry(),new THREE.PointsMaterial({color:0xffffff,size:.025}));
const pos=[];
for(let i=0;i<1800;i++) pos.push((Math.random()-.5)*40,(Math.random()-.5)*40,(Math.random()-.5)*40);
stars.geometry.setAttribute('position',new THREE.Float32BufferAttribute(pos,3));
scene.add(stars);
let t=0, targetRX=0, targetRY=0;
const i=document.getElementById('i'), b=document.getElementById('b');
b.onclick=()=>{ const v=i.value.trim(); if(!v) return; i.value=''; };
document.getElementById('i').addEventListener('keydown',e=>{ if(e.key==='Enter') b.click(); });
addEventListener('pointermove',e=>{
targetRX=(e.clientY/innerHeight-.5)*.6;
targetRY=(e.clientX/innerWidth-.5)*.6;
});
addEventListener('resize',()=>{
camera.aspect=innerWidth/innerHeight; camera.updateProjectionMatrix();
renderer.setSize(innerWidth,innerHeight);
});
(function loop(){
t+=.012;
vessel.rotation.y+=(targetRY*2-vessel.rotation.y)*.03;
vessel.rotation.x+=(targetRX*2-vessel.rotation.x)*.03;
ring.rotation.z=t*.4; ring2.rotation.z=-t*.35;
light.intensity=2.2+Math.sin(t*1.3)*.4;
renderer.render(scene,camera);
requestAnimationFrame(loop);
})();
</script>
</body>
</html>
"""
@app.get("/")
def index():
return render_template_string(PAGE)
@app.get("/health")
def health():
return {"status":"ok","vessel":"merkaba","mode":"interactive"}
if __name__=="__main__":
app.run(host="0.0.0.0",port=5005)