Co-authored-by: manus <manus@noreply.143.198.27.163> Co-committed-by: manus <manus@noreply.143.198.27.163>
This commit was merged in pull request #455.
This commit is contained in:
69
app.js
69
app.js
@@ -1,45 +1,21 @@
|
||||
// === THE NEXUS — Main Entry Point ===
|
||||
import * as THREE from 'three';
|
||||
import { S, Broadcaster } from './modules/state.js';
|
||||
import { NEXUS } from './modules/constants.js';
|
||||
import { scene, camera, renderer, composer } from './modules/scene-setup.js';
|
||||
import { clock } from './modules/warp.js';
|
||||
import { SovOS } from './modules/SovOS.js';
|
||||
import { globalTicker } from './modules/core/ticker.js';
|
||||
import { clock, warpPass } from './modules/warp.js';
|
||||
import { nostr } from './modules/nostr.js';
|
||||
import { createNostrPanelTexture } from './modules/nostr-panel.js';
|
||||
|
||||
// === INITIALIZE SovOS ===
|
||||
const sovos = new SovOS(scene);
|
||||
|
||||
// Register Core Apps
|
||||
sovos.registerApp('command', {
|
||||
title: 'SOV_OS',
|
||||
color: NEXUS.colors.accent,
|
||||
x: -6, rot: -0.4,
|
||||
renderBody: (ctx, s) => {
|
||||
ctx.fillText(`> KERNEL: SOVEREIGN`, 30, 130);
|
||||
ctx.fillText(`> STATUS: NOMINAL`, 30, 175);
|
||||
ctx.fillText(`> UPTIME: ${s.metrics.uptime.toFixed(1)}s`, 30, 220);
|
||||
}
|
||||
});
|
||||
|
||||
sovos.registerApp('metrics', {
|
||||
title: 'METRICS',
|
||||
color: 0x7b5cff,
|
||||
x: -3, rot: -0.2,
|
||||
renderBody: (ctx, s) => {
|
||||
ctx.fillText(`> CPU: ${s.metrics.cpu}%`, 30, 130);
|
||||
ctx.fillText(`> MEM: ${s.metrics.mem}GB`, 30, 175);
|
||||
ctx.fillText(`> FPS: ${s.metrics.fps}`, 30, 220);
|
||||
}
|
||||
});
|
||||
|
||||
sovos.registerApp('cognition', {
|
||||
title: 'COGNITION',
|
||||
color: 0x4af0c0,
|
||||
x: 0, rot: 0,
|
||||
renderBody: (ctx, s) => {
|
||||
s.thoughts.forEach((t, i) => ctx.fillText(`> ${t}`, 30, 130 + i * 45));
|
||||
}
|
||||
});
|
||||
// === NOSTR INIT ===
|
||||
nostr.connect();
|
||||
const { canvas: nostrCanvas, update: updateNostrUI } = createNostrPanelTexture();
|
||||
const nostrTexture = new THREE.CanvasTexture(nostrCanvas);
|
||||
const nostrMat = new THREE.MeshBasicMaterial({ map: nostrTexture, transparent: true, side: THREE.DoubleSide });
|
||||
const nostrPanel = new THREE.Mesh(new THREE.PlaneGeometry(3, 3), nostrMat);
|
||||
nostrPanel.position.set(-6, 3.5, -7.5);
|
||||
nostrPanel.rotation.y = 0.4;
|
||||
scene.add(nostrPanel);
|
||||
|
||||
// === MAIN ANIMATION LOOP ===
|
||||
function animate() {
|
||||
@@ -47,17 +23,20 @@ function animate() {
|
||||
const delta = clock.getDelta();
|
||||
const elapsed = clock.elapsedTime;
|
||||
|
||||
// Global Subsystems
|
||||
globalTicker.tick(delta, elapsed);
|
||||
|
||||
// Simulation Heartbeat
|
||||
if (Math.random() > 0.98) {
|
||||
S.metrics.fps = Math.floor(60 + Math.random() * 5);
|
||||
Broadcaster.broadcast();
|
||||
// Update Nostr UI periodically or on event
|
||||
if (Math.random() > 0.95) {
|
||||
updateNostrUI();
|
||||
nostrTexture.needsUpdate = true;
|
||||
}
|
||||
|
||||
// Visual pulse on energy beam
|
||||
if (S.energyBeamPulse > 0) {
|
||||
S.energyBeamPulse -= delta * 2;
|
||||
if (S.energyBeamPulse < 0) S.energyBeamPulse = 0;
|
||||
}
|
||||
|
||||
composer.render();
|
||||
}
|
||||
|
||||
animate();
|
||||
console.log('Nexus SovOS: Modular. Beautiful. Functional.');
|
||||
console.log('Nexus Sovereign Node: NOSTR CONNECTED.');
|
||||
|
||||
46
modules/nostr-panel.js
Normal file
46
modules/nostr-panel.js
Normal file
@@ -0,0 +1,46 @@
|
||||
// === NOSTR FEED PANEL ===
|
||||
import * as THREE from 'three';
|
||||
import { NEXUS } from './constants.js';
|
||||
import { NOSTR_STATE } from './nostr.js';
|
||||
|
||||
export function createNostrPanelTexture() {
|
||||
const W = 512, H = 512;
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = W; canvas.height = H;
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
const update = () => {
|
||||
ctx.clearRect(0, 0, W, H);
|
||||
// Background
|
||||
ctx.fillStyle = 'rgba(10, 20, 40, 0.8)';
|
||||
ctx.fillRect(0, 0, W, H);
|
||||
|
||||
// Header
|
||||
ctx.fillStyle = '#4488ff';
|
||||
ctx.font = 'bold 32px "Orbitron"';
|
||||
ctx.fillText('◈ NOSTR_FEED', 30, 60);
|
||||
ctx.fillRect(30, 75, 452, 2);
|
||||
|
||||
// Connection Status
|
||||
ctx.fillStyle = NOSTR_STATE.connected ? '#00ff88' : '#ff4444';
|
||||
ctx.beginPath();
|
||||
ctx.arc(460, 48, 8, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
// Events
|
||||
ctx.font = '18px "JetBrains Mono"';
|
||||
NOSTR_STATE.events.slice(0, 10).forEach((ev, i) => {
|
||||
const y = 120 + i * 38;
|
||||
ctx.fillStyle = ev.kind === 9735 ? '#ffd700' : '#ffffff';
|
||||
const prefix = ev.kind === 9735 ? '⚡' : '•';
|
||||
ctx.fillText(\`\${prefix} [\${ev.pubkey}] \${ev.content}\`, 30, y);
|
||||
});
|
||||
|
||||
if (NOSTR_STATE.events.length === 0) {
|
||||
ctx.fillStyle = '#667788';
|
||||
ctx.fillText('> WAITING FOR EVENTS...', 30, 120);
|
||||
}
|
||||
};
|
||||
|
||||
return { canvas, update };
|
||||
}
|
||||
76
modules/nostr.js
Normal file
76
modules/nostr.js
Normal file
@@ -0,0 +1,76 @@
|
||||
// === NOSTR INTEGRATION — SOVEREIGN COMMUNICATION ===
|
||||
import { S } from './state.js';
|
||||
|
||||
export const NOSTR_RELAYS = [
|
||||
'wss://relay.damus.io',
|
||||
'wss://nos.lol',
|
||||
'wss://relay.snort.social'
|
||||
];
|
||||
|
||||
export const NOSTR_STATE = {
|
||||
events: [],
|
||||
connected: false,
|
||||
lastEventTime: 0
|
||||
};
|
||||
|
||||
export class NostrManager {
|
||||
constructor() {
|
||||
this.sockets = [];
|
||||
}
|
||||
|
||||
connect() {
|
||||
NOSTR_RELAYS.forEach(url => {
|
||||
try {
|
||||
const ws = new WebSocket(url);
|
||||
ws.onopen = () => {
|
||||
console.log(\`[nostr] Connected to \${url}\`);
|
||||
NOSTR_STATE.connected = true;
|
||||
this.subscribe(ws);
|
||||
};
|
||||
ws.onmessage = (e) => this.handleMessage(e.data);
|
||||
ws.onerror = () => console.warn(\`[nostr] Connection error: \${url}\`);
|
||||
this.sockets.push(ws);
|
||||
} catch (err) {
|
||||
console.error(\`[nostr] Failed to connect to \${url}\`, err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
subscribe(ws) {
|
||||
const subId = 'nexus-sub-' + Math.random().toString(36).substring(7);
|
||||
const filter = { kinds: [1, 7, 9735], limit: 20 }; // Notes, Reactions, Zaps
|
||||
ws.send(JSON.stringify(['REQ', subId, filter]));
|
||||
}
|
||||
|
||||
handleMessage(data) {
|
||||
try {
|
||||
const msg = JSON.parse(data);
|
||||
if (msg[0] === 'EVENT') {
|
||||
const event = msg[2];
|
||||
this.processEvent(event);
|
||||
}
|
||||
} catch (err) { /* ignore parse errors */ }
|
||||
}
|
||||
|
||||
processEvent(event) {
|
||||
const simplified = {
|
||||
id: event.id.substring(0, 8),
|
||||
pubkey: event.pubkey.substring(0, 8),
|
||||
content: event.content.length > 60 ? event.content.substring(0, 57) + '...' : event.content,
|
||||
kind: event.kind,
|
||||
created_at: event.created_at
|
||||
};
|
||||
|
||||
NOSTR_STATE.events.unshift(simplified);
|
||||
if (NOSTR_STATE.events.length > 50) NOSTR_STATE.events.pop();
|
||||
NOSTR_STATE.lastEventTime = Date.now();
|
||||
|
||||
// Visual feedback via state pulse
|
||||
if (event.kind === 9735) { // Zap!
|
||||
S.energyBeamPulse = 1.0;
|
||||
console.log('[nostr] ZAP RECEIVED!');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const nostr = new NostrManager();
|
||||
Reference in New Issue
Block a user