Files
the-nexus/modules/sigil.js
Alexander Whitestone cbfacdfe19
Some checks failed
Deploy Nexus / deploy (push) Failing after 3s
Staging Smoke Test / smoke-test (push) Successful in 1s
refactor: split app.js (5416 lines) into 21 modules — hard cap 1000 lines/file
app.js: 5416 → 528 lines (entry point, animation loop, event wiring)
modules/state.js: shared mutable state object
modules/constants.js: color palette
modules/matrix-rain.js: matrix rain canvas effect
modules/scene-setup.js: scene, camera, renderer, lighting, stars
modules/platform.js: glass platform, perlin noise, floating island, clouds
modules/heatmap.js: commit heatmap
modules/sigil.js: Timmy sigil
modules/controls.js: mouse, overview, zoom, photo mode
modules/effects.js: energy beam, sovereignty meter, rune ring
modules/earth.js: holographic earth
modules/warp.js: warp tunnel, crystals, lightning
modules/dual-brain.js: dual-brain holographic panel
modules/audio.js: Web Audio, spatial, portal hums
modules/debug.js: debug mode, websocket, session export
modules/celebrations.js: easter egg, shockwave, fireworks
modules/portals.js: portal loading
modules/bookshelves.js: floating bookshelves, spine textures
modules/oath.js: The Oath interactive SOUL.md
modules/panels.js: agent status board, LoRA panel
modules/weather.js: weather system, portal health
modules/extras.js: gravity zones, speech, timelapse, bitcoin

Largest file: 528 lines (app.js). No file exceeds 1000.
All files pass node --check. No refactoring — mechanical split only.
2026-03-24 15:12:22 -04:00

183 lines
5.4 KiB
JavaScript

// === TIMMY SIGIL ===
import * as THREE from 'three';
import { scene } from './scene-setup.js';
const SIGIL_CANVAS_SIZE = 512;
const SIGIL_RADIUS = 3.8;
function drawSigilCanvas() {
const canvas = document.createElement('canvas');
canvas.width = SIGIL_CANVAS_SIZE;
canvas.height = SIGIL_CANVAS_SIZE;
const ctx = canvas.getContext('2d');
const cx = SIGIL_CANVAS_SIZE / 2;
const cy = SIGIL_CANVAS_SIZE / 2;
const r = cx * 0.88;
ctx.clearRect(0, 0, SIGIL_CANVAS_SIZE, SIGIL_CANVAS_SIZE);
const bgGrad = ctx.createRadialGradient(cx, cy, 0, cx, cy, r);
bgGrad.addColorStop(0, 'rgba(0, 200, 255, 0.10)');
bgGrad.addColorStop(0.5, 'rgba(0, 100, 200, 0.04)');
bgGrad.addColorStop(1, 'rgba(0, 0, 0, 0)');
ctx.fillStyle = bgGrad;
ctx.fillRect(0, 0, SIGIL_CANVAS_SIZE, SIGIL_CANVAS_SIZE);
function glowCircle(x, y, radius, color, alpha, lineW) {
ctx.save();
ctx.globalAlpha = alpha;
ctx.strokeStyle = color;
ctx.lineWidth = lineW;
ctx.shadowColor = color;
ctx.shadowBlur = 12;
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.stroke();
ctx.restore();
}
function hexagram(ox, oy, hr, color, alpha) {
ctx.save();
ctx.globalAlpha = alpha;
ctx.strokeStyle = color;
ctx.lineWidth = 1.4;
ctx.shadowColor = color;
ctx.shadowBlur = 10;
ctx.beginPath();
for (let i = 0; i < 3; i++) {
const a = (i / 3) * Math.PI * 2 - Math.PI / 2;
const px = ox + Math.cos(a) * hr;
const py = oy + Math.sin(a) * hr;
i === 0 ? ctx.moveTo(px, py) : ctx.lineTo(px, py);
}
ctx.closePath();
ctx.stroke();
ctx.beginPath();
for (let i = 0; i < 3; i++) {
const a = (i / 3) * Math.PI * 2 + Math.PI / 2;
const px = ox + Math.cos(a) * hr;
const py = oy + Math.sin(a) * hr;
i === 0 ? ctx.moveTo(px, py) : ctx.lineTo(px, py);
}
ctx.closePath();
ctx.stroke();
ctx.restore();
}
const petalR = r * 0.32;
glowCircle(cx, cy, petalR, '#00ccff', 0.65, 1.0);
for (let i = 0; i < 6; i++) {
const a = (i / 6) * Math.PI * 2;
glowCircle(cx + Math.cos(a) * petalR, cy + Math.sin(a) * petalR, petalR, '#00aadd', 0.50, 0.8);
}
for (let i = 0; i < 6; i++) {
const a = (i / 6) * Math.PI * 2 + Math.PI / 6;
glowCircle(cx + Math.cos(a) * petalR * 1.73, cy + Math.sin(a) * petalR * 1.73, petalR, '#0077aa', 0.25, 0.6);
}
hexagram(cx, cy, r * 0.62, '#ffd700', 0.75);
hexagram(cx, cy, r * 0.41, '#ffaa00', 0.50);
glowCircle(cx, cy, r * 0.92, '#0055aa', 0.40, 0.8);
glowCircle(cx, cy, r * 0.72, '#0099cc', 0.38, 0.8);
glowCircle(cx, cy, r * 0.52, '#00ccff', 0.42, 0.9);
glowCircle(cx, cy, r * 0.18, '#ffd700', 0.65, 1.2);
ctx.save();
ctx.globalAlpha = 0.28;
ctx.strokeStyle = '#00aaff';
ctx.lineWidth = 0.6;
ctx.shadowColor = '#00aaff';
ctx.shadowBlur = 5;
for (let i = 0; i < 12; i++) {
const a = (i / 12) * Math.PI * 2;
ctx.beginPath();
ctx.moveTo(cx + Math.cos(a) * r * 0.18, cy + Math.sin(a) * r * 0.18);
ctx.lineTo(cx + Math.cos(a) * r * 0.91, cy + Math.sin(a) * r * 0.91);
ctx.stroke();
}
ctx.restore();
ctx.save();
ctx.fillStyle = '#00ffcc';
ctx.shadowColor = '#00ffcc';
ctx.shadowBlur = 9;
for (let i = 0; i < 12; i++) {
const a = (i / 12) * Math.PI * 2;
ctx.globalAlpha = i % 2 === 0 ? 0.80 : 0.50;
ctx.beginPath();
ctx.arc(cx + Math.cos(a) * r * 0.91, cy + Math.sin(a) * r * 0.91, i % 2 === 0 ? 4 : 2.5, 0, Math.PI * 2);
ctx.fill();
}
ctx.restore();
ctx.save();
ctx.globalAlpha = 1.0;
ctx.fillStyle = '#ffffff';
ctx.shadowColor = '#88ddff';
ctx.shadowBlur = 18;
ctx.beginPath();
ctx.arc(cx, cy, 5, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
return canvas;
}
const sigilTexture = new THREE.CanvasTexture(drawSigilCanvas());
export const sigilMat = new THREE.MeshBasicMaterial({
map: sigilTexture,
transparent: true,
opacity: 0.80,
depthWrite: false,
blending: THREE.AdditiveBlending,
side: THREE.DoubleSide,
});
export const sigilMesh = new THREE.Mesh(
new THREE.CircleGeometry(SIGIL_RADIUS, 128),
sigilMat
);
sigilMesh.rotation.x = -Math.PI / 2;
sigilMesh.position.y = 0.010;
sigilMesh.userData.zoomLabel = 'Timmy Sigil';
scene.add(sigilMesh);
export const sigilRing1Mat = new THREE.MeshBasicMaterial({
color: 0x00ccff, transparent: true, opacity: 0.45, depthWrite: false, blending: THREE.AdditiveBlending,
});
export const sigilRing1 = new THREE.Mesh(
new THREE.TorusGeometry(SIGIL_RADIUS * 0.965, 0.025, 6, 96), sigilRing1Mat
);
sigilRing1.rotation.x = Math.PI / 2;
sigilRing1.position.y = 0.012;
scene.add(sigilRing1);
export const sigilRing2Mat = new THREE.MeshBasicMaterial({
color: 0xffd700, transparent: true, opacity: 0.40, depthWrite: false, blending: THREE.AdditiveBlending,
});
export const sigilRing2 = new THREE.Mesh(
new THREE.TorusGeometry(SIGIL_RADIUS * 0.62, 0.020, 6, 72), sigilRing2Mat
);
sigilRing2.rotation.x = Math.PI / 2;
sigilRing2.position.y = 0.013;
scene.add(sigilRing2);
export const sigilRing3Mat = new THREE.MeshBasicMaterial({
color: 0x00ffcc, transparent: true, opacity: 0.35, depthWrite: false, blending: THREE.AdditiveBlending,
});
export const sigilRing3 = new THREE.Mesh(
new THREE.TorusGeometry(SIGIL_RADIUS * 0.78, 0.018, 6, 80), sigilRing3Mat
);
sigilRing3.rotation.x = Math.PI / 2;
sigilRing3.position.y = 0.011;
scene.add(sigilRing3);
export const sigilLight = new THREE.PointLight(0x0088ff, 0.4, 8);
sigilLight.position.set(0, 0.5, 0);
scene.add(sigilLight);