This repository has been archived on 2026-03-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Timmy-time-dashboard/static/world/index.html

192 lines
7.5 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Timmy's Workshop</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="overlay">
<div id="status">
<div class="name">Timmy</div>
<div class="mood" id="mood-text">focused</div>
</div>
<div id="connection-dot"></div>
<button id="info-btn" class="info-button" aria-label="About The Matrix" title="About The Matrix">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="16" x2="12" y2="12"></line>
<line x1="12" y1="8" x2="12.01" y2="8"></line>
</svg>
</button>
<div id="speech-area">
<div class="bubble" id="speech-bubble"></div>
</div>
</div>
<!-- About Panel -->
<div id="about-panel" class="about-panel">
<div class="about-panel-content">
<button id="about-close" class="about-close" aria-label="Close">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
<h2>Welcome to The Matrix</h2>
<section>
<h3>🌌 The Matrix</h3>
<p>The Matrix is a 3D visualization of Timmy's AI agent workspace. Enter the workshop to see Timmy at work—pondering the arcane arts of code, managing tasks, and orchestrating autonomous agents in real-time.</p>
</section>
<section>
<h3>🛠️ The Workshop</h3>
<p>The Workshop is where you interact directly with Timmy:</p>
<ul>
<li><strong>Submit Jobs</strong> — Create tasks, delegate work, and track progress</li>
<li><strong>Chat with Agents</strong> — Converse with Timmy and his swarm of specialized agents</li>
<li><strong>Fund Sessions</strong> — Power your work with satoshis via Lightning Network</li>
</ul>
</section>
<section>
<h3>⚡ Lightning & Sats</h3>
<p>The Matrix runs on Bitcoin. Sessions are funded with satoshis (sats) over the Lightning Network—enabling fast, cheap micropayments that keep Timmy energized and working for you. No subscriptions, no limits—pay as you go.</p>
</section>
<div class="about-footer">
<span>Sovereign AI · Soul on Bitcoin</span>
</div>
</div>
<div id="about-backdrop" class="about-backdrop"></div>
</div>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js"
}
}
</script>
<script type="module">
import * as THREE from "three";
import { buildRoom } from "./scene.js";
import { createWizard } from "./wizard.js";
import { createFamiliar } from "./familiar.js";
import { setupControls } from "./controls.js";
import { StateReader } from "./state.js";
// --- Renderer ---
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 0.8;
document.body.prepend(renderer.domElement);
// --- Scene ---
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0a0a14);
scene.fog = new THREE.Fog(0x0a0a14, 5, 12);
// --- Camera (visitor at the door) ---
const camera = new THREE.PerspectiveCamera(
55, window.innerWidth / window.innerHeight, 0.1, 50
);
camera.position.set(0, 2.0, 4.5);
// --- Build scene elements ---
const { crystalBall, crystalLight, fireLight, candleLights } = buildRoom(scene);
const wizard = createWizard();
scene.add(wizard.group);
const familiar = createFamiliar();
scene.add(familiar.group);
// --- Controls ---
const controls = setupControls(camera, renderer.domElement);
// --- State ---
const stateReader = new StateReader();
const moodEl = document.getElementById("mood-text");
stateReader.onChange((state) => {
if (moodEl) {
moodEl.textContent = state.timmyState.mood;
}
});
stateReader.connect();
// --- About Panel ---
const infoBtn = document.getElementById("info-btn");
const aboutPanel = document.getElementById("about-panel");
const aboutClose = document.getElementById("about-close");
const aboutBackdrop = document.getElementById("about-backdrop");
function openAboutPanel() {
aboutPanel.classList.add("open");
document.body.style.overflow = "hidden";
}
function closeAboutPanel() {
aboutPanel.classList.remove("open");
document.body.style.overflow = "";
}
infoBtn.addEventListener("click", openAboutPanel);
aboutClose.addEventListener("click", closeAboutPanel);
aboutBackdrop.addEventListener("click", closeAboutPanel);
// Close on Escape key
document.addEventListener("keydown", (e) => {
if (e.key === "Escape" && aboutPanel.classList.contains("open")) {
closeAboutPanel();
}
});
// --- Resize ---
window.addEventListener("resize", () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// --- Animation loop ---
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const dt = clock.getDelta();
// Update scene elements
wizard.update(dt);
familiar.update(dt);
controls.update();
// Crystal ball subtle rotation + pulsing glow
crystalBall.rotation.y += dt * 0.3;
const pulse = 0.3 + Math.sin(Date.now() * 0.002) * 0.15;
crystalLight.intensity = pulse;
crystalBall.material.emissiveIntensity = pulse * 0.5;
// Fireplace flicker
fireLight.intensity = 1.2 + Math.sin(Date.now() * 0.005) * 0.15
+ Math.sin(Date.now() * 0.013) * 0.1;
// Candle flicker — each offset slightly for variety
const now = Date.now();
for (let i = 0; i < candleLights.length; i++) {
candleLights[i].intensity = 0.4
+ Math.sin(now * 0.007 + i * 2.1) * 0.1
+ Math.sin(now * 0.019 + i * 1.3) * 0.05;
}
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>