Research-Stack/6-Documentation/docs/semantics/obelisk_manifold.html
2026-05-05 21:09:48 -05:00

301 lines
11 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PIST Obelisk Manifold — Composite Coordinate Viewer</title>
<style>
body {
margin: 0;
overflow: hidden;
background-color: #050505;
font-family: 'Courier New', monospace;
}
canvas { display: block; }
#ui {
position: absolute;
top: 20px;
left: 20px;
color: #00ffcc;
pointer-events: none;
text-shadow: 0 0 8px rgba(0, 255, 204, 0.8);
}
h1 { margin: 0 0 5px 0; font-size: 1.1rem; letter-spacing: 2px; }
p { margin: 0; font-size: 0.85rem; opacity: 0.8; }
#coord-panel {
position: absolute;
top: 20px;
right: 20px;
color: #ffaa44;
pointer-events: none;
text-align: right;
text-shadow: 0 0 8px rgba(255, 170, 68, 0.6);
font-size: 0.8rem;
line-height: 1.6;
}
#coord-panel span { color: #00ffcc; }
#legend {
position: absolute;
bottom: 20px;
left: 20px;
color: #888;
font-size: 0.75rem;
pointer-events: none;
}
.legend-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 6px; }
</style>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.160.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/"
}
}
</script>
</head>
<body>
<div id="ui">
<h1>OBLISK MANIFOLD: ACTIVE</h1>
<p>Nodes Mapped: <span id="nodeCount">0</span> / 2000</p>
<p>Current Shell: <span id="shellDisplay">k=0</span></p>
</div>
<div id="coord-panel">
<div>n = <span id="n-val">0</span></div>
<div>k = <span id="k-val">0</span>, t = <span id="t-val">0</span></div>
<div>mass = <span id="m-val">0</span></div>
<div style="margin-top:8px; color:#666; font-size:0.7rem;">
tree:<br><span id="tree-val">[]</span><br>
surface: <span id="surf-val">x=0.00 y=0.00</span><br>
torus: <span id="torus-val">θ=0.00 φ=0.00</span>
</div>
</div>
<div id="legend">
<div><span class="legend-dot" style="background:#00ffcc"></span> tree address (base-20 path)</div>
<div><span class="legend-dot" style="background:#ff6644"></span> surface coordinate (1/x curve)</div>
<div><span class="legend-dot" style="background:#4488ff"></span> torus angle (Φ-irrational rotation)</div>
<div><span class="legend-dot" style="background:#ffaa00"></span> PIST shell position (k, t)</div>
</div>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// ── PIST Coordinate Primitives ──
const PHI = (1 + Math.sqrt(5)) / 2;
function pistK(n) { return Math.floor(Math.sqrt(n)); }
function pistT(n) { return n - pistK(n) * pistK(n); }
function pistMass(k, t) {
if (k === 0) return 0;
const tf = Math.min(t, 2 * k + 1 - t);
return tf * (2 * k + 1 - tf);
}
function treeAddress(n, depth) {
const path = [];
let rem = n;
for (let level = 0; level < depth; level++) {
path.push({ level, branch: rem % 20 });
rem = Math.floor(rem / 20);
}
return path;
}
function surfaceCoord(n) {
const x = 1.0 + (n % 255) * (255.0 / 255.0);
return { x: x, y: 1.0 / x, theta: (n * PHI) % (2 * Math.PI) };
}
function torusAngles(n) {
return {
theta: (n * PHI) % (2 * Math.PI),
phi: (n * PHI * PHI) % (2 * Math.PI),
psi: (n * PHI * PHI * PHI) % (2 * Math.PI)
};
}
// ── Scene ──
const scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0x050505, 0.025);
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 6, 22);
const renderer = new THREE.WebGLRenderer({ antialias: true, powerPreference: "high-performance" });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.autoRotate = false;
// ── The Obelisk (Torus Knot p=3, q=7) ──
const radius = 3.5, tube = 1.0;
const tubularSegments = 400, radialSegments = 64;
const p = 3, q = 7;
const obeliskGeo = new THREE.TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q);
const obeliskMat = new THREE.MeshBasicMaterial({
color: 0x2a2a2a,
wireframe: true,
transparent: true,
opacity: 0.25
});
const obelisk = new THREE.Mesh(obeliskGeo, obeliskMat);
obelisk.scale.set(1, 2.2, 1);
scene.add(obelisk);
const nodeGroup = new THREE.Group();
obelisk.add(nodeGroup);
// ── Node Mapping: Real PIST Coordinates ──
const vertices = obeliskGeo.attributes.position.array;
const vertexCount = vertices.length / 3;
let mappedNodes = 0;
const maxNodes = 2000;
const mappedIndices = new Set();
const nodeCounterUI = document.getElementById('nodeCount');
const shellDisplay = document.getElementById('shellDisplay');
// Color by coordinate type
function nodeColor(n) {
const mod = n % 4;
if (mod === 0) return 0x00ffcc; // tree: cyan
if (mod === 1) return 0xff6644; // surface: orange-red
if (mod === 2) return 0x4488ff; // torus: blue
return 0xffaa00; // shell: amber
}
function mapNode() {
if (mappedNodes >= maxNodes) return;
// Pick an unmapped vertex index
let idx;
let attempts = 0;
do {
idx = Math.floor(Math.random() * vertexCount);
attempts++;
} while (mappedIndices.has(idx) && attempts < 50);
if (mappedIndices.has(idx)) return;
mappedIndices.add(idx);
const vi = idx * 3;
const x = vertices[vi];
const y = vertices[vi + 1];
const z = vertices[vi + 2];
// Compute real PIST coordinates for this node index
const k = pistK(mappedNodes);
const t = pistT(mappedNodes);
const mass = pistMass(k, t);
const tree = treeAddress(mappedNodes, 3);
const surf = surfaceCoord(mappedNodes);
const torus = torusAngles(mappedNodes);
const color = nodeColor(mappedNodes);
const size = 0.04 + (mass / 5000) * 0.08; // mass = bigger
const nodeGeo = new THREE.SphereGeometry(size, 8, 8);
const nodeMat = new THREE.MeshBasicMaterial({ color });
const node = new THREE.Mesh(nodeGeo, nodeMat);
node.position.set(x, y, z);
// Store PIST data on the mesh for hover/click
node.userData = { n: mappedNodes, k, t, mass, tree, surf, torus };
nodeGroup.add(node);
mappedNodes++;
nodeCounterUI.innerText = mappedNodes;
shellDisplay.innerText = `k=${k}, t=${t}, mass=${mass}`;
}
const intervalId = setInterval(mapNode, 30);
// ── Active Indicator (follows current n) ──
const activeGeo = new THREE.SphereGeometry(0.25, 16, 16);
const activeMat = new THREE.MeshBasicMaterial({
color: 0xffffff, transparent: true, opacity: 0.9
});
const activeMesh = new THREE.Mesh(activeGeo, activeMat);
scene.add(activeMesh);
activeMesh.visible = false;
// ── Raycaster for hover ──
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
function onMouseMove(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
window.addEventListener('mousemove', onMouseMove, false);
// ── UI update ──
const uiN = document.getElementById('n-val');
const uiK = document.getElementById('k-val');
const uiT = document.getElementById('t-val');
const uiM = document.getElementById('m-val');
const uiTree = document.getElementById('tree-val');
const uiSurf = document.getElementById('surf-val');
const uiTorus = document.getElementById('torus-val');
function updateUIPanel(data) {
uiN.textContent = data.n;
uiK.textContent = data.k;
uiT.textContent = data.t;
uiM.textContent = data.mass;
uiTree.textContent = JSON.stringify(data.tree.map(n => n.branch));
uiSurf.textContent = `x=${data.surf.x.toFixed(2)} y=${data.surf.y.toFixed(4)}`;
uiTorus.textContent = `θ=${data.torus.theta.toFixed(2)} φ=${data.torus.phi.toFixed(2)}`;
}
// ── Animation ──
const clock = new THREE.Clock();
let currentN = 0;
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
obelisk.rotation.y += 0.15 * delta;
// Cycle active indicator through mapped nodes
if (mappedNodes > 0) {
currentN = (currentN + 1) % mappedNodes;
const children = nodeGroup.children;
if (children[currentN]) {
const pos = children[currentN].position.clone();
pos.applyMatrix4(obelisk.matrixWorld);
activeMesh.position.copy(pos);
activeMesh.visible = true;
updateUIPanel(children[currentN].userData);
}
}
// Raycaster hover
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(nodeGroup.children);
if (intersects.length > 0) {
const hit = intersects[0].object;
if (hit.userData && hit.userData.n !== undefined) {
updateUIPanel(hit.userData);
activeMesh.position.copy(hit.position.clone().applyMatrix4(obelisk.matrixWorld));
}
}
controls.update();
renderer.render(scene, camera);
}
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
animate();
</script>
</body>
</html>