[manus] Nostr Integration — Sovereign Communication (#454) (#455)
Some checks failed
Deploy Nexus / deploy (push) Failing after 8s
Staging Smoke Test / smoke-test (push) Successful in 1s

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:
manus
2026-03-24 19:58:25 +00:00
committed by Timmy Time
parent a2b2b1a9af
commit 24e71396cc
3 changed files with 146 additions and 45 deletions

69
app.js
View File

@@ -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
View 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
View 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();