独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TRIZ 理想最终解:零重量着陆机构原理</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@100;400;700&family=Noto+Sans+SC:wght@300;500;700&display=swap');
:root {
--bg-color: #060913;
--grid-color: rgba(30, 58, 138, 0.2);
--rocket-body: #e2e8f0;
--rocket-dark: #64748b;
--accent-cyan: #00f0ff;
--accent-blue: #3b82f6;
--accent-orange: #ff5500;
--accent-red: #ff003c;
--text-main: #f8fafc;
--text-dim: #94a3b8;
--font-mono: 'JetBrains Mono', monospace;
--font-sans: 'Noto Sans SC', sans-serif;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-color);
color: var(--text-main);
font-family: var(--font-sans);
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
background-image:
linear-gradient(var(--grid-color) 1px, transparent 1px),
linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
background-size: 40px 40px;
background-position: center center;
}
/* 绝对定位的数据面板,遵守极简、小字号、边缘放置的规则 */
.hud-panel {
position: absolute;
z-index: 10;
background: rgba(6, 9, 19, 0.7);
border: 1px solid rgba(0, 240, 255, 0.2);
backdrop-filter: blur(4px);
padding: 16px;
border-radius: 4px;
font-family: var(--font-mono);
font-size: 12px;
pointer-events: none;
}
.hud-left {
top: 40px;
left: 40px;
width: 280px;
}
.hud-right {
top: 40px;
right: 40px;
width: 240px;
}
.hud-title {
color: var(--accent-cyan);
font-weight: 700;
font-size: 14px;
margin-bottom: 12px;
border-bottom: 1px solid rgba(0, 240, 255, 0.3);
padding-bottom: 6px;
text-transform: uppercase;
letter-spacing: 1px;
font-family: var(--font-sans);
}
.hud-row {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
color: var(--text-dim);
}
.hud-value {
color: var(--text-main);
font-weight: 700;
text-shadow: 0 0 5px rgba(255, 255, 255, 0.3);
}
.hud-value.highlight {
color: var(--accent-orange);
text-shadow: 0 0 8px rgba(255, 85, 0, 0.5);
}
.hud-value.success {
color: var(--accent-cyan);
text-shadow: 0 0 8px rgba(0, 240, 255, 0.5);
}
.triz-concept {
margin-top: 16px;
padding-top: 12px;
border-top: 1px dashed rgba(148, 163, 184, 0.3);
font-family: var(--font-sans);
}
.triz-concept p {
line-height: 1.6;
margin-bottom: 8px;
color: var(--text-dim);
}
.triz-concept span.highlight-cyan {
color: var(--accent-cyan);
font-weight: 500;
}
/* 主动画容器 */
#svg-container {
width: 100%;
height: 100%;
max-width: 1200px;
max-height: 900px;
display: flex;
justify-content: center;
align-items: center;
}
svg {
width: 100%;
height: 100%;
overflow: visible;
}
/* SVG 样式 */
.glow-cyan { filter: drop-shadow(0 0 8px rgba(0, 240, 255, 0.6)); }
.glow-orange { filter: drop-shadow(0 0 12px rgba(255, 85, 0, 0.8)); }
.rocket-body { fill: url(#rocket-gradient); }
.grid-fin { fill: #1e293b; stroke: var(--accent-cyan); stroke-width: 1.5; }
.engine-bell { fill: #334155; }
.tower-struct { fill: none; stroke: #1e293b; stroke-width: 4; }
.tower-highlight { fill: none; stroke: var(--accent-blue); stroke-width: 1; opacity: 0.5; }
.catch-arm { fill: #0f172a; stroke: var(--accent-cyan); stroke-width: 2; }
.damper-cylinder { fill: #1e293b; stroke: #475569; stroke-width: 2; }
.damper-rod { fill: #cbd5e1; }
.damper-indicator { fill: var(--accent-blue); transition: fill 0.3s; }
.ghost-leg { fill: none; stroke: var(--accent-red); stroke-width: 2; stroke-dasharray: 4 4; opacity: 0; }
/* 激光雷达扫描线 */
.radar-scan {
fill: none;
stroke: var(--accent-cyan);
stroke-width: 1;
opacity: 0;
}
</style>
</head>
<body>
<!-- 左侧 HUD:理论基础与状态 -->
<div class="hud-panel hud-left">
<div class="hud-title">TRIZ 理想最终解 (IFR)</div>
<div class="triz-concept">
<p>传统矛盾:火箭需极高精度着陆,但自备着陆腿增加死重,降低运载效率。</p>
<p>IFR 策略:<span class="highlight-cyan">消除功能载体,保留功能。</span></p>
<p>空间分离:将“缓冲”功能从飞行器本体转移至超系统(地面设施)。火箭仅保留<span class="highlight-cyan">承力栅格舵</span>。</p>
<p style="margin-top: 10px; font-family: var(--font-mono); font-size: 11px; border-left: 2px solid var(--accent-cyan); padding-left: 8px;">
> 箭载着陆机构重量 = 0<br>
> 系统复杂度 = 转移至地面
</p>
</div>
</div>
<!-- 右侧 HUD:实时遥测数据 -->
<div class="hud-panel hud-right">
<div class="hud-title">遥测终端 / TELEMETRY</div>
<div class="hud-row">
<span>相对高度 (ALT)</span>
<span class="hud-value" id="ui-alt">--- m</span>
</div>
<div class="hud-row">
<span>下降速度 (VEL)</span>
<span class="hud-value" id="ui-vel">--- m/s</span>
</div>
<div class="hud-row">
<span>推力水平 (THR)</span>
<span class="hud-value" id="ui-thr">--- %</span>
</div>
<div class="hud-row" style="margin-top: 12px; border-top: 1px solid #1e293b; padding-top: 12px;">
<span>地面阻尼行程</span>
<span class="hud-value" id="ui-damper">0.0 / 25 m</span>
</div>
<div class="hud-row">
<span>单索张力负荷</span>
<span class="hud-value" id="ui-tension">0 kN</span>
</div>
<div class="hud-row" style="margin-top: 12px;">
<span>阶段 (PHASE)</span>
<span class="hud-value success" id="ui-phase">系统待命</span>
</div>
</div>
<div id="svg-container">
<svg viewBox="0 0 1000 1000" preserveAspectRatio="xMidYMid meet">
<defs>
<!-- 火箭金属质感渐变 -->
<linearGradient id="rocket-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#94a3b8" />
<stop offset="20%" stop-color="#f1f5f9" />
<stop offset="50%" stop-color="#cbd5e1" />
<stop offset="80%" stop-color="#64748b" />
<stop offset="100%" stop-color="#475569" />
</linearGradient>
<!-- 发动机尾焰渐变 -->
<radialGradient id="flame-gradient" cx="50%" cy="20%" r="80%" fx="50%" fy="10%">
<stop offset="0%" stop-color="#ffffff" />
<stop offset="20%" stop-color="#ffed4a" />
<stop offset="60%" stop-color="#ff5500" />
<stop offset="100%" stop-color="rgba(255, 0, 0, 0)" />
</radialGradient>
<!-- 网格模式 (背景刻度) -->
<pattern id="scale-grid" width="100" height="100" patternUnits="userSpaceOnUse">
<line x1="0" y1="0" x2="100" y2="0" stroke="rgba(255,255,255,0.05)" stroke-width="1" />
<line x1="0" y1="0" x2="0" y2="100" stroke="rgba(255,255,255,0.05)" stroke-width="1" />
<text x="5" y="15" fill="rgba(255,255,255,0.1)" font-size="10" font-family="monospace">10m</text>
</pattern>
<!-- 阻尼器发光滤镜 -->
<filter id="glow-filter" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="4" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
</defs>
<!-- 背景刻度 -->
<rect width="1000" height="1000" fill="url(#scale-grid)" />
<!-- 地面线 -->
<line x1="0" y1="950" x2="1000" y2="950" stroke="#1e293b" stroke-width="4" />
<line x1="0" y1="950" x2="1000" y2="950" stroke="var(--accent-cyan)" stroke-width="1" opacity="0.5" />
<!-- === 地面捕获设施 (超系统) === -->
<g id="ground-system">
<!-- 左塔 -->
<g class="tower" transform="translate(250, 0)">
<rect x="0" y="300" width="60" height="650" class="tower-struct" />
<path d="M0,350 L60,400 M0,400 L60,450 M0,450 L60,500 M0,500 L60,550 M0,550 L60,600 M0,600 L60,650 M0,650 L60,700 M0,700 L60,750 M0,750 L60,800 M0,800 L60,850 M0,850 L60,900" stroke="#1e293b" stroke-width="2" />
<!-- 塔身科技线 -->
<line x1="30" y1="300" x2="30" y2="950" class="tower-highlight" />
</g>
<!-- 右塔 -->
<g class="tower" transform="translate(690, 0)">
<rect x="0" y="300" width="60" height="650" class="tower-struct" />
<path d="M0,350 L60,400 M0,400 L60,450 M0,450 L60,500 M0,500 L60,550 M0,550 L60,600 M0,600 L60,650 M0,650 L60,700 M0,700 L60,750 M0,750 L60,800 M0,800 L60,850 M0,850 L60,900" stroke="#1e293b" stroke-width="2" />
<line x1="30" y1="300" x2="30" y2="950" class="tower-highlight" />
</g>
<!-- 动态捕获臂/柔性网架 (整个机构随动下沉) -->
<g id="catch-mechanism" transform="translate(0, 500)">
<!-- 左侧机械臂基础 -->
<rect x="230" y="-20" width="100" height="40" fill="#0f172a" stroke="#475569" stroke-width="2" rx="4" />
<!-- 右侧机械臂基础 -->
<rect x="670" y="-20" width="100" height="40" fill="#0f172a" stroke="#475569" stroke-width="2" rx="4" />
<!-- 左侧阻尼器与轨道 -->
<rect x="310" y="-10" width="40" height="20" class="damper-cylinder" />
<rect x="350" y="-4" width="70" height="8" class="damper-rod" id="left-arm-rod" />
<circle cx="420" cy="0" r="12" class="catch-arm glow-cyan" id="left-contact-node" />
<rect x="315" y="-6" width="10" height="12" class="damper-indicator" id="left-damper-led" />
<!-- 右侧阻尼器与轨道 -->
<rect x="650" y="-10" width="40" height="20" class="damper-cylinder" />
<rect x="580" y="-4" width="70" height="8" class="damper-rod" id="right-arm-rod" />
<circle cx="580" cy="0" r="12" class="catch-arm glow-cyan" id="right-contact-node" />
<rect x="675" y="-6" width="10" height="12" class="damper-indicator" id="right-damper-led" />
<!-- 引导激光束 (闭环引导可视化) -->
<path id="guidance-laser-l" d="M 420,0 L 500,-150" class="radar-scan" />
<path id="guidance-laser-r" d="M 580,0 L 500,-150" class="radar-scan" />
<!-- 捕捉网张力可视化连接线 (在后台,仅在接触后显现高张力状态) -->
<line x1="420" y1="0" x2="580" y2="0" stroke="var(--accent-orange)" stroke-width="4" stroke-dasharray="8 4" opacity="0" id="tension-net" filter="url(#glow-filter)" />
</g>
</g>
<!-- === 火箭本体 === -->
<!-- 初始位于上方,通过 JS 控制 transform -->
<g id="rocket" transform="translate(500, -200)">
<!-- 被消除的传统着陆腿 (幽灵状态,展示 IFR 消除死重) -->
<path d="M -35,180 L -70,250 L -80,250" class="ghost-leg" id="ghost-leg-l" />
<path d="M 35,180 L 70,250 L 80,250" class="ghost-leg" id="ghost-leg-r" />
<!-- 尾焰 -->
<path id="engine-flame" d="M -20,195 Q 0,400 20,195 Q 0,220 -20,195 Z" fill="url(#flame-gradient)" class="glow-orange" style="transform-origin: 0 195px;" />
<!-- 发动机喷口 -->
<path d="M -25,180 L 25,180 L 30,195 L -30,195 Z" class="engine-bell" />
<!-- 箭体 -->
<rect x="-35" y="-180" width="70" height="360" rx="10" class="rocket-body" />
<!-- 表面细节线 -->
<line x1="-35" y1="-100" x2="35" y2="-100" stroke="#64748b" stroke-width="1" />
<line x1="-35" y1="0" x2="35" y2="0" stroke="#64748b" stroke-width="1" />
<line x1="-35" y1="100" x2="35" y2="100" stroke="#64748b" stroke-width="1" />
<text x="0" y="50" fill="#64748b" font-family="monospace" font-size="24" font-weight="bold" transform="rotate(-90)" text-anchor="middle" opacity="0.3">IFR-X1</text>
<!-- 承力栅格舵 (核心捕获部件) -->
<!-- 左栅格舵 -->
<g transform="translate(-35, -140)" id="grid-fin-l">
<rect x="-40" y="0" width="40" height="15" class="grid-fin" rx="2" />
<!-- 内部网格暗示 -->
<line x1="-30" y1="0" x2="-30" y2="15" stroke="var(--accent-cyan)" stroke-width="1" />
<line x1="-20" y1="0" x2="-20" y2="15" stroke="var(--accent-cyan)" stroke-width="1" />
<line x1="-10" y1="0" x2="-10" y2="15" stroke="var(--accent-cyan)" stroke-width="1" />
</g>
<!-- 右栅格舵 -->
<g transform="translate(35, -140)" id="grid-fin-r">
<rect x="0" y="0" width="40" height="15" class="grid-fin" rx="2" />
<line x1="10" y1="0" x2="10" y2="15" stroke="var(--accent-cyan)" stroke-width="1" />
<line x1="20" y1="0" x2="20" y2="15" stroke="var(--accent-cyan)" stroke-width="1" />
<line x1="30" y1="0" x2="30" y2="15" stroke="var(--accent-cyan)" stroke-width="1" />
</g>
<!-- 接触点高亮圆环 (仅在入网瞬间闪烁) -->
<circle cx="-75" cy="-132.5" r="15" fill="none" stroke="var(--accent-orange)" stroke-width="3" opacity="0" id="impact-glow-l" filter="url(#glow-filter)" />
<circle cx="75" cy="-132.5" r="15" fill="none" stroke="var(--accent-orange)" stroke-width="3" opacity="0" id="impact-glow-r" filter="url(#glow-filter)" />
</g>
<!-- 视觉引导:动态箭头与说明文字 (绝对避免遮挡主体,放在中心外侧) -->
<g id="visual-cues" opacity="0">
<path d="M 330,520 L 330,620 M 320,610 L 330,620 L 340,610" fill="none" stroke="var(--accent-cyan)" stroke-width="2" />
<text x="310" y="570" fill="var(--accent-cyan)" font-size="12" font-family="var(--font-sans)">阻尼下沉 20-25m</text>
<path d="M 670,520 L 670,620 M 660,610 L 670,620 L 680,610" fill="none" stroke="var(--accent-cyan)" stroke-width="2" />
<text x="690" y="570" fill="var(--accent-cyan)" font-size="12" font-family="var(--font-sans)">吸收残余动能</text>
</g>
</svg>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// DOM 元素引用
const elements = {
rocket: document.getElementById('rocket'),
flame: document.getElementById('engine-flame'),
catchMechanism: document.getElementById('catch-mechanism'),
ghostLegs: [document.getElementById('ghost-leg-l'), document.getElementById('ghost-leg-r')],
lasers: [document.getElementById('guidance-laser-l'), document.getElementById('guidance-laser-r')],
impactGlows: [document.getElementById('impact-glow-l'), document.getElementById('impact-glow-r')],
damperLeds: [document.getElementById('left-damper-led'), document.getElementById('right-damper-led')],
damperRods: [document.getElementById('left-arm-rod'), document.getElementById('right-arm-rod')],
tensionNet: document.getElementById('tension-net'),
visualCues: document.getElementById('visual-cues'),
// UI 文本
uiAlt: document.getElementById('ui-alt'),
uiVel: document.getElementById('ui-vel'),
uiThr: document.getElementById('ui-thr'),
uiDamper: document.getElementById('ui-damper'),
uiTension: document.getElementById('ui-tension'),
uiPhase: document.getElementById('ui-phase'),
};
// 物理常量与配置 (映射到 SVG 坐标)
const config = {
cycleTime: 14000, // 完整动画周期 14 秒
startY: -100, // 火箭初始 Y
catchY: 345, // 栅格舵接触捕捉网时,火箭中心的 Y 坐标
groundY: 950,
mechBaseY: 360, // 机构初始 Y 坐标
mechTravel: 150, // 阻尼机构下沉距离 (视觉上夸大以便看清原理)
maxSpeed: 80,
targetSpeed: 6.5 // 入网残余速度 5-8 m/s
};
let animationFrameId;
let startTime = null;
// 缓动函数
const easeOutQuad = t => t * (2 - t);
const easeOutCubic = t => (--t) * t * t + 1;
const easeInOutSine = t => -(Math.cos(Math.PI * t) - 1) / 2;
function animate(timestamp) {
if (!startTime) startTime = timestamp;
// 计算当前周期内的时间 [0, cycleTime]
let elapsed = (timestamp - startTime) % config.cycleTime;
// 定义四个主要阶段
// 1. 高空减速入场 (0 - 4000ms)
// 2. 闭环雷达引导对准 (4000 - 7000ms)
// 3. 接触与阻尼下沉吸收动能 (7000 - 9000ms)
// 4. 锁定与重置 (9000 - 14000ms)
let rocketY = config.startY;
let rocketSpeed = 0;
let flameScale = 0;
let mechY = config.mechBaseY;
let damperCompress = 0; // 0 to 1
if (elapsed < 4000) {
// --- 阶段 1: 极速下降与主减速 ---
let p = elapsed / 4000;
let easeP = easeOutQuad(p);
rocketY = config.startY + (config.catchY - 150 - config.startY) * easeP;
rocketSpeed = config.maxSpeed - (config.maxSpeed - 20) * easeP;
flameScale = 1.2 + Math.random() * 0.3; // 强尾焰抖动
// UI 更新
elements.uiPhase.textContent = "反推减速下降";
elements.uiPhase.className = "hud-value";
elements.ghostLegs.forEach(el => el.style.opacity = Math.max(0, 1 - p * 3)); // 快速淡出传统腿
elements.lasers.forEach(el => el.style.opacity = 0);
} else if (elapsed < 7000) {
// --- 阶段 2: 悬停对准,闭环引导 ---
let p = (elapsed - 4000) / 3000;
rocketY = (config.catchY - 150) + 150 * p; // 线性慢速下降
rocketSpeed = 20 - (20 - config.targetSpeed) * p; // 降速至残余速度 5-8 m/s
flameScale = 0.5 + Math.random() * 0.1; // 较小尾焰
// 雷达扫描视觉效果
let scanOp = Math.sin(p * Math.PI * 10) * 0.5 + 0.5;
elements.lasers.forEach(el => el.style.opacity = scanOp);
// 跟踪激光末端对准火箭栅格舵
elements.lasers[0].setAttribute('d', `M 420,0 L ${500 - 75},${rocketY - config.mechBaseY - 132}`);
elements.lasers[1].setAttribute('d', `M 580,0 L ${500 + 75},${rocketY - config.mechBaseY - 132}`);
elements.uiPhase.textContent = "视觉雷达闭环引导";
elements.uiPhase.className = "hud-value highlight";
} else if (elapsed < 9000) {
// --- 阶段 3: 接触、熄火、系统随动阻尼 ---
let p = (elapsed - 7000) / 2000;
let easeP = easeOutCubic(p); // 阻尼减速特性
// 接触瞬间 (7000-7100ms)
if (elapsed < 7100) {
elements.impactGlows.forEach(el => el.style.opacity = 1);
elements.tensionNet.style.opacity = 0.8;
} else {
elements.impactGlows.forEach(el => el.style.opacity = Math.max(0, 1 - (elapsed-7100)/500));
}
flameScale = 0; // 熄火
rocketSpeed = config.targetSpeed * (1 - easeP);
// 火箭和机构一起下沉
mechY = config.mechBaseY + config.mechTravel * easeP;
rocketY = config.catchY + config.mechTravel * easeP;
damperCompress = easeP; // 阻尼器压缩度
elements.lasers.forEach(el => el.style.opacity = 0);
elements.uiPhase.textContent = "柔性捕获与阻尼缓冲";
elements.uiPhase.className = "hud-value highlight";
elements.visualCues.style.opacity = p < 0.5 ? p * 2 : 2 - p * 2; // 提示文字淡入淡出
} else if (elapsed < 12000) {
// --- 阶段 4: 锁定 ---
rocketY = config.catchY + config.mechTravel;
mechY = config.mechBaseY + config.mechTravel;
rocketSpeed = 0;
flameScale = 0;
damperCompress = 1;
elements.tensionNet.style.opacity = 0.3; // 保持静张力
elements.uiPhase.textContent = "成功锁定,动能清零";
elements.uiPhase.className = "hud-value success";
} else {
// --- 阶段 5: 重置动画准备 ---
let p = (elapsed - 12000) / 2000;
let easeP = easeInOutSine(p);
mechY = (config.mechBaseY + config.mechTravel) - (config.mechTravel * easeP);
rocketY = config.startY - 300; // 移出屏幕上方
damperCompress = 1 - easeP;
elements.tensionNet.style.opacity = 0;
elements.uiPhase.textContent = "系统复位中...";
elements.uiPhase.className = "hud-value";
}
// ==================== 应用视觉变换 ====================
// 1. 火箭本体与尾焰
elements.rocket.setAttribute('transform', `translate(500, ${rocketY})`);
elements.flame.style.transform = `scaleY(${flameScale})`;
elements.flame.style.opacity = flameScale > 0 ? 0.9 : 0;
// 2. 地面捕获机构下沉
elements.catchMechanism.setAttribute('transform', `translate(0, ${mechY})`);
// 3. 阻尼器视觉反馈 (变色与压缩)
// 颜色从蓝 (待命) 到 橙/红 (受力发热)
let r = Math.floor(59 + damperCompress * 196); // 3b -> ff
let g = Math.floor(130 - damperCompress * 45); // 82 -> 55
let b = Math.floor(246 - damperCompress * 246); // f6 -> 00
let damperColor = `rgb(${r}, ${g}, ${b})`;
elements.damperLeds.forEach(el => {
el.style.fill = damperColor;
el.style.filter = `drop-shadow(0 0 ${4 + damperCompress*8}px ${damperColor})`;
});
// 拉杆伸出/缩进模拟 (通过宽度变化粗略模拟)
elements.damperRods[0].setAttribute('width', 70 + damperCompress * 30);
elements.damperRods[1].setAttribute('x', 580 - damperCompress * 30);
elements.damperRods[1].setAttribute('width', 70 + damperCompress * 30);
// ==================== 更新 UI 数据 ====================
// 计算模拟的真实海拔 (将 SVG 坐标映射回米,基准点在地面)
let realAltitude = Math.max(0, (config.groundY - rocketY) * 0.3).toFixed(1);
elements.uiAlt.textContent = `${realAltitude} m`;
// 速度显示格式化
elements.uiVel.textContent = `${rocketSpeed.toFixed(1)} m/s`;
elements.uiVel.className = rocketSpeed <= config.targetSpeed && rocketSpeed > 0 ? "hud-value success" : "hud-value";
// 推力显示
let thrust = flameScale > 0 ? (30 + flameScale * 40).toFixed(0) : "0";
elements.uiThr.textContent = `${thrust} %`;
// 阻尼行程显示 (模拟最大 25m)
let travelMeters = (damperCompress * 25).toFixed(1);
elements.uiDamper.textContent = `${travelMeters} / 25.0 m`;
if(damperCompress > 0.1) {
elements.uiDamper.className = "hud-value highlight";
} else {
elements.uiDamper.className = "hud-value";
}
// 碳纤维索张力显示 (最大 800kN)
let tension = (damperCompress * 780 + (Math.random()*20 * damperCompress)).toFixed(0);
elements.uiTension.textContent = `${tension} kN`;
// 循环调用
animationFrameId = requestAnimationFrame(animate);
}
// 启动动画
animationFrameId = requestAnimationFrame(animate);
// 确保页面重新显示时时间戳逻辑不崩,或清理重新开始
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
cancelAnimationFrame(animationFrameId);
startTime = null; // 重置时间以防止切回时快进
} else {
animationFrameId = requestAnimationFrame(animate);
}
});
});
</script>
</body>
</html>
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
