You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1054 lines
60 KiB

<!DOCTYPE html>
<html lang="en" class="scroll-smooth">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Microgrid | Smart Energy System</title>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
<link href="https://fonts.googleapis.com" rel="preconnect"/>
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect"/>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;700;900&family=Montserrat:wght@400;500;700;800;900&family=Inter:wght@400;500;700;800;900&family=JetBrains+Mono:wght@500&display=swap" rel="stylesheet"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/11.0.5/swiper-bundle.min.css" />
<!-- AOS Animation Library -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/aos/2.3.4/aos.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vanilla-tilt/1.7.2/vanilla-tilt.min.js"></script>
<!-- Tailwind & Config -->
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<script id="tailwind-config">
tailwind.config = {
darkMode: "class",
theme: {
extend: {
colors: {
"primary": "#13eca4",
"background-light": "#f8fcfa",
"background-dark": "#10221c",
"pearlescent": "#f0f7f5",
"silver-accent": "#e2e8f0",
"about-us": "#ff6b00"
},
fontFamily: {
"display": ["Montserrat", "sans-serif"],
"sans": ["Montserrat", "sans-serif"],
"mono": ["JetBrains Mono", "Montserrat"],
"inter": ["Inter", "Montserrat"],
},
borderRadius: {
"DEFAULT": "0.5rem",
"lg": "1rem",
"xl": "1.5rem",
"2xl": "2rem",
"3xl": "3rem",
"full": "9999px"
},
backgroundImage: {
'liquid-gradient': 'linear-gradient(135deg, #f8fcfa 0%, #e8f5f1 50%, #dcfce7 100%)',
'glass-gradient': 'linear-gradient(180deg, rgba(255, 255, 255, 0.6) 0%, rgba(255, 255, 255, 0.3) 100%)',
'aurora': 'linear-gradient(135deg, rgba(19,236,164,0.1) 0%, rgba(13,166,112,0.05) 50%, rgba(248,252,250,0) 100%)',
'mesh': 'radial-gradient(at 40% 20%, rgba(19,236,164,0.08) 0px, transparent 50%), radial-gradient(at 80% 0%, rgba(16,34,28,0.05) 0px, transparent 50%), radial-gradient(at 0% 50%, rgba(19,236,164,0.05) 0px, transparent 50%)',
},
boxShadow: {
// 将光效统一映射为 primary 颜色 (13eca4 的 RGBA)
'glow': '0 0 20px rgba(19, 236, 164, 0.4)',
'glow-lg': '0 10px 30px rgba(19, 236, 164, 0.4)',
'bento': '0 20px 40px -15px rgba(0,0,0,0.05), 0 0 0 1px rgba(0,0,0,0.02)',
'bento-hover': '0 30px 60px -20px rgba(19,236,164,0.15), 0 0 0 1px rgba(19,236,164,0.3)',
'bento-dark': '0 30px 60px -15px rgba(0,0,0,0.3), 0 0 0 1px rgba(255,255,255,0.1)',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0', transform: 'translateY(10px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
scan: {
'0%': { top: '-10%', opacity: '0' },
'10%': { opacity: '1' },
'90%': { opacity: '1' },
'100%': { top: '110%', opacity: '0' },
},
rotateGlobe: {
'0%': { transform: 'rotate(0deg)' },
'100%': { transform: 'rotate(360deg)' },
},
dash: {
'0%': { strokeDashoffset: '1000' },
'100%': { strokeDashoffset: '0' },
},
globePulse: {
'0%': { boxShadow: '0 0 0px rgba(19,236,164,0)' },
'50%': { boxShadow: '0 0 50px rgba(19,236,164,0.4)', transform: 'scale(1.02)' },
'100%': { boxShadow: '0 0 0px rgba(19,236,164,0)' },
},
// 高级交互动画
pulseGlow: {
'0%': { textShadow: '0 0 10px rgba(19, 236, 164, 0.4)' },
'100%': { textShadow: '0 0 30px #ff6b00' }
},
sweep: { '100%': { left: '200%' } },
cardFlip: {
'0%': { opacity: '0', transform: 'rotateY(-90deg) translateZ(50px)' },
'100%': { opacity: '1', transform: 'rotateY(0deg) translateZ(0)' }
},
floatY: {
'0%, 100%': { transform: 'translateY(0)' },
'50%': { transform: 'translateY(-15px)' }
},
textShimmer: {
'0%': { backgroundPosition: '0% 50%' },
'100%': { backgroundPosition: '100% 50%' },
},
blobSpin: {
'0%': { transform: 'rotate(0deg) scale(1)' },
'50%': { transform: 'rotate(180deg) scale(1.1)' },
'100%': { transform: 'rotate(360deg) scale(1)' },
}
},
animation: {
'fade-in': 'fadeIn 0.5s ease-out forwards',
'scan-slow': 'scan 6s linear infinite',
'spin-slow': 'rotateGlobe 60s linear infinite',
'dash-flow': 'dash 3s linear infinite',
'globe-select': 'globePulse 0.8s ease-out',
'pulse-glow': 'pulseGlow 2s infinite alternate',
'sweep': 'sweep 3s infinite',
'flip-in': 'cardFlip 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards',
'float-1': 'floatY 3s ease-in-out infinite',
'float-2': 'floatY 3s ease-in-out infinite 1s',
'float-3': 'floatY 3s ease-in-out infinite 2s',
'text-shimmer': 'textShimmer 3s ease-out infinite alternate',
'blob-spin': 'blobSpin 20s infinite cubic-bezier(0.4, 0, 0.2, 1)',
}
},
},
}
</script>
</head>
<body class="bg-[#0a0f0d] text-gray-200 font-sans antialiased overflow-x-hidden selection:bg-[#ff8c00] selection:text-white">
<div id="canvas-container" class="fixed inset-0 z-0 pointer-events-none opacity-90"></div>
<div class="fixed inset-0 bg-gradient-to-t from-[#0a0f0d] via-[#0a0f0d]/50 to-transparent z-0 pointer-events-none"></div>
<main class="relative z-10 max-w-[1200px] mx-auto px-6">
<section id="mod-hero" class="min-h-screen flex flex-col justify-center text-center">
<span class="text-[#ff8c00] font-mono text-sm tracking-[0.3em] uppercase mb-6" data-aos="fade-down">
Smart Energy System
</span>
<h1 class="text-4xl md:text-[2.66rem] leading-none tracking-tighter text-white mb-8 drop-shadow-2xl" data-aos="zoom-in">
INTEGRATED INDEPENDENT
<span class="text-[#13eca4]">INTELLIGENT.</span>
</h1>
<p class="text-[1rem] text-gray-400 font-light max-w-4xl mx-auto leading-relaxed md:text-center" data-aos="fade-up">
The Next Generation of Microgrid Solutions Empowering industrial parks and zero-carbon communities with seamless, green, and autonomous energy.
</p>
</section>
<!-- === 新增:系统拓扑图模块 === -->
<section id="mod-topology" class="min-h-screen flex flex-col justify-center items-center text-center py-24 relative z-10 overflow-hidden bg-[#020504]/50">
<div class="absolute inset-0 z-0 opacity-[0.15] pointer-events-none hex-bg"></div>
<div class="absolute inset-0 z-0 opacity-[0.1] pointer-events-none" style="background-image: linear-gradient(rgba(19,236,164,0.1) 1px, transparent 1px), linear-gradient(90deg, rgba(19,236,164,0.1) 1px, transparent 1px); background-size: 60px 60px; transform: perspective(800px) rotateX(60deg) scale(2.5) translateY(-50px); transform-origin: top center;"></div>
<style>
/* 样式部分完全保留你的原始代码 */
.hex-bg { background-image: url("data:image/svg+xml,%3Csvg width='24' height='40' viewBox='0 0 24 40' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 10L12 3l12 7v14l-12 7-12-7V10z' stroke='rgba(19,236,164,0.05)' fill='none' fill-rule='evenodd'/%3E%3C/svg%3E"); }
.cyber-clip { clip-path: polygon(0 15px, 15px 0, 100% 0, 100% calc(100% - 15px), calc(100% - 15px) 100%, 0 100%); }
.cyber-hub { clip-path: polygon(30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%); }
.tilt-card { transform-style: preserve-3d; will-change: transform; transform: perspective(1000px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) scale3d(1, 1, 1); transition: transform 0.1s cubic-bezier(0.25, 0.46, 0.45, 0.94), border-color 0.4s ease; }
.tilt-card.reset { transition: transform 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94), border-color 0.4s ease; }
.svg-circuit-line { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.flow-packet { stroke-dasharray: 15, 150; animation: dashFlow 3s linear infinite; }
@keyframes dashFlow { 0% { stroke-dashoffset: 165; } 100% { stroke-dashoffset: 0; } }
.layer-stats { opacity: 1; transition: opacity 0.3s ease, transform 0.3s ease; transform: translateY(0); }
.layer-text { opacity: 0; pointer-events: none; transition: opacity 0.3s ease, transform 0.3s ease; transform: translateY(10px); }
.tilt-card:hover .layer-stats { opacity: 0; transform: translateY(-10px); pointer-events: none; }
.tilt-card:hover .layer-text { opacity: 1; pointer-events: auto; transform: translateY(0); }
</style>
<div class="relative z-30 mb-20" data-aos="fade-down">
<h2 class="text-4xl md:text-[2.66rem] mb-4 uppercase tracking-[0.2em] text-white flex items-center justify-center gap-4 drop-shadow-lg">
<!-- <span class="text-[#13eca4] opacity-50 font-light">&lt;</span> -->
Core Architecture of Microgrid System
<!-- <span class="text-[#13eca4] opacity-50 font-light">&gt;</span> -->
</h2>
<div class="flex items-center justify-center gap-4 text-[#13eca4] font-mono text-xs tracking-[0.4em]">
<span class="w-8 h-[1px] bg-gradient-to-r from-transparent to-[#13eca4]"></span>
INTELLIGENT MICROGRID NETWORK
<span class="w-8 h-[1px] bg-gradient-to-l from-transparent to-[#13eca4]"></span>
</div>
</div>
<div class="relative w-full max-w-[1400px] mx-auto z-30 flex items-center justify-center px-10 lg:px-20 min-h-[500px]">
<div class="hidden lg:block absolute inset-0 z-0 pointer-events-none">
<svg class="w-full h-full drop-shadow-[0_0_8px_rgba(19,236,164,0.6)]" preserveAspectRatio="xMidYMid meet" viewBox="0 0 1400 500">
<path d="M 380 130 L 450 130 Q 480 130 480 160 L 480 250 L 550 250" class="svg-circuit-line stroke-[#13eca4]/20" />
<path d="M 380 130 L 450 130 Q 480 130 480 160 L 480 250 L 550 250" class="svg-circuit-line stroke-[#13eca4] flow-packet" />
<path d="M 380 370 L 450 370 Q 480 370 480 340 L 480 250 L 550 250" class="svg-circuit-line stroke-[#ff8c00]/20" />
<path d="M 380 370 L 450 370 Q 480 370 480 340 L 480 250 L 550 250" class="svg-circuit-line stroke-[#ff8c00] flow-packet" style="animation-duration: 2.5s; animation-direction: reverse; filter: drop-shadow(0 0 8px #ff8c00);" />
<path d="M 850 250 L 1020 250" class="svg-circuit-line stroke-white/20" />
<path d="M 850 250 L 1020 250" class="svg-circuit-line stroke-white flow-packet" style="stroke-dasharray: 20, 100; animation-duration: 1.5s; filter: drop-shadow(0 0 8px #fff);" />
</svg>
</div>
<div class="grid grid-cols-1 lg:grid-cols-[minmax(300px,1.2fr)_auto_minmax(300px,1.2fr)] gap-8 lg:gap-16 w-full relative z-10 items-center">
<div class="flex flex-col gap-8 relative z-10">
<div class="tilt-card relative bg-[#060d0a]/90 backdrop-blur-md border border-[#13eca4]/20 p-8 cyber-clip cursor-pointer hover:border-[#13eca4]/80 shadow-xl text-left w-full lg:w-[290px] ml-auto group">
<div class="flex items-start justify-between mb-6 relative z-10">
<div class="flex items-center gap-4">
<div class="w-12 h-12 bg-[#13eca4]/10 rounded flex items-center justify-center border border-[#13eca4]/40 text-[#13eca4] group-hover:bg-[#13eca4] group-hover:text-black transition-colors duration-300">
<span class="material-symbols-outlined text-2xl">&#xec0f;</span>
</div>
<div>
<h3 class="text-xl text-white tracking-wider">Power Generation</h3>
<div class="text-[10px] text-[#13eca4] font-mono mt-1 opacity-70">NODE_TYPE: GEN_01</div>
</div>
</div>
</div>
<div class="relative h-[80px] w-full">
<div class="layer-stats absolute inset-0 w-full grid grid-cols-2 gap-3 font-mono text-xs">
<div class="bg-[#13eca4]/10 border border-[#13eca4]/20 p-3 text-[#13eca4] flex flex-col justify-center">
<span class="text-white/50 text-[10px] mb-1">VOLTAGE OUT</span>
<span class="text-base">400V DC</span>
</div>
<div class="bg-[#13eca4]/10 border border-[#13eca4]/20 p-3 text-[#13eca4] flex flex-col justify-center">
<span class="text-white/50 text-[10px] mb-1">STATUS</span>
<span class="text-base text-[#13eca4] animate-pulse">STABLE</span>
</div>
</div>
<div class="layer-text absolute inset-0 w-full overflow-hidden">
<p class="decrypt-text text-[13px] text-gray-300 leading-relaxed font-light" data-target="Harnessing renewable and conventional energy for consistent supply.">>_ Awaiting command...</p>
</div>
</div>
<div class="absolute bottom-0 right-0 w-6 h-6 border-b-2 border-r-2 border-[#13eca4]/30 group-hover:border-[#13eca4] transition-colors m-1"></div>
</div>
<div class="tilt-card relative bg-[#060d0a]/90 backdrop-blur-md border border-[#ff8c00]/20 p-8 cyber-clip cursor-pointer hover:border-[#ff8c00]/80 shadow-xl text-left w-full lg:w-[290px] ml-auto group">
<div class="flex items-start justify-between mb-6 relative z-10">
<div class="flex items-center gap-4">
<div class="w-12 h-12 bg-[#ff8c00]/10 rounded flex items-center justify-center border border-[#ff8c00]/40 text-[#ff8c00] group-hover:bg-[#ff8c00] group-hover:text-black transition-colors duration-300">
<span class="material-symbols-outlined text-2xl">&#xe1a3;</span>
</div>
<div>
<h3 class="text-xl text-white tracking-wider">Energy Storage</h3>
<div class="text-[10px] text-[#ff8c00] font-mono mt-1 opacity-70">NODE_TYPE: BATT_X</div>
</div>
</div>
</div>
<div class="relative h-[80px] w-full">
<div class="layer-stats absolute inset-0 w-full grid grid-cols-2 gap-3 font-mono text-xs">
<div class="bg-[#ff8c00]/10 border border-[#ff8c00]/20 p-3 text-[#ff8c00] flex flex-col justify-center">
<span class="text-white/50 text-[10px] mb-1">CAPACITY</span>
<span class="text-base">500 kWh</span>
</div>
<div class="bg-[#ff8c00]/10 border border-[#ff8c00]/20 p-3 text-[#ff8c00] flex flex-col justify-center">
<span class="text-white/50 text-[10px] mb-1">MODE</span>
<span class="text-base text-[#ff8c00] animate-pulse">CHARGE</span>
</div>
</div>
<div class="layer-text absolute inset-0 w-full overflow-hidden">
<p class="decrypt-text text-[13px] text-gray-300 leading-relaxed font-light" data-target="Storing surplus electricity to stabilize the grid day and night.">>_ Interfacing...</p>
</div>
</div>
<div class="absolute bottom-0 right-0 w-6 h-6 border-b-2 border-r-2 border-[#ff8c00]/30 group-hover:border-[#ff8c00] transition-colors m-1"></div>
</div>
</div>
<div class="flex justify-center items-center relative z-20 mx-4 py-8 lg:py-0">
<div class="relative flex flex-col items-center justify-center p-12 bg-[#020504]/90 backdrop-blur-lg border border-[#13eca4]/30 cyber-hub hover:border-[#13eca4] transition-all duration-500 w-[300px] h-[360px] shadow-[0_0_30px_rgba(19,236,164,0.05)] group">
<div class="relative w-32 h-32 flex items-center justify-center mb-8">
<div class="absolute inset-0 rounded-full border border-dashed border-[#13eca4]/30 animate-[spin_10s_linear_infinite]"></div>
<div class="absolute inset-2 rounded-full border-t-2 border-[#13eca4]/60 animate-[spin_3s_linear_infinite]"></div>
<div class="absolute inset-6 rounded bg-[#0a120e] border border-[#13eca4]/50 flex items-center justify-center overflow-hidden z-10 group-hover:shadow-[0_0_20px_rgba(19,236,164,0.4)] transition-shadow duration-500">
<span class="material-symbols-outlined text-[#13eca4] text-4xl">&#xe322;</span>
</div>
</div>
<div class="bg-[#13eca4]/10 border border-[#13eca4]/30 px-3 py-1 rounded-sm text-[#13eca4] font-mono text-[10px] mb-4 flex gap-2 items-center tracking-widest">
<span class="w-1.5 h-1.5 bg-[#13eca4] rounded-full animate-ping"></span> CONVERTER
</div>
<h3 class="text-xl text-white tracking-widest mb-2 z-10 group-hover:text-[#13eca4] transition-colors">Power Conversion</h3>
<p class="text-[11px] text-gray-400 font-mono tracking-widest opacity-80 text-center mt-2">AC/DC ⇌ DC/AC<br>EFF: <span class="text-[#13eca4]">99.1%</span></p>
</div>
</div>
<div class="flex flex-col justify-center relative z-10">
<div class="tilt-card relative bg-[#060d0a]/90 backdrop-blur-md border border-white/20 p-8 cyber-clip cursor-pointer hover:border-white/80 shadow-xl text-left w-full lg:w-[290px] group">
<div class="flex items-start justify-between mb-6 relative z-10">
<div class="flex items-center gap-4">
<div class="w-12 h-12 bg-white/10 rounded flex items-center justify-center border border-white/40 text-white group-hover:bg-white group-hover:text-black transition-colors duration-300">
<span class="material-symbols-outlined text-2xl">&#xe7ee;</span>
</div>
<div>
<h3 class="text-xl text-white tracking-wider">Demand Management</h3>
<div class="text-[10px] text-gray-400 font-mono mt-1 opacity-70">NODE_TYPE: LOAD_END</div>
</div>
</div>
</div>
<div class="relative h-[80px] w-full">
<div class="layer-stats absolute inset-0 w-full grid grid-cols-2 gap-3 font-mono text-xs">
<div class="bg-white/5 border border-white/10 p-3 text-white flex flex-col justify-center">
<span class="text-white/50 text-[10px] mb-1">REAL POWER</span>
<span class="text-base">120 kW</span>
</div>
<div class="bg-white/5 border border-white/10 p-3 text-white flex flex-col justify-center">
<span class="text-white/50 text-[10px] mb-1">POWER FACTOR</span>
<span class="text-base">0.98</span>
</div>
</div>
<div class="layer-text absolute inset-0 w-full overflow-hidden">
<p class="decrypt-text text-[13px] text-gray-300 leading-relaxed font-light" data-target="Distributing power smartly to meet diverse load requirements.">>_ Connecting...</p>
</div>
</div>
<div class="absolute bottom-0 right-0 w-6 h-6 border-b-2 border-r-2 border-white/30 group-hover:border-white transition-colors m-1"></div>
</div>
</div>
</div>
</div>
</section>
<script>
document.addEventListener("DOMContentLoaded", () => {
// 1. 极致轻量的 JS 3D Hover 引擎 (仅修改 CSS 变量)
const cards = document.querySelectorAll('.tilt-card');
cards.forEach(card => {
card.addEventListener('mousemove', e => {
// 移除恢复动画,防止移动时卡顿
card.classList.remove('reset');
const rect = card.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// 减弱偏转幅度,最大限制在 3 度以内,防止视差引起的边缘闪烁
const centerX = rect.width / 2;
const centerY = rect.height / 2;
const rotateX = ((y - centerY) / centerY) * -3;
const rotateY = ((x - centerX) / centerX) * 3;
// 将计算结果推给 CSS 变量,让 GPU 处理动画
card.style.setProperty('--rx', `${rotateX}deg`);
card.style.setProperty('--ry', `${rotateY}deg`);
});
card.addEventListener('mouseleave', () => {
// 鼠标移出时添加平滑恢复 class
card.classList.add('reset');
card.style.setProperty('--rx', `0deg`);
card.style.setProperty('--ry', `0deg`);
// 重置打字机文本
const decryptEl = card.querySelector('.decrypt-text');
if(decryptEl) {
decryptEl.dataset.isAnimating = "false";
decryptEl.innerHTML = `>_ Awaiting command...`;
}
});
// 2. 优化版的文本解密引擎 (使用 requestAnimationFrame 防抖)
card.addEventListener('mouseenter', () => {
const decryptEl = card.querySelector('.decrypt-text');
if(!decryptEl || decryptEl.dataset.isAnimating === "true") return;
decryptEl.dataset.isAnimating = "true";
const targetText = decryptEl.getAttribute('data-target');
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%&*';
let iteration = 0;
let cursorColor = "text-[#13eca4]";
if(card.innerHTML.includes('#ff8c00')) cursorColor = "text-[#ff8c00]";
else if(card.innerHTML.includes('border-white')) cursorColor = "text-white";
function decryptFrame() {
if(decryptEl.dataset.isAnimating === "false") return; // 如果鼠标移开提前打断
decryptEl.innerHTML = targetText.split("").map((letter, index) => {
if(index < iteration) {
return letter;
}
return chars[Math.floor(Math.random() * chars.length)];
}).join("") + `<span class="animate-pulse ${cursorColor} ml-1">_</span>`;
if(iteration < targetText.length) {
iteration += 1; // 加快解密速度
// 使用 setTimeout 配合 requestAnimationFrame 控制帧率,防止刷新过快导致视觉抖动
setTimeout(() => requestAnimationFrame(decryptFrame), 20);
} else {
decryptEl.dataset.isAnimating = "false";
decryptEl.innerHTML = targetText + `<span class="animate-pulse ${cursorColor} ml-1">_</span>`;
}
}
requestAnimationFrame(decryptFrame);
});
});
});
</script>
<section id="mod-security" class="min-h-screen flex items-center">
<div class="max-w-xl bg-[#0a0f0d]/80 backdrop-blur-md p-10 border-l-4 border-[#ff8c00] rounded-r-3xl shadow-2xl">
<span class="material-symbols-outlined text-5xl text-[#ff8c00] mb-6">&#xe32a;</span>
<h2 class="text-3xl mb-4 text-white">Safe &<br>Reliable</h2>
<p class="text-lg text-gray-400 leading-relaxed">Sustains island operation without disconnection, backed by multi-power redundancy to guarantee zero downtime for critical loads.</p>
</div>
</section>
<section id="mod-efficiency" class="min-h-screen flex items-center justify-end text-right">
<div class="max-w-xl bg-[#0a0f0d]/80 backdrop-blur-md p-10 border-r-4 border-[#13eca4] rounded-l-3xl shadow-2xl">
<span class="material-symbols-outlined text-5xl text-[#13eca4] mb-6">&#xf0cf;</span>
<h2 class="text-3xl mb-4 text-white">Smart &<br>Efficient</h2>
<p class="text-lg text-gray-400 leading-relaxed">Intelligent optimization and dispatch enable peak shaving and valley filling, effectively reducing electricity costs and energy consumption.</p>
</div>
</section>
<section id="mod-netzero" class="min-h-screen flex items-center">
<div class="max-w-xl bg-[#0a0f0d]/80 backdrop-blur-md p-10 border-l-4 border-white rounded-r-3xl shadow-2xl">
<span class="material-symbols-outlined text-5xl text-white mb-6">&#xea35;</span>
<h2 class="text-3xl mb-4 text-white">Green &<br>Low-Carbon</h2>
<p class="text-lg text-gray-400 leading-relaxed">Efficiently absorbs renewable energy and reduces carbon emissions, facilitating the realization of dual-carbon goals.</p>
</div>
</section>
<section id="mod-autonomous" class="min-h-screen flex items-center justify-end text-right">
<div class="max-w-xl bg-[#0a0f0d]/80 backdrop-blur-md p-10 border-r-4 border-[#ff8c00] rounded-l-3xl shadow-2xl">
<span class="material-symbols-outlined text-5xl text-[#ff8c00] mb-6">&#xe97a;</span>
<h2 class="text-3xl mb-4 text-white">Autonomous &<br>Controllable</h2>
<p class="text-lg text-gray-400 leading-relaxed">Operates independently of the external grid, significantly enhancing energy autonomy and risk resilience.</p>
</div>
</section>
<section id="mod-scenarios" class="min-h-screen flex flex-col justify-center items-center text-center pb-20 relative z-10" style="perspective: 2000px;">
<h2 class="text-4xl md:text-[2.66rem] mb-12 uppercase tracking-widest text-white mt-10 relative z-30">Applicable Scenarios</h2>
<div class="flex flex-wrap justify-center gap-6 font-mono text-sm max-w-4xl relative z-30" id="scenario-buttons">
<button class="scenario-btn px-8 py-3 border border-gray-700 bg-[#0a0f0d] hover:border-[#13eca4] hover:text-[#13eca4] transition-all duration-300 rounded-full focus:outline-none">Industrial Parks</button>
<button class="scenario-btn px-8 py-3 border border-gray-700 bg-[#0a0f0d] hover:border-[#13eca4] hover:text-[#13eca4] transition-all duration-300 rounded-full focus:outline-none">Data Centers</button>
<button class="scenario-btn px-8 py-3 border border-gray-700 bg-[#0a0f0d] hover:border-[#13eca4] hover:text-[#13eca4] transition-all duration-300 rounded-full focus:outline-none">Commercial Complexes</button>
<button class="scenario-btn px-8 py-3 border border-gray-700 bg-[#0a0f0d] hover:border-[#13eca4] hover:text-[#13eca4] transition-all duration-300 rounded-full focus:outline-none">Hospitals & Schools</button>
<button class="scenario-btn px-8 py-3 border border-gray-700 bg-[#0a0f0d] hover:border-[#13eca4] hover:text-[#13eca4] transition-all duration-300 rounded-full focus:outline-none">Remote Regions</button>
<button class="scenario-btn px-8 py-3 border border-gray-700 bg-[#0a0f0d] hover:border-[#13eca4] hover:text-[#13eca4] transition-all duration-300 rounded-full focus:outline-none">Islands</button>
<button class="scenario-btn active-scenario px-8 py-3 bg-[#13eca4]/10 border border-[#13eca4] text-[#13eca4] shadow-[0_0_15px_rgba(19,236,164,0.3)] transition-all duration-300 rounded-full focus:outline-none">Zero-Carbon Communities</button>
<button class="scenario-btn px-8 py-3 border border-gray-700 bg-[#0a0f0d] hover:border-[#13eca4] hover:text-[#13eca4] transition-all duration-300 rounded-full focus:outline-none">New Energy Stations</button>
</div>
<div id="card-wrapper" class="relative mt-12 w-full max-w-5xl h-[450px] z-20" style="transform-style: preserve-3d;">
<div id="scenario-card" class="absolute inset-0 w-full h-full rounded-3xl overflow-hidden border border-white/20 shadow-[0_50px_100px_rgba(0,0,0,0.8)] bg-[#0a0f0d]/90 backdrop-blur-xl opacity-0" style="transform: translateZ(-500px) rotateX(20deg); pointer-events: none;">
<div class="absolute inset-0 z-0 overflow-hidden">
<img id="card-img" src="" class="w-full h-full object-cover opacity-80" alt="Scenario Image" />
</div>
<div class="absolute inset-0 bg-gradient-to-t from-[#0a0f0d] via-transparent to-transparent z-10"></div>
<div class="absolute bottom-12 left-12 z-20 text-left">
<h3 id="card-title" class="text-3xl font-display text-[#13eca4] mb-4 tracking-tighter"></h3>
<p id="card-desc" class="text-lg text-gray-300 max-w-2xl leading-relaxed font-light"></p>
</div>
</div>
</div>
</section>
<section id="mod-contact" class="w-full py-24 relative z-10 overflow-hidden bg-gradient-to-b from-transparent to-[#0a0f0d]">
<div class="max-w-7xl mx-auto px-6">
<div class="flex items-center gap-4 mb-12" data-aos="fade-right">
<div class="h-[1px] w-12 bg-[#13eca4]"></div>
<span class="text-[#13eca4] font-mono text-xs uppercase tracking-[0.4em]">Get in Touch</span>
</div>
<div class="flex flex-col lg:flex-row lg:items-end lg:justify-between gap-12">
<div data-aos="fade-up" data-aos-delay="100">
<h2 class="text-gray-500 text-sm font-mono uppercase tracking-widest mb-2">Microgrid Project Leader</h2>
<div class="flex items-baseline gap-6">
<span class="text-4xl md:text-[2.66rem] font-mono tracking-tighter text-[#13eca4]">Yan</span>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 w-full lg:max-w-2xl" data-aos="fade-left" data-aos-delay="200">
<a href="mailto:sheyanxin@nenghui.com" class="group relative p-6 bg-white/[0.02] border border-white/10 rounded-2xl overflow-hidden transition-all duration-500 hover:border-[#13eca4]/50">
<div class="absolute inset-0 bg-gradient-to-r from-[#13eca4]/10 to-transparent translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-1000"></div>
<div class="relative flex items-center gap-4">
<div class="w-12 h-12 rounded-full bg-[#13eca4]/10 flex items-center justify-center text-[#13eca4]">
<span class="material-symbols-outlined">&#xe158;</span>
</div>
<div>
<div class="text-gray-500 text-[10px] uppercase tracking-widest">Send Email</div>
<div class="text-white font-medium group-hover:text-[#13eca4] transition-colors">sheyanxin@nenghui.com</div>
</div>
</div>
</a>
<a href="tel:8619120593729" class="group relative p-6 bg-white/[0.02] border border-white/10 rounded-2xl overflow-hidden transition-all duration-500 hover:border-[#13eca4]/50">
<div class="absolute inset-0 bg-gradient-to-r from-[#13eca4]/10 to-transparent translate-x-[-100%] group-hover:translate-x-[100%] transition-transform duration-1000"></div>
<div class="relative flex items-center gap-4">
<div class="w-12 h-12 rounded-full bg-[#13eca4]/10 flex items-center justify-center text-[#13eca4]">
<span class="material-symbols-outlined">&#xe0b0;</span>
</div>
<div>
<div class="text-gray-500 text-[10px] uppercase tracking-widest">Call Directly</div>
<div class="text-white font-medium group-hover:text-[#13eca4] transition-colors">+86 191 2059 3729</div>
</div>
</div>
</a>
</div>
</div>
</div>
</section>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/loaders/GLTFLoader.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/gsap/3.12.2/ScrollTrigger.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/aos/2.3.4/aos.js"></script>
<!-- Swiper JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/11.0.5/swiper-bundle.min.js"></script>
<script>
AOS.init({ once: true });
gsap.registerPlugin(ScrollTrigger);
// --- 基础场景设置 ---
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.z = 500;
function updateCameraFOV() {
if (window.innerWidth < 768) {
camera.fov = 75;
} else {
camera.fov = 55;
}
camera.updateProjectionMatrix();
}
updateCameraFOV();
const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('canvas-container').appendChild(renderer.domElement);
// --- 粒子系统基础参数 ---
const particleCount = window.innerWidth < 768 ? 9000 : 12000;
const geometry = new THREE.BufferGeometry();
const currentPositions = new Float32Array(particleCount * 3);
const renderPositions = new Float32Array(particleCount * 3);
const startPos = new Float32Array(particleCount * 3);
const targetPos = new Float32Array(particleCount * 3);
const colors = new Float32Array(particleCount * 3);
const colorPrimary = new THREE.Color(0x13eca4);
const colorAccent = new THREE.Color(0xff8c00);
const colorGray = new THREE.Color(0x555555);
for (let i = 0; i < particleCount; i++) {
const mix = Math.random();
const color = colorPrimary.clone().lerp(colorAccent, mix * 0.3);
colors.set([color.r, color.g, color.b], i * 3);
}
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
// --- 形状预计算 ---
const shapesGen = {
text: () => {
const canvas = document.createElement('canvas');
canvas.width = 1200; canvas.height = 300;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#000'; ctx.fillRect(0, 0, 1200, 300);
ctx.font = 'bold 200px "Arial", sans-serif';
ctx.fillStyle = '#fff'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle';
ctx.fillText( window.innerWidth < 768 ? 'NH' :'NENGHUI', 600, 150);
const data = ctx.getImageData(0, 0, 1200, 300).data;
let points = [];
for (let y = 0; y < 300; y += 3) {
for (let x = 0; x < 1200; x += 3) {
if (data[(y * 1200 + x) * 4] > 128) {
points.push({ x: x - 600, y: -(y - 150), z: (Math.random() - 0.5) * 20 });
}
}
}
const arr = new Float32Array(particleCount * 3);
for (let i = 0; i < particleCount; i++) {
const p = points[i % points.length];
arr.set([p.x, p.y, p.z], i * 3);
}
return arr;
},
nestedPolyhedron: () => {
const arr = new Float32Array(particleCount * 3);
for (let i = 0; i < particleCount; i++) {
const r = i % 2 === 0 ? 100 : 50;
const theta = Math.random() * Math.PI * 2;
const phi = Math.acos(Math.random() * 2 - 1);
let x = r * Math.sin(phi) * Math.cos(theta);
let y = r * Math.sin(phi) * Math.sin(theta);
let z = r * Math.cos(phi);
if (Math.abs(x) > r * 0.7) x = Math.sign(x) * r * 0.7;
arr.set([x, y, z], i * 3);
}
return arr;
},
symbioticLeaf: () => {
const arr = new Float32Array(particleCount * 3);
const leafParticles = Math.floor(particleCount * 0.85);
const carbonParticles = particleCount - leafParticles;
for (let i = 0; i < leafParticles; i++) {
const t = Math.random();
const y = t * 400 - 150;
const widthFactor = Math.sin(t * Math.PI) * (1.2 - 0.2 * t);
const maxWidth = 160;
let x, z;
const isVein = Math.random() < 0.4;
if (isVein) {
if (Math.random() < 0.3) {
x = (Math.random() - 0.5) * 4;
z = (Math.random() - 0.5) * 4;
} else {
const side = Math.random() > 0.5 ? 1 : -1;
const veinT = Math.floor(t * 10) / 10;
x = side * (t - veinT) * 300 + (side * veinT * 20);
x = THREE.MathUtils.clamp(x, -maxWidth * widthFactor, maxWidth * widthFactor);
z = (Math.random() - 0.5) * 10;
}
} else {
const rawX = (Math.random() - 0.5) * 2 * maxWidth * widthFactor;
x = Math.round(rawX / 15) * 15;
z = (Math.random() - 0.5) * 20;
}
const bend = Math.sin(t * Math.PI) * 30;
arr.set([x + bend, y, z], i * 3);
}
for (let i = 0; i < carbonParticles; i++) {
const idx = (leafParticles + i) * 3;
arr.set([
(Math.random() - 0.5) * 300,
-250 - Math.random() * 150,
(Math.random() - 0.5) * 60
], idx);
}
return arr;
},
concentricSphere: () => {
const arr = new Float32Array(particleCount * 3);
for (let i = 0; i < particleCount; i++) {
const r = i % 3 === 0 ? 140 : (i % 3 === 1 ? 90 : 40);
const phi = Math.acos(-1 + Math.random() * 2);
const theta = Math.random() * Math.PI * 2;
arr.set([r * Math.sin(phi) * Math.cos(theta), r * Math.sin(phi) * Math.sin(theta), r * Math.cos(phi)], i * 3);
}
return arr;
},
barGraph: () => {
const arr = new Float32Array(particleCount * 3);
for (let i = 0; i < particleCount; i++) {
const gridX = Math.floor(Math.random() * 8) - 4;
const gridZ = Math.floor(Math.random() * 8) - 4;
const height = (Math.sin(gridX) + Math.cos(gridZ) + 2) * 40 + 20;
arr.set([gridX * 40 + (Math.random() - 0.5) * 20, Math.random() * height - 100, gridZ * 40 + (Math.random() - 0.5) * 20], i * 3);
}
return arr;
},
shield: () => {
const arr = new Float32Array(particleCount * 3);
for (let i = 0; i < particleCount; i++) {
let x = (Math.random() - 0.5) * 200;
let y, z;
let topEdge = 100 + 15 * Math.cos(x * Math.PI / 100);
let bottomEdge = -120 + 220 * Math.pow(Math.abs(x) / 100, 2);
let t = Math.random();
if (Math.random() > 0.6) {
t = Math.random() > 0.5 ? Math.random() * 0.1 : 0.9 + Math.random() * 0.1;
}
y = bottomEdge + t * (topEdge - bottomEdge);
let maxZ = 30 * (1 - Math.pow(Math.abs(x) / 100, 2));
if (Math.abs(x) < 8 || Math.abs(y - 10) < 8) {
maxZ += 10;
}
z = (Math.random() - 0.5) * maxZ;
arr.set([x, y, z], i * 3);
}
return arr;
},
torusKnot: () => {
const arr = new Float32Array(particleCount * 3);
for (let i = 0; i < particleCount; i++) {
const t = Math.random() * Math.PI * 2;
const p = 2;
const q = 3;
const r = 50 * (2 + Math.cos(q * t));
const x = r * Math.cos(p * t);
const y = r * Math.sin(p * t);
const z = 50 * Math.sin(q * t);
const noise = 15;
arr.set([
x + (Math.random() - 0.5) * noise,
y + (Math.random() - 0.5) * noise,
z + (Math.random() - 0.5) * noise
], i * 3);
}
return arr;
},
networkNode: () => {
const arr = new Float32Array(particleCount * 3);
const nodes = [
{x: 0, y: 0, z: 0, r: 35},
{x: 120, y: 70, z: 40, r: 15},
{x: -110, y: -80, z: 20, r: 20},
{x: 90, y: -100, z: -40, r: 15},
{x: -100, y: 90, z: -30, r: 18},
{x: 0, y: 130, z: 10, r: 12},
{x: 0, y: -130, z: 0, r: 12}
];
for (let i = 0; i < particleCount; i++) {
const pType = Math.random();
if (pType < 0.5) {
const node = nodes[Math.floor(Math.random() * nodes.length)];
const theta = Math.random() * Math.PI * 2;
const phi = Math.acos((Math.random() * 2) - 1);
const r = node.r * (0.5 + 0.5 * Math.random());
arr.set([
node.x + r * Math.sin(phi) * Math.cos(theta),
node.y + r * Math.sin(phi) * Math.sin(theta),
node.z + r * Math.cos(phi)
], i * 3);
} else {
const targetNode = nodes[1 + Math.floor(Math.random() * (nodes.length - 1))];
const t = Math.random();
const noise = 3;
arr.set([
t * targetNode.x + (Math.random() - 0.5) * noise,
t * targetNode.y + (Math.random() - 0.5) * noise,
t * targetNode.z + (Math.random() - 0.5) * noise
], i * 3);
}
}
return arr;
}
};
const precalculatedShapes = {
text: shapesGen.text(),
nestedPolyhedron: shapesGen.nestedPolyhedron(),
symbioticLeaf: shapesGen.symbioticLeaf(),
concentricSphere: shapesGen.concentricSphere(),
barGraph: shapesGen.barGraph(),
shield: shapesGen.shield(),
torusKnot: shapesGen.torusKnot(),
networkNode: shapesGen.networkNode()
};
currentPositions.set(precalculatedShapes.text);
renderPositions.set(precalculatedShapes.text);
geometry.setAttribute('position', new THREE.BufferAttribute(renderPositions, 3));
const material = new THREE.PointsMaterial({
size: window.innerWidth < 768 ? 3.5 : 4.0,
vertexColors: true,
transparent: true,
opacity: 0.9,
blending: THREE.AdditiveBlending,
sizeAttenuation: true,
depthWrite: false
});
const particles = new THREE.Points(geometry, material);
scene.add(particles);
let time = 0;
let morphData = { progress: 0 };
let currentShapeKey = 'text';
let morphTween = null;
const rotationSpeed = { x: 0, y: 0 };
const waveConfig = { amplitude: 20 };
const leafConfigs = { carbonOpacity: 1.0, carbonYOffset: 0 };
function morphTo(shapeKey) {
if (currentShapeKey === shapeKey) return;
currentShapeKey = shapeKey;
if (morphTween) morphTween.kill();
// 颜色过渡处理
const colorAttribute = geometry.attributes.color;
const targetColors = new Float32Array(particleCount * 3);
const leafParticles = Math.floor(particleCount * 0.85);
for (let i = 0; i < particleCount; i++) {
let color;
if (shapeKey === 'symbioticLeaf') {
if (i < leafParticles) {
color = colorPrimary.clone().lerp(colorAccent, Math.random() * 0.2);
} else {
color = colorGray.clone();
}
} else {
color = colorPrimary.clone().lerp(colorAccent, Math.random() * 0.3);
}
targetColors.set([color.r, color.g, color.b], i * 3);
}
gsap.to(colorAttribute.array, {
endArray: targetColors,
duration: 1.5,
ease: "power2.inOut",
onUpdate: () => colorAttribute.needsUpdate = true
});
// 形状平滑过渡
for (let i = 0; i < currentPositions.length; i++) {
startPos[i] = currentPositions[i];
}
targetPos.set(precalculatedShapes[shapeKey]);
morphData.progress = 0;
morphTween = gsap.to(morphData, {
progress: 1,
duration: 2.0,
ease: "power3.inOut",
onUpdate: () => {
for (let i = 0; i < particleCount * 3; i++) {
currentPositions[i] = startPos[i] + (targetPos[i] - startPos[i]) * morphData.progress;
}
}
});
// 视角及其他动画
if (shapeKey === 'text') {
gsap.to(rotationSpeed, { x: 0, y: 0, duration: 1.5 });
const targetX = Math.round(particles.rotation.x / (Math.PI * 2)) * (Math.PI * 2);
const targetY = Math.round(particles.rotation.y / (Math.PI * 2)) * (Math.PI * 2);
gsap.to(particles.rotation, { x: targetX, y: targetY, duration: 2.0 });
} else if (shapeKey === 'shield') {
gsap.to(rotationSpeed, { x: 0, y: 0.002, duration: 1.5 });
const targetX = Math.round(particles.rotation.x / (Math.PI * 2)) * (Math.PI * 2);
gsap.to(particles.rotation, { x: targetX, duration: 2.0 });
} else if (shapeKey === 'symbioticLeaf') {
gsap.to(rotationSpeed, { x: 0.0005, y: 0.001, duration: 1.5 });
leafConfigs.carbonOpacity = 1.0;
leafConfigs.carbonYOffset = 0;
} else if (shapeKey === 'barGraph') {
gsap.to(rotationSpeed, { x: 0, y: 0.002, duration: 1.5 });
const targetX = Math.round(particles.rotation.x / (Math.PI * 2)) * (Math.PI * 2);
gsap.to(particles.rotation, { x: targetX + 0.4, duration: 2.0 });
} else {
gsap.to(rotationSpeed, { x: 0.001, y: 0.002, duration: 2.0 });
}
gsap.to(waveConfig, {
duration: 2.0,
amplitude: (shapeKey === 'text') ? 20 : 0
});
}
// --- 渲染循环与动态动画 ---
function animate() {
requestAnimationFrame(animate);
time += 0.02;
const positions = geometry.attributes.position.array;
const colorsArray = geometry.attributes.color.array;
const leafParticles = Math.floor(particleCount * 0.85);
for (let i = 0; i < particleCount; i++) {
let idx = i * 3;
let baseX = currentPositions[idx];
let baseY = currentPositions[idx + 1];
let baseZ = currentPositions[idx + 2];
if (currentShapeKey === 'symbioticLeaf' ) {
if (i < leafParticles) {
if (i % 7 === 0 ) {
if (Math.abs(baseX) < 100) {
const angle = time * 3 + (baseY * 0.02);
const r = 10 * Math.sin(time * 0.5);
positions[idx] = baseX + r * Math.cos(angle);
positions[idx + 1] = baseY;
positions[idx + 2] = baseZ + r * Math.sin(angle);
}
} else {
positions[idx] = baseX + Math.sin(time + baseY * 0.1) * 2;
positions[idx + 1] = baseY;
positions[idx + 2] = baseZ;
}
}
} else if (waveConfig.amplitude > 0.01) {
const phase = baseX * 0.006 + time;
const waveY = Math.sin(phase) * (waveConfig.amplitude * 0.4);
const waveZ = Math.cos(phase * 0.8) * waveConfig.amplitude;
positions[idx] = baseX;
positions[idx + 1] = baseY + waveY;
positions[idx + 2] = baseZ + waveZ;
} else {
positions[idx] = baseX;
positions[idx + 1] = baseY;
positions[idx + 2] = baseZ;
}
if (currentShapeKey === 'symbioticLeaf') {
if (i >= leafParticles) {
let y = baseY + (time * 50) % 200;
let opacity = 1.0;
if (y > -150) {
opacity = THREE.MathUtils.lerp(1.0, 0.0, (y + 150) / 100);
}
if (y > -50) opacity = 0;
positions[idx + 1] = y;
colorsArray[idx] = colorGray.r * opacity;
colorsArray[idx + 1] = colorGray.g * opacity;
colorsArray[idx + 2] = colorGray.b * opacity;
}
}
}
geometry.attributes.position.needsUpdate = true;
if (currentShapeKey === 'symbioticLeaf') {
geometry.attributes.color.needsUpdate = true;
}
particles.rotation.x += rotationSpeed.x;
particles.rotation.y += rotationSpeed.y;
renderer.render(scene, camera);
}
animate();
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
updateCameraFOV();
});
// --- 滚动监听:新增对拓扑图的监控数组 ---
const shapeList = ['text', 'shield', 'concentricSphere', 'symbioticLeaf', 'torusKnot', 'networkNode', 'barGraph', 'nestedPolyhedron'];
const sections = ['#mod-hero', '#mod-security', '#mod-efficiency', '#mod-netzero', '#mod-autonomous', '#mod-topology', '#mod-scenarios', '#mod-contact'];
sections.forEach((id, idx) => {
ScrollTrigger.create({
trigger: id,
start: "top 55%",
end: "bottom 45%",
onEnter: () => morphTo(shapeList[idx]),
onEnterBack: () => morphTo(shapeList[idx])
});
});
</script>
<script>
// --- 场景卡片 3D 跃出动画 ---
const scenarioData = {
"Industrial Parks": { img: "https://nenghui.com/wp-content/uploads/2026/03/icrogrid-Industrial-parks.jpg", desc: "Optimize energy consumption and reduce operational costs for smart industrial zones with intelligent management." },
"Data Centers": { img: "https://nenghui.com/wp-content/uploads/2026/03/icrogrid-data-center.jpg", desc: "Ensuring continuous mission-critical power supply for data centers with robust and resilient microgrids." },
"Commercial Complexes": { img: "https://nenghui.com/wp-content/uploads/2026/03/icrogrid-Commercial-complexes.jpg", desc: "Optimize operational costs for commercial hubs through intelligent energy distribution and Peak Shaving." },
"Hospitals & Schools": { img: "https://nenghui.com/wp-content/uploads/2026/03/icrogrid-Hospitals-schools.jpg", desc: "Ensuring uninterrupted power supply for critical medical services and secure educational campus environments." },
"Remote Regions": { img: "https://nenghui.com/wp-content/uploads/2026/03/icrogrid-Remote-regions.jpg", desc: "Overcoming geographical barriers with advanced microgrid technology to illuminate the world's remotest corners." },
"Islands": { img: "https://nenghui.com/wp-content/uploads/2026/03/icrogrid-Islands.jpg", desc: "Achieve reliable energy independence for remote islands through sustainable solar and storage systems." },
"Zero-Carbon Communities": { img: "https://nenghui.com/wp-content/uploads/2026/03/icrogrid-Zero-carbon-communities.jpg", desc: "Building a sustainable future for modern living through intelligent and eco-friendly microgrid systems." },
"New Energy Stations": { img: "https://nenghui.com/wp-content/uploads/2026/03/icrogrid-New-energy-stations.jpg", desc: "Enhancing grid stability and renewable integration through advanced storage-based microgrid management systems." }
};
const scenarioButtons = document.querySelectorAll('.scenario-btn');
const scenarioCard = document.getElementById('scenario-card');
const cardImg = document.getElementById('card-img');
const cardTitle = document.getElementById('card-title');
const cardDesc = document.getElementById('card-desc');
let currentActiveBtn = document.querySelector('.active-scenario');
function updateCardContent(scenarioName) {
const data = scenarioData[scenarioName];
const tl = gsap.timeline();
tl.to(scenarioCard, { rotationY: 90, opacity: 0, duration: 0.4, ease: "power2.in" })
.call(() => {
cardImg.src = data.img;
cardTitle.innerText = scenarioName;
cardDesc.innerText = data.desc;
})
.fromTo(scenarioCard,
{ rotationY: -90 },
{ rotationY: 0, opacity: 1, duration: 0.6, ease: "back.out(1.7)" }
);
}
scenarioButtons.forEach(btn => {
btn.addEventListener('click', () => {
if (btn === currentActiveBtn) return;
scenarioButtons.forEach(b => {
b.classList.remove('active-scenario', 'bg-[#13eca4]/10', 'border-[#13eca4]', 'text-[#13eca4]', 'shadow-[0_0_15px_rgba(19,236,164,0.3)]');
b.classList.add('border-gray-700', 'bg-[#0a0f0d]');
});
btn.classList.add('active-scenario', 'bg-[#13eca4]/10', 'border-[#13eca4]', 'text-[#13eca4]', 'shadow-[0_0_15px_rgba(19,236,164,0.3)]');
currentActiveBtn = btn;
updateCardContent(btn.innerText.trim());
});
});
if (currentActiveBtn) {
const data = scenarioData[currentActiveBtn.innerText.trim()];
cardImg.src = data.img;
cardTitle.innerText = currentActiveBtn.innerText.trim();
cardDesc.innerText = data.desc;
}
ScrollTrigger.create({
trigger: '#mod-scenarios',
start: "top 60%",
end: "bottom top",
onEnter: () => {
gsap.fromTo(scenarioCard,
{ z: -1000, rotationX: 45, rotationY: -30, opacity: 0, scale: 0.5 },
{ z: 0, rotationX: 0, rotationY: 0, opacity: 1, scale: 1, duration: 1.5, ease: "expo.out" }
);
},
onLeaveBack: () => {
gsap.to(scenarioCard, {
z: -800, rotationX: 20, opacity: 0, scale: 0.7, duration: 0.8, ease: "power2.in"
});
},
onLeave: () => {
gsap.to(scenarioCard, {
y: -200, z: 200, rotationX: -20, opacity: 0, duration: 0.8, ease: "power2.in"
});
},
onEnterBack: () => {
gsap.to(scenarioCard, {
y: 0, z: 0, rotationX: 0, opacity: 1, scale: 1, duration: 1, ease: "back.out(1.2)"
});
}
});
</script>
</body>
</html>