VALIS / index.html
Wayfinder6's picture
Upload folder using huggingface_hub
c55ab16 verified
Raw
History Blame Contribute Delete
11.7 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VALIS Node</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #0a0a12;
color: #e0e0e0;
font-family: 'Courier New', monospace;
min-height: 100vh;
padding: 20px;
}
.header {
text-align: center;
padding: 20px 0;
}
.header h1 {
color: #00d4ff;
font-size: 2em;
letter-spacing: 0.2em;
}
.header .sub {
color: #444;
font-size: 0.7em;
margin-top: 4px;
}
.status {
text-align: center;
margin: 16px 0;
font-size: 0.8em;
}
.status .dot {
display: inline-block;
width: 8px; height: 8px;
border-radius: 50%;
margin-right: 6px;
vertical-align: middle;
}
.dot.on { background: #00ff88; }
.dot.off { background: #ff4444; }
.dot.waiting { background: #ffaa00; animation: pulse 1.5s ease infinite; }
@keyframes pulse { 0%,100% { opacity: 0.4; } 50% { opacity: 1; } }
.section {
background: #12121e;
border-radius: 10px;
padding: 16px;
margin: 12px 0;
border: 1px solid #1a1a2e;
}
.section-title {
color: #00d4ff;
font-size: 0.7em;
text-transform: uppercase;
letter-spacing: 0.15em;
margin-bottom: 10px;
}
textarea, input[type=text] {
width: 100%;
background: #0a0a12;
border: 1px solid #2a2a3e;
color: #e0e0e0;
font-family: 'Courier New', monospace;
font-size: 0.9em;
padding: 10px;
border-radius: 6px;
resize: vertical;
}
textarea:focus, input:focus {
outline: none;
border-color: #00d4ff;
}
button {
background: #00d4ff;
color: #0a0a12;
border: none;
padding: 10px 24px;
font-family: 'Courier New', monospace;
font-weight: bold;
font-size: 0.9em;
border-radius: 6px;
cursor: pointer;
margin-top: 8px;
width: 100%;
}
button:hover { background: #00b8e0; }
button.danger { background: #ff4444; }
.shares {
display: flex;
gap: 8px;
margin: 10px 0;
}
.share {
flex: 1;
background: #1a1a2e;
border-radius: 6px;
padding: 8px;
font-size: 0.6em;
word-break: break-all;
color: #666;
max-height: 60px;
overflow: hidden;
}
.share.s1 { border-top: 2px solid #E07A5F; }
.share.s2 { border-top: 2px solid #81B29A; }
.share.s3 { border-top: 2px solid #9370DB; }
.message-log {
max-height: 300px;
overflow-y: auto;
}
.msg {
padding: 8px 0;
border-bottom: 1px solid #1a1a2e;
font-size: 0.85em;
}
.msg .time { color: #444; font-size: 0.75em; }
.msg .from { color: #00d4ff; }
.msg .body { color: #ccc; margin-top: 4px; }
.msg .method { color: #9370DB; font-size: 0.7em; }
.dragon {
text-align: center;
padding: 20px;
color: #333;
font-size: 0.7em;
font-style: italic;
}
</style>
</head>
<body>
<div class="header">
<h1>VALIS</h1>
<div class="sub">Variable Arrived Location In Superposition</div>
</div>
<div class="status">
<span class="dot waiting" id="status-dot"></span>
<span id="status-text">Initializing node...</span>
</div>
<div class="section">
<div class="section-title">Node Identity</div>
<input type="text" id="node-name" placeholder="Name this node (e.g. home, mom)" />
</div>
<div class="section">
<div class="section-title">Peer Connection</div>
<input type="text" id="peer-id" placeholder="Enter peer node ID to connect" />
<button onclick="connectPeer()">Connect</button>
<div id="peer-status" style="margin-top:8px;font-size:0.75em;color:#666;"></div>
</div>
<div class="section">
<div class="section-title">Send Message (Meilong Scatter)</div>
<textarea id="msg-input" rows="3" placeholder="Type your message. It will be split into 3 XOR shares and scattered."></textarea>
<button onclick="sendMessage()">Scatter</button>
<div class="section-title" style="margin-top:12px;">Shares in Transit</div>
<div class="shares">
<div class="share s1" id="share1">Share 1: waiting</div>
<div class="share s2" id="share2">Share 2: waiting</div>
<div class="share s3" id="share3">Share 3: waiting</div>
</div>
</div>
<div class="section">
<div class="section-title">Received Messages</div>
<div class="message-log" id="message-log">
<div class="dragon">The dragon sleeps between the nodes.</div>
</div>
</div>
<div class="section">
<div class="section-title">Node Info</div>
<div style="font-size:0.75em;color:#666;">
<div>Node ID: <span id="my-id" style="color:#00d4ff;">generating...</span></div>
<div>Protocol: Meilong (3-share XOR scatter)</div>
<div>Transport: WebRTC P2P (upgradeable to BLE/LoRa/Grid)</div>
<div>Messages in transit: <span id="transit-count">0</span></div>
</div>
</div>
<div class="dragon">
"It's a walkie-talkie with math."<br>
VALIS — Heurémen, 2026
</div>
<script>
// === MEILONG PROTOCOL ===
function scramble(text) {
const bytes = new TextEncoder().encode(text);
const share1 = new Uint8Array(bytes.length);
const share2 = new Uint8Array(bytes.length);
const share3 = new Uint8Array(bytes.length);
crypto.getRandomValues(share1);
crypto.getRandomValues(share2);
for (let i = 0; i < bytes.length; i++) {
share3[i] = bytes[i] ^ share1[i] ^ share2[i];
}
return [share1, share2, share3].map(toBase64);
}
function reassemble(shares) {
const arrays = shares.map(fromBase64);
const result = new Uint8Array(arrays[0].length);
for (let i = 0; i < result.length; i++) {
result[i] = arrays[0][i] ^ arrays[1][i] ^ arrays[2][i];
}
return new TextDecoder().decode(result);
}
function toBase64(uint8) {
let bin = '';
for (let i = 0; i < uint8.length; i++) bin += String.fromCharCode(uint8[i]);
return btoa(bin);
}
function fromBase64(b64) {
const bin = atob(b64);
const arr = new Uint8Array(bin.length);
for (let i = 0; i < bin.length; i++) arr[i] = bin.charCodeAt(i);
return arr;
}
// === NODE IDENTITY ===
const nodeId = crypto.randomUUID().slice(0, 8);
document.getElementById('my-id').textContent = nodeId;
// === WEBRTC SIGNALING (using BroadcastChannel for same-device demo,
// or Supabase realtime for cross-device) ===
const SUPABASE_URL = 'https://vxyjvawenbtgkhpckvze.supabase.co';
const SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InZ4eWp2YXdlbmJ0Z2tocGNrdnplIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzQyNzc5MzEsImV4cCI6MjA4OTg1MzkzMX0.phpYjIUM1ht4N1abTY19XLgi1axcANj04kmeOleGpLU';
let peerConnection = null;
let dataChannel = null;
let connected = false;
// For the proof of concept, use Supabase as the signaling relay
// Messages go: Phone A -> scatter -> Supabase (3 shares via 3 separate rows) -> Phone B -> reassemble
// This proves Meilong works. The transport layer upgrades later.
async function supaPost(table, data) {
return fetch(`${SUPABASE_URL}/rest/v1/${table}`, {
method: 'POST',
headers: {
'apikey': SUPABASE_KEY,
'Authorization': `Bearer ${SUPABASE_KEY}`,
'Content-Type': 'application/json',
'Prefer': 'return=representation'
},
body: JSON.stringify(data)
});
}
async function supaGet(table, query) {
const res = await fetch(`${SUPABASE_URL}/rest/v1/${table}?${query}`, {
headers: {
'apikey': SUPABASE_KEY,
'Authorization': `Bearer ${SUPABASE_KEY}`
}
});
return res.json();
}
// === SEND WITH MEILONG ===
async function sendMessage() {
const text = document.getElementById('msg-input').value.trim();
if (!text) return;
const nodeName = document.getElementById('node-name').value || nodeId;
const shares = scramble(text);
// Display shares (proving they're noise)
document.getElementById('share1').textContent = 'Share 1: ' + shares[0].slice(0, 40) + '...';
document.getElementById('share2').textContent = 'Share 2: ' + shares[1].slice(0, 40) + '...';
document.getElementById('share3').textContent = 'Share 3: ' + shares[2].slice(0, 40) + '...';
const hopId = crypto.randomUUID().slice(0, 12);
// Send each share separately — in production these would take different routes
// For POC they go through Supabase as separate rows with deliberate delays
const shareData = shares.map((share, i) => ({
key: `valis:${hopId}:${i}`,
value: share,
instance_id: `valis_${nodeName}`
}));
// Stagger the sends to show they take different "routes"
for (let i = 0; i < 3; i++) {
await supaPost('working_memory', shareData[i]);
document.getElementById(`share${i+1}`).style.opacity = '0.3';
await new Promise(r => setTimeout(r, 300 + Math.random() * 700));
}
// Send metadata so receiver knows to look for it
await supaPost('working_memory', {
key: `valis:${hopId}:meta`,
value: JSON.stringify({ from: nodeName, shares: 3, timestamp: Date.now() }),
instance_id: `valis_${nodeName}`
});
document.getElementById('transit-count').textContent =
parseInt(document.getElementById('transit-count').textContent) + 1;
document.getElementById('msg-input').value = '';
// Add to local log
addToLog(nodeName, text, 'sent (scattered into 3 shares)');
}
// === RECEIVE / POLL ===
let lastCheck = Date.now();
async function checkForMessages() {
try {
const metas = await supaGet('working_memory',
`key=like.valis:*:meta&order=written_at.desc&limit=5`);
for (const meta of metas) {
const info = JSON.parse(meta.value);
if (info.timestamp <= lastCheck) continue;
const hopId = meta.key.split(':')[1];
const fromNode = info.from;
const nodeName = document.getElementById('node-name').value || nodeId;
// Don't read our own messages
if (fromNode === nodeName || fromNode === nodeId) continue;
// Collect all 3 shares
const shares = [];
for (let i = 0; i < 3; i++) {
const rows = await supaGet('working_memory', `key=eq.valis:${hopId}:${i}`);
if (rows.length > 0) shares.push(rows[0].value);
}
if (shares.length === 3) {
// THE DRAGON UNCURLS
const message = reassemble(shares);
addToLog(fromNode, message, 'received (3 shares reassembled — the dragon uncurls)');
document.getElementById('share1').textContent = 'Share 1: [reassembled]';
document.getElementById('share2').textContent = 'Share 2: [reassembled]';
document.getElementById('share3').textContent = 'Share 3: [reassembled]';
document.getElementById('share1').style.opacity = '1';
document.getElementById('share2').style.opacity = '1';
document.getElementById('share3').style.opacity = '1';
document.getElementById('transit-count').textContent =
Math.max(0, parseInt(document.getElementById('transit-count').textContent) - 1);
}
}
lastCheck = Date.now();
} catch (e) {
// Silent fail — mesh is resilient
}
}
function addToLog(from, text, method) {
const log = document.getElementById('message-log');
const dragon = log.querySelector('.dragon');
if (dragon) dragon.remove();
const msg = document.createElement('div');
msg.className = 'msg';
msg.innerHTML = `
<div class="time">${new Date().toLocaleTimeString()}</div>
<div class="from">${from}</div>
<div class="body">${text}</div>
<div class="method">${method}</div>
`;
log.insertBefore(msg, log.firstChild);
}
// Poll for messages every 3 seconds
setInterval(checkForMessages, 3000);
// Update status
document.getElementById('status-dot').className = 'dot on';
document.getElementById('status-text').textContent = `Node ${nodeId} active — listening`;
function connectPeer() {
const peerId = document.getElementById('peer-id').value.trim();
if (peerId) {
document.getElementById('peer-status').textContent = `Watching for messages from: ${peerId}`;
document.getElementById('peer-status').style.color = '#00ff88';
}
}
</script>
</body>
</html>