vessel: add merkaba live portal + caddy /vessel route
This commit is contained in:
parent
a9000e8d4b
commit
65bc70d7f7
105
vessel.py
Normal file
105
vessel.py
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
"""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)
|
||||
Loading…
Reference in New Issue
Block a user