Skip to main content

Web Applications

This guide covers building browser-based applications with the Zeq OS JavaScript and TypeScript SDKs, including real-time HulyaPulse synchronization via WebSocket, React integration patterns, and deployment through nginx.

Setup

npm install @zeq-os/sdk
import { ZeqProcessor, HulyaSync, OperatorRegistry } from '@zeq-os/sdk';

const processor = new ZeqProcessor();
const sync = new HulyaSync();
const registry = await OperatorRegistry.default();

console.log(`${registry.count} operators loaded`);
console.log(sync.daemonTick());

Subscribing to HulyaPulse via WebSocket

The Sync Engine on port 4001 broadcasts HulyaPulse ticks at 1.287 Hz. Every web application that needs real-time temporal data should subscribe to this stream.

Basic WebSocket Connection

function connectHulyaPulse() {
const ws = new WebSocket('ws://localhost:4001/ws');

ws.onopen = () => {
console.log('Connected to HulyaPulse');
};

ws.onmessage = (event) => {
const tick = JSON.parse(event.data);
console.log(`Zeqond ${tick.zeqond} | Phase ${tick.phase.toFixed(4)} | KO42 ${tick.ko42.toFixed(6)}`);
};

ws.onerror = (error) => {
console.error('HulyaPulse connection error:', error);
};

// Auto-reconnect after 1 Zeqond (777ms)
ws.onclose = () => {
console.log('Disconnected — reconnecting in 1 Zeqond...');
setTimeout(connectHulyaPulse, 777);
};

return ws;
}

const pulse = connectHulyaPulse();

Tick Format

Every 0.777 seconds (1 Zeqond), the Sync Engine broadcasts a JSON object:

{
"type": "tick",
"zeqond": 3296847201,
"phase": 0.4521,
"ko42": 0.000891,
"timestamp": 1740499200.123,
"frequency": 1.287,
"connections": 12
}
FieldTypeDescription
zeqondintegerCurrent Zeqond count since epoch
phasefloatPhase within current Zeqond [0, 1)
ko42floatKO42.1 automatic metric tensioner value
timestampfloatUnix timestamp
frequencyfloatHulyaPulse frequency (always 1.287)
connectionsintegerNumber of connected WebSocket clients

React Integration

useHulyaPulse Hook

Create a custom React hook that manages the WebSocket connection lifecycle and provides tick data to components:

import { useState, useEffect, useRef, useCallback } from 'react';

interface HulyaTick {
zeqond: number;
phase: number;
ko42: number;
timestamp: number;
frequency: number;
connections: number;
}

function useHulyaPulse(url: string = 'ws://localhost:4001/ws'): HulyaTick | null {
const [tick, setTick] = useState<HulyaTick | null>(null);
const wsRef = useRef<WebSocket | null>(null);
const reconnectTimeout = useRef<NodeJS.Timeout>();

const connect = useCallback(() => {
const ws = new WebSocket(url);
wsRef.current = ws;

ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'tick') {
setTick(data);
}
};

// Auto-reconnect after 1 Zeqond (777ms)
ws.onclose = () => {
reconnectTimeout.current = setTimeout(connect, 777);
};
}, [url]);

useEffect(() => {
connect();
return () => {
clearTimeout(reconnectTimeout.current);
wsRef.current?.close();
};
}, [connect]);

return tick;
}

Using the Hook in a Component

function PulseIndicator() {
const tick = useHulyaPulse();

if (!tick) return <div>Connecting to HulyaPulse...</div>;

return (
<div className="pulse-indicator">
<h3>HulyaPulse Live</h3>
<p>Zeqond: {tick.zeqond}</p>
<p>Phase: {tick.phase.toFixed(4)}</p>
<p>KO42: {tick.ko42.toFixed(6)}</p>
<p>Frequency: {tick.frequency} Hz</p>
<p>Clients: {tick.connections}</p>
</div>
);
}

Example: Physics Calculator Page

A web page that takes a physics query from the user and processes it through the 7-Step Wizard Protocol:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Zeq OS Physics Calculator</title>
<style>
body { font-family: monospace; max-width: 720px; margin: 2em auto; }
input { width: 100%; padding: 8px; font-size: 16px; }
pre { background: #1a1a2e; color: #e0e0e0; padding: 16px; border-radius: 4px; }
.pulse { color: #00d4aa; font-weight: bold; }
</style>
</head>
<body>
<h1>Zeq OS Physics Calculator</h1>
<input id="query" placeholder="Enter a physics query..." />
<button onclick="compute()">Process (7-Step Wizard)</button>

<div id="pulse" class="pulse">Connecting to HulyaPulse...</div>
<pre id="result">Awaiting query...</pre>

<script type="module">
import { ZeqProcessor, HulyaSync } from '@zeq-os/sdk';

const processor = new ZeqProcessor();
const sync = new HulyaSync();

// Live HulyaPulse display
const ws = new WebSocket('ws://localhost:4001/ws');
ws.onmessage = (event) => {
const tick = JSON.parse(event.data);
document.getElementById('pulse').textContent =
`Zeqond ${tick.zeqond} | Phase ${tick.phase.toFixed(4)} | KO42 ${tick.ko42.toFixed(6)}`;
};
ws.onclose = () => setTimeout(() => location.reload(), 777);

// Physics computation
window.compute = function() {
const query = document.getElementById('query').value;
const result = processor.processQuery(query);

document.getElementById('result').textContent = JSON.stringify({
query: query,
domains: result.domains,
operators: result.selectedOperators,
masterSum: result.masterSum,
phaseCoherence: result.phaseCoherence,
zeqond: result.zeqond,
precisionMet: result.phaseCoherence <= 0.1
}, null, 2);
};
</script>
</body>
</html>

Example: Live Dashboard

A dashboard that displays real-time HulyaPulse state, Zeqond counter, and operator registry statistics:

import React, { useState, useEffect } from 'react';
import { OperatorRegistry } from '@zeq-os/sdk';

// Uses the useHulyaPulse hook defined above

function ZeqDashboard() {
const tick = useHulyaPulse();
const [registry, setRegistry] = useState<OperatorRegistry | null>(null);

useEffect(() => {
OperatorRegistry.default().then(setRegistry);
}, []);

if (!tick || !registry) return <div>Loading...</div>;

// Phase bar: visual representation of current phase [0, 1)
const phasePercent = (tick.phase * 100).toFixed(1);

return (
<div className="zeq-dashboard">
<header>
<h1>ZeqBoard</h1>
<span className="live-dot" /> Live at {tick.frequency} Hz
</header>

<section className="pulse-section">
<h2>HulyaPulse</h2>
<div className="metric">
<label>Zeqond</label>
<span className="value">{tick.zeqond.toLocaleString()}</span>
</div>
<div className="metric">
<label>Phase</label>
<div className="phase-bar">
<div className="phase-fill" style={{ width: `${phasePercent}%` }} />
</div>
<span>{phasePercent}%</span>
</div>
<div className="metric">
<label>KO42</label>
<span className="value">{tick.ko42.toFixed(6)}</span>
</div>
</section>

<section className="registry-section">
<h2>Operator Registry</h2>
<div className="metric">
<label>Total Operators</label>
<span className="value">{registry.count}</span>
</div>
<div className="metric">
<label>Categories</label>
<span className="value">{registry.categories.length}</span>
</div>
</section>

<section className="connections-section">
<h2>Network</h2>
<div className="metric">
<label>WebSocket Clients</label>
<span className="value">{tick.connections}</span>
</div>
</section>
</div>
);
}

export default ZeqDashboard;

Serving with nginx

Static HTML applications are served under /apps/ routes. The project includes a unified app server (apps/app-server.js) for development, but for production, use nginx to serve the static files:

nginx Configuration

server {
listen 80;
server_name your-domain.com;

# Static web applications
location /apps/physics-calculator/ {
alias /var/www/zeq-os/apps/physics-calculator/;
index index.html;
try_files $uri $uri/ /apps/physics-calculator/index.html;
}

location /apps/dashboard/ {
alias /var/www/zeq-os/apps/dashboard/;
index index.html;
try_files $uri $uri/ /apps/dashboard/index.html;
}

# API Gateway proxy (port 4000)
location /api/ {
proxy_pass http://localhost:4000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}

# WebSocket Sync Engine proxy (port 4001)
location /ws {
proxy_pass http://localhost:4001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400;
}
}

Key Points

  • Static HTML files go under /var/www/zeq-os/apps/<app-name>/
  • The API Gateway on port 4000 is proxied through /api/
  • The WebSocket Sync Engine on port 4001 is proxied through /ws
  • proxy_read_timeout 86400 keeps WebSocket connections alive for 24 hours
  • WebSocket upgrade headers (Upgrade, Connection) are required for the /ws proxy

Development Mode

During development, use the unified app server instead of nginx:

# From the project root
node apps/app-server.js

This serves static HTML apps on ports 3002, 3005-3008, and 3010. See the Applications overview for the full port map.

Next Steps