独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>无反推火箭柔性回收系统 - IFR理想解</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap');
:root {
--bg-color: #07090f;
--grid-color: rgba(23, 42, 69, 0.5);
--accent-cyan: #00f3ff;
--accent-orange: #ff5500;
--text-main: #a9b7c6;
--text-dim: #5c7080;
--font-mono: 'JetBrains Mono', monospace;
}
body, html {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
background-color: var(--bg-color);
background-image:
linear-gradient(var(--grid-color) 1px, transparent 1px),
linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
background-size: 40px 40px;
font-family: var(--font-mono);
overflow: hidden;
color: var(--text-main);
display: flex;
justify-content: center;
align-items: center;
}
/* 绝对避免遮挡中央画面的遥测面板 */
.telemetry-panel {
position: absolute;
background: rgba(7, 9, 15, 0.85);
border: 1px solid rgba(0, 243, 255, 0.3);
box-shadow: 0 0 15px rgba(0, 243, 255, 0.05);
backdrop-filter: blur(8px);
padding: 12px 16px;
z-index: 100;
pointer-events: none;
display: flex;
flex-direction: column;
gap: 8px;
}
.panel-top-left {
top: 24px;
left: 24px;
border-left: 3px solid var(--accent-cyan);
}
.panel-bottom-right {
bottom: 24px;
right: 24px;
border-right: 3px solid var(--accent-orange);
align-items: flex-end;
text-align: right;
}
.sys-title {
font-size: 12px;
font-weight: 700;
color: var(--accent-cyan);
letter-spacing: 1px;
margin-bottom: 4px;
}
.data-row {
font-size: 10px;
display: flex;
gap: 12px;
justify-content: space-between;
width: 180px;
}
.data-label { color: var(--text-dim); }
.data-value { color: #fff; font-weight: 700; font-variant-numeric: tabular-nums;}
.value-cyan { color: var(--accent-cyan); }
.value-orange { color: var(--accent-orange); }
.ifr-notice {
position: absolute;
bottom: 24px;
left: 24px;
font-size: 10px;
color: var(--text-dim);
max-width: 250px;
line-height: 1.4;
pointer-events: none;
}
.ifr-highlight {
color: var(--accent-cyan);
font-weight: bold;
}
/* 核心动画容器,占满屏幕但不超出 */
#stage-container {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
svg {
width: 100%;
height: 100%;
max-width: 1400px;
max-height: 900px;
filter: drop-shadow(0 0 20px rgba(0, 0, 0, 0.5));
}
/* 屏幕震动特效 */
@keyframes shake {
0%, 100% { transform: translate(0, 0); }
20% { transform: translate(-3px, 4px) rotate(-0.5deg); }
40% { transform: translate(4px, -2px) rotate(0.5deg); }
60% { transform: translate(-4px, -4px) rotate(-0.5deg); }
80% { transform: translate(2px, 3px) rotate(0.5deg); }
}
.shake-active {
animation: shake 0.4s cubic-bezier(.36,.07,.19,.97) both;
}
/* 微小的元件内联文字说明 */
.svg-label {
font-family: var(--font-mono);
font-size: 10px;
fill: var(--text-dim);
letter-spacing: 0.5px;
}
.svg-label.highlight { fill: var(--accent-cyan); }
.svg-label.alert { fill: var(--accent-orange); }
</style>
</head>
<body>
<!-- 顶部左侧:系统状态概览 -->
<div class="telemetry-panel panel-top-left">
<div class="sys-title">AERO-RECOVERY SYS // TRIZ IFR</div>
<div class="data-row"><span class="data-label">PHASE:</span> <span class="data-value value-cyan" id="ui-phase">AWAITING</span></div>
<div class="data-row"><span class="data-label">ALTITUDE:</span> <span class="data-value" id="ui-alt">--- m</span></div>
<div class="data-row"><span class="data-label">VELOCITY:</span> <span class="data-value" id="ui-vel">--- m/s</span></div>
</div>
<!-- 底部右侧:关键子系统遥测 -->
<div class="telemetry-panel panel-bottom-right">
<div class="sys-title">SUBSYSTEM TELEMETRY</div>
<div class="data-row"><span class="data-label">PARAFOIL AREA:</span> <span class="data-value" id="ui-area">0 m²</span></div>
<div class="data-row"><span class="data-label">AIRBAG PRESSURE:</span> <span class="data-value value-orange" id="ui-press">0 kPa</span></div>
<div class="data-row"><span class="data-label">VALVE STATUS:</span> <span class="data-value" id="ui-valve">CLOSED</span></div>
</div>
<!-- 底部左侧:设计原理解释 -->
<div class="ifr-notice">
[IFR] 消除死重与额外燃料:<br>利用大气气动阻力作为减速<span class="ifr-highlight">资源</span>,通过1200㎡滑翔翼伞实现无动力定向巡航。<br>末端利用高压多室气囊及泄压阀吸收地表冲击动能。
</div>
<div id="stage-container">
<!-- 核心SVG画布 -->
<svg id="main-svg" viewBox="0 0 1200 800" preserveAspectRatio="xMidYMid meet">
<defs>
<!-- 发光滤镜 -->
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="4" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<filter id="glow-strong" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="8" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<!-- 渐变定义 -->
<linearGradient id="rocket-body" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#2a3242" />
<stop offset="30%" stop-color="#4f5b72" />
<stop offset="70%" stop-color="#8090a8" />
<stop offset="100%" stop-color="#1f2533" />
</linearGradient>
<linearGradient id="parafoil-grad" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#00f3ff" stop-opacity="0.9" />
<stop offset="100%" stop-color="#0066ff" stop-opacity="0.4" />
</linearGradient>
<radialGradient id="airbag-grad" cx="50%" cy="50%" r="50%" fx="30%" fy="30%">
<stop offset="0%" stop-color="#ffaa00" stop-opacity="0.9" />
<stop offset="70%" stop-color="#ff5500" stop-opacity="0.8" />
<stop offset="100%" stop-color="#aa1100" stop-opacity="0.9" />
</radialGradient>
</defs>
<!-- 场景元素 -->
<!-- 运动轨迹线 -->
<path id="trajectory" d="M1100,-100 Q800,200 600,750" fill="none" stroke="rgba(0, 243, 255, 0.15)" stroke-width="2" stroke-dasharray="8 8" />
<!-- 地面 -->
<g id="ground-group">
<rect x="0" y="750" width="1200" height="50" fill="#04060a" />
<line x1="0" y1="750" x2="1200" y2="750" stroke="var(--accent-cyan)" stroke-width="1" filter="url(#glow)" />
<polygon points="500,750 520,770 680,770 700,750" fill="rgba(0, 243, 255, 0.05)" stroke="var(--accent-cyan)" stroke-width="0.5" />
<text x="600" y="765" class="svg-label" text-anchor="middle">RECOVERY ZONE // NOMINAL</text>
</g>
<!-- 火箭主体组合(包含降落伞和气囊,整体随轨迹运动) -->
<g id="vehicle-assembly">
<!-- 主翼伞 (初始隐藏/缩小) -->
<g id="parafoil-system" opacity="0" transform="scale(0.1) translate(0, -150)">
<!-- 伞缆 -->
<path d="M-120,-80 L-10,0 M-60,-100 L-5,0 M0,-110 L0,0 M60,-100 L5,0 M120,-80 L10,0" stroke="rgba(255,255,255,0.4)" stroke-width="1" />
<!-- 翼伞本体 (冲压结构截面) -->
<path d="M-150,-80 C-150,-110 -80,-130 0,-130 C80,-130 150,-110 150,-80 C150,-70 140,-65 120,-65 C100,-75 80,-75 60,-65 C40,-75 20,-75 0,-65 C-20,-75 -40,-75 -60,-65 C-80,-75 -100,-75 -120,-65 C-140,-65 -150,-70 -150,-80 Z"
fill="url(#parafoil-grad)" stroke="#00f3ff" stroke-width="1.5" filter="url(#glow)" />
<!-- 微小原理文字 -->
<text x="0" y="-145" class="svg-label highlight" text-anchor="middle">1200m² RAM-AIR PARAFOIL [AERO-DRAG UTILIZED]</text>
</g>
<!-- 火箭箭体 (水平或小倾角姿态) -->
<g id="rocket-body-group" transform="rotate(0)">
<!-- 喷管 (熄火状态) -->
<polygon points="-60,10 -80,18 -80,-18 -60,-10" fill="#111" stroke="#333" stroke-width="1" />
<!-- 箭身圆柱 (为了演示侧收横向姿态,此处箭体横置,X为长度向) -->
<path d="M-60,-15 L60,-15 C75,-15 85,-5 85,0 C85,5 75,15 60,15 L-60,15 Z" fill="url(#rocket-body)" stroke="#555" stroke-width="1" />
<!-- 栅格舵(收起) -->
<rect x="50" y="-18" width="10" height="4" fill="#333" />
<rect x="50" y="14" width="10" height="4" fill="#333" />
<!-- 气囊组 (初始隐藏,触地前充气) -->
<g id="airbag-system" opacity="0">
<!-- 底部主气囊 -->
<ellipse cx="-50" cy="25" rx="20" ry="20" fill="url(#airbag-grad)" stroke="#ffaa00" stroke-width="1.5" />
<!-- 侧边缓冲气囊 -->
<ellipse cx="0" cy="25" rx="18" ry="18" fill="url(#airbag-grad)" stroke="#ffaa00" stroke-width="1.5" />
<ellipse cx="45" cy="25" rx="15" ry="15" fill="url(#airbag-grad)" stroke="#ffaa00" stroke-width="1.5" />
<!-- 气压标签跟随 -->
<text x="0" y="55" class="svg-label alert" text-anchor="middle" id="svg-pressure-txt">45 kPa PRE-PRESSURIZED</text>
</g>
<!-- 泄压阀排气粒子特效 (触地瞬间触发) -->
<g id="exhaust-particles" opacity="0">
<!-- 向左上方排气 -->
<path d="M-60,10 L-100,-20 M-55,5 L-90,-10 M-65,15 L-110,-30" stroke="rgba(255,255,255,0.8)" stroke-width="2" stroke-linecap="round" />
<!-- 向右上方排气 -->
<path d="M50,10 L90,-20 M45,5 L80,-10 M55,15 L100,-30" stroke="rgba(255,255,255,0.8)" stroke-width="2" stroke-linecap="round" />
<text x="0" y="-30" class="svg-label alert" text-anchor="middle" id="svg-valve-txt">VALVE OPEN [80 kPa THRESHOLD]</text>
</g>
</g>
</g>
</svg>
</div>
<script>
document.addEventListener("DOMContentLoaded", () => {
// 获取DOM元素
const elVehicle = document.getElementById('vehicle-assembly');
const elParafoil = document.getElementById('parafoil-system');
const elRocket = document.getElementById('rocket-body-group');
const elAirbags = document.getElementById('airbag-system');
const elExhaust = document.getElementById('exhaust-particles');
const container = document.getElementById('stage-container');
// UI 元素
const uiPhase = document.getElementById('ui-phase');
const uiAlt = document.getElementById('ui-alt');
const uiVel = document.getElementById('ui-vel');
const uiArea = document.getElementById('ui-area');
const uiPress = document.getElementById('ui-press');
const uiValve = document.getElementById('ui-valve');
// SVG 内部文字状态
const svgPressTxt = document.getElementById('svg-pressure-txt');
const svgValveTxt = document.getElementById('svg-valve-txt');
// 动画参数设定 (时间轴循环总长: 14000 毫秒)
const CYCLE_DURATION = 14000;
let startTime = performance.now();
// 轨迹关键点映射控制
// 阶段:
// 0% - 15%: 自由落体姿态调整 (15km)
// 15% - 25%: 主翼伞展开减速 (8km)
// 25% - 75%: 稳定滑翔寻的
// 75% - 82%: 接近地面 (50m),气囊充气
// 82% - 85%: 触地,气囊压缩,泄压
// 85% - 92%: 翼伞脱落,静止展示
// 92% - 100%: 准备重置
function easeOutCubic(x) {
return 1 - Math.pow(1 - x, 3);
}
function easeOutElastic(x) {
const c4 = (2 * Math.PI) / 3;
return x === 0 ? 0 : x === 1 ? 1 : Math.pow(2, -10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1;
}
// 核心渲染循环
function renderFrame(now) {
// 计算当前周期内的进度 (0.0 到 1.0)
let elapsed = (now - startTime) % CYCLE_DURATION;
let t = elapsed / CYCLE_DURATION;
// --- 物理状态变量 ---
let x = 0, y = 0, rot = 0;
let pScale = 0, pOpacity = 0; // 翼伞状态
let aScaleX = 1, aScaleY = 1, aOpacity = 0; // 气囊状态
let eOpacity = 0; // 泄压排气状态
let pOffset = 0; // 翼伞脱落位移
// --- 遥测数据变量 ---
let alt = 0, vel = 0, phase = "", area = 0, press = 0, valve = "CLOSED";
// --- 阶段逻辑计算 ---
if (t < 0.15) {
// 自由落体 & 调姿阶段 (高速斜下)
let pt = t / 0.15; // 0~1
x = 1100 - pt * 200;
y = -100 + pt * 300;
rot = 45 - pt * 45; // 从45度转为0度(水平)
phase = "ATTITUDE ADJUST";
alt = Math.round(15000 - pt * 7000);
vel = Math.round(2500 - pt * 1500);
} else if (t < 0.25) {
// 翼伞展开阶段
let pt = (t - 0.15) / 0.10;
x = 900 - pt * 100;
y = 200 + pt * 150;
rot = 0;
// 翼伞展开特效
pOpacity = pt;
pScale = easeOutElastic(pt);
phase = "PARAFOIL DEPLOY";
alt = Math.round(8000 - pt * 4000);
vel = Math.round(1000 - easeOutCubic(pt) * 850);
area = Math.round(pt * 1200);
} else if (t < 0.75) {
// 稳定滑翔阶段
let pt = (t - 0.25) / 0.50;
x = 800 - pt * 200;
y = 350 + pt * 350;
rot = 0;
pOpacity = 1;
pScale = 1;
phase = "GLIDING TARGETING";
alt = Math.max(50, Math.round(4000 - pt * 3950));
vel = 150; // 恒定滑翔速度
area = 1200;
} else if (t < 0.82) {
// 气囊充气阶段 (接近地面50m)
let pt = (t - 0.75) / 0.07;
x = 600;
y = 700 + pt * 45; // 接近 745 (考虑火箭半径和地面位置)
pOpacity = 1;
pScale = 1;
// 气囊猛烈充气
aOpacity = 1;
aScaleX = aScaleY = easeOutElastic(pt);
phase = "AIRBAG INFLATION";
alt = Math.max(5, Math.round(50 - pt * 45));
vel = Math.max(20, Math.round(150 - pt * 130)); // 终点末速
area = 1200;
press = Math.round(pt * 45); // 充至 45kPa
} else if (t < 0.85) {
// 触地压缩与泄压阶段
let pt = (t - 0.82) / 0.03;
x = 600;
y = 745 + pt * 3; // 几乎停止,产生微小下压
pOpacity = 1;
pScale = 1;
aOpacity = 1;
// 形变吸收冲击
aScaleY = 1 - pt * 0.5; // Y轴压扁
aScaleX = 1 + pt * 0.3; // X轴外扩
// 开启泄压阀
eOpacity = pt > 0.1 ? (1 - pt) * 2 : 0;
valve = "OPEN (EXHAUSTING)";
svgValveTxt.setAttribute('opacity', pt > 0.1 ? 1 : 0);
// 触发屏幕震动 (仅在瞬间触发一次类)
if (pt > 0.1 && pt < 0.2 && !container.classList.contains('shake-active')) {
container.classList.add('shake-active');
setTimeout(() => container.classList.remove('shake-active'), 400);
}
phase = "TOUCHDOWN & ABSORB";
alt = 0;
vel = 0;
area = 1200;
press = Math.min(80, 45 + Math.round(pt * 35)); // 峰值 80kPa
} else {
// 翼伞脱落静止展示阶段
let pt = Math.min(1, (t - 0.85) / 0.07);
x = 600;
y = 748;
// 翼伞脱落飘走
pOffset = pt * 100;
pOpacity = 1 - pt;
pScale = 1;
aOpacity = 1;
// 泄压后气囊稍微回弹维持瘪态
aScaleY = 0.5 + pt * 0.1;
aScaleX = 1.3 - pt * 0.1;
eOpacity = 0;
valve = "CLOSED (LOCKED)";
svgValveTxt.setAttribute('opacity', 0);
phase = "SYSTEM SECURED";
alt = 0;
vel = 0;
area = Math.max(0, 1200 - Math.round(pt * 1200));
press = Math.max(10, 80 - Math.round(pt * 70));
}
// --- 渲染到 DOM ---
// 火箭总成位置
elVehicle.setAttribute('transform', `translate(${x}, ${y})`);
// 火箭姿态
elRocket.setAttribute('transform', `rotate(${rot})`);
// 翼伞
elParafoil.setAttribute('opacity', pOpacity);
elParafoil.setAttribute('transform', `translate(${pOffset}, ${-pOffset}) scale(${pScale}) translate(0, -130)`);
// 气囊
elAirbags.setAttribute('opacity', aOpacity);
elAirbags.setAttribute('transform', `scale(${aScaleX}, ${aScaleY})`);
// 泄压特效
elExhaust.setAttribute('opacity', eOpacity);
if (eOpacity > 0) {
// 动态缩放排气线产生喷射感
let exhaustScale = 1 + (Math.random() * 0.2);
elExhaust.setAttribute('transform', `scale(${exhaustScale})`);
}
// --- 更新遥测 UI ---
uiPhase.innerText = phase;
uiAlt.innerText = alt.toString().padStart(5, '0') + " m";
uiVel.innerText = vel.toString().padStart(4, '0') + " m/s";
uiArea.innerText = area + " m²";
uiPress.innerText = press + " kPa";
if(press > 70) uiPress.style.color = "#ff1100";
else uiPress.style.color = "var(--accent-orange)";
uiValve.innerText = valve;
if(valve.includes("OPEN")) uiValve.style.color = "#ff1100";
else uiValve.style.color = "var(--text-main)";
svgPressTxt.textContent = press > 10 ? `${press} kPa PRESSURE` : "";
// 循环请求下一帧
requestAnimationFrame(renderFrame);
}
// 启动动画
requestAnimationFrame(renderFrame);
});
</script>
</body>
</html>
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
