LLM-test/test/code/2/GLM-4.7.html

1173 lines
48 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>赛博朋克 2078 - 神经网络城市可视化平台</title>
<!-- 引入外部字体 -->
<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=Orbitron:wght@400;700;900&family=Rajdhani:wght@300;500;700&display=swap" rel="stylesheet">
<!-- 引入 Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- 引入样式重置与基础样式 -->
<style>
:root {
--neon-pink: #ff00ff;
--neon-blue: #00ffff;
--neon-purple: #8800ff;
--bg-dark: #050505;
--bg-panel: rgba(10, 10, 16, 0.85);
--text-main: #e0e0e0;
--font-display: 'Orbitron', sans-serif;
--font-body: 'Rajdhani', sans-serif;
--border-glow: 0 0 10px rgba(0, 255, 255, 0.5);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
scrollbar-width: thin;
scrollbar-color: var(--neon-blue) var(--bg-dark);
}
body {
background-color: var(--bg-dark);
color: var(--text-main);
font-family: var(--font-body);
overflow-x: hidden;
background-image:
radial-gradient(circle at 50% 50%, rgba(0, 255, 255, 0.05) 0%, transparent 50%),
linear-gradient(rgba(0, 0, 0, 0.8) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 0, 0, 0.8) 1px, transparent 1px);
background-size: 100% 100%, 40px 40px, 40px 40px;
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #0a0a0a;
}
::-webkit-scrollbar-thumb {
background: var(--neon-blue);
border-radius: 4px;
}
/* 工具类 */
.neon-text-blue {
text-shadow: 0 0 5px var(--neon-blue), 0 0 10px var(--neon-blue);
color: var(--neon-blue);
}
.neon-text-pink {
text-shadow: 0 0 5px var(--neon-pink), 0 0 10px var(--neon-pink);
color: var(--neon-pink);
}
.glass-panel {
background: var(--bg-panel);
backdrop-filter: blur(10px);
border: 1px solid rgba(0, 255, 255, 0.2);
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.5);
position: relative;
overflow: hidden;
}
.glass-panel::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0; height: 1px;
background: linear-gradient(90deg, transparent, var(--neon-blue), transparent);
opacity: 0.5;
}
.corner-deco {
position: absolute;
width: 10px;
height: 10px;
border: 2px solid var(--neon-blue);
transition: all 0.3s ease;
}
.tl { top: -1px; left: -1px; border-right: none; border-bottom: none; }
.tr { top: -1px; right: -1px; border-left: none; border-bottom: none; }
.bl { bottom: -1px; left: -1px; border-right: none; border-top: none; }
.br { bottom: -1px; right: -1px; border-left: none; border-top: none; }
/* Glitch 效果 */
.glitch-wrapper {
position: relative;
display: inline-block;
}
.glitch {
position: relative;
color: white;
font-weight: bold;
}
.glitch::before, .glitch::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--bg-dark);
}
.glitch::before {
left: 2px;
text-shadow: -1px 0 var(--neon-pink);
clip: rect(24px, 550px, 90px, 0);
animation: glitch-anim-2 3s infinite linear alternate-reverse;
}
.glitch::after {
left: -2px;
text-shadow: -1px 0 var(--neon-blue);
clip: rect(85px, 550px, 140px, 0);
animation: glitch-anim 2.5s infinite linear alternate-reverse;
}
@keyframes glitch-anim {
0% { clip: rect(11px, 9999px, 34px, 0); }
100% { clip: rect(66px, 9999px, 81px, 0); }
}
@keyframes glitch-anim-2 {
0% { clip: rect(89px, 9999px, 96px, 0); }
100% { clip: rect(12px, 9999px, 58px, 0); }
}
/* 模块一:开场动画 */
#intro-overlay {
position: fixed;
top: 0; left: 0; width: 100%; height: 100%;
background: #000;
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
#intro-canvas {
position: absolute;
top: 0; left: 0;
}
.intro-text {
font-family: var(--font-display);
font-size: 3rem;
color: var(--neon-blue);
opacity: 0;
z-index: 10;
letter-spacing: 5px;
text-transform: uppercase;
}
/* 模块二3D城市概览 */
#city-view-section {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
}
#three-canvas {
width: 100%;
height: 100%;
display: block;
}
.hud-overlay {
position: absolute;
top: 20px;
right: 20px;
width: 300px;
padding: 15px;
z-index: 10;
pointer-events: none; /* 让鼠标事件穿透到3D场景 */
}
.time-display {
font-family: var(--font-display);
font-size: 1.5rem;
border-bottom: 1px solid var(--neon-pink);
padding-bottom: 5px;
margin-bottom: 10px;
}
.city-metrics div {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
font-size: 0.9rem;
}
/* 模块三:神经网络可视化 */
#neural-network-section {
padding: 50px 20px;
min-height: 80vh;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
#neural-container {
width: 100%;
max-width: 1200px;
height: 500px;
margin-top: 30px;
border: 1px solid var(--neon-purple);
box-shadow: 0 0 20px rgba(136, 0, 255, 0.2);
background: rgba(0, 0, 0, 0.6);
}
.neural-stats {
display: flex;
gap: 20px;
margin-bottom: 20px;
}
.stat-box {
padding: 10px 20px;
border: 1px solid var(--neon-blue);
background: rgba(0, 255, 255, 0.05);
font-family: var(--font-display);
font-size: 1.2rem;
}
/* 模块四:智能系统监控 */
#dashboard-section {
padding: 50px 5%;
background: linear-gradient(180deg, transparent, rgba(0,0,0,0.8));
}
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
}
.monitor-card {
height: 250px;
padding: 20px;
display: flex;
flex-direction: column;
}
.card-header {
font-family: var(--font-display);
color: var(--neon-blue);
margin-bottom: 15px;
display: flex;
justify-content: space-between;
align-items: center;
}
/* 仪表盘 */
#gauge-container {
flex: 1;
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
/* 示波器 */
#oscilloscope-canvas {
width: 100%;
height: 100%;
background: #000;
}
/* 服务器网格 */
.server-grid {
display: grid;
grid-template-columns: repeat(10, 1fr);
gap: 5px;
margin-top: 10px;
flex: 1;
}
.server-node {
background: #222;
height: 20px;
transition: background 0.3s;
}
.server-node.active { background: #0f0; box-shadow: 0 0 5px #0f0; }
.server-node.error { background: #f00; box-shadow: 0 0 5px #f00; }
/* 日志窗口 */
.log-window {
background: #000;
font-family: 'Courier New', monospace;
font-size: 0.8rem;
color: #0f0;
padding: 10px;
overflow-y: auto;
flex: 1;
border: 1px solid #333;
height: 150px;
position: relative;
}
.log-window::after {
content: " ";
display: block;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06));
background-size: 100% 2px, 3px 100%;
pointer-events: none;
}
/* 模块五:时间线导航 */
#timeline-section {
padding: 50px 0;
overflow: hidden;
}
.timeline-container {
display: flex;
gap: 30px;
padding: 20px 5%;
overflow-x: auto;
padding-bottom: 40px; /* 阴影空间 */
cursor: grab;
}
.timeline-container:active {
cursor: grabbing;
}
.time-node {
flex: 0 0 auto;
width: 200px;
height: 80px;
border: 1px solid var(--text-main);
display: flex;
align-items: center;
justify-content: center;
clip-path: polygon(10% 0, 100% 0, 100% 70%, 90% 100%, 0 100%, 0 30%);
background: rgba(255, 255, 255, 0.05);
transition: all 0.3s;
cursor: pointer;
position: relative;
}
.time-node:hover {
background: rgba(0, 255, 255, 0.2);
border-color: var(--neon-blue);
transform: translateY(-5px);
}
.time-node.active {
border-color: var(--neon-pink);
box-shadow: 0 0 15px var(--neon-pink);
background: rgba(255, 0, 255, 0.1);
}
.node-detail {
position: absolute;
bottom: -40px;
left: 0;
width: 100%;
text-align: center;
font-size: 0.8rem;
color: var(--neon-blue);
opacity: 0;
transition: opacity 0.3s;
}
.time-node:hover .node-detail {
opacity: 1;
}
/* 模块六:全息数据卡片 */
#hologram-section {
padding: 100px 5%;
perspective: 1000px;
display: flex;
justify-content: center;
gap: 50px;
flex-wrap: wrap;
}
.holo-card {
width: 280px;
height: 380px;
background: rgba(0, 20, 40, 0.6);
border: 1px solid rgba(0, 255, 255, 0.3);
border-radius: 10px;
transform-style: preserve-3d;
transform: rotateX(10deg) rotateY(0deg);
transition: transform 0.1s ease-out, box-shadow 0.3s;
position: relative;
overflow: hidden;
}
.holo-card::before {
content: '';
position: absolute;
top: -50%; left: -50%;
width: 200%; height: 200%;
background: linear-gradient(45deg, transparent 45%, rgba(0, 255, 255, 0.1) 50%, transparent 55%);
transform: rotate(45deg);
animation: shine 3s infinite;
pointer-events: none;
}
@keyframes shine {
0% { transform: translateX(-100%) rotate(45deg); }
100% { transform: translateX(100%) rotate(45deg); }
}
.holo-card:hover {
transform: rotateX(0deg) translateY(-20px);
box-shadow: 0 20px 50px rgba(0, 255, 255, 0.2);
z-index: 10;
}
.holo-content {
padding: 20px;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.holo-icon {
font-size: 3rem;
color: var(--neon-blue);
margin-bottom: 20px;
}
.holo-data {
font-size: 2.5rem;
font-weight: bold;
font-family: var(--font-display);
text-align: right;
}
.holo-desc {
font-size: 0.9rem;
color: #aaa;
opacity: 0.8;
}
.holo-hidden-info {
height: 0;
overflow: hidden;
transition: height 0.3s;
color: var(--neon-pink);
}
.holo-card:hover .holo-hidden-info {
height: 60px;
}
/* 模块七:命令控制台 */
#console-section {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background: rgba(0, 0, 0, 0.9);
border-top: 1px solid var(--neon-blue);
padding: 15px;
display: flex;
justify-content: center;
z-index: 1000;
}
.console-wrapper {
width: 100%;
max-width: 800px;
position: relative;
}
.console-input {
width: 100%;
background: transparent;
border: none;
border-bottom: 2px solid var(--neon-blue);
color: var(--neon-blue);
font-family: 'Courier New', monospace;
font-size: 1.2rem;
padding: 5px;
outline: none;
}
.console-input::placeholder {
color: rgba(0, 255, 255, 0.3);
}
.scan-line {
position: fixed;
top: 0; left: 0; width: 100%; height: 5px;
background: var(--neon-blue);
box-shadow: 0 0 20px var(--neon-blue);
opacity: 0;
pointer-events: none;
z-index: 9998;
}
/* 响应式设计 */
@media (max-width: 768px) {
.intro-text { font-size: 2rem; }
#neural-container { height: 300px; }
.dashboard-grid { grid-template-columns: 1fr; }
.holo-card { width: 100%; max-width: 300px; margin: 10px; }
#hologram-section { flex-direction: column; align-items: center; }
}
</style>
</head>
<body>
<!-- 模块一:沉浸式开场 -->
<div id="intro-overlay">
<canvas id="intro-canvas"></canvas>
<div class="intro-text">NEURAL NETWORK LINKED</div>
</div>
<!-- 扫描线反馈 -->
<div class="scan-line" id="scan-line"></div>
<!-- 主内容区 -->
<main id="main-content" style="display: none; opacity: 0;">
<!-- 模块二3D城市 -->
<section id="city-view-section">
<canvas id="three-canvas"></canvas>
<div class="glass-panel hud-overlay">
<div class="corner-deco tl"></div><div class="corner-deco tr"></div>
<div class="corner-deco bl"></div><div class="corner-deco br"></div>
<div class="time-display" id="clock">2078.01.01 00:00:00</div>
<div class="city-metrics">
<div><span>电网负载</span> <span class="neon-text-blue">87%</span></div>
<div><span>网络延迟</span> <span class="neon-text-pink">12ms</span></div>
<div><span>安全等级</span> <span style="color:#0f0">稳定</span></div>
<div><span>活跃节点</span> <span>4,096</span></div>
</div>
</div>
</section>
<!-- 模块三:神经网络 -->
<section id="neural-network-section">
<h2 class="neon-text-blue glitch-wrapper"><span class="glitch" data-text="NEURAL DATA STREAM">NEURAL DATA STREAM</span></h2>
<div class="neural-stats">
<div class="stat-box">神经元活跃度: <span id="neuron-activity">98.2%</span></div>
<div class="stat-box">数据吞吐: <span id="throughput">402 TB/s</span></div>
</div>
<div id="neural-container"></div>
</section>
<!-- 模块四:系统监控 -->
<section id="dashboard-section">
<h2 class="neon-text-pink" style="margin-bottom: 30px;">SYSTEM MONITOR</h2>
<div class="dashboard-grid">
<!-- CPU 仪表 -->
<div class="glass-panel monitor-card">
<div class="card-header"><span><i class="fas fa-microchip"></i> CPU LOAD</span> <span id="cpu-val">45%</span></div>
<div id="gauge-container">
<svg width="150" height="80" viewBox="0 0 150 80">
<path d="M10,70 A65,65 0 0,1 140,70" fill="none" stroke="#333" stroke-width="10" stroke-linecap="round"/>
<path id="gauge-path" d="M10,70 A65,65 0 0,1 140,70" fill="none" stroke="var(--neon-blue)" stroke-width="10" stroke-linecap="round" stroke-dasharray="200" stroke-dashoffset="100"/>
<text x="75" y="50" text-anchor="middle" fill="#fff" font-family="Orbitron" font-size="20" id="gauge-text">45%</text>
</svg>
</div>
</div>
<!-- 网络流量 -->
<div class="glass-panel monitor-card">
<div class="card-header"><span><i class="fas fa-wifi"></i> NET TRAFFIC</span> <span>Live</span></div>
<canvas id="oscilloscope-canvas"></canvas>
</div>
<!-- 服务器状态 -->
<div class="glass-panel monitor-card">
<div class="card-header"><span><i class="fas fa-server"></i> CLUSTER STATUS</span> <span>Online</span></div>
<div class="server-grid" id="server-grid">
<!-- JS 生成节点 -->
</div>
</div>
<!-- 系统日志 -->
<div class="glass-panel monitor-card">
<div class="card-header"><span><i class="fas fa-terminal"></i> SYSTEM LOGS</span></div>
<div class="log-window" id="system-log">
<div>[SYSTEM] Boot sequence initialized...</div>
</div>
</div>
</div>
</section>
<!-- 模块五:时间线 -->
<section id="timeline-section">
<h2 class="neon-text-blue" style="text-align: center; margin-bottom: 20px;">HISTORICAL ARCHIVES</h2>
<div class="timeline-container" id="timeline">
<!-- JS 生成时间节点 -->
</div>
</section>
<!-- 模块六:全息卡片 -->
<section id="hologram-section">
<div class="holo-card">
<div class="holo-content">
<div>
<i class="fas fa-users holo-icon"></i>
<div class="holo-data">14.2M</div>
<div class="holo-desc">CITY POPULATION</div>
</div>
<div class="holo-hidden-info">
<p>自然增长: 0.5%</p>
<p>移民流入: 120k/yr</p>
</div>
</div>
</div>
<div class="holo-card">
<div class="holo-content">
<div>
<i class="fas fa-bolt holo-icon" style="color: var(--neon-pink)"></i>
<div class="holo-data">850 GW</div>
<div class="holo-desc">ENERGY CONSUMPTION</div>
</div>
<div class="holo-hidden-info">
<p>聚变贡献: 80%</p>
<p>太阳能: 15%</p>
</div>
</div>
</div>
<div class="holo-card">
<div class="holo-content">
<div>
<i class="fas fa-brain holo-icon" style="color: var(--neon-purple)"></i>
<div class="holo-data">99.9%</div>
<div class="holo-desc">AI SYNC RATE</div>
</div>
<div class="holo-hidden-info">
<p>核心: 'Central'</p>
<p>子节点: 504 connected</p>
</div>
</div>
</div>
</section>
<!-- 底部占位 -->
<footer style="height: 100px; display: flex; align-items: center; justify-content: center; color: #555;">
<p>&copy; 2078 NEURAL NETWORK CITY CORP. ALL RIGHTS RESERVED.</p>
</footer>
</main>
<!-- 模块七:控制台 -->
<div id="console-section">
<div class="console-wrapper">
<input type="text" class="console-input" id="command-input" placeholder="ENTER COMMAND (e.g., 'SYSTEM DIAGNOSTIC')..." autocomplete="off">
</div>
</div>
<!-- 引入外部脚本库 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
<!-- 主逻辑脚本 -->
<script>
document.addEventListener('DOMContentLoaded', () => {
// ==========================================
// 模块一:沉浸式开场动画
// ==========================================
const introCanvas = document.getElementById('intro-canvas');
const introCtx = introCanvas.getContext('2d');
const introOverlay = document.getElementById('intro-overlay');
const introText = document.querySelector('.intro-text');
const mainContent = document.getElementById('main-content');
let introWidth, introHeight; // 修正:变量重名
let introFrame = 0;
const totalIntroFrames = 180; // 约3秒
function resizeIntro() {
introWidth = window.innerWidth;
introHeight = window.innerHeight;
introCanvas.width = introWidth;
introCanvas.height = introHeight;
}
window.addEventListener('resize', resizeIntro);
resizeIntro();
const nodes = Array.from({length: 50}, () => ({
x: Math.random() * introWidth,
y: Math.random() * introHeight,
vx: (Math.random() - 0.5) * 2,
vy: (Math.random() - 0.5) * 2
}));
function playIntro() {
if (introFrame > totalIntroFrames) {
// 动画结束,过渡到主界面
gsap.to(introOverlay, { opacity: 0, duration: 1, onComplete: () => {
introOverlay.style.display = 'none';
mainContent.style.display = 'block';
gsap.to(mainContent, { opacity: 1, duration: 1.5 });
}});
return;
}
introCtx.fillStyle = 'rgba(0, 0, 0, 0.1)';
introCtx.fillRect(0, 0, introWidth, introHeight);
const progress = introFrame / totalIntroFrames;
const centerX = introWidth / 2;
const centerY = introHeight / 2;
const maxDist = Math.max(introWidth, introHeight) * 0.8;
// 更新节点位置
introCtx.fillStyle = '#00ffff';
nodes.forEach(node => {
node.x += node.vx;
node.y += node.vy;
// 边界反弹
if(node.x < 0 || node.x > introWidth) node.vx *= -1;
if(node.y < 0 || node.y > introHeight) node.vy *= -1;
// 绘制节点
const dist = Math.sqrt((node.x - centerX)**2 + (node.y - centerY)**2);
// 随着动画进行,限制节点范围向内收缩,然后反向扩散
// 简化:始终绘制连线,最后文字显现
introCtx.beginPath();
introCtx.arc(node.x, node.y, 2, 0, Math.PI * 2);
introCtx.fill();
// 连线
nodes.forEach(other => {
const d = Math.sqrt((node.x - other.x)**2 + (node.y - other.y)**2);
if (d < 150) {
introCtx.strokeStyle = `rgba(0, 255, 255, ${1 - d/150})`;
introCtx.beginPath();
introCtx.moveTo(node.x, node.y);
introCtx.lineTo(other.x, other.y);
introCtx.stroke();
}
});
});
// 文字渐显
if (introFrame > 100) {
introText.style.opacity = (introFrame - 100) / 80;
}
introFrame++;
requestAnimationFrame(playIntro);
}
playIntro();
// ==========================================
// 模块二Three.js 3D城市 (优化版)
// ==========================================
const threeCanvas = document.getElementById('three-canvas');
const scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0x050505, 0.0025);
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 40, 60);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer({ canvas: threeCanvas, antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); // 性能优化:限制像素比
// 城市生成逻辑
const cityGroup = new THREE.Group();
scene.add(cityGroup);
const buildingGeo = new THREE.BoxGeometry(1, 1, 1);
buildingGeo.translate(0, 0.5, 0);
// 使用Phong材质但去除过多光照计算
const buildingMat = new THREE.MeshPhongMaterial({
color: 0x111111,
emissive: 0x000510, // 微弱自发光
specular: 0x111111,
shininess: 30,
flatShading: true
});
// 霓虹灯材质 (使用BasicMaterial不受光照影响模拟发光效果)
const neonColors = [0x00ffff, 0xff00ff, 0x8800ff, 0x00ff00];
const neonGeo = new THREE.BoxGeometry(0.8, 0.2, 0.8);
neonGeo.translate(0, 0.1, 0);
const gridSize = 40;
const spacing = 1.5;
// 存储所有霓虹灯,以便后续交互变色
const neonLightsMeshes = [];
for (let x = -gridSize/2; x < gridSize/2; x++) {
for (let z = -gridSize/2; z < gridSize/2; z++) {
const dist = Math.sqrt(x*x + z*z);
const maxH = Math.max(2, (gridSize/2 - dist) * 2 + Math.random() * 5);
const height = Math.random() * maxH;
if (height < 1) continue;
const building = new THREE.Mesh(buildingGeo, buildingMat);
building.position.set(x * spacing, 0, z * spacing);
building.scale.set(1, height, 1);
cityGroup.add(building);
// 添加简单的侧面线条作为LED
const edges = new THREE.EdgesGeometry(buildingGeo);
const lineMat = new THREE.LineBasicMaterial({ color: 0x001133, transparent: true, opacity: 0.3 });
const lines = new THREE.LineSegments(edges, lineMat);
lines.position.copy(building.position);
lines.scale.copy(building.scale);
cityGroup.add(lines);
// 使用自发光几何体代替 PointLight
// 30%的建筑物顶部有霓虹灯
if (Math.random() > 0.7) {
const color = neonColors[Math.floor(Math.random() * neonColors.length)];
const neonMat = new THREE.MeshBasicMaterial({ color: color });
const neonMesh = new THREE.Mesh(neonGeo, neonMat);
// 放置在建筑物顶部
neonMesh.position.set(x * spacing, height, z * spacing);
// 随机缩放一点
const scale = 0.8 + Math.random() * 0.4;
neonMesh.scale.set(scale, 1, scale);
cityGroup.add(neonMesh);
neonLightsMeshes.push(neonMesh); // 存储以便后续控制
}
}
}
// 地面网格
const gridHelper = new THREE.GridHelper(100, 100, 0xff00ff, 0x111111);
scene.add(gridHelper);
// 优化的光照系统:仅保留少量强光源
const ambientLight = new THREE.AmbientLight(0x404040, 1.5); // 增强环境光
scene.add(ambientLight);
const dirLight = new THREE.DirectionalLight(0xffffff, 0.5);
dirLight.position.set(50, 100, 50);
scene.add(dirLight);
// 添加几个移动的彩色点光源来模拟巡逻车或无人机,营造动态氛围
const movingLights = [];
const lightColors = [0x00ffff, 0xff00ff, 0x00ff00];
for(let i=0; i<5; i++) {
const light = new THREE.PointLight(lightColors[i % 3], 2, 40);
light.position.set((Math.random()-0.5)*60, 20, (Math.random()-0.5)*60);
scene.add(light);
movingLights.push({
light: light,
speedX: (Math.random() - 0.5) * 0.2,
speedZ: (Math.random() - 0.5) * 0.2
});
}
// 粒子流 (模拟飞行载具)
const particlesGeo = new THREE.BufferGeometry();
const particleCount = 200;
const posArray = new Float32Array(particleCount * 3);
const speedArray = [];
for(let i=0; i<particleCount*3; i+=3) {
posArray[i] = (Math.random() - 0.5) * 80; // x
posArray[i+1] = Math.random() * 20 + 5; // y
posArray[i+2] = (Math.random() - 0.5) * 80; // z
speedArray.push({
x: (Math.random() - 0.5) * 0.2,
y: 0,
z: (Math.random() - 0.5) * 0.2
});
}
particlesGeo.setAttribute('position', new THREE.BufferAttribute(posArray, 3));
const particlesMat = new THREE.PointsMaterial({
size: 0.3,
color: 0xff00ff,
transparent: true,
opacity: 0.8
});
const particleSystem = new THREE.Points(particlesGeo, particlesMat);
scene.add(particleSystem);
// 交互:鼠标拖拽
let isDragging = false;
let previousMousePosition = { x: 0, y: 0 };
let targetRotationX = 0;
let targetRotationY = 0;
threeCanvas.addEventListener('mousedown', () => isDragging = true);
document.addEventListener('mouseup', () => isDragging = false);
document.addEventListener('mousemove', (e) => {
if (isDragging) {
const deltaMove = {
x: e.offsetX - previousMousePosition.x,
y: e.offsetY - previousMousePosition.y
};
targetRotationY += deltaMove.x * 0.005;
targetRotationX += deltaMove.y * 0.005;
targetRotationX = Math.max(-Math.PI/4, Math.min(Math.PI/4, targetRotationX));
}
previousMousePosition = { x: e.offsetX, y: e.offsetY };
});
threeCanvas.addEventListener('wheel', (e) => {
e.preventDefault();
camera.position.z += e.deltaY * 0.05;
camera.position.z = Math.max(20, Math.min(100, camera.position.z));
});
// 3D动画循环
function animateThree() {
requestAnimationFrame(animateThree);
// 平滑旋转
cityGroup.rotation.y += (targetRotationY - cityGroup.rotation.y) * 0.1;
cityGroup.rotation.x += (targetRotationX - cityGroup.rotation.x) * 0.1;
// 粒子运动
const positions = particleSystem.geometry.attributes.position.array;
for(let i=0; i<particleCount; i++) {
positions[i*3] += speedArray[i].x;
positions[i*3+1] += speedArray[i].y;
positions[i*3+2] += speedArray[i].z;
if(Math.abs(positions[i*3]) > 40) positions[i*3] *= -0.9;
if(Math.abs(positions[i*3+2]) > 40) positions[i*3+2] *= -0.9;
}
particleSystem.geometry.attributes.position.needsUpdate = true;
// 移动灯光动画
movingLights.forEach(obj => {
obj.light.position.x += obj.speedX;
obj.light.position.z += obj.speedZ;
if(Math.abs(obj.light.position.x) > 50) obj.speedX *= -1;
if(Math.abs(obj.light.position.z) > 50) obj.speedZ *= -1;
});
if(!isDragging) {
targetRotationY += 0.001;
}
renderer.render(scene, camera);
}
animateThree();
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// ==========================================
// 模块三D3.js 神经网络 (修正变量重名)
// ==========================================
const neuralContainer = document.getElementById('neural-container');
const neuralWidth = neuralContainer.clientWidth;
const neuralHeight = neuralContainer.clientHeight;
const svg = d3.select("#neural-container").append("svg")
.attr("width", "100%")
.attr("height", "100%");
const defs = svg.append("defs");
const gradient = defs.append("linearGradient")
.attr("id", "pulse-gradient")
.attr("x1", "0%").attr("y1", "0%")
.attr("x2", "100%").attr("y2", "0%");
gradient.append("stop").attr("offset", "0%").attr("stop-color", "rgba(0,255,255,0)");
gradient.append("stop").attr("offset", "50%").attr("stop-color", "rgba(0,255,255,1)");
gradient.append("stop").attr("offset", "100%").attr("stop-color", "rgba(0,255,255,0)");
const nodesData = Array.from({length: 30}, (_, i) => ({ id: i }));
const linksData = [];
for(let i=0; i<30; i++) {
const target = Math.floor(Math.random() * 30);
if(i !== target) linksData.push({ source: i, target: target });
}
const simulation = d3.forceSimulation(nodesData)
.force("link", d3.forceLink(linksData).id(d => d.id).distance(100))
.force("charge", d3.forceManyBody().strength(-200))
.force("center", d3.forceCenter(neuralWidth / 2, neuralHeight / 2));
const link = svg.append("g").selectAll("line").data(linksData).join("line")
.attr("stroke", "#333").attr("stroke-width", 1);
const pulses = svg.append("g").selectAll("circle").data(linksData).join("circle")
.attr("r", 2).attr("fill", "var(--neon-blue)")
.style("filter", "drop-shadow(0 0 2px var(--neon-blue))");
const node = svg.append("g").selectAll("circle").data(nodesData).join("circle")
.attr("r", 5).attr("fill", "#000").attr("stroke", "var(--neon-pink)").attr("stroke-width", 2)
.call(d3.drag().on("start", dragstarted).on("drag", dragged).on("end", dragended));
simulation.on("tick", () => {
link.attr("x1", d => d.source.x).attr("y1", d => d.source.y)
.attr("x2", d => d.target.x).attr("y2", d => d.target.y);
node.attr("cx", d => d.x).attr("cy", d => d.y);
const time = Date.now() * 0.001;
pulses.attr("cx", d => d.source.x + (d.target.x - d.source.x) * ((time + d.index) % 1))
.attr("cy", d => d.source.y + (d.target.y - d.source.y) * ((time + d.index) % 1));
});
function dragstarted(event, d) { if (!event.active) simulation.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; }
function dragged(event, d) { d.fx = event.x; d.fy = event.y; }
function dragended(event, d) { if (!event.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; }
window.addEventListener('resize', () => {
const w = neuralContainer.clientWidth;
const h = neuralContainer.clientHeight;
simulation.force("center", d3.forceCenter(w / 2, h / 2));
simulation.alpha(0.3).restart();
});
// ==========================================
// 模块四:仪表盘逻辑
// ==========================================
const gaugePath = document.getElementById('gauge-path');
const gaugeText = document.getElementById('gauge-text');
const cpuVal = document.getElementById('cpu-val');
function updateGauge() {
const val = Math.floor(30 + Math.random() * 50);
const offset = 200 - (val / 100) * 200;
gaugePath.style.strokeDashoffset = offset;
gaugeText.textContent = val + '%';
cpuVal.textContent = val + '%';
if(val > 80) gaugePath.style.stroke = 'var(--neon-pink)';
else gaugePath.style.stroke = 'var(--neon-blue)';
}
setInterval(updateGauge, 2000);
const oscCanvas = document.getElementById('oscilloscope-canvas');
const oscCtx = oscCanvas.getContext('2d');
let oscOffset = 0;
function resizeOsc() {
oscCanvas.width = oscCanvas.parentElement.clientWidth;
oscCanvas.height = oscCanvas.parentElement.clientHeight - 40;
}
window.addEventListener('resize', resizeOsc);
resizeOsc();
function drawOscilloscope() {
requestAnimationFrame(drawOscilloscope);
const w = oscCanvas.width, h = oscCanvas.height;
oscCtx.fillStyle = 'rgba(0,0,0,0.1)'; oscCtx.fillRect(0, 0, w, h);
oscCtx.beginPath(); oscCtx.strokeStyle = '#0f0'; oscCtx.lineWidth = 2;
for(let x=0; x<w; x++) {
const y = h/2 + Math.sin((x + oscOffset) * 0.05) * (h/3) + Math.sin((x + oscOffset * 2) * 0.1) * (h/6);
if(x===0) oscCtx.moveTo(x, y); else oscCtx.lineTo(x, y);
}
oscCtx.stroke(); oscOffset += 2;
}
drawOscilloscope();
const serverGrid = document.getElementById('server-grid');
for(let i=0; i<40; i++) {
const div = document.createElement('div'); div.className = 'server-node active'; serverGrid.appendChild(div);
}
setInterval(() => {
const nodes = document.querySelectorAll('.server-node');
const randIndex = Math.floor(Math.random() * nodes.length);
nodes[randIndex].className = `server-node ${Math.random() > 0.9 ? 'error' : 'active'}`;
}, 500);
const logWindow = document.getElementById('system-log');
const logs = ["Data packet received from Node_44", "Encryption key rotation successful", "Connection timeout: Port 8080", "Neural sync rate optimized", "Energy spike detected in Sector 7", "Firewall breach attempt blocked", "Garbage collection started"];
setInterval(() => {
const log = document.createElement('div');
log.textContent = `[${new Date().toLocaleTimeString()}] ${logs[Math.floor(Math.random()*logs.length)]}`;
logWindow.appendChild(log);
logWindow.scrollTop = logWindow.scrollHeight;
if(logWindow.children.length > 20) logWindow.removeChild(logWindow.firstChild);
}, 1500);
// ==========================================
// 模块五:交互式时间线
// ==========================================
const timelineContainer = document.getElementById('timeline');
const years = [2024, 2035, 2050, 2065, 2070, 2078];
years.forEach((year, index) => {
const node = document.createElement('div');
node.className = 'time-node';
if(index === years.length - 1) node.classList.add('active');
node.innerHTML = `${year}<div class="node-detail">CLICK TO VIEW ARCHIVE</div>`;
node.addEventListener('click', () => {
document.querySelectorAll('.time-node').forEach(n => n.classList.remove('active'));
node.classList.add('active');
const ratio = (year - 2024) / (2078 - 2024);
const r = Math.floor(ratio * 255), g = Math.floor((1-ratio) * 255);
const color = new THREE.Color(`rgb(${r}, ${g}, 255)`);
// 修改霓虹灯光颜色
neonLightsMeshes.forEach(mesh => {
if (Math.random() > 0.5) mesh.material.color.set(color);
});
const log = document.createElement('div');
log.style.color = "var(--neon-pink)";
log.textContent = `[USER] Switching view to Year ${year}...`;
logWindow.appendChild(log);
logWindow.scrollTop = logWindow.scrollHeight;
});
timelineContainer.appendChild(node);
});
let isDown = false, startX, scrollLeft;
timelineContainer.addEventListener('mousedown', (e) => { isDown = true; startX = e.pageX - timelineContainer.offsetLeft; scrollLeft = timelineContainer.scrollLeft; });
timelineContainer.addEventListener('mouseleave', () => isDown = false);
timelineContainer.addEventListener('mouseup', () => isDown = false);
timelineContainer.addEventListener('mousemove', (e) => {
if(!isDown) return; e.preventDefault();
const x = e.pageX - timelineContainer.offsetLeft;
timelineContainer.scrollLeft = scrollLeft - (x - startX) * 2;
});
// ==========================================
// 模块六:全息卡片交互
// ==========================================
const cards = document.querySelectorAll('.holo-card');
cards.forEach(card => {
card.addEventListener('mousemove', (e) => {
const rect = card.getBoundingClientRect();
const x = e.clientX - rect.left, y = e.clientY - rect.top;
const centerX = rect.width / 2, centerY = rect.height / 2;
const rotateX = ((y - centerY) / centerY) * -10;
const rotateY = ((x - centerX) / centerX) * 10;
card.style.transform = `rotateX(${10 + rotateX}deg) rotateY(${rotateY}deg) translateY(-20px)`;
});
card.addEventListener('mouseleave', () => { card.style.transform = `rotateX(10deg) rotateY(0deg)`; });
});
// ==========================================
// 模块七:命令控制台
// ==========================================
const commandInput = document.getElementById('command-input');
const scanLine = document.getElementById('scan-line');
function triggerScan() {
const tl = gsap.timeline();
tl.to(scanLine, { top: "100%", opacity: 1, duration: 1.5, ease: "power2.inOut" })
.to(scanLine, { opacity: 0, duration: 0.1 });
}
commandInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
const cmd = commandInput.value.toUpperCase().trim();
if (!cmd) return;
const userLog = document.createElement('div');
userLog.style.color = "#fff"; userLog.textContent = `> USER: ${cmd}`;
logWindow.appendChild(userLog); commandInput.value = '';
triggerScan();
setTimeout(() => {
const resLog = document.createElement('div');
resLog.style.color = "var(--neon-blue)";
if (cmd.includes('ENERGY')) {
resLog.textContent = `[SYSTEM] Displaying Energy Grid Map...`;
neonLightsMeshes.forEach(mesh => mesh.material.color.setHex(0xffff00));
} else if (cmd.includes('DIAGNOSTIC')) {
resLog.textContent = `[SYSTEM] Diagnostic Complete: 98% Systems Optimal.`;
} else if (cmd.includes('RESET')) {
resLog.textContent = `[SYSTEM] View Reset to Default.`;
neonLightsMeshes.forEach(mesh => mesh.material.color.setHex(neonColors[Math.floor(Math.random()*neonColors.length)]));
} else {
resLog.textContent = `[SYSTEM] Command "${cmd}" recognized. Executing...`;
}
logWindow.appendChild(resLog); logWindow.scrollTop = logWindow.scrollHeight;
}, 800);
}
});
function updateClock() {
const now = new Date();
const year = 2078;
const timeStr = `${year}.${String(now.getMonth()+1).padStart(2,'0')}.${String(now.getDate()).padStart(2,'0')} ${String(now.getHours()).padStart(2,'0')}:${String(now.getMinutes()).padStart(2,'0')}:${String(now.getSeconds()).padStart(2,'0')}`;
document.getElementById('clock').textContent = timeStr;
}
setInterval(updateClock, 1000); updateClock();
setInterval(() => {
const activity = (95 + Math.random() * 5).toFixed(1);
const throughput = Math.floor(400 + Math.random() * 50);
document.getElementById('neuron-activity').textContent = activity + '%';
document.getElementById('throughput').textContent = throughput + ' TB/s';
}, 2000);
});
</script>
</body>
</html>