// === MATRIX RAIN === + === ASSET LOADER === import * as THREE from 'three'; import { S } from './state.js'; // === ASSET LOADER === export const loadedAssets = new Map(); // Forward ref: animate() is set by app.js after all modules load let _animateFn = null; export function setAnimateFn(fn) { _animateFn = fn; } export const loadingManager = new THREE.LoadingManager(() => { document.getElementById('loading-bar').style.width = '100%'; document.getElementById('loading').style.display = 'none'; if (_animateFn) _animateFn(); }); loadingManager.onProgress = (url, itemsLoaded, itemsTotal) => { const progress = (itemsLoaded / itemsTotal) * 100; document.getElementById('loading-bar').style.width = `${progress}%`; }; // === MATRIX RAIN === const matrixCanvas = document.createElement('canvas'); matrixCanvas.id = 'matrix-rain'; matrixCanvas.width = window.innerWidth; matrixCanvas.height = window.innerHeight; document.body.appendChild(matrixCanvas); const matrixCtx = matrixCanvas.getContext('2d'); const MATRIX_CHARS = 'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン0123456789ABCDEF'; const MATRIX_FONT_SIZE = 14; const MATRIX_COL_COUNT = Math.floor(window.innerWidth / MATRIX_FONT_SIZE); const matrixDrops = new Array(MATRIX_COL_COUNT).fill(1); // totalActivity is provided by warp module — imported lazily via a setter let _totalActivityFn = () => 0; export function setTotalActivityFn(fn) { _totalActivityFn = fn; } function drawMatrixRain() { matrixCtx.fillStyle = 'rgba(0, 0, 8, 0.05)'; matrixCtx.fillRect(0, 0, matrixCanvas.width, matrixCanvas.height); matrixCtx.font = `${MATRIX_FONT_SIZE}px monospace`; const activity = _totalActivityFn(); const density = 0.1 + activity * 0.9; const activeColCount = Math.max(1, Math.floor(matrixDrops.length * density)); for (let i = 0; i < matrixDrops.length; i++) { if (i >= activeColCount) { if (matrixDrops[i] * MATRIX_FONT_SIZE > matrixCanvas.height) continue; } let char; if (S._matrixCommitHashes.length > 0 && Math.random() < 0.02) { const hash = S._matrixCommitHashes[Math.floor(Math.random() * S._matrixCommitHashes.length)]; char = hash[Math.floor(Math.random() * hash.length)]; } else { char = MATRIX_CHARS[Math.floor(Math.random() * MATRIX_CHARS.length)]; } const x = i * MATRIX_FONT_SIZE; const y = matrixDrops[i] * MATRIX_FONT_SIZE; matrixCtx.fillStyle = '#aaffaa'; matrixCtx.fillText(char, x, y); const resetThreshold = 0.975 - activity * 0.015; if (y > matrixCanvas.height && Math.random() > resetThreshold) { matrixDrops[i] = 0; } matrixDrops[i]++; } } setInterval(drawMatrixRain, 50); window.addEventListener('resize', () => { matrixCanvas.width = window.innerWidth; matrixCanvas.height = window.innerHeight; });