独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TRIZ IFR - 柔性曲臂与磁吸过载保护系统</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Chakra+Petch:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap');
:root {
--bg-color: #030712;
--grid-color: rgba(30, 41, 59, 0.5);
--cyan-glow: #00f0ff;
--cyan-dim: rgba(0, 240, 255, 0.15);
--neon-pink: #ff2a6d;
--neon-orange: #ff9f1c;
--neon-green: #05ffa1;
--text-main: #f8fafc;
--text-muted: #94a3b8;
--panel-bg: rgba(15, 23, 42, 0.7);
}
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
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: 'Noto Sans SC', sans-serif;
color: var(--text-main);
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
}
/* 径向暗角渐变增加深度 */
.vignette {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: radial-gradient(circle at 50% 50%, transparent 20%, #030712 100%);
pointer-events: none;
z-index: 0;
}
#animation-container {
position: relative;
width: 100vw;
height: 100vh;
max-width: 1600px;
max-height: 900px;
z-index: 1;
display: flex;
justify-content: center;
align-items: center;
}
svg {
width: 100%;
height: 100%;
filter: drop-shadow(0 0 20px rgba(0,0,0,0.5));
}
/* UI 面板与数据展示 */
.hud-panel {
position: absolute;
background: var(--panel-bg);
border: 1px solid rgba(0, 240, 255, 0.2);
backdrop-filter: blur(10px);
padding: 24px;
border-radius: 8px;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.6), inset 0 0 20px rgba(0, 240, 255, 0.05);
pointer-events: none;
}
.hud-panel::before {
content: '';
position: absolute;
top: -1px; left: -1px;
width: 20px; height: 20px;
border-top: 2px solid var(--cyan-glow);
border-left: 2px solid var(--cyan-glow);
}
.hud-panel::after {
content: '';
position: absolute;
bottom: -1px; right: -1px;
width: 20px; height: 20px;
border-bottom: 2px solid var(--cyan-glow);
border-right: 2px solid var(--cyan-glow);
}
#panel-ifr {
top: 40px;
left: 40px;
width: 320px;
}
#panel-status {
bottom: 40px;
right: 40px;
width: 360px;
}
h2 {
font-family: 'Chakra Petch', sans-serif;
font-size: 24px;
margin: 0 0 16px 0;
color: var(--cyan-glow);
letter-spacing: 2px;
text-transform: uppercase;
display: flex;
align-items: center;
gap: 10px;
}
h2::before {
content: '';
display: inline-block;
width: 8px;
height: 24px;
background: var(--cyan-glow);
}
.data-row {
display: flex;
justify-content: space-between;
margin-bottom: 12px;
font-size: 14px;
border-bottom: 1px dashed rgba(255,255,255,0.1);
padding-bottom: 4px;
}
.data-row .label {
color: var(--text-muted);
}
.data-row .value {
font-family: 'Chakra Petch', sans-serif;
font-weight: 600;
color: var(--neon-green);
}
.data-row .value.warning {
color: var(--neon-pink);
text-shadow: 0 0 10px rgba(255, 42, 109, 0.8);
animation: pulse 0.5s infinite alternate;
}
.ifr-concept {
margin-top: 20px;
}
.ifr-item {
margin-bottom: 16px;
padding-left: 12px;
border-left: 2px solid var(--neon-orange);
}
.ifr-item:nth-child(2) { border-left-color: var(--cyan-glow); }
.ifr-item .title {
font-weight: 700;
font-size: 15px;
margin-bottom: 4px;
color: #fff;
}
.ifr-item .desc {
font-size: 13px;
color: var(--text-muted);
line-height: 1.5;
}
@keyframes pulse {
from { opacity: 0.8; }
to { opacity: 1; transform: scale(1.02); }
}
.glowing-text {
font-family: 'Chakra Petch', sans-serif;
font-weight: 700;
}
</style>
</head>
<body>
<div class="vignette"></div>
<div id="animation-container">
<!-- SVG Canvas -->
<svg id="main-svg" viewBox="0 0 1200 800" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- Filters for glowing effects -->
<filter id="glow-cyan" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="6" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<filter id="glow-orange" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="5" result="blur" />
<feComponentTransfer in="blur" result="glow">
<feFuncA type="linear" slope="2"/>
</feComponentTransfer>
<feMerge>
<feMergeNode in="glow" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<filter id="glow-red" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="8" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<!-- Gradients -->
<linearGradient id="glass-grad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="rgba(0, 240, 255, 0.02)" />
<stop offset="80%" stop-color="rgba(0, 240, 255, 0.08)" />
<stop offset="100%" stop-color="rgba(0, 240, 255, 0.3)" />
</linearGradient>
<linearGradient id="metal-grad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#1e293b" />
<stop offset="50%" stop-color="#334155" />
<stop offset="100%" stop-color="#0f172a" />
</linearGradient>
</defs>
<!-- BACKGROUND & ENVIRONMENT -->
<g id="environment">
<!-- Car Door Framework -->
<path d="M 680 750 L 680 400 Q 680 380 660 380 L 600 380 L 600 750 Z" fill="url(#metal-grad)" stroke="#475569" stroke-width="2"/>
<path d="M 600 450 L 580 430 L 580 750 L 600 750 Z" fill="#0f172a" stroke="#334155" stroke-width="1"/>
<!-- Glass Panel (Y-axis Support) -->
<rect x="420" y="50" width="15" height="700" fill="url(#glass-grad)" stroke="rgba(0,240,255,0.5)" stroke-width="1"/>
<line x1="435" y1="50" x2="435" y2="750" stroke="#00f0ff" stroke-width="3" filter="url(#glow-cyan)"/>
<!-- Coordinate / Technical markers -->
<text x="400" y="40" fill="#00f0ff" font-family="Chakra Petch" font-size="12" text-anchor="end" opacity="0.8">Y-AXIS (GLASS SUPPORT)</text>
<path d="M 405 50 L 415 50 L 415 750 L 405 750" fill="none" stroke="#00f0ff" stroke-width="1" opacity="0.5"/>
</g>
<!-- MECHANISM COMPONENTS -->
<!-- 1. Split Base System -->
<g id="base-system">
<!-- 3M VHB Tape & Steel Plate (Glued to door) -->
<!-- Door is at X=580. Plate is attached to door surface -->
<rect id="plate-3m" x="570" y="500" width="10" height="80" fill="#ff9f1c" rx="2" filter="url(#glow-orange)"/>
<!-- Main Magnetic Base (Detachable) -->
<g id="magnet-base">
<!-- Base body -->
<rect id="base-body" x="535" y="490" width="35" height="100" fill="#1e293b" stroke="#00f0ff" stroke-width="1.5" rx="4"/>
<!-- Magnet contact surface (Red/Magenta to indicate magnetic lock) -->
<rect id="magnet-lock" x="565" y="500" width="5" height="80" fill="#ff2a6d" />
<!-- Hinge / connection point for the arm -->
<circle cx="545" cy="540" r="5" fill="#00f0ff" filter="url(#glow-cyan)"/>
<circle cx="545" cy="540" r="2" fill="#fff" />
<!-- Magnetic Field Lines (Visible when attached) -->
<g id="mag-fields" stroke="#ff2a6d" stroke-width="1" opacity="0.6" stroke-dasharray="2 2">
<line x1="570" y1="510" x2="585" y2="510" />
<line x1="570" y1="540" x2="585" y2="540" />
<line x1="570" y1="570" x2="585" y2="570" />
</g>
</g>
</g>
<!-- 2. The Thin Spring Arm (Dynamic Path) -->
<!-- Start at Base (545, 540), End at Slider -->
<path id="spring-arm" d="M 545 540 Q 480 500 450 600" fill="none" stroke="#e2e8f0" stroke-width="2" stroke-linecap="round"/>
<!-- Glow effect to show stress -->
<path id="spring-arm-stress" d="M 545 540 Q 480 500 450 600" fill="none" stroke="#ff2a6d" stroke-width="6" stroke-linecap="round" opacity="0" filter="url(#glow-red)"/>
<!-- 3. Top Slider Assembly -->
<g id="slider-assembly">
<!-- PTFE / Teflon Slider touching the glass (X=435) -->
<rect id="teflon-slider" x="435" y="580" width="15" height="40" fill="#05ffa1" rx="4" filter="url(#glow-cyan)"/>
<!-- Connecting rod/bracket -->
<path d="M 450 590 L 460 590 L 460 610 L 450 610 Z" fill="#475569" />
<circle cx="455" cy="600" r="4" fill="#00f0ff" />
<!-- Interaction spark/glow when moving -->
<ellipse id="friction-spark" cx="435" cy="600" rx="4" ry="15" fill="#ffffff" opacity="0.8" filter="url(#glow-cyan)"/>
</g>
<!-- 4. Obstacle / Jam Simulator -->
<g id="jam-block" opacity="0">
<rect x="420" y="250" width="60" height="30" fill="#ff2a6d" rx="4" filter="url(#glow-red)"/>
<path d="M 420 250 L 480 280 L 420 280 Z" fill="rgba(0,0,0,0.3)"/> <!-- Shading -->
<text x="450" y="270" fill="white" font-family="Noto Sans SC" font-weight="700" font-size="14" text-anchor="middle" dominant-baseline="middle">卡滞异物</text>
</g>
<!-- DYNAMIC HUD ANNOTATIONS IN SVG -->
<!-- Base connection line -->
<path id="anno-line-base" d="M 535 540 L 450 540 L 430 450 L 320 450" fill="none" stroke="#94a3b8" stroke-width="1" stroke-dasharray="4 2"/>
<text id="anno-text-base" x="310" y="445" fill="#ff9f1c" font-size="14" text-anchor="end" class="glowing-text">磁吸主体 (过载释放点)</text>
<!-- Arm connection line -->
<path id="anno-line-arm" d="M 480 400 L 400 400 L 380 350 L 320 350" fill="none" stroke="#94a3b8" stroke-width="1" stroke-dasharray="4 2"/>
<text x="310" y="345" fill="#e2e8f0" font-size="14" text-anchor="end" class="glowing-text">1.5mm极薄高强弹簧钢板</text>
<text x="310" y="365" fill="#94a3b8" font-size="12" text-anchor="end">无Y向承载,厚度趋近于0</text>
<!-- Slider connection line -->
<path id="anno-line-slider" d="M 435 600 L 350 600 L 330 650 L 320 650" fill="none" stroke="#94a3b8" stroke-width="1" stroke-dasharray="4 2"/>
<text id="anno-text-slider" x="310" y="645" fill="#05ffa1" font-size="14" text-anchor="end" class="glowing-text">特氟龙(PTFE)柔性滑块</text>
<text x="310" y="665" fill="#94a3b8" font-size="12" text-anchor="end">借用玻璃刚度,摩擦系数 <0.05</text>
<!-- Force Vector Arrows -->
<g id="force-vectors">
<!-- Z-Axis Lift Force -->
<path id="arrow-z" d="M 465 620 L 465 660 M 460 625 L 465 620 L 470 625" fill="none" stroke="#00f0ff" stroke-width="2"/>
<text id="text-force-z" x="475" y="645" fill="#00f0ff" font-family="Chakra Petch" font-size="14" font-weight="bold">Fz</text>
<!-- Y-Axis Support Force (Glass pushing back) -->
<path id="arrow-y" d="M 410 600 L 430 600 M 425 595 L 430 600 L 425 605" fill="none" stroke="#05ffa1" stroke-width="2" opacity="0.8"/>
<text x="390" y="605" fill="#05ffa1" font-family="Chakra Petch" font-size="14" font-weight="bold">Fy</text>
</g>
</svg>
</div>
<!-- UI Overlay / HUD Panels -->
<div class="hud-panel" id="panel-ifr">
<h2>最终理想解 [IFR]</h2>
<div class="ifr-concept">
<div class="ifr-item">
<div class="title">1. 彻底消除悬臂受力</div>
<div class="desc">放弃曲臂“悬空硬抗”,转而利用<strong>原车玻璃作为Y向支撑面</strong>。曲臂仅提供Z向推力,实现极薄厚度与0间隙收纳。</div>
</div>
<div class="ifr-item">
<div class="title">2. 巧妙引入磁力保护</div>
<div class="desc">放弃强化3M胶,利用<strong>分体式磁吸底座</strong>作为可重复安装的过载释放机制。受阻时主动断开,保护系统。</div>
</div>
</div>
</div>
<div class="hud-panel" id="panel-status">
<h2>系统遥测 [TELEMETRY]</h2>
<div class="data-row">
<span class="label">当前运行阶段:</span>
<span class="value" id="ui-phase">系统初始化</span>
</div>
<div class="data-row">
<span class="label">电机输出推力 (Fz):</span>
<span class="value" id="ui-force">0.0 N</span>
</div>
<div class="data-row">
<span class="label">滑块接触面摩擦系数:</span>
<span class="value" style="color:var(--neon-green)">μ = 0.042</span>
</div>
<div class="data-row">
<span class="label">磁吸锁止状态:</span>
<span class="value" id="ui-magnet-status">吸附稳定 [🔒]</span>
</div>
<div class="data-row">
<span class="label">安全阈值 / 防夹力:</span>
<span class="value" style="color:var(--text-muted)">50.0 N / 60.0 N</span>
</div>
</div>
<script>
/**
* 柔性曲臂与磁吸过载保护 - 动画核心逻辑
* 采用 RequestAnimationFrame 实现精确的物理与状态同步控制
*/
// --- 核心 DOM 元素 ---
const els = {
slider: document.getElementById('slider-assembly'),
arm: document.getElementById('spring-arm'),
armStress: document.getElementById('spring-arm-stress'),
magnetBase: document.getElementById('magnet-base'),
magFields: document.getElementById('mag-fields'),
jamBlock: document.getElementById('jam-block'),
frictionSpark: document.getElementById('friction-spark'),
arrowZ: document.getElementById('arrow-z'),
// 动态标注线
lineSlider: document.getElementById('anno-line-slider'),
textSlider: document.getElementById('anno-text-slider'),
lineArm: document.getElementById('anno-line-arm'),
// UI 更新
uiPhase: document.getElementById('ui-phase'),
uiForce: document.getElementById('ui-force'),
uiMagnetStatus: document.getElementById('ui-magnet-status')
};
// --- 坐标与物理常量 ---
const config = {
baseStaticX: 545, // 磁吸底座连接点基准X
baseStaticY: 540, // 磁吸底座连接点基准Y
plateX: 570, // 3M胶板表面X
sliderStrokeMin: 580, // 滑块最底部 Y
sliderStrokeMax: 100, // 滑块最顶部 Y
jamY: 250, // 卡滞物底部 Y
magThreshold: 50, // 磁吸断开阈值 N
};
// --- 时间轴关键帧定义 (无限循环剧本) ---
// 剧本总时长:约 14 秒
const timeline = [
{ t: 0, state: 'IDLE', desc: '待机状态', targetY: 580, jamOpacity: 0, force: 0 },
{ t: 1000, state: 'UP', desc: '正常升起 - 玻璃Y向支撑', targetY: 100, jamOpacity: 0, force: 15 },
{ t: 4000, state: 'DOWN', desc: '平滑收纳 - 极薄曲臂0间隙', targetY: 580, jamOpacity: 0, force: 10 },
{ t: 7000, state: 'IDLE', desc: '遭遇极端工况 / 异物入侵', targetY: 580, jamOpacity: 1, force: 0 },
{ t: 8000, state: 'JAM_UP', desc: '升降启动', targetY: 250, jamOpacity: 1, force: 15 }, // 上升到碰触卡滞物
{ t: 9500, state: 'JAMMED', desc: '系统卡滞 - 应力急剧上升', targetY: 250, jamOpacity: 1, force: 65 }, // 电机继续推,推力飙升超过50
{ t: 11000, state: 'RELEASE',desc: '过载卸力 - 磁吸主动脱落', targetY: 250, jamOpacity: 1, force: 0 }, // 超过50N后脱落,拉力归零
{ t: 13500, state: 'RESET', desc: '系统复位', targetY: 580, jamOpacity: 0, force: 0 },
{ t: 14000, state: 'END', desc: '循环', targetY: 580, jamOpacity: 0, force: 0 }
];
// --- 缓动函数 ---
function lerp(start, end, amt) {
return (1 - amt) * start + amt * end;
}
function easeInOutQuad(t) {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
}
let startTime = null;
let totalDuration = timeline[timeline.length - 1].t;
function animate(timestamp) {
if (!startTime) startTime = timestamp;
let elapsed = (timestamp - startTime) % totalDuration;
// 查找当前所处的时间段
let currentFrame, nextFrame;
for (let i = 0; i < timeline.length - 1; i++) {
if (elapsed >= timeline[i].t && elapsed < timeline[i + 1].t) {
currentFrame = timeline[i];
nextFrame = timeline[i + 1];
break;
}
}
if (!currentFrame) currentFrame = timeline[timeline.length - 2];
if (!nextFrame) nextFrame = timeline[timeline.length - 1];
// 计算当前段的进度 (0.0 到 1.0)
let segmentDuration = nextFrame.t - currentFrame.t;
let segmentElapsed = elapsed - currentFrame.t;
let rawProgress = segmentElapsed / segmentDuration;
let progress = easeInOutQuad(rawProgress);
// --- 动态值插值计算 ---
let currentY = lerp(currentFrame.targetY, nextFrame.targetY, progress);
let currentForce = lerp(currentFrame.force, nextFrame.force, progress);
let currentJamOpacity = currentFrame.state === 'IDLE' && nextFrame.state === 'JAM_UP' ?
lerp(0, 1, progress) :
(currentFrame.state === 'RESET' ? lerp(1, 0, progress) : currentFrame.jamOpacity);
// --- 特殊状态逻辑处理 ---
let isJammed = currentFrame.state === 'JAMMED';
let isReleased = currentFrame.state === 'RELEASE' || currentFrame.state === 'RESET';
// 1. 磁吸底座脱落逻辑 (位移与旋转)
let baseRot = 0;
let baseXOffset = 0;
let baseYOffset = 0;
if (currentFrame.state === 'JAMMED') {
// 卡滞阶段:推力>50,触发脱落临界状态(微小震动预警)
if (currentForce > 45 && currentForce <= config.magThreshold) {
baseRot = Math.sin(timestamp / 20) * 1; // 震动
}
} else if (isReleased) {
// 完全脱落阶段
let releaseProgress = 1;
if (currentFrame.state === 'RELEASE') {
releaseProgress = Math.min(1, rawProgress * 3); // 快速脱落
} else if (currentFrame.state === 'RESET') {
releaseProgress = 1 - progress; // 复位归位
}
baseRot = -15 * releaseProgress; // 倾斜
baseXOffset = -10 * releaseProgress; // 向左弹出
baseYOffset = 25 * releaseProgress; // 向下掉落
}
let currentBaseX = config.baseStaticX + baseXOffset;
let currentBaseY = config.baseStaticY + baseYOffset;
// 2. 柔性曲臂弯曲变形逻辑 (二次贝塞尔曲线)
// 正常状态:控制点X稍微偏左,使其呈现平滑的C型
// 卡滞受力状态:推力变大,控制点X极度偏左,呈现严重的弓形弯曲
let sliderCY = currentY + 20; // 滑块中心连接点
let baseCX = currentBaseX;
let baseCY = currentBaseY;
// 基础弯曲度
let ctrlX = baseCX - 60;
let ctrlY = (baseCY + sliderCY) / 2;
if (isJammed) {
// 力度越大,弓得越厉害
let stressBend = Math.max(0, currentForce - 15) * 2.5;
ctrlX -= stressBend;
}
// --- 渲染更新 SVG ---
// 滑块位置
els.slider.setAttribute('transform', `translate(0, ${currentY - 580})`);
// 卡滞物透明度
els.jamBlock.setAttribute('opacity', currentJamOpacity);
// 磁吸底座位置旋转 (以右上角 570, 490 为基准点进行旋转,但其实底座是从胶板分离的)
// 修改为以底座中心偏下为旋转轴系点更加自然
els.magnetBase.setAttribute('transform', `translate(${baseXOffset}, ${baseYOffset}) rotate(${baseRot}, 550, 560)`);
// 磁力线可见度
els.magFields.setAttribute('opacity', isReleased ? 0 : 0.6);
// 曲臂路径更新
let armPath = `M ${baseCX} ${baseCY} Q ${ctrlX} ${ctrlY} 455 ${sliderCY}`;
els.arm.setAttribute('d', armPath);
els.armStress.setAttribute('d', armPath);
// 曲臂受力高亮 (红色发光)
let stressOpacity = 0;
if (currentForce > 20 && !isReleased) {
stressOpacity = Math.min(1, (currentForce - 20) / 30);
}
els.armStress.setAttribute('opacity', stressOpacity);
// 摩擦火花 / 接触高亮
let isMoving = Math.abs(currentFrame.targetY - nextFrame.targetY) > 0 && currentForce > 0;
els.frictionSpark.setAttribute('opacity', isMoving ? 0.8 + Math.sin(timestamp/50)*0.2 : 0);
// 动态标注线更新,保持追踪
els.lineSlider.setAttribute('d', `M 435 ${sliderCY} L 350 ${sliderCY} L 330 650 L 320 650`);
// 控制点Y变化导致辅助线微调
els.lineArm.setAttribute('d', `M ${ctrlX+20} ${ctrlY} L 400 ${ctrlY} L 380 350 L 320 350`);
// --- UI 面板数据更新 ---
els.uiPhase.innerText = currentFrame.desc;
els.uiPhase.style.color = (isJammed || isReleased) ? "var(--neon-orange)" : "var(--cyan-glow)";
els.uiForce.innerText = currentForce.toFixed(1) + " N";
if (currentForce > config.magThreshold) {
els.uiForce.className = "value warning";
} else {
els.uiForce.className = "value";
els.uiForce.style.color = currentForce > 30 ? "var(--neon-orange)" : "var(--neon-green)";
}
if (isReleased) {
els.uiMagnetStatus.innerHTML = "<span style='color:var(--neon-pink)'>脱落卸力 [⚠️保护触发]</span>";
} else if (currentForce > 45) {
els.uiMagnetStatus.innerHTML = "<span style='color:var(--neon-orange)'>临界状态 [⚡]</span>";
} else {
els.uiMagnetStatus.innerHTML = "<span style='color:var(--neon-green)'>吸附稳定 [🔒]</span>";
}
requestAnimationFrame(animate);
}
// 页面加载完成后自动启动动画,无需人工交互
window.addEventListener('DOMContentLoaded', () => {
requestAnimationFrame(animate);
});
</script>
</body>
</html>
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
