Split the monolithic 5393-line app.js into 32 focused ES modules under modules/ with a thin ~330-line orchestrator. No bundler required — runs in-browser via import maps. Module structure: core/ — scene, ticker, state, theme, audio data/ — gitea, weather, bitcoin, loaders terrain/ — stars, clouds, island effects/ — matrix-rain, energy-beam, lightning, shockwave, rune-ring, gravity-zones panels/ — heatmap, sigil, sovereignty, dual-brain, batcave, earth, agent-board, lora-panel portals/ — portal-system, commit-banners narrative/ — bookshelves, oath, chat utils/ — perlin All files pass node --check. No new dependencies. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
35 lines
1.1 KiB
JavaScript
35 lines
1.1 KiB
JavaScript
// modules/data/bitcoin.js — Bitcoin block height polling
|
|
import { state } from '../core/state.js';
|
|
|
|
const blockHeightDisplay = document.getElementById('block-height-display');
|
|
const blockHeightValue = document.getElementById('block-height-value');
|
|
|
|
export async function fetchBlockHeight() {
|
|
try {
|
|
const res = await fetch('https://blockstream.info/api/blocks/tip/height');
|
|
if (!res.ok) return;
|
|
const height = parseInt(await res.text(), 10);
|
|
if (isNaN(height)) return;
|
|
|
|
if (state.lastBlockHeight !== 0 && height !== state.lastBlockHeight) {
|
|
if (blockHeightDisplay) {
|
|
blockHeightDisplay.classList.remove('fresh');
|
|
void blockHeightDisplay.offsetWidth;
|
|
blockHeightDisplay.classList.add('fresh');
|
|
}
|
|
state.starPulseIntensity = 1.0;
|
|
}
|
|
|
|
state.lastBlockHeight = height;
|
|
state.blockHeight = height;
|
|
if (blockHeightValue) blockHeightValue.textContent = height.toLocaleString();
|
|
} catch (_) {
|
|
// Network unavailable — keep last known value
|
|
}
|
|
}
|
|
|
|
export function startBlockPolling() {
|
|
fetchBlockHeight();
|
|
setInterval(fetchBlockHeight, 60000);
|
|
}
|