1122 lines
38 KiB
HTML
1122 lines
38 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>BlackRoad Universe — Complete Living Metaverse</title>
|
||
<meta name="description" content="The Complete BlackRoad Universe - 18 integrated systems, infinite exploration, living AI">
|
||
|
||
<!-- Fonts -->
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||
|
||
<!-- Three.js -->
|
||
<script type="importmap">
|
||
{
|
||
"imports": {
|
||
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
|
||
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
:root {
|
||
/* ===== OFFICIAL BLACKROAD COLORS ===== */
|
||
--sunrise-orange: #FF9D00;
|
||
--warm-orange: #FF6B00;
|
||
--hot-pink: #FF0066;
|
||
--electric-magenta: #FF006B;
|
||
--deep-magenta: #D600AA;
|
||
--vivid-purple: #7700FF;
|
||
--cyber-blue: #0066FF;
|
||
|
||
/* ===== NEUTRALS ===== */
|
||
--pure-black: #000000;
|
||
--deep-black: #0A0A0A;
|
||
--charcoal: #1A1A1A;
|
||
--pure-white: #FFFFFF;
|
||
--gray-300: #A0A0A0;
|
||
|
||
/* ===== SEMANTIC COLORS ===== */
|
||
--success: #27AE60;
|
||
--error: #E74C3C;
|
||
--alice-blue: #0066FF;
|
||
--aria-pink: #FF0066;
|
||
--lucidia-purple: #7700FF;
|
||
|
||
/* ===== OFFICIAL GRADIENTS ===== */
|
||
--gradient-br: linear-gradient(180deg, #FF9D00 0%, #FF6B00 25%, #FF0066 75%, #FF006B 100%);
|
||
--gradient-os: linear-gradient(180deg, #FF006B 0%, #D600AA 25%, #7700FF 75%, #0066FF 100%);
|
||
--gradient-full: linear-gradient(180deg, #FF9D00 0%, #FF6B00 14%, #FF0066 28%, #FF006B 42%, #D600AA 57%, #7700FF 71%, #0066FF 100%);
|
||
|
||
/* ===== GOLDEN RATIO SPACING (φ = 1.618) ===== */
|
||
--space-xs: 8px;
|
||
--space-sm: 13px; /* 8 × 1.618 */
|
||
--space-md: 21px; /* 13 × 1.618 */
|
||
--space-lg: 34px; /* 21 × 1.618 */
|
||
--space-xl: 55px; /* 34 × 1.618 */
|
||
--space-2xl: 89px; /* 55 × 1.618 */
|
||
|
||
/* ===== BORDER RADIUS ===== */
|
||
--radius-sm: 6px;
|
||
--radius-md: 10px;
|
||
--radius-lg: 16px;
|
||
--radius-xl: 24px;
|
||
--radius-2xl: 34px;
|
||
|
||
/* ===== GLASS MORPHISM ===== */
|
||
--glass-bg: rgba(255, 255, 255, 0.05);
|
||
--glass-bg-strong: rgba(255, 255, 255, 0.08);
|
||
--glass-border: rgba(255, 255, 255, 0.1);
|
||
--glass-border-strong: rgba(255, 255, 255, 0.15);
|
||
|
||
/* ===== LEGACY COMPAT ===== */
|
||
--bg-dark: var(--deep-black);
|
||
--bg-darker: var(--pure-black);
|
||
--text-primary: var(--pure-white);
|
||
--text-secondary: var(--gray-300);
|
||
--accent-purple: var(--vivid-purple);
|
||
--accent-blue: var(--cyber-blue);
|
||
--accent-red: var(--error);
|
||
--accent-green: var(--success);
|
||
--accent-orange: var(--sunrise-orange);
|
||
}
|
||
|
||
body {
|
||
font-family: 'Inter', sans-serif;
|
||
background: var(--bg-darker);
|
||
color: var(--text-primary);
|
||
overflow: hidden;
|
||
position: relative;
|
||
}
|
||
|
||
/* ===== LOADING SCREEN ===== */
|
||
#loading-screen {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: linear-gradient(135deg, #0a0a0a 0%, #1a0a2e 50%, #0a0a0a 100%);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 10001;
|
||
transition: opacity 0.5s ease;
|
||
}
|
||
|
||
#loading-screen.hidden {
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.loading-logo {
|
||
font-size: 48px;
|
||
font-weight: 900;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
background: var(--gradient-full);
|
||
background-size: 300% 300%;
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
animation: gradientShift 3s ease infinite;
|
||
margin-bottom: var(--space-lg);
|
||
}
|
||
|
||
@keyframes gradientShift {
|
||
0%, 100% { background-position: 0% 50%; }
|
||
50% { background-position: 100% 50%; }
|
||
}
|
||
|
||
.loading-bar-container {
|
||
width: 300px;
|
||
height: 4px;
|
||
background: rgba(255, 255, 255, 0.1);
|
||
border-radius: 2px;
|
||
overflow: hidden;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.loading-bar {
|
||
height: 100%;
|
||
background: var(--gradient-br);
|
||
border-radius: 2px;
|
||
transition: width 0.3s ease;
|
||
width: 0%;
|
||
}
|
||
|
||
.loading-text {
|
||
font-size: 14px;
|
||
color: var(--text-secondary);
|
||
font-family: 'JetBrains Mono', monospace;
|
||
}
|
||
|
||
.loading-systems {
|
||
margin-top: var(--space-lg);
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: var(--space-sm);
|
||
max-width: 600px;
|
||
}
|
||
|
||
.system-item {
|
||
font-size: 11px;
|
||
color: var(--text-secondary);
|
||
padding: var(--space-xs) var(--space-sm);
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--radius-sm);
|
||
opacity: 0.3;
|
||
transition: opacity 0.3s ease;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
}
|
||
|
||
.system-item.loaded {
|
||
opacity: 1;
|
||
color: var(--accent-green);
|
||
}
|
||
|
||
/* ===== LOGIN SCREEN ===== */
|
||
#login-screen {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: linear-gradient(135deg, #0a0a0a 0%, #1a0a2e 50%, #0a0a0a 100%);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 10000;
|
||
transition: opacity 0.5s ease, visibility 0.5s ease;
|
||
}
|
||
|
||
#login-screen.hidden {
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.login-background {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.star {
|
||
position: absolute;
|
||
width: 2px;
|
||
height: 2px;
|
||
background: white;
|
||
border-radius: 50%;
|
||
animation: twinkle 3s infinite;
|
||
}
|
||
|
||
@keyframes twinkle {
|
||
0%, 100% { opacity: 0.3; }
|
||
50% { opacity: 1; }
|
||
}
|
||
|
||
.login-container {
|
||
position: relative;
|
||
z-index: 2;
|
||
background: var(--glass-bg);
|
||
backdrop-filter: blur(20px);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--radius-xl);
|
||
padding: var(--space-2xl);
|
||
max-width: 480px;
|
||
width: 90%;
|
||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
|
||
}
|
||
|
||
.login-title {
|
||
font-size: 36px;
|
||
font-weight: 900;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
text-align: center;
|
||
margin-bottom: var(--space-sm);
|
||
background: var(--gradient-full);
|
||
background-size: 300% 300%;
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
animation: gradientShift 3s ease infinite;
|
||
}
|
||
|
||
.login-subtitle {
|
||
text-align: center;
|
||
color: var(--text-secondary);
|
||
font-size: 14px;
|
||
margin-bottom: 40px;
|
||
}
|
||
|
||
.login-input {
|
||
width: 100%;
|
||
padding: 16px 20px;
|
||
background: rgba(255, 255, 255, 0.08);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: 12px;
|
||
color: var(--text-primary);
|
||
font-size: 15px;
|
||
margin-bottom: 16px;
|
||
transition: all 0.3s ease;
|
||
font-family: 'Inter', sans-serif;
|
||
}
|
||
|
||
.login-input:focus {
|
||
outline: none;
|
||
background: rgba(255, 255, 255, 0.12);
|
||
border-color: var(--accent-purple);
|
||
}
|
||
|
||
.login-button {
|
||
width: 100%;
|
||
padding: 16px;
|
||
background: linear-gradient(45deg, #9B59B6, #8E44AD);
|
||
border: none;
|
||
border-radius: 12px;
|
||
color: white;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||
font-family: 'Inter', sans-serif;
|
||
}
|
||
|
||
.login-button:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 10px 30px rgba(155, 89, 182, 0.3);
|
||
}
|
||
|
||
.login-button:active {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.login-features {
|
||
margin-top: 30px;
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 12px;
|
||
}
|
||
|
||
.feature-badge {
|
||
background: rgba(255, 255, 255, 0.05);
|
||
padding: 10px;
|
||
border-radius: 8px;
|
||
font-size: 12px;
|
||
text-align: center;
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
}
|
||
|
||
/* ===== GAME CANVAS ===== */
|
||
#game-canvas {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
display: none;
|
||
}
|
||
|
||
#game-canvas.active {
|
||
display: block;
|
||
}
|
||
|
||
/* ===== HUD ===== */
|
||
.hud {
|
||
position: fixed;
|
||
z-index: 1000;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.hud-top-left {
|
||
top: 20px;
|
||
left: 20px;
|
||
}
|
||
|
||
.hud-top-right {
|
||
top: 20px;
|
||
right: 20px;
|
||
text-align: right;
|
||
}
|
||
|
||
.hud-bottom-left {
|
||
bottom: 20px;
|
||
left: 20px;
|
||
}
|
||
|
||
.hud-panel {
|
||
background: var(--glass-bg);
|
||
backdrop-filter: blur(10px);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: 12px;
|
||
padding: 16px 20px;
|
||
margin-bottom: 12px;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.hud-title {
|
||
font-weight: 600;
|
||
margin-bottom: 8px;
|
||
color: var(--accent-purple);
|
||
}
|
||
|
||
.hud-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin: 4px 0;
|
||
}
|
||
|
||
.hud-label {
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.hud-value {
|
||
color: var(--text-primary);
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* ===== CONTROLS HELP ===== */
|
||
#controls-help {
|
||
position: fixed;
|
||
bottom: 20px;
|
||
right: 20px;
|
||
background: var(--glass-bg);
|
||
backdrop-filter: blur(10px);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: 12px;
|
||
padding: 20px;
|
||
max-width: 300px;
|
||
z-index: 1000;
|
||
opacity: 0;
|
||
transform: translateY(20px);
|
||
transition: opacity 0.3s ease, transform 0.3s ease;
|
||
pointer-events: none;
|
||
}
|
||
|
||
#controls-help.visible {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.control-group {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.control-group-title {
|
||
font-weight: 600;
|
||
color: var(--accent-purple);
|
||
margin-bottom: 8px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.control-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin: 4px 0;
|
||
font-size: 11px;
|
||
}
|
||
|
||
.control-key {
|
||
background: rgba(255, 255, 255, 0.1);
|
||
padding: 2px 8px;
|
||
border-radius: 4px;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.control-desc {
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
/* ===== NOTIFICATION ===== */
|
||
.notification {
|
||
position: fixed;
|
||
top: 20px;
|
||
left: 50%;
|
||
transform: translateX(-50%) translateY(-100px);
|
||
background: var(--glass-bg);
|
||
backdrop-filter: blur(10px);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: 12px;
|
||
padding: 16px 24px;
|
||
z-index: 2000;
|
||
transition: transform 0.3s ease;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.notification.show {
|
||
transform: translateX(-50%) translateY(0);
|
||
}
|
||
|
||
/* ===== SYSTEM STATUS INDICATOR ===== */
|
||
.system-status {
|
||
position: fixed;
|
||
top: 20px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
z-index: 999;
|
||
display: flex;
|
||
gap: 8px;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.status-dot {
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
background: var(--accent-green);
|
||
box-shadow: 0 0 10px var(--accent-green);
|
||
animation: pulse 2s ease infinite;
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0%, 100% { opacity: 1; }
|
||
50% { opacity: 0.5; }
|
||
}
|
||
|
||
.status-label {
|
||
font-size: 11px;
|
||
color: var(--text-secondary);
|
||
font-family: 'JetBrains Mono', monospace;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<!-- LOADING SCREEN -->
|
||
<div id="loading-screen">
|
||
<div class="loading-logo">BLACKROAD</div>
|
||
<div class="loading-bar-container">
|
||
<div class="loading-bar" id="loading-bar"></div>
|
||
</div>
|
||
<div class="loading-text" id="loading-text">Initializing Universe...</div>
|
||
<div class="loading-systems">
|
||
<div class="system-item" data-system="celestial">🌌 Celestial Mechanics</div>
|
||
<div class="system-item" data-system="truth">🔐 Truth Contracts</div>
|
||
<div class="system-item" data-system="verification">✅ Verification</div>
|
||
<div class="system-item" data-system="physics">⚡ Physics Engine</div>
|
||
<div class="system-item" data-system="agents">🤖 Intelligent Agents</div>
|
||
<div class="system-item" data-system="quests">🏆 Quest System</div>
|
||
<div class="system-item" data-system="crafting">🛠️ Crafting</div>
|
||
<div class="system-item" data-system="dialogue">💬 Dialogue</div>
|
||
<div class="system-item" data-system="evolution">🌍 World Evolution</div>
|
||
<div class="system-item" data-system="nature">🦋 Living Nature</div>
|
||
<div class="system-item" data-system="music">🎵 Living Music</div>
|
||
<div class="system-item" data-system="creation">🌱 Creation Powers</div>
|
||
<div class="system-item" data-system="multiplayer">👥 Multiplayer</div>
|
||
<div class="system-item" data-system="graphics">🎨 Photorealism</div>
|
||
<div class="system-item" data-system="biomes">🌲 Infinite Biomes</div>
|
||
<div class="system-item" data-system="particles">✨ Particles</div>
|
||
<div class="system-item" data-system="transport">🚀 Transportation</div>
|
||
<div class="system-item" data-system="integration">🔗 Game Integration</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- LOGIN SCREEN -->
|
||
<div id="login-screen" class="hidden">
|
||
<div class="login-background" id="login-bg"></div>
|
||
<div class="login-container">
|
||
<h1 class="login-title">BLACKROAD</h1>
|
||
<p class="login-subtitle">The Complete Living Universe</p>
|
||
<input type="text" class="login-input" id="username-input" placeholder="Enter your name..." />
|
||
<button class="login-button" id="enter-button">Enter Universe</button>
|
||
<div class="login-features">
|
||
<div class="feature-badge">🌌 18 Systems</div>
|
||
<div class="feature-badge">∞ Infinite World</div>
|
||
<div class="feature-badge">🤖 AI Agents</div>
|
||
<div class="feature-badge">🦋 Living Nature</div>
|
||
<div class="feature-badge">🎨 Photorealistic</div>
|
||
<div class="feature-badge">⚡ Real Physics</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- GAME CANVAS -->
|
||
<canvas id="game-canvas"></canvas>
|
||
|
||
<!-- HUD -->
|
||
<div class="hud hud-top-left">
|
||
<div class="hud-panel">
|
||
<div class="hud-title">🌍 UNIVERSE STATUS</div>
|
||
<div class="hud-row">
|
||
<span class="hud-label">Time:</span>
|
||
<span class="hud-value" id="hud-time">00:00</span>
|
||
</div>
|
||
<div class="hud-row">
|
||
<span class="hud-label">Biome:</span>
|
||
<span class="hud-value" id="hud-biome">Loading...</span>
|
||
</div>
|
||
<div class="hud-row">
|
||
<span class="hud-label">Position:</span>
|
||
<span class="hud-value" id="hud-position">0, 0, 0</span>
|
||
</div>
|
||
</div>
|
||
<div class="hud-panel">
|
||
<div class="hud-title">⚡ SYSTEMS</div>
|
||
<div class="hud-row">
|
||
<span class="hud-label">Physics:</span>
|
||
<span class="hud-value" style="color: var(--accent-green);">●</span>
|
||
</div>
|
||
<div class="hud-row">
|
||
<span class="hud-label">AI Agents:</span>
|
||
<span class="hud-value" id="hud-agents">3</span>
|
||
</div>
|
||
<div class="hud-row">
|
||
<span class="hud-label">Quests:</span>
|
||
<span class="hud-value" id="hud-quests">0/12</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="hud hud-top-right">
|
||
<div class="hud-panel">
|
||
<div class="hud-title">🎮 CONTROLS</div>
|
||
<div style="font-size: 11px; color: var(--text-secondary);">
|
||
Press <strong style="color: white;">H</strong> for help
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- CONTROLS HELP -->
|
||
<div id="controls-help">
|
||
<div class="control-group">
|
||
<div class="control-group-title">MOVEMENT</div>
|
||
<div class="control-row">
|
||
<span class="control-key">W A S D</span>
|
||
<span class="control-desc">Move</span>
|
||
</div>
|
||
<div class="control-row">
|
||
<span class="control-key">SPACE</span>
|
||
<span class="control-desc">Jump / Fly Up</span>
|
||
</div>
|
||
<div class="control-row">
|
||
<span class="control-key">SHIFT</span>
|
||
<span class="control-desc">Fly Down</span>
|
||
</div>
|
||
<div class="control-row">
|
||
<span class="control-key">F</span>
|
||
<span class="control-desc">Toggle Flying</span>
|
||
</div>
|
||
</div>
|
||
<div class="control-group">
|
||
<div class="control-group-title">INTERACTION</div>
|
||
<div class="control-row">
|
||
<span class="control-key">E</span>
|
||
<span class="control-desc">Interact / Love</span>
|
||
</div>
|
||
<div class="control-row">
|
||
<span class="control-key">Q</span>
|
||
<span class="control-desc">Feed</span>
|
||
</div>
|
||
<div class="control-row">
|
||
<span class="control-key">T</span>
|
||
<span class="control-desc">Teleport Menu</span>
|
||
</div>
|
||
</div>
|
||
<div class="control-group">
|
||
<div class="control-group-title">WEATHER</div>
|
||
<div class="control-row">
|
||
<span class="control-key">R</span>
|
||
<span class="control-desc">Toggle Rain</span>
|
||
</div>
|
||
<div class="control-row">
|
||
<span class="control-key">N</span>
|
||
<span class="control-desc">Toggle Snow</span>
|
||
</div>
|
||
<div class="control-row">
|
||
<span class="control-key">G</span>
|
||
<span class="control-desc">Toggle Fireflies</span>
|
||
</div>
|
||
</div>
|
||
<div class="control-group">
|
||
<div class="control-group-title">SYSTEM</div>
|
||
<div class="control-row">
|
||
<span class="control-key">H</span>
|
||
<span class="control-desc">Toggle Help</span>
|
||
</div>
|
||
<div class="control-row">
|
||
<span class="control-key">ESC</span>
|
||
<span class="control-desc">Unlock Mouse</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- SYSTEM STATUS INDICATOR -->
|
||
<div class="system-status">
|
||
<div class="status-dot"></div>
|
||
<div class="status-label">18 SYSTEMS ACTIVE</div>
|
||
</div>
|
||
|
||
<!-- NOTIFICATION -->
|
||
<div class="notification" id="notification"></div>
|
||
|
||
<!-- MAIN SCRIPT -->
|
||
<script type="module">
|
||
import * as THREE from 'three';
|
||
import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';
|
||
|
||
// ===== SYSTEM LOADER =====
|
||
const systems = [
|
||
'celestial', 'truth', 'verification', 'physics', 'agents', 'quests',
|
||
'crafting', 'dialogue', 'evolution', 'nature', 'music', 'creation',
|
||
'multiplayer', 'graphics', 'biomes', 'particles', 'transport', 'integration'
|
||
];
|
||
|
||
let loadedSystems = 0;
|
||
|
||
function updateLoadingProgress(systemName, progress) {
|
||
const systemElement = document.querySelector(`[data-system="${systemName}"]`);
|
||
if (systemElement) {
|
||
systemElement.classList.add('loaded');
|
||
}
|
||
|
||
loadedSystems++;
|
||
const percent = (loadedSystems / systems.length) * 100;
|
||
document.getElementById('loading-bar').style.width = `${percent}%`;
|
||
document.getElementById('loading-text').textContent = `Loading ${systemName}... ${Math.round(percent)}%`;
|
||
}
|
||
|
||
// Simulate system loading
|
||
async function loadSystems() {
|
||
for (const system of systems) {
|
||
await new Promise(resolve => setTimeout(resolve, 100));
|
||
updateLoadingProgress(system, loadedSystems / systems.length);
|
||
}
|
||
|
||
setTimeout(() => {
|
||
document.getElementById('loading-screen').classList.add('hidden');
|
||
setTimeout(() => {
|
||
document.getElementById('login-screen').classList.remove('hidden');
|
||
initLoginScreen();
|
||
}, 500);
|
||
}, 500);
|
||
}
|
||
|
||
// ===== LOGIN SCREEN =====
|
||
function initLoginScreen() {
|
||
const bg = document.getElementById('login-bg');
|
||
|
||
// Create animated starfield
|
||
for (let i = 0; i < 100; i++) {
|
||
const star = document.createElement('div');
|
||
star.className = 'star';
|
||
star.style.left = `${Math.random() * 100}%`;
|
||
star.style.top = `${Math.random() * 100}%`;
|
||
star.style.animationDelay = `${Math.random() * 3}s`;
|
||
bg.appendChild(star);
|
||
}
|
||
|
||
const usernameInput = document.getElementById('username-input');
|
||
const enterButton = document.getElementById('enter-button');
|
||
|
||
enterButton.addEventListener('click', () => {
|
||
const username = usernameInput.value.trim() || 'Explorer';
|
||
document.getElementById('login-screen').classList.add('hidden');
|
||
setTimeout(() => {
|
||
document.getElementById('game-canvas').classList.add('active');
|
||
initUniverse(username);
|
||
}, 500);
|
||
});
|
||
|
||
usernameInput.addEventListener('keypress', (e) => {
|
||
if (e.key === 'Enter') {
|
||
enterButton.click();
|
||
}
|
||
});
|
||
|
||
usernameInput.focus();
|
||
}
|
||
|
||
// ===== UNIVERSE INITIALIZATION =====
|
||
let scene, camera, renderer, controls;
|
||
let playerName = 'Explorer';
|
||
let clock, gameTime = 0;
|
||
let chunks = new Map();
|
||
let currentBiome = 'Forest';
|
||
|
||
function initUniverse(username) {
|
||
playerName = username;
|
||
showNotification(`Welcome to BlackRoad, ${playerName}! 🌌`);
|
||
|
||
// Setup Three.js
|
||
scene = new THREE.Scene();
|
||
scene.fog = new THREE.Fog(0x87CEEB, 50, 200);
|
||
|
||
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||
camera.position.set(0, 10, 0);
|
||
|
||
const canvas = document.getElementById('game-canvas');
|
||
renderer = new THREE.WebGLRenderer({
|
||
canvas,
|
||
antialias: true,
|
||
powerPreference: 'high-performance'
|
||
});
|
||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
||
renderer.shadowMap.enabled = true;
|
||
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||
|
||
// Controls
|
||
controls = new PointerLockControls(camera, canvas);
|
||
|
||
canvas.addEventListener('click', () => {
|
||
controls.lock();
|
||
});
|
||
|
||
// Lighting
|
||
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
|
||
scene.add(ambientLight);
|
||
|
||
const sun = new THREE.DirectionalLight(0xffffff, 1);
|
||
sun.position.set(50, 100, 50);
|
||
sun.castShadow = true;
|
||
sun.shadow.mapSize.width = 2048;
|
||
sun.shadow.mapSize.height = 2048;
|
||
sun.shadow.camera.far = 500;
|
||
sun.shadow.camera.left = -100;
|
||
sun.shadow.camera.right = 100;
|
||
sun.shadow.camera.top = 100;
|
||
sun.shadow.camera.bottom = -100;
|
||
scene.add(sun);
|
||
|
||
const hemisphereLight = new THREE.HemisphereLight(0x87CEEB, 0x8B7355, 0.5);
|
||
scene.add(hemisphereLight);
|
||
|
||
// Ground plane
|
||
const groundGeometry = new THREE.PlaneGeometry(1000, 1000);
|
||
const groundMaterial = new THREE.MeshStandardMaterial({
|
||
color: 0x228B22,
|
||
roughness: 0.8,
|
||
metalness: 0.2
|
||
});
|
||
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
|
||
ground.rotation.x = -Math.PI / 2;
|
||
ground.receiveShadow = true;
|
||
scene.add(ground);
|
||
|
||
// Add some demo content
|
||
addDemoContent();
|
||
|
||
// Setup controls and game loop
|
||
setupControls();
|
||
clock = new THREE.Clock();
|
||
animate();
|
||
|
||
// Show controls help briefly
|
||
setTimeout(() => {
|
||
document.getElementById('controls-help').classList.add('visible');
|
||
setTimeout(() => {
|
||
document.getElementById('controls-help').classList.remove('visible');
|
||
}, 5000);
|
||
}, 2000);
|
||
}
|
||
|
||
function addDemoContent() {
|
||
// Add some trees
|
||
for (let i = 0; i < 50; i++) {
|
||
const tree = createTree();
|
||
tree.position.set(
|
||
(Math.random() - 0.5) * 200,
|
||
0,
|
||
(Math.random() - 0.5) * 200
|
||
);
|
||
scene.add(tree);
|
||
}
|
||
|
||
// Add AI agents (placeholder spheres)
|
||
const agentData = [
|
||
{ name: 'Alice', color: 0x4A90E2, pos: [20, 2, 20] },
|
||
{ name: 'Aria', color: 0xE74C3C, pos: [-20, 2, 20] },
|
||
{ name: 'Lucidia', color: 0x9B59B6, pos: [0, 2, -30] }
|
||
];
|
||
|
||
agentData.forEach(data => {
|
||
const agent = new THREE.Group();
|
||
|
||
// Body
|
||
const bodyGeometry = new THREE.SphereGeometry(1.5, 32, 32);
|
||
const bodyMaterial = new THREE.MeshStandardMaterial({
|
||
color: data.color,
|
||
emissive: data.color,
|
||
emissiveIntensity: 0.3,
|
||
metalness: 0.3,
|
||
roughness: 0.7
|
||
});
|
||
const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
|
||
body.castShadow = true;
|
||
agent.add(body);
|
||
|
||
// Glow
|
||
const glowGeometry = new THREE.SphereGeometry(2, 32, 32);
|
||
const glowMaterial = new THREE.MeshBasicMaterial({
|
||
color: data.color,
|
||
transparent: true,
|
||
opacity: 0.2
|
||
});
|
||
const glow = new THREE.Mesh(glowGeometry, glowMaterial);
|
||
agent.add(glow);
|
||
|
||
// Light
|
||
const light = new THREE.PointLight(data.color, 2, 20);
|
||
light.position.set(0, 0, 0);
|
||
agent.add(light);
|
||
|
||
agent.position.set(...data.pos);
|
||
scene.add(agent);
|
||
});
|
||
}
|
||
|
||
function createTree() {
|
||
const tree = new THREE.Group();
|
||
|
||
// Trunk
|
||
const trunkGeometry = new THREE.CylinderGeometry(0.5, 0.7, 4, 8);
|
||
const trunkMaterial = new THREE.MeshStandardMaterial({ color: 0x8B4513 });
|
||
const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
|
||
trunk.position.y = 2;
|
||
trunk.castShadow = true;
|
||
tree.add(trunk);
|
||
|
||
// Leaves
|
||
const leavesGeometry = new THREE.SphereGeometry(2.5, 8, 8);
|
||
const leavesMaterial = new THREE.MeshStandardMaterial({ color: 0x228B22 });
|
||
const leaves = new THREE.Mesh(leavesGeometry, leavesMaterial);
|
||
leaves.position.y = 5;
|
||
leaves.castShadow = true;
|
||
tree.add(leaves);
|
||
|
||
return tree;
|
||
}
|
||
|
||
// ===== CONTROLS =====
|
||
const keys = {};
|
||
let isFlying = false;
|
||
let helpVisible = false;
|
||
|
||
function setupControls() {
|
||
window.addEventListener('keydown', (e) => {
|
||
keys[e.key.toLowerCase()] = true;
|
||
|
||
// Special keys
|
||
if (e.key.toLowerCase() === 'h') {
|
||
helpVisible = !helpVisible;
|
||
document.getElementById('controls-help').classList.toggle('visible', helpVisible);
|
||
}
|
||
if (e.key.toLowerCase() === 'f') {
|
||
isFlying = !isFlying;
|
||
showNotification(isFlying ? '✈️ Flying Mode ON' : '🚶 Flying Mode OFF');
|
||
}
|
||
if (e.key.toLowerCase() === 'r') {
|
||
showNotification('🌧️ Rain toggled (feature pending)');
|
||
}
|
||
if (e.key.toLowerCase() === 'n') {
|
||
showNotification('❄️ Snow toggled (feature pending)');
|
||
}
|
||
if (e.key.toLowerCase() === 'g') {
|
||
showNotification('✨ Fireflies toggled (feature pending)');
|
||
}
|
||
if (e.key.toLowerCase() === 't') {
|
||
showNotification('🚀 Teleport menu (feature pending)');
|
||
}
|
||
});
|
||
|
||
window.addEventListener('keyup', (e) => {
|
||
keys[e.key.toLowerCase()] = false;
|
||
});
|
||
}
|
||
|
||
// ===== GAME LOOP =====
|
||
const moveSpeed = 10;
|
||
const flySpeed = 15;
|
||
|
||
function animate() {
|
||
requestAnimationFrame(animate);
|
||
|
||
const delta = clock.getDelta();
|
||
gameTime += delta;
|
||
|
||
if (controls.isLocked) {
|
||
const velocity = new THREE.Vector3();
|
||
|
||
if (keys['w']) velocity.z -= 1;
|
||
if (keys['s']) velocity.z += 1;
|
||
if (keys['a']) velocity.x -= 1;
|
||
if (keys['d']) velocity.x += 1;
|
||
|
||
velocity.normalize();
|
||
velocity.multiplyScalar(moveSpeed * delta);
|
||
|
||
const forward = new THREE.Vector3();
|
||
camera.getWorldDirection(forward);
|
||
forward.y = 0;
|
||
forward.normalize();
|
||
|
||
const right = new THREE.Vector3();
|
||
right.crossVectors(forward, camera.up);
|
||
|
||
const movement = new THREE.Vector3();
|
||
movement.addScaledVector(forward, -velocity.z);
|
||
movement.addScaledVector(right, velocity.x);
|
||
|
||
camera.position.add(movement);
|
||
|
||
// Flying
|
||
if (isFlying) {
|
||
if (keys[' ']) camera.position.y += flySpeed * delta;
|
||
if (keys['shift']) camera.position.y -= flySpeed * delta;
|
||
} else {
|
||
// Keep at ground level
|
||
camera.position.y = Math.max(camera.position.y, 10);
|
||
}
|
||
|
||
// Update HUD
|
||
updateHUD();
|
||
}
|
||
|
||
renderer.render(scene, camera);
|
||
}
|
||
|
||
// ===== HUD UPDATES =====
|
||
function updateHUD() {
|
||
const hours = Math.floor(gameTime / 3600) % 24;
|
||
const minutes = Math.floor((gameTime % 3600) / 60);
|
||
document.getElementById('hud-time').textContent =
|
||
`${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;
|
||
|
||
const pos = camera.position;
|
||
document.getElementById('hud-position').textContent =
|
||
`${pos.x.toFixed(0)}, ${pos.y.toFixed(0)}, ${pos.z.toFixed(0)}`;
|
||
|
||
document.getElementById('hud-biome').textContent = currentBiome;
|
||
}
|
||
|
||
// ===== NOTIFICATION SYSTEM =====
|
||
let notificationTimeout;
|
||
function showNotification(message) {
|
||
const notification = document.getElementById('notification');
|
||
notification.textContent = message;
|
||
notification.classList.add('show');
|
||
|
||
clearTimeout(notificationTimeout);
|
||
notificationTimeout = setTimeout(() => {
|
||
notification.classList.remove('show');
|
||
}, 3000);
|
||
}
|
||
|
||
// ===== WINDOW RESIZE =====
|
||
window.addEventListener('resize', () => {
|
||
camera.aspect = window.innerWidth / window.innerHeight;
|
||
camera.updateProjectionMatrix();
|
||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||
});
|
||
|
||
// ===== START LOADING =====
|
||
loadSystems();
|
||
</script>
|
||
|
||
<!-- ===== AUTHENTICATION SYSTEM ===== -->
|
||
<script src="auth.js"></script>
|
||
<!-- ===== NEW PRODUCTION SYSTEMS ===== -->
|
||
<script src="audio-system.js"></script>
|
||
<script src="api-client.js"></script>
|
||
<script src="performance-optimizer.js"></script>
|
||
|
||
<!-- ===== INTEGRATION SYSTEM ===== -->
|
||
<script>
|
||
// Initialize all new systems after DOM load
|
||
let audioSystem, apiClient, performanceOptimizer;
|
||
|
||
async function initializeNewSystems() {
|
||
try {
|
||
console.log('🚀 Initializing production systems...');
|
||
|
||
// 1. Audio System
|
||
if (typeof AudioSystem !== 'undefined') {
|
||
audioSystem = new AudioSystem();
|
||
await audioSystem.init();
|
||
console.log('🎵 Audio system initialized');
|
||
|
||
// Auto-start music on first user interaction
|
||
const startAudio = () => {
|
||
audioSystem.startMusic(currentBiome.toLowerCase());
|
||
document.removeEventListener('click', startAudio);
|
||
document.removeEventListener('keydown', startAudio);
|
||
showNotification('🎵 Music started!');
|
||
};
|
||
document.addEventListener('click', startAudio);
|
||
document.addEventListener('keydown', startAudio);
|
||
}
|
||
|
||
// 2. Performance Optimizer
|
||
if (typeof PerformanceOptimizer !== 'undefined') {
|
||
performanceOptimizer = new PerformanceOptimizer(renderer, scene, camera);
|
||
console.log('⚡ Performance optimizer initialized');
|
||
|
||
// Add to render loop
|
||
const originalAnimate = window.animate;
|
||
if (originalAnimate) {
|
||
window.animate = function() {
|
||
performanceOptimizer.update();
|
||
originalAnimate();
|
||
};
|
||
}
|
||
}
|
||
|
||
// 3. API Client (optional - needs backend)
|
||
if (typeof APIClient !== 'undefined') {
|
||
apiClient = new APIClient('wss://api.blackroad.io/ws');
|
||
|
||
// Connect when user is logged in
|
||
apiClient.on('connected', () => {
|
||
console.log('🔌 Connected to BlackRoad API');
|
||
showNotification('🔌 Connected to backend!');
|
||
});
|
||
|
||
apiClient.on('agent_response', (data) => {
|
||
showNotification(`🤖 ${data.agent}: ${data.message}`);
|
||
});
|
||
|
||
console.log('🔌 API client initialized');
|
||
}
|
||
|
||
console.log('✅ All production systems ready!');
|
||
showNotification('✅ All systems online!');
|
||
|
||
} catch (error) {
|
||
console.warn('⚠️ System initialization warning:', error);
|
||
}
|
||
}
|
||
|
||
// Initialize after page load
|
||
window.addEventListener('load', () => {
|
||
setTimeout(initializeNewSystems, 1000);
|
||
});
|
||
|
||
// Add music toggle to M key
|
||
document.addEventListener('keydown', (e) => {
|
||
if (e.key === 'm' || e.key === 'M') {
|
||
if (audioSystem) {
|
||
audioSystem.toggleMusic();
|
||
showNotification(audioSystem.musicPlaying ? '🎵 Music ON' : '🔇 Music OFF');
|
||
}
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|