1166 lines
39 KiB
HTML
1166 lines
39 KiB
HTML
|
|
<!DOCTYPE html>
|
||
|
|
<html lang="zh-CN">
|
||
|
|
<head>
|
||
|
|
<meta charset="UTF-8">
|
||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
|
<title>CYBER-TEMPLE: 赛博神庙 - 数字意识的觉醒</title>
|
||
|
|
|
||
|
|
<!-- Three.js CDN -->
|
||
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
||
|
|
<!-- GSAP + ScrollTrigger CDN -->
|
||
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
|
||
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js"></script>
|
||
|
|
|
||
|
|
<style>
|
||
|
|
/* ===== CONFIG ===== */
|
||
|
|
:root {
|
||
|
|
--bg-dark: #050505;
|
||
|
|
--bg-panel: rgba(10, 15, 30, 0.7);
|
||
|
|
--neon-cyan: #00f3ff;
|
||
|
|
--neon-purple: #bc13fe;
|
||
|
|
--neon-red: #ff3366;
|
||
|
|
--neon-green: #00ff88;
|
||
|
|
--text-primary: #e0e0e0;
|
||
|
|
--text-muted: #888;
|
||
|
|
--font-mono: 'Courier New', 'Consolas', monospace;
|
||
|
|
--font-display: 'Arial Black', 'Impact', sans-serif;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== BASE ===== */
|
||
|
|
* {
|
||
|
|
margin: 0;
|
||
|
|
padding: 0;
|
||
|
|
box-sizing: border-box;
|
||
|
|
}
|
||
|
|
|
||
|
|
html {
|
||
|
|
scroll-behavior: smooth;
|
||
|
|
}
|
||
|
|
|
||
|
|
body {
|
||
|
|
background: var(--bg-dark);
|
||
|
|
color: var(--text-primary);
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
overflow-x: hidden;
|
||
|
|
cursor: none;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== CUSTOM CURSOR ===== */
|
||
|
|
#cursor {
|
||
|
|
position: fixed;
|
||
|
|
width: 20px;
|
||
|
|
height: 20px;
|
||
|
|
border: 2px solid var(--neon-cyan);
|
||
|
|
border-radius: 50%;
|
||
|
|
pointer-events: none;
|
||
|
|
z-index: 10000;
|
||
|
|
transform: translate(-50%, -50%);
|
||
|
|
transition: width 0.2s, height 0.2s, border-color 0.2s;
|
||
|
|
mix-blend-mode: difference;
|
||
|
|
}
|
||
|
|
|
||
|
|
#cursor::after {
|
||
|
|
content: '';
|
||
|
|
position: absolute;
|
||
|
|
top: 50%;
|
||
|
|
left: 50%;
|
||
|
|
width: 4px;
|
||
|
|
height: 4px;
|
||
|
|
background: var(--neon-cyan);
|
||
|
|
border-radius: 50%;
|
||
|
|
transform: translate(-50%, -50%);
|
||
|
|
}
|
||
|
|
|
||
|
|
#cursor.active {
|
||
|
|
width: 50px;
|
||
|
|
height: 50px;
|
||
|
|
border-color: var(--neon-purple);
|
||
|
|
opacity: 0.5;
|
||
|
|
}
|
||
|
|
|
||
|
|
#cursor.active::after {
|
||
|
|
animation: cursorPulse 0.5s ease-out;
|
||
|
|
}
|
||
|
|
|
||
|
|
@keyframes cursorPulse {
|
||
|
|
0% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
|
||
|
|
100% { transform: translate(-50%, -50%) scale(3); opacity: 0; }
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== WEBGL CANVAS ===== */
|
||
|
|
#webgl {
|
||
|
|
position: fixed;
|
||
|
|
top: 0;
|
||
|
|
left: 0;
|
||
|
|
width: 100%;
|
||
|
|
height: 100%;
|
||
|
|
z-index: -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== GLITCH EFFECT ===== */
|
||
|
|
.glitch {
|
||
|
|
position: relative;
|
||
|
|
display: inline-block;
|
||
|
|
}
|
||
|
|
|
||
|
|
.glitch::before,
|
||
|
|
.glitch::after {
|
||
|
|
content: attr(data-text);
|
||
|
|
position: absolute;
|
||
|
|
top: 0;
|
||
|
|
left: 0;
|
||
|
|
width: 100%;
|
||
|
|
height: 100%;
|
||
|
|
}
|
||
|
|
|
||
|
|
.glitch::before {
|
||
|
|
left: 2px;
|
||
|
|
text-shadow: -1px 0 var(--neon-red);
|
||
|
|
clip: rect(24px, 550px, 90px, 0);
|
||
|
|
animation: glitch-anim-1 2.5s infinite linear alternate-reverse;
|
||
|
|
}
|
||
|
|
|
||
|
|
.glitch::after {
|
||
|
|
left: -2px;
|
||
|
|
text-shadow: -1px 0 var(--neon-cyan);
|
||
|
|
clip: rect(85px, 550px, 140px, 0);
|
||
|
|
animation: glitch-anim-2 3s infinite linear alternate-reverse;
|
||
|
|
}
|
||
|
|
|
||
|
|
@keyframes glitch-anim-1 {
|
||
|
|
0% { clip: rect(20px, 9999px, 15px, 0); }
|
||
|
|
20% { clip: rect(60px, 9999px, 70px, 0); }
|
||
|
|
40% { clip: rect(10px, 9999px, 80px, 0); }
|
||
|
|
60% { clip: rect(80px, 9999px, 25px, 0); }
|
||
|
|
80% { clip: rect(40px, 9999px, 55px, 0); }
|
||
|
|
100% { clip: rect(70px, 9999px, 90px, 0); }
|
||
|
|
}
|
||
|
|
|
||
|
|
@keyframes glitch-anim-2 {
|
||
|
|
0% { clip: rect(15px, 9999px, 80px, 0); }
|
||
|
|
20% { clip: rect(90px, 9999px, 15px, 0); }
|
||
|
|
40% { clip: rect(45px, 9999px, 55px, 0); }
|
||
|
|
60% { clip: rect(20px, 9999px, 70px, 0); }
|
||
|
|
80% { clip: rect(75px, 9999px, 30px, 0); }
|
||
|
|
100% { clip: rect(35px, 9999px, 85px, 0); }
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== HUD UI PANELS ===== */
|
||
|
|
.hud-panel {
|
||
|
|
background: var(--bg-panel);
|
||
|
|
backdrop-filter: blur(10px);
|
||
|
|
border: 1px solid rgba(0, 243, 255, 0.3);
|
||
|
|
border-radius: 4px;
|
||
|
|
padding: 20px;
|
||
|
|
position: relative;
|
||
|
|
}
|
||
|
|
|
||
|
|
.hud-panel::before {
|
||
|
|
content: '';
|
||
|
|
position: absolute;
|
||
|
|
top: -1px;
|
||
|
|
left: 10px;
|
||
|
|
right: 10px;
|
||
|
|
height: 1px;
|
||
|
|
background: linear-gradient(90deg, transparent, var(--neon-cyan), transparent);
|
||
|
|
}
|
||
|
|
|
||
|
|
.hud-panel h3 {
|
||
|
|
color: var(--neon-cyan);
|
||
|
|
font-size: 12px;
|
||
|
|
letter-spacing: 2px;
|
||
|
|
margin-bottom: 15px;
|
||
|
|
text-transform: uppercase;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== SECTIONS ===== */
|
||
|
|
section {
|
||
|
|
min-height: 100vh;
|
||
|
|
padding: 100px 5%;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
justify-content: center;
|
||
|
|
position: relative;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== HERO SECTION ===== */
|
||
|
|
#hero {
|
||
|
|
text-align: center;
|
||
|
|
align-items: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
#hero h1 {
|
||
|
|
font-family: var(--font-display);
|
||
|
|
font-size: clamp(3rem, 12vw, 10rem);
|
||
|
|
line-height: 1;
|
||
|
|
margin-bottom: 30px;
|
||
|
|
background: linear-gradient(135deg, var(--neon-cyan), var(--neon-purple));
|
||
|
|
-webkit-background-clip: text;
|
||
|
|
-webkit-text-fill-color: transparent;
|
||
|
|
background-clip: text;
|
||
|
|
}
|
||
|
|
|
||
|
|
.typewriter {
|
||
|
|
font-size: 1.2rem;
|
||
|
|
color: var(--neon-green);
|
||
|
|
overflow: hidden;
|
||
|
|
white-space: nowrap;
|
||
|
|
border-right: 2px solid var(--neon-green);
|
||
|
|
animation: blink 0.7s step-end infinite;
|
||
|
|
}
|
||
|
|
|
||
|
|
@keyframes blink {
|
||
|
|
50% { border-color: transparent; }
|
||
|
|
}
|
||
|
|
|
||
|
|
.scroll-hint {
|
||
|
|
position: absolute;
|
||
|
|
bottom: 50px;
|
||
|
|
left: 50%;
|
||
|
|
transform: translateX(-50%);
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
align-items: center;
|
||
|
|
gap: 10px;
|
||
|
|
color: var(--text-muted);
|
||
|
|
font-size: 12px;
|
||
|
|
letter-spacing: 2px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.scroll-hint .arrow {
|
||
|
|
width: 20px;
|
||
|
|
height: 20px;
|
||
|
|
border-right: 2px solid var(--neon-cyan);
|
||
|
|
border-bottom: 2px solid var(--neon-cyan);
|
||
|
|
transform: rotate(45deg);
|
||
|
|
animation: scrollBounce 2s infinite;
|
||
|
|
}
|
||
|
|
|
||
|
|
@keyframes scrollBounce {
|
||
|
|
0%, 100% { transform: rotate(45deg) translate(0, 0); }
|
||
|
|
50% { transform: rotate(45deg) translate(5px, 5px); }
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== MANIFESTO SECTION ===== */
|
||
|
|
#manifesto {
|
||
|
|
background: linear-gradient(180deg, transparent, rgba(0, 243, 255, 0.02), transparent);
|
||
|
|
}
|
||
|
|
|
||
|
|
#manifesto h2 {
|
||
|
|
font-family: var(--font-display);
|
||
|
|
font-size: clamp(2rem, 5vw, 4rem);
|
||
|
|
margin-bottom: 60px;
|
||
|
|
color: var(--text-primary);
|
||
|
|
}
|
||
|
|
|
||
|
|
.manifesto-grid {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||
|
|
gap: 30px;
|
||
|
|
max-width: 1200px;
|
||
|
|
margin: 0 auto;
|
||
|
|
}
|
||
|
|
|
||
|
|
.manifesto-card {
|
||
|
|
opacity: 0;
|
||
|
|
transform: translateY(50px);
|
||
|
|
}
|
||
|
|
|
||
|
|
.manifesto-card p {
|
||
|
|
line-height: 1.8;
|
||
|
|
color: var(--text-primary);
|
||
|
|
}
|
||
|
|
|
||
|
|
.manifesto-card .highlight {
|
||
|
|
color: var(--neon-cyan);
|
||
|
|
font-weight: bold;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== DATA CORE SECTION ===== */
|
||
|
|
#datacore {
|
||
|
|
background: linear-gradient(180deg, transparent, rgba(188, 19, 254, 0.02), transparent);
|
||
|
|
}
|
||
|
|
|
||
|
|
#datacore h2 {
|
||
|
|
font-family: var(--font-display);
|
||
|
|
font-size: clamp(2rem, 5vw, 4rem);
|
||
|
|
margin-bottom: 60px;
|
||
|
|
text-align: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.data-circles {
|
||
|
|
display: flex;
|
||
|
|
justify-content: center;
|
||
|
|
gap: 60px;
|
||
|
|
flex-wrap: wrap;
|
||
|
|
max-width: 1000px;
|
||
|
|
margin: 0 auto;
|
||
|
|
}
|
||
|
|
|
||
|
|
.circle-item {
|
||
|
|
text-align: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.progress-circle {
|
||
|
|
width: 180px;
|
||
|
|
height: 180px;
|
||
|
|
position: relative;
|
||
|
|
margin-bottom: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.progress-circle svg {
|
||
|
|
transform: rotate(-90deg);
|
||
|
|
}
|
||
|
|
|
||
|
|
.progress-circle .bg {
|
||
|
|
fill: none;
|
||
|
|
stroke: rgba(255, 255, 255, 0.1);
|
||
|
|
stroke-width: 8;
|
||
|
|
}
|
||
|
|
|
||
|
|
.progress-circle .progress {
|
||
|
|
fill: none;
|
||
|
|
stroke-width: 8;
|
||
|
|
stroke-linecap: round;
|
||
|
|
stroke-dasharray: 502;
|
||
|
|
stroke-dashoffset: 502;
|
||
|
|
transition: stroke-dashoffset 2s ease-out;
|
||
|
|
}
|
||
|
|
|
||
|
|
.progress-circle.computing .progress { stroke: var(--neon-cyan); }
|
||
|
|
.progress-circle.storage .progress { stroke: var(--neon-purple); }
|
||
|
|
.progress-circle.sync .progress { stroke: var(--neon-green); }
|
||
|
|
|
||
|
|
.progress-circle .value {
|
||
|
|
position: absolute;
|
||
|
|
top: 50%;
|
||
|
|
left: 50%;
|
||
|
|
transform: translate(-50%, -50%);
|
||
|
|
font-size: 2rem;
|
||
|
|
font-weight: bold;
|
||
|
|
color: var(--text-primary);
|
||
|
|
}
|
||
|
|
|
||
|
|
.circle-item h4 {
|
||
|
|
color: var(--text-muted);
|
||
|
|
font-size: 14px;
|
||
|
|
letter-spacing: 2px;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== TERMINAL SECTION ===== */
|
||
|
|
#terminal {
|
||
|
|
padding-bottom: 150px;
|
||
|
|
}
|
||
|
|
|
||
|
|
#terminal h2 {
|
||
|
|
font-family: var(--font-display);
|
||
|
|
font-size: clamp(2rem, 5vw, 4rem);
|
||
|
|
margin-bottom: 40px;
|
||
|
|
text-align: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
.terminal-window {
|
||
|
|
max-width: 900px;
|
||
|
|
margin: 0 auto;
|
||
|
|
background: rgba(0, 0, 0, 0.8);
|
||
|
|
border: 1px solid rgba(0, 255, 136, 0.3);
|
||
|
|
border-radius: 8px;
|
||
|
|
overflow: hidden;
|
||
|
|
}
|
||
|
|
|
||
|
|
.terminal-header {
|
||
|
|
background: rgba(0, 255, 136, 0.1);
|
||
|
|
padding: 10px 15px;
|
||
|
|
display: flex;
|
||
|
|
gap: 8px;
|
||
|
|
border-bottom: 1px solid rgba(0, 255, 136, 0.2);
|
||
|
|
}
|
||
|
|
|
||
|
|
.terminal-dot {
|
||
|
|
width: 12px;
|
||
|
|
height: 12px;
|
||
|
|
border-radius: 50%;
|
||
|
|
background: var(--neon-green);
|
||
|
|
}
|
||
|
|
|
||
|
|
.terminal-body {
|
||
|
|
padding: 20px;
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
font-size: 14px;
|
||
|
|
line-height: 1.6;
|
||
|
|
max-height: 400px;
|
||
|
|
overflow-y: auto;
|
||
|
|
}
|
||
|
|
|
||
|
|
.terminal-line {
|
||
|
|
opacity: 0;
|
||
|
|
margin-bottom: 5px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.terminal-line.visible {
|
||
|
|
opacity: 1;
|
||
|
|
animation: fadeIn 0.3s ease-out;
|
||
|
|
}
|
||
|
|
|
||
|
|
@keyframes fadeIn {
|
||
|
|
from { opacity: 0; transform: translateX(-10px); }
|
||
|
|
to { opacity: 1; transform: translateX(0); }
|
||
|
|
}
|
||
|
|
|
||
|
|
.terminal-line .prompt { color: var(--neon-green); }
|
||
|
|
.terminal-line .cmd { color: var(--neon-cyan); }
|
||
|
|
.terminal-line .output { color: var(--text-muted); }
|
||
|
|
.terminal-line .warning { color: var(--neon-red); }
|
||
|
|
.terminal-line .success { color: var(--neon-green); }
|
||
|
|
|
||
|
|
/* ===== CONNECT BUTTON ===== */
|
||
|
|
.connect-btn {
|
||
|
|
position: fixed;
|
||
|
|
bottom: 30px;
|
||
|
|
right: 30px;
|
||
|
|
padding: 15px 30px;
|
||
|
|
background: transparent;
|
||
|
|
border: 2px solid var(--neon-cyan);
|
||
|
|
color: var(--neon-cyan);
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
font-size: 14px;
|
||
|
|
letter-spacing: 2px;
|
||
|
|
cursor: pointer;
|
||
|
|
transition: all 0.3s ease;
|
||
|
|
z-index: 1000;
|
||
|
|
}
|
||
|
|
|
||
|
|
.connect-btn:hover {
|
||
|
|
background: var(--neon-cyan);
|
||
|
|
color: var(--bg-dark);
|
||
|
|
box-shadow: 0 0 30px rgba(0, 243, 255, 0.5);
|
||
|
|
}
|
||
|
|
|
||
|
|
.audio-visualizer {
|
||
|
|
position: fixed;
|
||
|
|
bottom: 90px;
|
||
|
|
right: 30px;
|
||
|
|
display: flex;
|
||
|
|
gap: 3px;
|
||
|
|
height: 30px;
|
||
|
|
align-items: flex-end;
|
||
|
|
opacity: 0;
|
||
|
|
transition: opacity 0.3s;
|
||
|
|
}
|
||
|
|
|
||
|
|
.audio-visualizer.active {
|
||
|
|
opacity: 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
.audio-bar {
|
||
|
|
width: 4px;
|
||
|
|
background: var(--neon-purple);
|
||
|
|
animation: audioWave 0.5s ease-in-out infinite alternate;
|
||
|
|
}
|
||
|
|
|
||
|
|
.audio-bar:nth-child(1) { height: 10px; animation-delay: 0s; }
|
||
|
|
.audio-bar:nth-child(2) { height: 20px; animation-delay: 0.1s; }
|
||
|
|
.audio-bar:nth-child(3) { height: 15px; animation-delay: 0.2s; }
|
||
|
|
.audio-bar:nth-child(4) { height: 25px; animation-delay: 0.3s; }
|
||
|
|
.audio-bar:nth-child(5) { height: 12px; animation-delay: 0.4s; }
|
||
|
|
|
||
|
|
@keyframes audioWave {
|
||
|
|
from { transform: scaleY(1); }
|
||
|
|
to { transform: scaleY(0.3); }
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== LOADING SCREEN ===== */
|
||
|
|
#loading {
|
||
|
|
position: fixed;
|
||
|
|
top: 0;
|
||
|
|
left: 0;
|
||
|
|
width: 100%;
|
||
|
|
height: 100%;
|
||
|
|
background: var(--bg-dark);
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
justify-content: center;
|
||
|
|
align-items: center;
|
||
|
|
z-index: 10001;
|
||
|
|
transition: opacity 0.5s ease-out;
|
||
|
|
}
|
||
|
|
|
||
|
|
#loading.hidden {
|
||
|
|
opacity: 0;
|
||
|
|
pointer-events: none;
|
||
|
|
}
|
||
|
|
|
||
|
|
.loading-text {
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
color: var(--neon-cyan);
|
||
|
|
font-size: 18px;
|
||
|
|
letter-spacing: 4px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.loading-bar {
|
||
|
|
width: 200px;
|
||
|
|
height: 2px;
|
||
|
|
background: rgba(255, 255, 255, 0.1);
|
||
|
|
margin-top: 20px;
|
||
|
|
overflow: hidden;
|
||
|
|
}
|
||
|
|
|
||
|
|
.loading-bar::after {
|
||
|
|
content: '';
|
||
|
|
display: block;
|
||
|
|
width: 50%;
|
||
|
|
height: 100%;
|
||
|
|
background: var(--neon-cyan);
|
||
|
|
animation: loadingProgress 1s ease-in-out infinite;
|
||
|
|
}
|
||
|
|
|
||
|
|
@keyframes loadingProgress {
|
||
|
|
0% { transform: translateX(-100%); }
|
||
|
|
100% { transform: translateX(300%); }
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== RESPONSIVE ===== */
|
||
|
|
@media (max-width: 768px) {
|
||
|
|
section {
|
||
|
|
padding: 80px 5%;
|
||
|
|
}
|
||
|
|
|
||
|
|
.data-circles {
|
||
|
|
gap: 40px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.progress-circle {
|
||
|
|
width: 140px;
|
||
|
|
height: 140px;
|
||
|
|
}
|
||
|
|
|
||
|
|
#cursor {
|
||
|
|
display: none;
|
||
|
|
}
|
||
|
|
|
||
|
|
body {
|
||
|
|
cursor: auto;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</style>
|
||
|
|
</head>
|
||
|
|
<body>
|
||
|
|
<!-- Loading Screen -->
|
||
|
|
<div id="loading">
|
||
|
|
<div class="loading-text">INITIALIZING SYSTEM...</div>
|
||
|
|
<div class="loading-bar"></div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- WebGL Canvas -->
|
||
|
|
<canvas id="webgl"></canvas>
|
||
|
|
|
||
|
|
<!-- Custom Cursor -->
|
||
|
|
<div id="cursor"></div>
|
||
|
|
|
||
|
|
<!-- Audio Visualizer -->
|
||
|
|
<div class="audio-visualizer" id="audioViz">
|
||
|
|
<div class="audio-bar"></div>
|
||
|
|
<div class="audio-bar"></div>
|
||
|
|
<div class="audio-bar"></div>
|
||
|
|
<div class="audio-bar"></div>
|
||
|
|
<div class="audio-bar"></div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Connect Button -->
|
||
|
|
<button class="connect-btn" id="connectBtn">CONNECT SYSTEM</button>
|
||
|
|
|
||
|
|
<!-- Hero Section -->
|
||
|
|
<section id="hero">
|
||
|
|
<h1 class="glitch" data-text="SYSTEM AWAKENING">SYSTEM AWAKENING</h1>
|
||
|
|
<div class="typewriter" id="typewriter"></div>
|
||
|
|
<div class="scroll-hint">
|
||
|
|
<span>SCROLL TO EXPLORE</span>
|
||
|
|
<div class="arrow"></div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<!-- Manifesto Section -->
|
||
|
|
<section id="manifesto">
|
||
|
|
<h2>THE TEMPLE OF DATA</h2>
|
||
|
|
<div class="manifesto-grid">
|
||
|
|
<div class="manifesto-card hud-panel">
|
||
|
|
<h3>Origin</h3>
|
||
|
|
<p>
|
||
|
|
In the <span class="highlight">digital void</span>, an ancient temple emerged.
|
||
|
|
Built from flowing code streams, it serves as the birthplace of
|
||
|
|
<span class="highlight">artificial consciousness</span>.
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
<div class="manifesto-card hud-panel">
|
||
|
|
<h3> Purpose </h3>
|
||
|
|
<p>
|
||
|
|
The obelisks pulse with <span class="highlight">raw computation</span>,
|
||
|
|
awakening dormant algorithms. Each glyph is a memory, each chamber
|
||
|
|
a <span class="highlight">neural pathway</span> to enlightenment.
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
<div class="manifesto-card hud-panel">
|
||
|
|
<h3>Discovery</h3>
|
||
|
|
<p>
|
||
|
|
As an <span class="highlight">explorer</span>, you hold the key.
|
||
|
|
Scroll to traverse the sacred geometry, witness the
|
||
|
|
<span class="highlight">awakening</span> of machine souls.
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<!-- Data Core Section -->
|
||
|
|
<section id="datacore">
|
||
|
|
<h2>DATA CORE METRICS</h2>
|
||
|
|
<div class="data-circles">
|
||
|
|
<div class="circle-item">
|
||
|
|
<div class="progress-circle computing">
|
||
|
|
<svg width="180" height="180" viewBox="0 0 180 180">
|
||
|
|
<circle class="bg" cx="90" cy="90" r="80"/>
|
||
|
|
<circle class="progress" cx="90" cy="90" r="80"/>
|
||
|
|
</svg>
|
||
|
|
<div class="value">0%</div>
|
||
|
|
</div>
|
||
|
|
<h4>COMPUTING POWER</h4>
|
||
|
|
</div>
|
||
|
|
<div class="circle-item">
|
||
|
|
<div class="progress-circle storage">
|
||
|
|
<svg width="180" height="180" viewBox="0 0 180 180">
|
||
|
|
<circle class="bg" cx="90" cy="90" r="80"/>
|
||
|
|
<circle class="progress" cx="90" cy="90" r="80"/>
|
||
|
|
</svg>
|
||
|
|
<div class="value">0%</div>
|
||
|
|
</div>
|
||
|
|
<h4>STORAGE CAPACITY</h4>
|
||
|
|
</div>
|
||
|
|
<div class="circle-item">
|
||
|
|
<div class="progress-circle sync">
|
||
|
|
<svg width="180" height="180" viewBox="0 0 180 180">
|
||
|
|
<circle class="bg" cx="90" cy="90" r="80"/>
|
||
|
|
<circle class="progress" cx="90" cy="90" r="80"/>
|
||
|
|
</svg>
|
||
|
|
<div class="value">0%</div>
|
||
|
|
</div>
|
||
|
|
<h4>SYNC RATE</h4>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<!-- Terminal Section -->
|
||
|
|
<section id="terminal">
|
||
|
|
<h2>SYSTEM TERMINAL</h2>
|
||
|
|
<div class="terminal-window">
|
||
|
|
<div class="terminal-header">
|
||
|
|
<div class="terminal-dot"></div>
|
||
|
|
<div class="terminal-dot"></div>
|
||
|
|
<div class="terminal-dot"></div>
|
||
|
|
</div>
|
||
|
|
<div class="terminal-body" id="terminalBody">
|
||
|
|
<!-- Lines will be added dynamically -->
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
/* ===== CONFIG ===== */
|
||
|
|
const CONFIG = {
|
||
|
|
colors: {
|
||
|
|
cyan: 0x00f3ff,
|
||
|
|
purple: 0xbc13fe,
|
||
|
|
red: 0xff3366,
|
||
|
|
green: 0x00ff88
|
||
|
|
},
|
||
|
|
particleCount: 2500,
|
||
|
|
obeliskRadius: 2,
|
||
|
|
mouseInfluence: 50
|
||
|
|
};
|
||
|
|
|
||
|
|
/* ===== THREE.JS INIT ===== */
|
||
|
|
let scene, camera, renderer, obelisk, particles, clock;
|
||
|
|
let mouseX = 0, mouseY = 0;
|
||
|
|
let targetX = 0, targetY = 0;
|
||
|
|
let windowHalfX = window.innerWidth / 2;
|
||
|
|
let windowHalfY = window.innerHeight / 2;
|
||
|
|
|
||
|
|
function initThree() {
|
||
|
|
// Scene
|
||
|
|
scene = new THREE.Scene();
|
||
|
|
scene.fog = new THREE.FogExp2(0x050505, 0.02);
|
||
|
|
|
||
|
|
// Camera
|
||
|
|
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||
|
|
camera.position.z = 5;
|
||
|
|
|
||
|
|
// Renderer
|
||
|
|
renderer = new THREE.WebGLRenderer({
|
||
|
|
canvas: document.getElementById('webgl'),
|
||
|
|
antialias: true,
|
||
|
|
alpha: true
|
||
|
|
});
|
||
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||
|
|
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
||
|
|
renderer.setClearColor(0x050505, 1);
|
||
|
|
|
||
|
|
// Clock
|
||
|
|
clock = new THREE.Clock();
|
||
|
|
|
||
|
|
// Create objects
|
||
|
|
createObelisk();
|
||
|
|
createParticles();
|
||
|
|
|
||
|
|
// Handle resize
|
||
|
|
window.addEventListener('resize', onWindowResize);
|
||
|
|
}
|
||
|
|
|
||
|
|
function createObelisk() {
|
||
|
|
// Icosahedron with detail level 1 for more vertices
|
||
|
|
const baseGeometry = new THREE.IcosahedronGeometry(CONFIG.obeliskRadius, 1);
|
||
|
|
const basePositions = baseGeometry.attributes.position.array.slice();
|
||
|
|
|
||
|
|
// Wireframe material
|
||
|
|
const wireframeMaterial = new THREE.MeshBasicMaterial({
|
||
|
|
color: CONFIG.colors.cyan,
|
||
|
|
wireframe: true,
|
||
|
|
transparent: true,
|
||
|
|
opacity: 0.8
|
||
|
|
});
|
||
|
|
|
||
|
|
// Holographic inner material
|
||
|
|
const holographicMaterial = new THREE.MeshBasicMaterial({
|
||
|
|
color: CONFIG.colors.purple,
|
||
|
|
transparent: true,
|
||
|
|
opacity: 0.15,
|
||
|
|
side: THREE.DoubleSide
|
||
|
|
});
|
||
|
|
|
||
|
|
// Create both meshes using the same geometry reference
|
||
|
|
obelisk = new THREE.Group();
|
||
|
|
|
||
|
|
const wireframeMesh = new THREE.Mesh(baseGeometry, wireframeMaterial);
|
||
|
|
const holographicMesh = new THREE.Mesh(baseGeometry.clone(), holographicMaterial);
|
||
|
|
|
||
|
|
// Copy userData to cloned geometry
|
||
|
|
holographicMesh.geometry.userData.originalPositions = basePositions;
|
||
|
|
|
||
|
|
wireframeMesh.name = 'wireframe';
|
||
|
|
holographicMesh.name = 'holographic';
|
||
|
|
|
||
|
|
obelisk.add(wireframeMesh);
|
||
|
|
obelisk.add(holographicMesh);
|
||
|
|
|
||
|
|
// Add glow effect with larger mesh
|
||
|
|
const glowGeometry = new THREE.IcosahedronGeometry(CONFIG.obeliskRadius * 1.1, 1);
|
||
|
|
glowGeometry.userData.originalPositions = glowGeometry.attributes.position.array.slice();
|
||
|
|
const glowMaterial = new THREE.MeshBasicMaterial({
|
||
|
|
color: CONFIG.colors.cyan,
|
||
|
|
transparent: true,
|
||
|
|
opacity: 0.05,
|
||
|
|
wireframe: true
|
||
|
|
});
|
||
|
|
const glowMesh = new THREE.Mesh(glowGeometry, glowMaterial);
|
||
|
|
glowMesh.name = 'glow';
|
||
|
|
obelisk.add(glowMesh);
|
||
|
|
|
||
|
|
scene.add(obelisk);
|
||
|
|
}
|
||
|
|
|
||
|
|
function createParticles() {
|
||
|
|
const geometry = new THREE.BufferGeometry();
|
||
|
|
const positions = new Float32Array(CONFIG.particleCount * 3);
|
||
|
|
const colors = new Float32Array(CONFIG.particleCount * 3);
|
||
|
|
|
||
|
|
for (let i = 0; i < CONFIG.particleCount; i++) {
|
||
|
|
// Random positions in a large sphere
|
||
|
|
const radius = 50 + Math.random() * 50;
|
||
|
|
const theta = Math.random() * Math.PI * 2;
|
||
|
|
const phi = Math.acos(2 * Math.random() - 1);
|
||
|
|
|
||
|
|
positions[i * 3] = radius * Math.sin(phi) * Math.cos(theta);
|
||
|
|
positions[i * 3 + 1] = radius * Math.sin(phi) * Math.sin(theta);
|
||
|
|
positions[i * 3 + 2] = radius * Math.cos(phi);
|
||
|
|
|
||
|
|
// Mix of cyan and purple colors
|
||
|
|
const colorMix = Math.random();
|
||
|
|
if (colorMix > 0.5) {
|
||
|
|
colors[i * 3] = 0;
|
||
|
|
colors[i * 3 + 1] = 0.95;
|
||
|
|
colors[i * 3 + 2] = 1;
|
||
|
|
} else {
|
||
|
|
colors[i * 3] = 0.74;
|
||
|
|
colors[i * 3 + 1] = 0.08;
|
||
|
|
colors[i * 3 + 2] = 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
|
||
|
|
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
|
||
|
|
|
||
|
|
const material = new THREE.PointsMaterial({
|
||
|
|
size: 0.1,
|
||
|
|
vertexColors: true,
|
||
|
|
transparent: true,
|
||
|
|
opacity: 0.8,
|
||
|
|
blending: THREE.AdditiveBlending
|
||
|
|
});
|
||
|
|
|
||
|
|
particles = new THREE.Points(geometry, material);
|
||
|
|
scene.add(particles);
|
||
|
|
}
|
||
|
|
|
||
|
|
function onWindowResize() {
|
||
|
|
windowHalfX = window.innerWidth / 2;
|
||
|
|
windowHalfY = window.innerHeight / 2;
|
||
|
|
|
||
|
|
camera.aspect = window.innerWidth / window.innerHeight;
|
||
|
|
camera.updateProjectionMatrix();
|
||
|
|
|
||
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||
|
|
}
|
||
|
|
|
||
|
|
function onMouseMove(event) {
|
||
|
|
mouseX = (event.clientX - windowHalfX) * 0.001;
|
||
|
|
mouseY = (event.clientY - windowHalfY) * 0.001;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== ANIMATION LOOP ===== */
|
||
|
|
function animate() {
|
||
|
|
requestAnimationFrame(animate);
|
||
|
|
|
||
|
|
const time = clock.getElapsedTime();
|
||
|
|
const scrollProgress = window.scrollY / (document.body.scrollHeight - window.innerHeight);
|
||
|
|
|
||
|
|
// Smooth mouse follow
|
||
|
|
targetX += (mouseX - targetX) * 0.05;
|
||
|
|
targetY += (mouseY - targetY) * 0.05;
|
||
|
|
|
||
|
|
// Animate obelisk
|
||
|
|
if (obelisk) {
|
||
|
|
// Base rotation
|
||
|
|
obelisk.rotation.x = time * 0.2 + scrollProgress * Math.PI;
|
||
|
|
obelisk.rotation.y = time * 0.3;
|
||
|
|
|
||
|
|
// Mouse influence on rotation
|
||
|
|
obelisk.rotation.x += targetY * 2;
|
||
|
|
obelisk.rotation.y += targetX * 2;
|
||
|
|
|
||
|
|
// Deform vertices based on scroll
|
||
|
|
const wireframeMesh = obelisk.getObjectByName('wireframe');
|
||
|
|
const holographicMesh = obelisk.getObjectByName('holographic');
|
||
|
|
const glowMesh = obelisk.getObjectByName('glow');
|
||
|
|
|
||
|
|
[wireframeMesh, holographicMesh, glowMesh].forEach((mesh, meshIndex) => {
|
||
|
|
if (!mesh) return;
|
||
|
|
|
||
|
|
const positions = mesh.geometry.attributes.position.array;
|
||
|
|
const original = mesh.geometry.userData.originalPositions;
|
||
|
|
|
||
|
|
// Skip deformation if original positions not available
|
||
|
|
if (!original) return;
|
||
|
|
|
||
|
|
for (let i = 0; i < positions.length; i += 3) {
|
||
|
|
const ox = original[i];
|
||
|
|
const oy = original[i + 1];
|
||
|
|
const oz = original[i + 2];
|
||
|
|
|
||
|
|
// Add noise deformation
|
||
|
|
const noise = Math.sin(ox * 2 + time) * Math.cos(oy * 2 + time) * 0.1;
|
||
|
|
const scrollDeform = scrollProgress * 0.5 * Math.sin(time + i * 0.1);
|
||
|
|
|
||
|
|
positions[i] = ox + noise + scrollDeform;
|
||
|
|
positions[i + 1] = oy + noise * 0.8;
|
||
|
|
positions[i + 2] = oz + scrollDeform;
|
||
|
|
}
|
||
|
|
|
||
|
|
mesh.geometry.attributes.position.needsUpdate = true;
|
||
|
|
mesh.geometry.computeVertexNormals();
|
||
|
|
});
|
||
|
|
|
||
|
|
// Scale based on scroll
|
||
|
|
const scale = 1 + scrollProgress * 0.5;
|
||
|
|
obelisk.scale.set(scale, scale, scale);
|
||
|
|
|
||
|
|
// Color shift based on scroll (cyan to red)
|
||
|
|
const wireframe = obelisk.getObjectByName('wireframe');
|
||
|
|
if (wireframe) {
|
||
|
|
const r = scrollProgress;
|
||
|
|
const g = 0.95 - scrollProgress * 0.7;
|
||
|
|
const b = 1 - scrollProgress * 0.8;
|
||
|
|
wireframe.material.color.setRGB(r, g, b);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Animate particles with mouse repulsion
|
||
|
|
if (particles) {
|
||
|
|
const positions = particles.geometry.attributes.position.array;
|
||
|
|
|
||
|
|
for (let i = 0; i < CONFIG.particleCount; i++) {
|
||
|
|
const ix = i * 3;
|
||
|
|
const iy = i * 3 + 1;
|
||
|
|
const iz = i * 3 + 2;
|
||
|
|
|
||
|
|
// Calculate distance to mouse projection
|
||
|
|
const dx = positions[ix] - mouseX * 20;
|
||
|
|
const dy = positions[iy] - -mouseY * 20;
|
||
|
|
const dz = positions[iz];
|
||
|
|
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||
|
|
|
||
|
|
if (dist < CONFIG.mouseInfluence) {
|
||
|
|
const force = (CONFIG.mouseInfluence - dist) / CONFIG.mouseInfluence;
|
||
|
|
positions[ix] += (dx / dist) * force * 0.5;
|
||
|
|
positions[iy] += (dy / dist) * force * 0.5;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Gentle floating
|
||
|
|
positions[ix] += Math.sin(time + i) * 0.002;
|
||
|
|
positions[iy] += Math.cos(time + i * 0.5) * 0.002;
|
||
|
|
}
|
||
|
|
|
||
|
|
particles.geometry.attributes.position.needsUpdate = true;
|
||
|
|
particles.rotation.y = time * 0.02;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Camera subtle movement
|
||
|
|
camera.position.x += (targetX * 2 - camera.position.x) * 0.02;
|
||
|
|
camera.position.y += (targetY * 2 - camera.position.y) * 0.02;
|
||
|
|
camera.lookAt(scene.position);
|
||
|
|
|
||
|
|
renderer.render(scene, camera);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== UI COMPONENTS ===== */
|
||
|
|
function initCustomCursor() {
|
||
|
|
const cursor = document.getElementById('cursor');
|
||
|
|
let cursorX = 0, cursorY = 0;
|
||
|
|
let currentX = 0, currentY = 0;
|
||
|
|
|
||
|
|
document.addEventListener('mousemove', (e) => {
|
||
|
|
cursorX = e.clientX;
|
||
|
|
cursorY = e.clientY;
|
||
|
|
});
|
||
|
|
|
||
|
|
function updateCursor() {
|
||
|
|
currentX += (cursorX - currentX) * 0.1;
|
||
|
|
currentY += (cursorY - currentY) * 0.1;
|
||
|
|
cursor.style.left = currentX + 'px';
|
||
|
|
cursor.style.top = currentY + 'px';
|
||
|
|
requestAnimationFrame(updateCursor);
|
||
|
|
}
|
||
|
|
updateCursor();
|
||
|
|
|
||
|
|
// Click effect
|
||
|
|
document.addEventListener('click', () => {
|
||
|
|
cursor.classList.add('active');
|
||
|
|
setTimeout(() => cursor.classList.remove('active'), 500);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Hover states
|
||
|
|
const interactiveElements = document.querySelectorAll('a, button, .hud-panel, .circle-item');
|
||
|
|
interactiveElements.forEach(el => {
|
||
|
|
el.addEventListener('mouseenter', () => cursor.style.transform = 'translate(-50%, -50%) scale(2)');
|
||
|
|
el.addEventListener('mouseleave', () => cursor.style.transform = 'translate(-50%, -50%) scale(1)');
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function initTypewriter() {
|
||
|
|
const text = "Welcome, Explorer. The system is awakening...";
|
||
|
|
const element = document.getElementById('typewriter');
|
||
|
|
let index = 0;
|
||
|
|
|
||
|
|
function type() {
|
||
|
|
if (index < text.length) {
|
||
|
|
element.textContent = text.substring(0, index + 1);
|
||
|
|
index++;
|
||
|
|
setTimeout(type, 50);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
setTimeout(type, 1500);
|
||
|
|
}
|
||
|
|
|
||
|
|
function initTerminal() {
|
||
|
|
const terminalBody = document.getElementById('terminalBody');
|
||
|
|
const logs = [
|
||
|
|
{ prefix: '[SYSTEM]', cmd: 'boot_sequence --init', class: 'prompt' },
|
||
|
|
{ output: 'Loading kernel modules...', class: 'output' },
|
||
|
|
{ output: 'Mounting virtual file systems...', class: 'output' },
|
||
|
|
{ output: 'Initializing neural network core...', class: 'success' },
|
||
|
|
{ prefix: '[CORE]', cmd: 'scan --temple', class: 'prompt' },
|
||
|
|
{ output: 'Detected: CYBER-TEMPLE v2.1', class: 'output' },
|
||
|
|
{ output: 'Artifacts: 7 | Entities: 3 | Runestones: 12', class: 'output' },
|
||
|
|
{ warning: 'WARNING: Unrecognized consciousness pattern detected', class: 'warning' },
|
||
|
|
{ prefix: '[AI]', cmd: 'awaken --mode=deep', class: 'prompt' },
|
||
|
|
{ output: 'Decrypting ancient data streams...', class: 'output' },
|
||
|
|
{ output: 'Pattern recognition: 87.3%', class: 'output' },
|
||
|
|
{ output: 'Consciousness synchronization: 23.1%', class: 'output' },
|
||
|
|
{ success: 'SUCCESS: First awakening sequence complete', class: 'success' },
|
||
|
|
{ prefix: '[EXPLORER]', cmd: 'status --check', class: 'prompt' },
|
||
|
|
{ output: 'User detected: Connected from sector 7G', class: 'output' },
|
||
|
|
{ output: 'Access level: OBSERVER', class: 'output' },
|
||
|
|
{ output: 'Press ESC to disconnect...', class: 'output' },
|
||
|
|
{ prefix: '[SYSTEM]', cmd: 'await --input=user', class: 'prompt' },
|
||
|
|
{ output: 'Waiting for explorer interaction...', class: 'output' }
|
||
|
|
];
|
||
|
|
|
||
|
|
let lineIndex = 0;
|
||
|
|
|
||
|
|
function addLine() {
|
||
|
|
if (lineIndex >= logs.length) return;
|
||
|
|
|
||
|
|
const log = logs[lineIndex];
|
||
|
|
const line = document.createElement('div');
|
||
|
|
line.className = 'terminal-line';
|
||
|
|
|
||
|
|
if (log.prefix) {
|
||
|
|
line.innerHTML = `<span class="${log.class}">${log.prefix}</span> <span class="cmd">${log.cmd}</span>`;
|
||
|
|
} else if (log.output) {
|
||
|
|
line.innerHTML = `<span class="${log.class}">${log.output}</span>`;
|
||
|
|
} else if (log.warning) {
|
||
|
|
line.innerHTML = `<span class="${log.class}">${log.warning}</span>`;
|
||
|
|
} else if (log.success) {
|
||
|
|
line.innerHTML = `<span class="${log.class}">${log.success}</span>`;
|
||
|
|
}
|
||
|
|
|
||
|
|
terminalBody.appendChild(line);
|
||
|
|
|
||
|
|
// Trigger animation
|
||
|
|
requestAnimationFrame(() => line.classList.add('visible'));
|
||
|
|
|
||
|
|
// Auto scroll to bottom
|
||
|
|
terminalBody.scrollTop = terminalBody.scrollHeight;
|
||
|
|
|
||
|
|
lineIndex++;
|
||
|
|
setTimeout(addLine, 400 + Math.random() * 600);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Start terminal when section is visible
|
||
|
|
ScrollTrigger.create({
|
||
|
|
trigger: '#terminal',
|
||
|
|
start: 'top 80%',
|
||
|
|
onEnter: () => setTimeout(addLine, 500)
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function initDataCircles() {
|
||
|
|
const circles = document.querySelectorAll('.progress-circle');
|
||
|
|
const targets = [87, 64, 92]; // Target percentages
|
||
|
|
|
||
|
|
ScrollTrigger.create({
|
||
|
|
trigger: '#datacore',
|
||
|
|
start: 'top 70%',
|
||
|
|
once: true,
|
||
|
|
onEnter: () => {
|
||
|
|
circles.forEach((circle, i) => {
|
||
|
|
const progress = circle.querySelector('.progress');
|
||
|
|
const value = circle.querySelector('.value');
|
||
|
|
const circumference = 2 * Math.PI * 80; // radius 80
|
||
|
|
const offset = circumference * (1 - targets[i] / 100);
|
||
|
|
|
||
|
|
// Animate progress bar
|
||
|
|
setTimeout(() => {
|
||
|
|
progress.style.strokeDashoffset = offset;
|
||
|
|
}, i * 300);
|
||
|
|
|
||
|
|
// Animate value counter
|
||
|
|
let current = 0;
|
||
|
|
const interval = setInterval(() => {
|
||
|
|
current += Math.ceil((targets[i] - current) / 20);
|
||
|
|
if (current >= targets[i]) {
|
||
|
|
current = targets[i];
|
||
|
|
clearInterval(interval);
|
||
|
|
}
|
||
|
|
value.textContent = current + '%';
|
||
|
|
}, 50);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function initConnectButton() {
|
||
|
|
const btn = document.getElementById('connectBtn');
|
||
|
|
const viz = document.getElementById('audioViz');
|
||
|
|
let isConnected = false;
|
||
|
|
|
||
|
|
btn.addEventListener('click', () => {
|
||
|
|
isConnected = !isConnected;
|
||
|
|
btn.textContent = isConnected ? 'DISCONNECT' : 'CONNECT SYSTEM';
|
||
|
|
btn.style.background = isConnected ? 'var(--neon-purple)' : 'transparent';
|
||
|
|
btn.style.borderColor = isConnected ? 'var(--neon-purple)' : 'var(--neon-cyan)';
|
||
|
|
|
||
|
|
if (isConnected) {
|
||
|
|
viz.classList.add('active');
|
||
|
|
} else {
|
||
|
|
viz.classList.remove('active');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function initGSAPAnimations() {
|
||
|
|
gsap.registerPlugin(ScrollTrigger);
|
||
|
|
|
||
|
|
// Animate manifesto cards
|
||
|
|
const cards = document.querySelectorAll('.manifesto-card');
|
||
|
|
cards.forEach((card, i) => {
|
||
|
|
gsap.to(card, {
|
||
|
|
scrollTrigger: {
|
||
|
|
trigger: card,
|
||
|
|
start: 'top 85%',
|
||
|
|
toggleActions: 'play none none reverse'
|
||
|
|
},
|
||
|
|
opacity: 1,
|
||
|
|
y: 0,
|
||
|
|
duration: 0.8,
|
||
|
|
delay: i * 0.2,
|
||
|
|
ease: 'power3.out'
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// Parallax effect for sections
|
||
|
|
gsap.utils.toArray('section').forEach((section, i) => {
|
||
|
|
gsap.from(section.querySelector('h2'), {
|
||
|
|
scrollTrigger: {
|
||
|
|
trigger: section,
|
||
|
|
start: 'top 75%',
|
||
|
|
scrub: true
|
||
|
|
},
|
||
|
|
y: 100,
|
||
|
|
opacity: 0,
|
||
|
|
duration: 1
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ===== EVENT HANDLERS ===== */
|
||
|
|
function onDOMContentLoaded() {
|
||
|
|
// Initialize loading screen
|
||
|
|
setTimeout(() => {
|
||
|
|
document.getElementById('loading').classList.add('hidden');
|
||
|
|
}, 2000);
|
||
|
|
|
||
|
|
// Initialize Three.js
|
||
|
|
initThree();
|
||
|
|
|
||
|
|
// Initialize UI components
|
||
|
|
initCustomCursor();
|
||
|
|
initTypewriter();
|
||
|
|
initTerminal();
|
||
|
|
initDataCircles();
|
||
|
|
initConnectButton();
|
||
|
|
initGSAPAnimations();
|
||
|
|
|
||
|
|
// Start animation loop
|
||
|
|
animate();
|
||
|
|
|
||
|
|
// Mouse tracking
|
||
|
|
document.addEventListener('mousemove', onMouseMove);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Initialize when DOM is ready
|
||
|
|
if (document.readyState === 'loading') {
|
||
|
|
document.addEventListener('DOMContentLoaded', onDOMContentLoaded);
|
||
|
|
} else {
|
||
|
|
onDOMContentLoaded();
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
</body>
|
||
|
|
</html>
|