独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>算力毛细血管网 · 液态路由原理动画</title>
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=Azeret+Mono:wght@300;400;500&display=swap" rel="stylesheet">
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{
--bg:#060b18;--surface:#0c1425;--border:rgba(255,255,255,0.06);
--private:#00e5c7;--private-dim:rgba(0,229,199,0.15);
--public:#ff8c42;--public-dim:rgba(255,140,66,0.12);
--router:#00ffa3;--router-glow:rgba(0,255,163,0.35);
--infer:#c084fc;--text:#e8edf5;--muted:#5a6d8a;--accent:#00ffa3;
}
body{
background:var(--bg);color:var(--text);
font-family:'Azeret Mono',monospace;
height:100vh;overflow:hidden;display:flex;align-items:center;justify-content:center;
}
#wrap{width:100vw;height:100vh;position:relative;display:flex;align-items:center;justify-content:center}
svg#main{width:100%;height:100%;display:block}
/* ─── 标题面板 ─── */
#title-panel{
position:fixed;top:20px;left:24px;z-index:10;pointer-events:none;
}
#title-panel h1{
font-family:'Syne',sans-serif;font-size:26px;font-weight:800;
background:linear-gradient(135deg,var(--private),var(--router));
-webkit-background-clip:text;-webkit-text-fill-color:transparent;
letter-spacing:-0.5px;
}
#title-panel .sub{
font-size:11px;color:var(--muted);margin-top:3px;letter-spacing:1.5px;text-transform:uppercase;
}
/* ─── 指标面板 ─── */
#metrics{
position:fixed;top:18px;right:24px;z-index:10;
display:flex;flex-direction:column;gap:8px;pointer-events:none;
}
.met{
background:rgba(12,20,37,0.88);backdrop-filter:blur(14px);
border:1px solid var(--border);border-radius:10px;padding:9px 16px;
display:flex;align-items:center;gap:10px;min-width:210px;
}
.met-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}
.met-body{display:flex;flex-direction:column;gap:1px}
.met-label{font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:.8px}
.met-val{font-size:15px;font-weight:600;font-family:'Syne',sans-serif}
/* ─── 控制面板 ─── */
#controls{
position:fixed;bottom:22px;left:50%;transform:translateX(-50%);z-index:10;
background:rgba(12,20,37,0.92);backdrop-filter:blur(18px);
border:1px solid rgba(0,255,163,0.15);border-radius:14px;
padding:14px 30px;display:flex;gap:36px;align-items:center;
}
.ctrl{display:flex;flex-direction:column;gap:3px}
.ctrl label{font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:1px}
.ctrl input[type=range]{
-webkit-appearance:none;width:170px;height:3px;
background:rgba(255,255,255,0.08);border-radius:2px;outline:none;cursor:pointer;
}
.ctrl input[type=range]::-webkit-slider-thumb{
-webkit-appearance:none;width:14px;height:14px;
background:var(--accent);border-radius:50%;cursor:pointer;
box-shadow:0 0 10px var(--router-glow);
}
.ctrl .val{font-size:12px;color:var(--accent);font-weight:500}
.ctrl .hint{font-size:9px;color:var(--muted);margin-top:1px}
/* ─── 图例 ─── */
#legend{
position:fixed;bottom:80px;left:24px;z-index:10;
display:flex;flex-direction:column;gap:6px;pointer-events:none;
}
.leg{display:flex;align-items:center;gap:8px;font-size:10px;color:var(--muted)}
.leg-line{width:22px;height:3px;border-radius:2px}
/* ─── 流量指示器 ─── */
#traffic-indicator{
position:fixed;bottom:80px;right:24px;z-index:10;pointer-events:none;
text-align:right;
}
#traffic-indicator .lbl{font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:1px}
#traffic-indicator .state{font-size:22px;font-weight:700;font-family:'Syne',sans-serif;margin-top:2px}
@media(prefers-reduced-motion:reduce){
svg *{animation:none!important;transition:none!important}
}
</style>
</head>
<body>
<div id="wrap">
<svg id="main" viewBox="0 0 1400 900" preserveAspectRatio="xMidYMid meet">
<defs>
<!-- 背景径向渐变 -->
<radialGradient id="bg-grad" cx="50%" cy="50%" r="65%">
<stop offset="0%" stop-color="#0f1a2e"/><stop offset="100%" stop-color="#060b18"/>
</radialGradient>
<!-- 路由器渐变 -->
<radialGradient id="rtr-grad" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#00ffa3"/><stop offset="80%" stop-color="#00cc80"/><stop offset="100%" stop-color="#009960"/>
</radialGradient>
<!-- 发光滤镜 -->
<filter id="gl" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="6" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
<filter id="gl2" x="-80%" y="-80%" width="260%" height="260%">
<feGaussianBlur stdDeviation="14" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
<filter id="gl3" x="-100%" y="-100%" width="300%" height="300%">
<feGaussianBlur stdDeviation="25" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
<!-- 网格图案 -->
<pattern id="grid" width="60" height="60" patternUnits="userSpaceOnUse">
<path d="M60,0 L0,0 0,60" fill="none" stroke="rgba(255,255,255,0.018)" stroke-width="0.5"/>
</pattern>
</defs>
<!-- 背景 -->
<rect width="1400" height="900" fill="url(#bg-grad)"/>
<rect width="1400" height="900" fill="url(#grid)"/>
<!-- 大气光晕 -->
<circle cx="700" cy="450" r="260" fill="rgba(0,255,163,0.015)" filter="url(#gl3)"/>
<circle cx="230" cy="450" r="140" fill="rgba(0,229,199,0.012)" filter="url(#gl3)"/>
<circle cx="1170" cy="450" r="140" fill="rgba(255,140,66,0.008)" filter="url(#gl3)"/>
<!-- ═══════ 管壁层(宽描边,低透明度) ═══════ -->
<g id="vessels" opacity="1">
<!-- 顶部:业务→感应器 -->
<path d="M700,108 C700,140 700,170 700,195" fill="none" stroke="rgba(232,237,245,0.06)" stroke-width="14" stroke-linecap="round"/>
<!-- 感应器→路由器 -->
<path d="M700,240 C700,290 700,350 700,400" fill="none" stroke="rgba(232,237,245,0.06)" stroke-width="14" stroke-linecap="round"/>
<!-- 左侧毛细管壁 -->
<path d="M642,425 C530,400 380,348 265,335" fill="none" stroke="rgba(0,229,199,0.07)" stroke-width="16" stroke-linecap="round"/>
<path d="M632,450 C480,450 340,450 200,450" fill="none" stroke="rgba(0,229,199,0.07)" stroke-width="16" stroke-linecap="round"/>
<path d="M642,475 C530,500 380,552 265,565" fill="none" stroke="rgba(0,229,199,0.07)" stroke-width="16" stroke-linecap="round"/>
<!-- 右侧毛细管壁 -->
<path id="vw-r1" d="M758,425 C870,400 1020,348 1135,335" fill="none" stroke="rgba(255,140,66,0.03)" stroke-width="16" stroke-linecap="round"/>
<path id="vw-r2" d="M768,450 C920,450 1060,450 1200,450" fill="none" stroke="rgba(255,140,66,0.03)" stroke-width="16" stroke-linecap="round"/>
<path id="vw-r3" d="M758,475 C870,500 1020,552 1135,565" fill="none" stroke="rgba(255,140,66,0.03)" stroke-width="16" stroke-linecap="round"/>
</g>
<!-- ═══════ 流动路径层(细描边 + dash 动画) ═══════ -->
<g id="flow-paths">
<!-- 顶部下行 -->
<path id="fp-top" d="M700,108 C700,140 700,170 700,195" fill="none" stroke="#e8edf5" stroke-width="2.5" stroke-linecap="round" opacity="0.5"
stroke-dasharray="6 10">
<animate attributeName="stroke-dashoffset" from="0" to="-16" dur="1s" repeatCount="indefinite"/>
</path>
<path id="fp-sr" d="M700,240 C700,290 700,350 700,400" fill="none" stroke="#e8edf5" stroke-width="2.5" stroke-linecap="round" opacity="0.5"
stroke-dasharray="6 10">
<animate attributeName="stroke-dashoffset" from="0" to="-16" dur="0.8s" repeatCount="indefinite"/>
</path>
<!-- 左侧流动 -->
<path id="fp-l1" d="M642,425 C530,400 380,348 265,335" fill="none" stroke="#00e5c7" stroke-width="2" stroke-linecap="round" opacity="0.65"
stroke-dasharray="5 9">
<animate attributeName="stroke-dashoffset" from="0" to="-14" dur="1.2s" repeatCount="indefinite"/>
</path>
<path id="fp-l2" d="M632,450 C480,450 340,450 200,450" fill="none" stroke="#00e5c7" stroke-width="2" stroke-linecap="round" opacity="0.65"
stroke-dasharray="5 9">
<animate attributeName="stroke-dashoffset" from="0" to="-14" dur="1s" repeatCount="indefinite"/>
</path>
<path id="fp-l3" d="M642,475 C530,500 380,552 265,565" fill="none" stroke="#00e5c7" stroke-width="2" stroke-linecap="round" opacity="0.65"
stroke-dasharray="5 9">
<animate attributeName="stroke-dashoffset" from="0" to="-14" dur="1.2s" repeatCount="indefinite"/>
</path>
<!-- 右侧流动 -->
<path id="fp-r1" d="M758,425 C870,400 1020,348 1135,335" fill="none" stroke="#ff8c42" stroke-width="2" stroke-linecap="round" opacity="0.2"
stroke-dasharray="5 9">
<animate attributeName="stroke-dashoffset" from="0" to="-14" dur="1.2s" repeatCount="indefinite"/>
</path>
<path id="fp-r2" d="M768,450 C920,450 1060,450 1200,450" fill="none" stroke="#ff8c42" stroke-width="2" stroke-linecap="round" opacity="0.2"
stroke-dasharray="5 9">
<animate attributeName="stroke-dashoffset" from="0" to="-14" dur="1s" repeatCount="indefinite"/>
</path>
<path id="fp-r3" d="M758,475 C870,500 1020,552 1135,565" fill="none" stroke="#ff8c42" stroke-width="2" stroke-linecap="round" opacity="0.2"
stroke-dasharray="5 9">
<animate attributeName="stroke-dashoffset" from="0" to="-14" dur="1.2s" repeatCount="indefinite"/>
</path>
<!-- 底部汇聚路径 -->
<path id="fp-bl" d="M200,480 C200,570 440,680 580,740" fill="none" stroke="#00e5c7" stroke-width="1.5" stroke-linecap="round" opacity="0.35"
stroke-dasharray="4 8">
<animate attributeName="stroke-dashoffset" from="0" to="-12" dur="1.4s" repeatCount="indefinite"/>
</path>
<path id="fp-bc" d="M700,510 C700,580 700,660 700,720" fill="none" stroke="rgba(232,237,245,0.25)" stroke-width="1.5" stroke-linecap="round"
stroke-dasharray="4 8">
<animate attributeName="stroke-dashoffset" from="0" to="-12" dur="1.2s" repeatCount="indefinite"/>
</path>
<path id="fp-br" d="M1200,480 C1200,570 960,680 820,740" fill="none" stroke="#ff8c42" stroke-width="1.5" stroke-linecap="round" opacity="0.15"
stroke-dasharray="4 8">
<animate attributeName="stroke-dashoffset" from="0" to="-12" dur="1.4s" repeatCount="indefinite"/>
</path>
</g>
<!-- ═══════ 节点层 ═══════ -->
<!-- 业务请求源 -->
<g id="node-req">
<circle cx="700" cy="82" r="24" fill="#0c1425" stroke="#e8edf5" stroke-width="1.5" filter="url(#gl)"/>
<text x="700" y="78" text-anchor="middle" fill="#e8edf5" font-size="9" font-family="Syne,sans-serif" font-weight="700">REQ</text>
<text x="700" y="92" text-anchor="middle" fill="#5a6d8a" font-size="7">业务请求</text>
</g>
<!-- 潮汐感应器 -->
<g id="node-sensor">
<circle cx="700" cy="218" r="28" fill="#0c1425" stroke="#e8edf5" stroke-width="1.5" filter="url(#gl)"/>
<text x="700" y="215" text-anchor="middle" fill="#e8edf5" font-size="9" font-family="Syne,sans-serif" font-weight="600">潮汐</text>
<text x="700" y="228" text-anchor="middle" fill="#5a6d8a" font-size="7">感应器</text>
<!-- 队列条 -->
<rect x="744" y="204" width="5" height="28" rx="2.5" fill="#0c1425" stroke="rgba(255,255,255,0.08)" stroke-width="0.5"/>
<rect id="queue-fill" x="744" y="232" width="5" height="0" rx="2.5" fill="#00ffa3" opacity="0.85">
<animate attributeName="opacity" values="0.85;1;0.85" dur="1s" repeatCount="indefinite"/>
</rect>
</g>
<!-- ═══ 液态路由器(中心) ═══ -->
<g id="node-router">
<!-- 脉冲环 -->
<circle cx="700" cy="450" r="60" fill="none" stroke="#00ffa3" stroke-width="0.8">
<animate attributeName="r" values="60;150" dur="3s" repeatCount="indefinite"/>
<animate attributeName="opacity" values="0.5;0" dur="3s" repeatCount="indefinite"/>
</circle>
<circle cx="700" cy="450" r="60" fill="none" stroke="#00ffa3" stroke-width="0.8">
<animate attributeName="r" values="60;150" dur="3s" begin="1s" repeatCount="indefinite"/>
<animate attributeName="opacity" values="0.5;0" dur="3s" begin="1s" repeatCount="indefinite"/>
</circle>
<circle cx="700" cy="450" r="60" fill="none" stroke="#00ffa3" stroke-width="0.8">
<animate attributeName="r" values="60;150" dur="3s" begin="2s" repeatCount="indefinite"/>
<animate attributeName="opacity" values="0.5;0" dur="3s" begin="2s" repeatCount="indefinite"/>
</circle>
<!-- 外环 -->
<circle cx="700" cy="450" r="62" fill="#080e1e" stroke="#00ffa3" stroke-width="2" opacity="0.85" filter="url(#gl)"/>
<!-- 内核 -->
<circle id="router-core" cx="700" cy="450" r="36" fill="url(#rtr-grad)" opacity="0.92" filter="url(#gl2)">
<animate attributeName="r" values="36;39;36" dur="2s" repeatCount="indefinite"/>
</circle>
<text x="700" y="447" text-anchor="middle" fill="#060b18" font-size="10" font-family="Syne,sans-serif" font-weight="800">液态</text>
<text x="700" y="460" text-anchor="middle" fill="#060b18" font-size="10" font-family="Syne,sans-serif" font-weight="800">路由</text>
</g>
<!-- ═══ 私云节点 ═══ -->
<g id="node-priv">
<g>
<circle cx="265" cy="335" r="32" fill="#080e1e" stroke="#00e5c7" stroke-width="1.5" filter="url(#gl)"/>
<circle cx="265" cy="335" r="16" fill="#00e5c7" opacity="0.15"/>
<text x="265" y="332" text-anchor="middle" fill="#00e5c7" font-size="9" font-family="Syne,sans-serif" font-weight="700">私云</text>
<text x="265" y="345" text-anchor="middle" fill="#00e5c7" font-size="11" font-weight="700">α</text>
</g>
<g>
<circle cx="200" cy="450" r="32" fill="#080e1e" stroke="#00e5c7" stroke-width="1.5" filter="url(#gl)"/>
<circle cx="200" cy="450" r="16" fill="#00e5c7" opacity="0.15"/>
<text x="200" y="447" text-anchor="middle" fill="#00e5c7" font-size="9" font-family="Syne,sans-serif" font-weight="700">私云</text>
<text x="200" y="460" text-anchor="middle" fill="#00e5c7" font-size="11" font-weight="700">β</text>
</g>
<g>
<circle cx="265" cy="565" r="32" fill="#080e1e" stroke="#00e5c7" stroke-width="1.5" filter="url(#gl)"/>
<circle cx="265" cy="565" r="16" fill="#00e5c7" opacity="0.15"/>
<text x="265" y="562" text-anchor="middle" fill="#00e5c7" font-size="9" font-family="Syne,sans-serif" font-weight="700">私云</text>
<text x="265" y="575" text-anchor="middle" fill="#00e5c7" font-size="11" font-weight="700">γ</text>
</g>
<!-- 区域标签 -->
<text x="230" y="640" text-anchor="middle" fill="#00e5c7" font-size="14" font-family="Syne,sans-serif" font-weight="700" opacity="0.7">私云算力池</text>
<text x="230" y="658" text-anchor="middle" fill="#5a6d8a" font-size="9">安全域 · 优先调度</text>
</g>
<!-- ═══ 公云节点 ═══ -->
<g id="node-pub">
<g id="pub-a" opacity="0.25">
<circle cx="1135" cy="335" r="32" fill="#080e1e" stroke="#ff8c42" stroke-width="1.5" filter="url(#gl)"/>
<circle cx="1135" cy="335" r="16" fill="#ff8c42" opacity="0.1"/>
<text x="1135" y="332" text-anchor="middle" fill="#ff8c42" font-size="9" font-family="Syne,sans-serif" font-weight="700">公云</text>
<text x="1135" y="345" text-anchor="middle" fill="#ff8c42" font-size="11" font-weight="700">α</text>
</g>
<g id="pub-b" opacity="0.25">
<circle cx="1200" cy="450" r="32" fill="#080e1e" stroke="#ff8c42" stroke-width="1.5" filter="url(#gl)"/>
<circle cx="1200" cy="450" r="16" fill="#ff8c42" opacity="0.1"/>
<text x="1200" y="447" text-anchor="middle" fill="#ff8c42" font-size="9" font-family="Syne,sans-serif" font-weight="700">公云</text>
<text x="1200" y="460" text-anchor="middle" fill="#ff8c42" font-size="11" font-weight="700">β</text>
</g>
<g id="pub-c" opacity="0.25">
<circle cx="1135" cy="565" r="32" fill="#080e1e" stroke="#ff8c42" stroke-width="1.5" filter="url(#gl)"/>
<circle cx="1135" cy="565" r="16" fill="#ff8c42" opacity="0.1"/>
<text x="1135" y="562" text-anchor="middle" fill="#ff8c42" font-size="9" font-family="Syne,sans-serif" font-weight="700">公云</text>
<text x="1135" y="575" text-anchor="middle" fill="#ff8c42" font-size="11" font-weight="700">γ</text>
</g>
<text x="1170" y="640" text-anchor="middle" fill="#ff8c42" font-size="14" font-family="Syne,sans-serif" font-weight="700" opacity="0.7">公云算力池</text>
<text x="1170" y="658" text-anchor="middle" fill="#5a6d8a" font-size="9">弹性域 · 溢出扩容</text>
</g>
<!-- ═══ 微推理元 ═══ -->
<g id="node-infer">
<g id="inf-0"><circle cx="490" cy="750" r="12" fill="#0c1425" stroke="#c084fc" stroke-width="1" opacity="0.4"/><circle cx="490" cy="750" r="5" fill="#c084fc" opacity="0.1"/></g>
<g id="inf-1"><circle cx="570" cy="738" r="12" fill="#0c1425" stroke="#c084fc" stroke-width="1" opacity="0.4"/><circle cx="570" cy="738" r="5" fill="#c084fc" opacity="0.1"/></g>
<g id="inf-2"><circle cx="650" cy="730" r="12" fill="#0c1425" stroke="#c084fc" stroke-width="1" opacity="0.4"/><circle cx="650" cy="730" r="5" fill="#c084fc" opacity="0.1"/></g>
<g id="inf-3"><circle cx="750" cy="730" r="12" fill="#0c1425" stroke="#c084fc" stroke-width="1" opacity="0.4"/><circle cx="750" cy="730" r="5" fill="#c084fc" opacity="0.1"/></g>
<g id="inf-4"><circle cx="830" cy="738" r="12" fill="#0c1425" stroke="#c084fc" stroke-width="1" opacity="0.4"/><circle cx="830" cy="738" r="5" fill="#c084fc" opacity="0.1"/></g>
<g id="inf-5"><circle cx="910" cy="750" r="12" fill="#0c1425" stroke="#c084fc" stroke-width="1" opacity="0.4"/><circle cx="910" cy="750" r="5" fill="#c084fc" opacity="0.1"/></g>
<text x="700" y="790" text-anchor="middle" fill="#c084fc" font-size="13" font-family="Syne,sans-serif" font-weight="700" opacity="0.7">微推理元处理层</text>
<text x="700" y="806" text-anchor="middle" fill="#5a6d8a" font-size="9">无状态 · 即插即用</text>
</g>
<!-- ═══ 粒子容器 ═══ -->
<g id="particles"></g>
<!-- ═══ 状态标注 ═══ -->
<g id="state-label" opacity="0">
<rect x="630" y="510" width="140" height="30" rx="6" fill="rgba(12,20,37,0.85)" stroke="rgba(255,140,66,0.3)" stroke-width="0.8"/>
<text id="state-text" x="700" y="530" text-anchor="middle" fill="#ff8c42" font-size="10" font-family="Syne,sans-serif" font-weight="600">公云溢出扩容中</text>
</g>
</svg>
</div>
<!-- 标题 -->
<div id="title-panel">
<h1>算力毛细血管网</h1>
<div class="sub">Liquid Routing · Ideal Final Result</div>
</div>
<!-- 指标 -->
<div id="metrics">
<div class="met">
<div class="met-dot" style="background:#00ffa3"></div>
<div class="met-body">
<span class="met-label">调度微周期</span>
<span class="met-val" id="m-cycle">320ms</span>
</div>
</div>
<div class="met">
<div class="met-dot" style="background:#ff8c42"></div>
<div class="met-body">
<span class="met-label">跨云迁移中断</span>
<span class="met-val" id="m-migrate">—</span>
</div>
</div>
<div class="met">
<div class="met-dot" style="background:#c084fc"></div>
<div class="met-body">
<span class="met-label">算力利用率</span>
<span class="met-val" id="m-util">62%</span>
</div>
</div>
</div>
<!-- 控制 -->
<div id="controls">
<div class="ctrl">
<label>流量强度</label>
<input type="range" id="sl-traffic" min="0" max="100" value="50">
<span class="val" id="v-traffic">50%</span>
<span class="hint">拖动控制业务流量</span>
</div>
<div class="ctrl">
<label>调度微周期</label>
<input type="range" id="sl-speed" min="20" max="100" value="60">
<span class="val" id="v-speed">300ms</span>
<span class="hint">影响路由决策频率</span>
</div>
</div>
<!-- 图例 -->
<div id="legend">
<div class="leg"><div class="leg-line" style="background:#00e5c7"></div>私云算力流(常驻)</div>
<div class="leg"><div class="leg-line" style="background:#ff8c42"></div>公云算力流(弹性)</div>
<div class="leg"><div class="leg-line" style="background:#00ffa3"></div>液态路由决策</div>
<div class="leg"><div class="leg-line" style="background:#c084fc"></div>微推理元处理</div>
</div>
<!-- 流量状态 -->
<div id="traffic-indicator">
<div class="lbl">当前流量状态</div>
<div class="state" id="traffic-state" style="color:#00e5c7">平潮</div>
</div>
<script>
(function(){
'use strict';
const SVG_NS = 'http://www.w3.org/2000/svg';
const svg = document.getElementById('main');
const pGroup = document.getElementById('particles');
/* ── 引用关键元素 ── */
const queueFill = document.getElementById('queue-fill');
const stateLabel = document.getElementById('state-label');
const stateText = document.getElementById('state-text');
const mCycle = document.getElementById('m-cycle');
const mMigrate = document.getElementById('m-migrate');
const mUtil = document.getElementById('m-util');
const trafficStateEl = document.getElementById('traffic-state');
/* 公云节点组 */
const pubGroups = ['pub-a','pub-b','pub-c'].map(id => document.getElementById(id));
/* 微推理元内核 */
const infCores = [0,1,2,3,4,5].map(i => {
const g = document.getElementById('inf-' + i);
return g ? g.querySelectorAll('circle')[1] : null;
});
/* 右侧管壁 */
const vwR = ['vw-r1','vw-r2','vw-r3'].map(id => document.getElementById(id));
/* 右侧流动路径 */
const fpR = ['fp-r1','fp-r2','fp-r3'].map(id => document.getElementById(id));
/* 底部右侧路径 */
const fpBR = document.getElementById('fp-br');
/* ── 路径定义(用于粒子跟随) ── */
const pathDefs = {
topIn: 'M700,108 C700,140 700,170 700,195',
senRtr: 'M700,240 C700,290 700,350 700,400',
l1: 'M642,425 C530,400 380,348 265,335',
l2: 'M632,450 C480,450 340,450 200,450',
l3: 'M642,475 C530,500 380,552 265,565',
r1: 'M758,425 C870,400 1020,348 1135,335',
r2: 'M768,450 C920,450 1060,450 1200,450',
r3: 'M758,475 C870,500 1020,552 1135,565',
bl: 'M200,480 C200,570 440,680 580,740',
bc: 'M700,510 C700,580 700,660 700,720',
br: 'M1200,480 C1200,570 960,680 820,740'
};
/* 创建隐藏的路径元素用于 getPointAtLength */
const pathEls = {};
for(const [k,d] of Object.entries(pathDefs)){
const p = document.createElementNS(SVG_NS,'path');
p.setAttribute('d', d);
p.setAttribute('fill','none');
p.setAttribute('stroke','none');
svg.appendChild(p);
pathEls[k] = p;
}
/* ── 粒子类 ── */
const allParticles = [];
class Particle {
constructor(pathKey, color, size, speed, group){
this.pathKey = pathKey;
this.pathEl = pathEls[pathKey];
this.totalLen = this.pathEl.getTotalLength();
this.color = color;
this.size = size;
this.baseSpeed = speed;
this.group = group; // 'top','private','public','bottom'
this.progress = Math.random();
this.active = true;
this.el = document.createElementNS(SVG_NS,'circle');
this.el.setAttribute('r', size);
this.el.setAttribute('fill', color);
this.el.setAttribute('opacity','0');
if(group === 'public'){
this.el.setAttribute('filter','url(#gl)');
}
pGroup.appendChild(this.el);
allParticles.push(this);
}
update(dt, traffic, speedFactor){
/* 公云粒子在低流量时淡出 */
if(this.group === 'public'){
this.active = traffic > 0.3;
this.el.setAttribute('opacity', this.active ? String(Math.min(1, (traffic - 0.3) / 0.3)) : '0');
if(!this.active) return;
}
if(this.group === 'bottom-r'){
this.active = traffic > 0.35;
this.el.setAttribute('opacity', this.active ? String(Math.min(0.8, (traffic - 0.35) / 0.3)) : '0');
if(!this.active) return;
}
const spd = this.baseSpeed * speedFactor;
this.progress += spd * dt;
if(this.progress > 1) this.progress -= 1;
const pt = this.pathEl.getPointAtLength(this.progress * this.totalLen);
this.el.setAttribute('cx', pt.x);
this.el.setAttribute('cy', pt.y);
/* 淡入淡出 */
let op = 1;
if(this.progress < 0.08) op = this.progress / 0.08;
else if(this.progress > 0.92) op = (1 - this.progress) / 0.08;
op = Math.max(0, Math.min(1, op));
if(this.group === 'public'){
op *= Math.min(1, (traffic - 0.3) / 0.3);
}
/* 非公云/底右粒子始终可见 */
if(this.group !== 'public' && this.group !== 'bottom-r'){
this.el.setAttribute('opacity', op.toFixed(3));
} else if(this.active){
this.el.setAttribute('opacity', op.toFixed(3));
}
}
}
/* ── 创建粒子 ── */
function spawnParticles(){
/* 顶部下行粒子 */
for(let i=0;i<4;i++) new Particle('topIn','#e8edf5',2.2,0.35,'top');
for(let i=0;i<5;i++) new Particle('senRtr','#e8edf5',2.5,0.4,'top');
/* 私云路径粒子 */
for(let i=0;i<5;i++) new Particle('l1','#00e5c7',2.8,0.3,'private');
for(let i=0;i<5;i++) new Particle('l2','#00e5c7',2.8,0.32,'private');
for(let i=0;i<5;i++) new Particle('l3','#00e5c7',2.8,0.3,'private');
/* 公云路径粒子 */
for(let i=0;i<5;i++) new Particle('r1','#ff8c42',3,0.3,'public');
for(let i=0;i<5;i++) new Particle('r2','#ff8c42',3,0.32,'public');
for(let i=0;i<5;i++) new Particle('r3','#ff8c42',3,0.3,'public');
/* 底部汇聚粒子 */
for(let i=0;i<3;i++) new Particle('bl','#00e5c7',2,0.28,'bottom-l');
for(let i=0;i<4;i++) new Particle('bc','rgba(232,237,245,0.7)',2,0.3,'bottom-c');
for(let i=0;i<3;i++) new Particle('br','#ff8c42',2,0.28,'bottom-r');
}
spawnParticles();
/* ── 流量控制 ── */
let manualTraffic = -1; // -1 = 自动模式
let manualSpeed = -1;
const slTraffic = document.getElementById('sl-traffic');
const slSpeed = document.getElementById('sl-speed');
const vTraffic = document.getElementById('v-traffic');
const vSpeed = document.getElementById('v-speed');
slTraffic.addEventListener('input', function(){
manualTraffic = this.value / 100;
vTraffic.textContent = this.value + '%';
});
slSpeed.addEventListener('input', function(){
manualSpeed = this.value / 100;
vSpeed.textContent = Math.round(500 * (1 - this.value / 100 * 0.8)) + 'ms';
});
/* ── 主动画循环 ── */
let lastTime = 0;
function animate(time){
if(!lastTime) lastTime = time;
const dt = Math.min((time - lastTime) / 1000, 0.05);
lastTime = time;
/* 计算流量强度(自动模式用正弦波) */
let traffic;
if(manualTraffic >= 0){
traffic = manualTraffic;
} else {
/* 自动模式:平滑正弦振荡 */
traffic = (Math.sin(time / 5000) + 1) / 2;
slTraffic.value = Math.round(traffic * 100);
vTraffic.textContent = Math.round(traffic * 100) + '%';
}
/* 速度因子 */
let speedFactor;
if(manualSpeed >= 0){
speedFactor = 0.5 + manualSpeed * 1.2;
} else {
speedFactor = 0.8 + traffic * 0.6;
}
/* ── 更新粒子 ── */
for(const p of allParticles){
p.update(dt, traffic, speedFactor);
}
/* ── 更新潮汐感应器队列 ── */
const queueH = Math.round(traffic * 28);
queueFill.setAttribute('y', String(232 - queueH));
queueFill.setAttribute('height', String(queueH));
/* 队列颜色随压力变化 */
if(traffic > 0.7){
queueFill.setAttribute('fill','#ff8c42');
} else if(traffic > 0.4){
queueFill.setAttribute('fill','#00ffa3');
} else {
queueFill.setAttribute('fill','#00e5c7');
}
/* ── 更新公云节点可见性 ── */
const pubOpacity = traffic > 0.25 ? Math.min(1, 0.2 + (traffic - 0.25) * 1.2) : 0.2;
for(const g of pubGroups){
if(g) g.setAttribute('opacity', pubOpacity.toFixed(3));
}
/* ── 更新右侧管壁宽度 ── */
const vwWidth = 8 + traffic * 14;
const vwOpacity = 0.02 + traffic * 0.09;
for(const w of vwR){
if(w){
w.setAttribute('stroke-width', vwWidth.toFixed(1));
w.setAttribute('stroke', 'rgba(255,140,66,' + vwOpacity.toFixed(3) + ')');
}
}
/* ── 更新右侧流动路径 ── */
const fpOpacity = traffic > 0.25 ? 0.15 + (traffic - 0.25) * 1.0 : 0.15;
const fpWidth = 1.5 + traffic * 3;
for(const fp of fpR){
if(fp){
fp.setAttribute('opacity', Math.min(0.85, fpOpacity).toFixed(3));
fp.setAttribute('stroke-width', fpWidth.toFixed(1));
}
}
/* 底部右侧路径 */
if(fpBR){
const brOp = traffic > 0.3 ? 0.1 + (traffic - 0.3) * 0.8 : 0.1;
fpBR.setAttribute('opacity', Math.min(0.6, brOp).toFixed(3));
}
/* ── 溢出扩容状态标注 ── */
if(traffic > 0.55){
stateLabel.setAttribute('opacity', String(Math.min(1, (traffic - 0.55) * 3)));
if(traffic > 0.8){
stateText.textContent = '全量扩容 · 公私云协同';
stateText.setAttribute('fill','#ff6b2b');
} else {
stateText.textContent = '公云溢出扩容中';
stateText.setAttribute('fill','#ff8c42');
}
} else {
stateLabel.setAttribute('opacity', '0');
}
/* ── 微推理元激活 ── */
const activeInfs = Math.floor(1 + traffic * 5.5);
for(let i = 0; i < infCores.length; i++){
if(!infCores[i]) continue;
const coreOpacity = i < activeInfs ? 0.3 + traffic * 0.4 : 0.05;
infCores[i].setAttribute('opacity', coreOpacity.toFixed(3));
const parentG = infCores[i].parentElement;
if(parentG){
parentG.setAttribute('opacity', i < activeInfs ? '0.8' : '0.3');
}
}
/* ── 更新指标面板 ── */
const cycleMs = Math.round(500 * (1 - traffic * 0.6));
mCycle.textContent = cycleMs + 'ms';
if(traffic > 0.3){
const migrateMs = Math.round(20 + (1 - traffic) * 40);
mMigrate.textContent = migrateMs + 'ms';
} else {
mMigrate.textContent = '—';
}
const util = Math.round(45 + traffic * 48);
mUtil.textContent = util + '%';
/* ── 流量状态文字 ── */
if(traffic < 0.25){
trafficStateEl.textContent = '退潮';
trafficStateEl.style.color = '#00e5c7';
} else if(traffic < 0.55){
trafficStateEl.textContent = '平潮';
trafficStateEl.style.color = '#00ffa3';
} else if(traffic < 0.8){
trafficStateEl.textContent = '涨潮';
trafficStateEl.style.color = '#ff8c42';
} else {
trafficStateEl.textContent = '洪峰';
trafficStateEl.style.color = '#ff6b2b';
}
requestAnimationFrame(animate);
}
/* ── 自动启动 ── */
requestAnimationFrame(animate);
/* ── 背景漂浮粒子(装饰) ── */
function createBgDust(){
const dustGroup = document.createElementNS(SVG_NS,'g');
dustGroup.setAttribute('opacity','0.25');
svg.insertBefore(dustGroup, svg.children[2]); // 插入到背景之后
for(let i = 0; i < 40; i++){
const c = document.createElementNS(SVG_NS,'circle');
c.setAttribute('cx', String(Math.random() * 1400));
c.setAttribute('cy', String(Math.random() * 900));
c.setAttribute('r', String(0.5 + Math.random() * 1.2));
c.setAttribute('fill', Math.random() > 0.5 ? '#00e5c7' : '#ff8c42');
c.setAttribute('opacity', String(0.15 + Math.random() * 0.25));
/* 缓慢漂浮动画 */
const animX = document.createElementNS(SVG_NS,'animate');
animX.setAttribute('attributeName','cx');
const cx = parseFloat(c.getAttribute('cx'));
const dx = 15 + Math.random() * 30;
animX.setAttribute('values', cx + ';' + (cx + dx) + ';' + cx);
animX.setAttribute('dur', (8 + Math.random() * 12) + 's');
animX.setAttribute('repeatCount','indefinite');
const animY = document.createElementNS(SVG_NS,'animate');
animY.setAttribute('attributeName','cy');
const cy = parseFloat(c.getAttribute('cy'));
const dy = 10 + Math.random() * 20;
animY.setAttribute('values', cy + ';' + (cy + dy) + ';' + cy);
animY.setAttribute('dur', (10 + Math.random() * 14) + 's');
animY.setAttribute('repeatCount','indefinite');
c.appendChild(animX);
c.appendChild(animY);
dustGroup.appendChild(c);
}
}
createBgDust();
})();
</script>
</body>
</html>
这个动画实现了以下核心设计:
视觉叙事聚焦 IFR(最终理想解):画面直接展示"算力毛细血管网"的理想运行状态——液态路由器如心脏般持续脉动,算力资源像血液一样在公私云之间自如流动,无需任何前后对比。
核心创新点的视觉引导:
- 毛细血管舒缩效应:当流量升高时,通向公云的路径(琥珀色)在描边宽度、透明度、粒子密度三个维度同时"舒张",低流量时自动"收缩",直接映射方案的核心机理
- 液态路由器脉冲环:三层扩散环持续从中心向外传播,象征实时调度决策
- 潮汐感应器队列条:颜色从青绿→翠绿→琥珀渐变,直观反映压力等级
交互控制:
- 流量强度滑块:手动干预业务流量,观察公云弹性扩缩的完整过程(也可自动正弦振荡)
- 调度微周期滑块:调节路由决策频率,影响粒子流速与指标读数
关键参数实时呈现:右侧指标面板动态显示调度微周期(≤500ms)、跨云迁移中断时间(≤50ms)和算力利用率,均随流量状态联动变化。
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
