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

1173 lines
48 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>