独立渲染引擎就绪引擎就绪
<!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=Share+Tech+Mono&family=Syncopate:wght@400;700&display=swap');
:root {
--bg-color: #08080c;
--grid-color: #1a1a24;
--stair-fill: #151520;
--stair-edge: #2dd4bf;
--neon-cyan: #00f0ff;
--neon-orange: #ff5500;
--cabin-metal: #242430;
--text-main: #e2e8f0;
--text-muted: #64748b;
}
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background-color: var(--bg-color);
color: var(--text-main);
font-family: 'Share Tech Mono', monospace;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
}
/* 核心动画容器 */
#animation-container {
position: relative;
width: 100%;
max-width: 1400px;
height: 100%;
max-height: 900px;
display: flex;
justify-content: center;
align-items: center;
box-shadow: inset 0 0 100px rgba(0, 240, 255, 0.05);
}
svg {
width: 100%;
height: 100%;
/* 保证在各种屏幕比例下居中显示且不被裁剪 */
object-fit: contain;
}
/* UI 覆盖层 (HUD) */
.hud-panel {
position: absolute;
background: rgba(10, 10, 15, 0.85);
border: 1px solid rgba(0, 240, 255, 0.3);
backdrop-filter: blur(10px);
padding: 20px;
border-radius: 4px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.5), inset 0 0 20px rgba(0, 240, 255, 0.1);
pointer-events: auto;
}
#title-panel {
top: 30px;
left: 30px;
max-width: 450px;
}
#title-panel h1 {
font-family: 'Syncopate', sans-serif;
font-size: 20px;
color: var(--neon-cyan);
margin: 0 0 10px 0;
text-transform: uppercase;
letter-spacing: 2px;
text-shadow: 0 0 10px rgba(0, 240, 255, 0.5);
}
#title-panel h2 {
font-size: 14px;
color: var(--neon-orange);
margin: 0 0 15px 0;
text-transform: uppercase;
}
.desc-text {
font-size: 13px;
color: var(--text-muted);
line-height: 1.6;
margin-bottom: 10px;
}
.highlight-text {
color: #fff;
border-bottom: 1px solid var(--neon-cyan);
}
#control-panel {
bottom: 30px;
right: 30px;
width: 300px;
}
.control-group {
margin-bottom: 15px;
}
.control-group:last-child {
margin-bottom: 0;
}
.control-label {
display: flex;
justify-content: space-between;
font-size: 12px;
color: var(--neon-cyan);
margin-bottom: 8px;
text-transform: uppercase;
}
input[type=range] {
-webkit-appearance: none;
width: 100%;
background: transparent;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 16px;
width: 8px;
background: var(--neon-orange);
cursor: pointer;
margin-top: -6px;
box-shadow: 0 0 10px var(--neon-orange);
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 4px;
cursor: pointer;
background: rgba(255,255,255,0.1);
border-radius: 2px;
}
/* 实时数据监控面板 */
#telemetry-panel {
top: 30px;
right: 30px;
width: 250px;
}
.data-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px dashed rgba(255,255,255,0.1);
}
.data-row:last-child { border-bottom: none; }
.data-label { color: var(--text-muted); font-size: 12px; }
.data-value { color: var(--neon-cyan); font-size: 16px; font-weight: bold; font-family: 'Share Tech Mono', monospace;}
.data-value.warning { color: var(--neon-orange); }
/* SVG 样式 */
.track-base {
fill: none;
stroke: #111;
stroke-width: 66;
stroke-linecap: round;
stroke-linejoin: round;
filter: drop-shadow(0 10px 15px rgba(0,0,0,0.8));
}
.track-tread {
fill: none;
stroke: #2a2a35;
stroke-width: 60;
stroke-linecap: round;
stroke-linejoin: round;
}
.track-grip {
fill: none;
stroke: var(--neon-orange);
stroke-width: 64;
stroke-linecap: round;
stroke-linejoin: round;
stroke-dasharray: 8 24;
opacity: 0.9;
/* Dash offset 会由 JS 动态控制以展示履带卷动 */
}
.stair-visual {
fill: url(#hatch-pattern);
stroke: var(--stair-edge);
stroke-width: 3;
filter: drop-shadow(0 0 8px rgba(45, 212, 191, 0.3));
}
/* 隐藏用于运动学计算的虚拟平滑路径 */
.kinematic-path {
fill: none;
stroke: red;
stroke-width: 2;
opacity: 0;
}
.vector-arrow {
transition: opacity 0.2s ease;
}
</style>
</head>
<body>
<div id="animation-container">
<!-- SVG 动画主体 -->
<svg viewBox="0 0 1600 900" id="main-svg" preserveAspectRatio="xMidYMid meet">
<defs>
<!-- 背景网格 -->
<pattern id="bg-grid" width="40" height="40" patternUnits="userSpaceOnUse">
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="rgba(255,255,255,0.03)" stroke-width="1"/>
</pattern>
<!-- 台阶填充纹理 -->
<pattern id="hatch-pattern" width="10" height="10" patternTransform="rotate(45 0 0)" patternUnits="userSpaceOnUse">
<rect width="10" height="10" fill="var(--stair-fill)"/>
<line x1="0" y1="0" x2="0" y2="10" stroke="rgba(255,255,255,0.03)" stroke-width="2"/>
</pattern>
<!-- 发光滤镜 -->
<filter id="neon-glow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur1" />
<feGaussianBlur in="SourceGraphic" stdDeviation="15" result="blur2" />
<feMerge>
<feMergeNode in="blur2" />
<feMergeNode in="blur1" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<!-- 机舱组件渐变 -->
<linearGradient id="metal-grad" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#3f3f5a"/>
<stop offset="100%" stop-color="#1a1a24"/>
</linearGradient>
<!-- 箭头标记 -->
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#00f0ff" />
</marker>
</defs>
<!-- 渲染背景 -->
<rect width="100%" height="100%" fill="url(#bg-grid)" />
<g transform="translate(100, 150)">
<!-- 视觉渲染用的真实不规则台阶轮廓 -->
<!-- 包含了直角、锐利突起和不规则斜坡,以验证失效边界与理想状态 -->
<path class="stair-visual" d="M -200 600 L 300 600 L 300 450 L 550 450 L 650 300 L 800 300 L 800 250 L 900 250 L 900 100 L 1600 100 L 1600 800 L -200 800 Z" />
<!-- 用于运动学约束的隐藏平滑路径 (底盘中心轨迹) -->
<!-- 轨迹相比台阶向左上偏移约 35px,并在拐角处做贝塞尔平滑,模拟柔性履带的包络特性 -->
<path id="kinematic-path" class="kinematic-path" d="
M -200 565
L 265 565 C 265 565, 265 565, 265 520
L 265 485 C 265 415, 265 415, 335 415
L 510 415 C 550 415, 550 415, 570 385
L 615 315 C 635 280, 635 280, 670 265
L 765 265 C 765 265, 765 265, 765 235
L 765 215 C 765 215, 765 215, 800 215
L 865 215 C 865 215, 865 215, 865 185
L 865 135 C 865 65, 865 65, 935 65
L 1600 65" />
<!-- 车辆本体 Group -->
<g id="vehicle-assembly">
<!-- 履带底层阴影与主形状 -->
<path id="track-base" class="track-base" d="" />
<!-- 履带主体黑色橡胶 -->
<path id="track-tread" class="track-tread" d="" />
<!-- 履带外侧防滑纹 (橙色动态卷动) -->
<path id="track-grip" class="track-grip" d="" />
<!-- 内部独立驱动舱段 (3个) -->
<!-- 舱段1 (前) -->
<g id="cabin-1">
<rect x="-35" y="-18" width="70" height="36" rx="6" fill="url(#metal-grad)" stroke="#00f0ff" stroke-width="1.5" opacity="0.9"/>
<circle cx="0" cy="0" r="10" fill="none" stroke="#ff5500" stroke-width="2"/>
<line x1="-20" y1="0" x2="-10" y2="0" stroke="#00f0ff" stroke-width="2"/>
<line x1="20" y1="0" x2="10" y2="0" stroke="#00f0ff" stroke-width="2"/>
<text x="0" y="3" fill="#00f0ff" font-size="10" text-anchor="middle" font-family="sans-serif">M1</text>
</g>
<!-- 舱段2 (中) -->
<g id="cabin-2">
<rect x="-35" y="-18" width="70" height="36" rx="6" fill="url(#metal-grad)" stroke="#00f0ff" stroke-width="1.5" opacity="0.9"/>
<circle cx="0" cy="0" r="10" fill="none" stroke="#ff5500" stroke-width="2"/>
<text x="0" y="3" fill="#00f0ff" font-size="10" text-anchor="middle" font-family="sans-serif">M2</text>
</g>
<!-- 舱段3 (后) -->
<g id="cabin-3">
<rect x="-35" y="-18" width="70" height="36" rx="6" fill="url(#metal-grad)" stroke="#00f0ff" stroke-width="1.5" opacity="0.9"/>
<circle cx="0" cy="0" r="10" fill="none" stroke="#ff5500" stroke-width="2"/>
<line x1="-20" y1="0" x2="-10" y2="0" stroke="#00f0ff" stroke-width="2"/>
<line x1="20" y1="0" x2="10" y2="0" stroke="#00f0ff" stroke-width="2"/>
<text x="0" y="3" fill="#00f0ff" font-size="10" text-anchor="middle" font-family="sans-serif">M3</text>
</g>
<!-- 被动铰接关节与发光指示器 (资源利用重点) -->
<!-- 铰链 12 -->
<circle id="hinge-12-glow" cx="0" cy="0" r="25" fill="var(--neon-cyan)" filter="url(#neon-glow)" opacity="0" style="transition: opacity 0.1s; pointer-events:none;"/>
<circle id="hinge-12" cx="0" cy="0" r="5" fill="#fff" stroke="#000" stroke-width="2"/>
<!-- 铰链 23 -->
<circle id="hinge-23-glow" cx="0" cy="0" r="25" fill="var(--neon-cyan)" filter="url(#neon-glow)" opacity="0" style="transition: opacity 0.1s; pointer-events:none;"/>
<circle id="hinge-23" cx="0" cy="0" r="5" fill="#fff" stroke="#000" stroke-width="2"/>
<!-- 动态推力矢量箭头 -->
<g id="force-vector-front" class="vector-arrow" opacity="0">
<line x1="0" y1="-20" x2="0" y2="-60" stroke="#00f0ff" stroke-width="3" marker-end="url(#arrowhead)"/>
<text x="5" y="-65" fill="#00f0ff" font-size="12">贴合摩擦力</text>
</g>
</g>
<!-- 场景标注 -->
<g transform="translate(420, 630)">
<line x1="0" y1="0" x2="-60" y2="-30" stroke="var(--text-muted)" stroke-dasharray="2 2"/>
<text x="10" y="5" fill="var(--text-muted)" font-size="12">传统刚性底盘失效点:直角台阶</text>
</g>
<g transform="translate(680, 480)">
<line x1="0" y1="0" x2="-40" y2="-40" stroke="var(--text-muted)" stroke-dasharray="2 2"/>
<text x="10" y="5" fill="var(--text-muted)" font-size="12">不规则高度差</text>
</g>
</g>
</svg>
<!-- 文本信息区 -->
<div id="title-panel" class="hud-panel">
<h1>TRIZ Ideal Final Result</h1>
<h2>多段式柔性自适应底盘</h2>
<div class="desc-text">
<span class="highlight-text">技术矛盾:</span>传统刚性底盘为保证稳定性,无法适应高度随机的不规则台阶,极易悬空打滑。
</div>
<div class="desc-text">
<span class="highlight-text">解决方案 (化整为零):</span>放弃整体刚性大梁,由 3 个独立驱动舱段组成。利用<strong style="color:var(--neon-cyan)">被动弹簧铰链</strong>与<strong style="color:var(--neon-orange)">高弹性宽体橡胶履带</strong>串联。
</div>
<div class="desc-text">
当车头触及台阶,前端受力向上被动弯折,犹如毛毛虫般“趴”在立面上,巧妙利用现有重力与推力资源完成被动贴合,无需复杂的传感控制。
</div>
</div>
<!-- 遥测数据监控区 -->
<div id="telemetry-panel" class="hud-panel">
<h2 style="font-size: 14px; color: #fff; margin: 0 0 15px 0; border-bottom: 1px solid rgba(255,255,255,0.2); padding-bottom: 5px;">状态遥测 / TELEMETRY</h2>
<div class="data-row">
<span class="data-label">主推进速度</span>
<span class="data-value" id="val-speed">1.0 m/s</span>
</div>
<div class="data-row">
<span class="data-label">前部关节形变 (Max 45°)</span>
<span class="data-value" id="val-angle-front">0.0°</span>
</div>
<div class="data-row">
<span class="data-label">后部关节形变 (Max 45°)</span>
<span class="data-value" id="val-angle-rear">0.0°</span>
</div>
<div class="data-row">
<span class="data-label">底盘姿态状态</span>
<span class="data-value" id="val-status">巡航 [刚性]</span>
</div>
</div>
<!-- 控制面板 -->
<div id="control-panel" class="hud-panel">
<div class="control-group">
<div class="control-label">
<span>驱动电机转速 (Speed)</span>
<span id="speed-display">1.5x</span>
</div>
<input type="range" id="speed-slider" min="0.5" max="3" step="0.1" value="1.5">
</div>
<div class="control-group" style="margin-top: 15px;">
<div class="control-label">
<span>履带弹性模量 (视觉演示)</span>
</div>
<input type="range" id="elastic-slider" min="0" max="100" value="80">
</div>
</div>
</div>
<script>
// 页面加载完成后立即自动执行动画,不依赖用户交互
window.addEventListener('DOMContentLoaded', () => {
// --- 核心运动学与 DOM 元素获取 ---
const path = document.getElementById('kinematic-path');
const pathLength = path.getTotalLength();
const trackBase = document.getElementById('track-base');
const trackTread = document.getElementById('track-tread');
const trackGrip = document.getElementById('track-grip');
const cabin1 = document.getElementById('cabin-1');
const cabin2 = document.getElementById('cabin-2');
const cabin3 = document.getElementById('cabin-3');
const hinge12 = document.getElementById('hinge-12');
const hinge12Glow = document.getElementById('hinge-12-glow');
const hinge23 = document.getElementById('hinge-23');
const hinge23Glow = document.getElementById('hinge-23-glow');
const forceVector = document.getElementById('force-vector-front');
const valSpeed = document.getElementById('val-speed');
const valAngleFront = document.getElementById('val-angle-front');
const valAngleRear = document.getElementById('val-angle-rear');
const valStatus = document.getElementById('val-status');
const speedSlider = document.getElementById('speed-slider');
const speedDisplay = document.getElementById('speed-display');
const elasticSlider = document.getElementById('elastic-slider');
// --- 物理与状态参数 ---
let globalProgress = 20; // 动画初始位置,稍稍进入画面
let baseSpeed = 1.8;
const SEGMENT_LENGTH = 75; // 舱段间距约束 (近似为节点间的弧长距离)
let lastTimestamp = 0;
// UI 交互绑定
speedSlider.addEventListener('input', (e) => {
baseSpeed = parseFloat(e.target.value) * 1.2;
speedDisplay.textContent = e.target.value + 'x';
valSpeed.textContent = (parseFloat(e.target.value) * 0.8).toFixed(1) + ' m/s';
});
elasticSlider.addEventListener('input', (e) => {
const val = e.target.value;
// 调整履带的张力视觉感受
const tensionColor = `rgba(255, ${85 + (100-val)*1.7}, 0, 0.9)`;
trackGrip.style.stroke = tensionColor;
});
// 角度计算辅助函数 (将 atan2 转为角度)
function getAngle(p1, p2) {
return Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
}
// --- 主渲染循环 ---
function animate(timestamp) {
if (!lastTimestamp) lastTimestamp = timestamp;
const dt = timestamp - lastTimestamp;
lastTimestamp = timestamp;
// 保持帧率独立的运动
globalProgress += baseSpeed * (dt / 16.6);
// 循环播放逻辑 (重开即播,到达终点自动重置)
if (globalProgress > pathLength - 100) {
globalProgress = 20;
// 瞬间消除过渡效果防止跳跃闪烁
trackGrip.style.transition = 'none';
} else {
trackGrip.style.transition = '';
}
// 履带上的 4 个核心接触点 (包络 3 个舱段)
// 分别位于:前沿、前铰链、后铰链、后沿
const posF = path.getPointAtLength(globalProgress + SEGMENT_LENGTH * 1.5);
const posM1 = path.getPointAtLength(globalProgress + SEGMENT_LENGTH * 0.5);
const posM2 = path.getPointAtLength(globalProgress - SEGMENT_LENGTH * 0.5);
const posR = path.getPointAtLength(globalProgress - SEGMENT_LENGTH * 1.5);
// 1. 绘制高弹性履带包络线
// 利用 SVG thick stroke 和 round linejoin 实现完美的胶囊状外壳
const trackPathDef = `M ${posF.x} ${posF.y} L ${posM1.x} ${posM1.y} L ${posM2.x} ${posM2.y} L ${posR.x} ${posR.y}`;
trackBase.setAttribute('d', trackPathDef);
trackTread.setAttribute('d', trackPathDef);
trackGrip.setAttribute('d', trackPathDef);
// 卷动履带花纹
trackGrip.setAttribute('stroke-dashoffset', -globalProgress * 1.5);
// 2. 更新舱段姿态 (位移与旋转)
const updateCabinTransform = (element, pStart, pEnd) => {
const cx = (pStart.x + pEnd.x) / 2;
const cy = (pStart.y + pEnd.y) / 2;
const angle = getAngle(pEnd, pStart);
element.setAttribute('transform', `translate(${cx}, ${cy}) rotate(${angle})`);
return angle;
};
const angleCabin1 = updateCabinTransform(cabin1, posF, posM1);
const angleCabin2 = updateCabinTransform(cabin2, posM1, posM2);
const angleCabin3 = updateCabinTransform(cabin3, posM2, posR);
// 3. 计算关节弯折并处理 IFR 视觉引导
// 夹角差值计算,并处理越界 (如 +179 与 -179 的差)
let diff1 = angleCabin1 - angleCabin2;
if (diff1 > 180) diff1 -= 360; else if (diff1 < -180) diff1 += 360;
let diff2 = angleCabin2 - angleCabin3;
if (diff2 > 180) diff2 -= 360; else if (diff2 < -180) diff2 += 360;
const absDiff1 = Math.abs(diff1);
const absDiff2 = Math.abs(diff2);
// 铰链位置更新
hinge12.setAttribute('cx', posM1.x); hinge12.setAttribute('cy', posM1.y);
hinge12Glow.setAttribute('cx', posM1.x); hinge12Glow.setAttribute('cy', posM1.y);
hinge23.setAttribute('cx', posM2.x); hinge23.setAttribute('cy', posM2.y);
hinge23Glow.setAttribute('cx', posM2.x); hinge23Glow.setAttribute('cy', posM2.y);
// 视觉引导:当弯折发生时,点亮对应铰链,突出“被动适应”的核心原理
const threshold = 5; // 超过 5 度视为进入形变状态
hinge12Glow.style.opacity = absDiff1 > threshold ? Math.min(absDiff1 / 45, 1).toString() : '0';
hinge23Glow.style.opacity = absDiff2 > threshold ? Math.min(absDiff2 / 45, 1).toString() : '0';
// 更新数据面板
valAngleFront.textContent = absDiff1.toFixed(1) + '°';
valAngleFront.className = absDiff1 > 35 ? 'data-value warning' : 'data-value';
valAngleRear.textContent = absDiff2.toFixed(1) + '°';
valAngleRear.className = absDiff2 > 35 ? 'data-value warning' : 'data-value';
if (absDiff1 > threshold || absDiff2 > threshold) {
valStatus.textContent = '仿形蠕动 [柔性贴合]';
valStatus.style.color = 'var(--neon-orange)';
} else {
valStatus.textContent = '平移巡航 [重力复原]';
valStatus.style.color = 'var(--neon-cyan)';
}
// 视觉引导 2:当车头接触立面且向上翘起时,展示向上的摩擦牵引力
if (angleCabin1 < -30 && angleCabin1 > -100) {
forceVector.setAttribute('transform', `translate(${posF.x}, ${posF.y})`);
forceVector.setAttribute('opacity', '1');
} else {
forceVector.setAttribute('opacity', '0');
}
requestAnimationFrame(animate);
}
// 启动自动播放
requestAnimationFrame(animate);
});
</script>
</body>
</html>
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
