返回主页
景安游乐场 · 3D 星际穿梭 (Warp Speed Travel)
基于 3D 物理空间建模与 Canvas 2D 高速渲染。结合 3D 透视投影公式 (X/Z, Y/Z) 实现近大远小与深度淡入,支持鼠标偏转视差、滚轮无级调速以及长按唤醒超光速拉伸拖尾。
💻 仅代码
🌓 左右分屏
👁️ 仅看特效
运行调试
实时源码编辑器 (HTML/CSS/JS)
支持 Tab 缩进
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>3D 星际穿梭 (Warp Speed Travel)</title> <style> * { box-sizing: border-box; user-select: none; margin: 0; padding: 0; } body, html { width: 100%; height: 100%; overflow: hidden; background: #020208; font-family: 'Segoe UI', -apple-system, sans-serif; color: #ffffff; } #starfield { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: block; z-index: 1; } /* 宇宙背景微光渐变,叠加深度感 */ .nebula-bg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: radial-gradient(circle at 30% 30%, rgba(139, 92, 246, 0.08) 0%, transparent 60%), radial-gradient(circle at 80% 70%, rgba(6, 182, 212, 0.06) 0%, transparent 50%), radial-gradient(circle at 50% 50%, rgba(2, 2, 8, 1) 0%, #03001e 100%); z-index: 0; pointer-events: none; transition: transform 0.5s cubic-bezier(0.25, 0.8, 0.25, 1); } /* 超空间跃迁闪烁屏罩 */ .flash-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: #ffffff; opacity: 0; z-index: 2; pointer-events: none; transition: opacity 0.8s ease; } /* 高清科技玻璃感 HUD 悬浮板 */ .hud-panel { position: absolute; top: 30px; left: 30px; width: 320px; background: rgba(10, 11, 22, 0.55); border: 1px solid rgba(0, 210, 255, 0.25); border-radius: 16px; padding: 24px; backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); box-shadow: 0 10px 40px rgba(0, 0, 0, 0.6), inset 0 0 15px rgba(0, 210, 255, 0.05); z-index: 10; transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); transform-origin: top left; } .hud-panel.minimized { transform: scale(0) translate(-50px, -50px); opacity: 0; pointer-events: none; } .hud-header { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid rgba(255, 255, 255, 0.1); padding-bottom: 12px; margin-bottom: 16px; } .hud-title { font-size: 16px; font-weight: 600; letter-spacing: 1px; color: #00d2ff; text-shadow: 0 0 10px rgba(0, 210, 255, 0.5); display: flex; align-items: center; gap: 8px; } .status-dot { width: 8px; height: 8px; border-radius: 50%; background: #00e676; box-shadow: 0 0 8px #00e676; animation: pulse 1.5s infinite alternate; } @keyframes pulse { 0% { opacity: 0.4; } 100% { opacity: 1; } } .hud-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; font-size: 13px; } .hud-label { color: rgba(255, 255, 255, 0.5); } .hud-value { font-family: monospace; font-weight: bold; color: #00d2ff; text-shadow: 0 0 5px rgba(0, 210, 255, 0.3); } /* 参数控制滑动条 */ .control-group { margin-top: 16px; padding-top: 16px; border-top: 1px solid rgba(255, 255, 255, 0.08); } .control-title { font-size: 12px; color: rgba(255, 255, 255, 0.6); margin-bottom: 8px; display: flex; justify-content: space-between; } .slider-wrapper { position: relative; display: flex; align-items: center; } input[type=range] { -webkit-appearance: none; appearance: none; width: 100%; background: rgba(255, 255, 255, 0.1); height: 4px; border-radius: 2px; outline: none; } input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; height: 14px; width: 14px; border-radius: 50%; background: #00d2ff; cursor: pointer; box-shadow: 0 0 8px rgba(0, 210, 255, 0.8); transition: transform 0.1s; } input[type=range]::-webkit-slider-thumb:hover { transform: scale(1.3); } /* 操作提示卡 */ .tips-box { background: rgba(0, 210, 255, 0.05); border-left: 2px solid #00d2ff; border-radius: 4px; padding: 8px 12px; font-size: 11px; color: rgba(255, 255, 255, 0.7); line-height: 1.5; margin-top: 16px; } /* 右上角显示/隐藏控制面板的按钮 */ .toggle-hud-btn { position: absolute; top: 30px; right: 30px; width: 44px; height: 44px; border-radius: 50%; background: rgba(10, 11, 22, 0.6); border: 1px solid rgba(0, 210, 255, 0.3); display: flex; justify-content: center; align-items: center; cursor: pointer; z-index: 10; backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); transition: all 0.3s ease; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3); } .toggle-hud-btn:hover { border-color: #00d2ff; box-shadow: 0 0 15px rgba(0, 210, 255, 0.5); transform: scale(1.05); } .toggle-hud-btn svg { width: 20px; height: 20px; fill: #00d2ff; transition: transform 0.4s; } /* 鼠标长按“跃迁”提示框 */ .boost-prompt { position: absolute; bottom: 40px; left: 50%; transform: translateX(-50%); z-index: 5; font-size: 13px; letter-spacing: 2px; color: rgba(255, 255, 255, 0.5); background: rgba(0, 0, 0, 0.4); border: 1px solid rgba(255, 255, 255, 0.08); padding: 10px 24px; border-radius: 20px; backdrop-filter: blur(4px); pointer-events: none; transition: all 0.4s ease; display: flex; align-items: center; gap: 10px; } .boost-prompt.warp-active { opacity: 0; transform: translateX(-50%) translateY(20px) scale(0.9); } .boost-indicator { width: 6px; height: 6px; background-color: #00d2ff; border-radius: 50%; box-shadow: 0 0 8px #00d2ff; display: inline-block; animation: pulse-cyan 1s infinite alternate; } @keyframes pulse-cyan { 0% { transform: scale(0.8); opacity: 0.5; } 100% { transform: scale(1.3); opacity: 1; } } </style> </head> <body> <div class="nebula-bg" id="nebula"></div> <div class="flash-overlay" id="flash"></div> <canvas id="starfield"></canvas> <!-- 右上角 HUD 显隐开关 --> <button class="toggle-hud-btn" id="toggleHud" title="显示/隐藏控制面板"> <svg viewBox="0 0 24 24"> <path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/> </svg> </button> <!-- HUD 信息板 --> <div class="hud-panel" id="hudPanel"> <div class="hud-header"> <div class="hud-title"> <span class="status-dot"></span> <span>跃迁控制台</span> </div> <div style="font-size: 11px; color: rgba(255,255,255,0.4); font-family: monospace;">SYS: OK</div> </div> <div class="hud-row"> <span class="hud-label">跃迁速度 (Cruise Speed)</span> <span class="hud-value" id="valSpeed">1.50</span> </div> <div class="hud-row"> <span class="hud-label">航向视角 (Fov Length)</span> <span class="hud-value" id="valFov">200</span> </div> <div class="hud-row"> <span class="hud-label">星河容积 (Star Count)</span> <span class="hud-value" id="valCount">500</span> </div> <div class="hud-row"> <span class="hud-label">超视视差 (Engine Status)</span> <span class="hud-value" id="valEngine" style="color: #00e676;">CRUISE</span> </div> <!-- 参数控制区 --> <div class="control-group"> <div class="control-title"> <span>巡航基速 (Cruise Velocity)</span> <span id="sliderSpeedText">1.5</span> </div> <div class="slider-wrapper"> <input type="range" id="sliderSpeed" min="0.2" max="6.0" step="0.1" value="1.5"> </div> </div> <div class="control-group"> <div class="control-title"> <span>透视角距 (Perspective Fov)</span> <span id="sliderFovText">200</span> </div> <div class="slider-wrapper"> <input type="range" id="sliderFov" min="80" max="400" step="10" value="200"> </div> </div> <div class="control-group"> <div class="control-title"> <span>超空间容量 (Star Density)</span> <span id="sliderCountText">500</span> </div> <div class="slider-wrapper"> <input type="range" id="sliderCount" min="100" max="1000" step="20" value="500"> </div> </div> <div class="tips-box"> 👉 <b>鼠标滚动</b>:微调跃迁速度<br> 👉 <b>鼠标移动</b>:控制航向(产生物理视差)<br> 👉 <b>点击并按住鼠标</b>:激活 <b>超空间跃迁暴走</b> </div> </div> <!-- 跃迁提示 --> <div class="boost-prompt" id="boostPrompt"> <span class="boost-indicator"></span> <span>长按屏幕任何位置激活 <b>HYPERDRIVE</b> 跃迁暴走</span> </div> <script> const canvas = document.getElementById("starfield"); const ctx = canvas.getContext("2d"); const nebula = document.getElementById("nebula"); const flash = document.getElementById("flash"); const hudPanel = document.getElementById("hudPanel"); const toggleHud = document.getElementById("toggleHud"); const boostPrompt = document.getElementById("boostPrompt"); // HUD 数据元素 const valSpeed = document.getElementById("valSpeed"); const valFov = document.getElementById("valFov"); const valCount = document.getElementById("valCount"); const valEngine = document.getElementById("valEngine"); // Slider 控件 const sliderSpeed = document.getElementById("sliderSpeed"); const sliderFov = document.getElementById("sliderFov"); const sliderCount = document.getElementById("sliderCount"); const sliderSpeedText = document.getElementById("sliderSpeedText"); const sliderFovText = document.getElementById("sliderFovText"); const sliderCountText = document.getElementById("sliderCountText"); // 系统参数配置 let numStars = 500; let baseSpeed = 1.5; // 用户拉条设定的标准巡航基速 let speed = 1.5; // 当前实际运行速度(平滑缓动) let targetSpeed = 1.5; // 目标运行速度 let fov = 200; // 投影焦距 let stars = []; let mouse = { x: null, y: null, targetX: 0, targetY: 0, active: false }; let isBoosting = false; // 是否正在超空间暴走 // 窗口大小响应 function resize() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; // 重新计算已存在星星的投影原点 } window.addEventListener("resize", resize); resize(); // 恒星实体类 class Star { constructor() { this.reset(); // 深度初始化:防止星流扎堆,在[0, width]深度随机分散分布 this.z = Math.random() * canvas.width; } reset() { // 相对中心点的 3D 物理空间坐标 // 为产生纵深展开范围,生成面设定比画布大 1.5 倍 this.x = (Math.random() - 0.5) * canvas.width * 2; this.y = (Math.random() - 0.5) * canvas.height * 2; this.z = canvas.width; // 置于投影最远端 // 上一帧的投影屏幕坐标(用于高速拉伸拖尾) this.px = null; this.py = null; // 光谱随机分级:1.蓝白巨星 2.纯白矮星 3.浅黄矮星 4.暖橙巨星 const colors = [ "rgba(180, 229, 252, 1)", "rgba(255, 255, 255, 1)", "rgba(255, 245, 157, 1)", "rgba(255, 171, 145, 1)" ]; this.color = colors[Math.floor(Math.random() * colors.length)]; } update() { // Z 轴递减:星体向屏幕方向奔流过来 this.z -= speed; // 击穿视平面后重置到宇宙深处 if (this.z <= 0) { this.reset(); } } draw() { // 平移变换原点至屏幕中心,并融合鼠标偏移产生动视差 let cx = canvas.width / 2; let cy = canvas.height / 2; if (mouse.active) { // 鼠标在左侧,背景整体稍微向右滑,符合人类生理视觉的错觉 cx += mouse.targetX * 0.15; cy += mouse.targetY * 0.15; } // 经典 3D 核心透视投影公式 const sx = (this.x / this.z) * fov + cx; const sy = (this.y / this.z) * fov + cy; // 过滤出屏粒子 if (sx < 0 || sx > canvas.width || sy < 0 || sy > canvas.height) { this.reset(); return; } // 视差大小:近大远小,最大不超过 3px,防止屏幕中心的大块星星晃眼 const size = (1 - this.z / canvas.width) * 3.0; // 视差亮度:星体越近越明亮,最远端自然淡入(Opacity Fade-In),防止突兀出现 const opacity = (1 - this.z / canvas.width); ctx.save(); ctx.globalAlpha = opacity; // 当速度极大(超空间跃迁)且有上一帧记录时,绘制极光拖尾 if (this.px !== null && speed > 5.0) { ctx.strokeStyle = this.color; ctx.lineWidth = size > 0.1 ? size : 0.1; ctx.beginPath(); ctx.moveTo(this.px, this.py); ctx.lineTo(sx, sy); ctx.stroke(); } else { // 常规状态绘制璀璨的像素圆点 ctx.fillStyle = this.color; ctx.beginPath(); ctx.arc(sx, sy, size > 0.1 ? size : 0.1, 0, Math.PI * 2); ctx.fill(); } ctx.restore(); // 备份本帧绝对投影坐标 this.px = sx; this.py = sy; } } // 初始化星群 function initStars() { stars = []; for (let i = 0; i < numStars; i++) { stars.push(new Star()); } valCount.textContent = numStars; } initStars(); // 平滑渲染循环 (rAF) function animate() { // 超跃迁极速模式下,用低透明度蒙版实现全画布天然“彗星动感模糊” if (isBoosting) { ctx.fillStyle = "rgba(2, 2, 8, 0.22)"; // 更强的残影 } else { ctx.fillStyle = "rgba(2, 2, 8, 0.14)"; // 标准残影,消除重叠闪烁 } ctx.fillRect(0, 0, canvas.width, canvas.height); // 速度平滑物理过渡(Lerp) speed += (targetSpeed - speed) * 0.08; valSpeed.textContent = speed.toFixed(2); // 绘制星群 stars.forEach(star => { star.update(); star.draw(); }); // 星光闪烁及物理背景轻微错落动 if (mouse.active) { // 星空背景随视角进行对立方向平滑拉移 nebula.style.transform = `scale(1.05) translate(${mouse.targetX * -0.05}px, ${mouse.targetY * -0.05}px)`; } else { nebula.style.transform = "scale(1) translate(0, 0)"; } requestAnimationFrame(animate); } animate(); // 鼠标相对视口中心的矢量计算 window.addEventListener("mousemove", (e) => { mouse.x = e.clientX; mouse.y = e.clientY; mouse.targetX = e.clientX - canvas.width / 2; mouse.targetY = e.clientY - canvas.height / 2; mouse.active = true; }); window.addEventListener("mouseleave", () => { mouse.active = false; }); // 滚轮动态调节基速 window.addEventListener("wheel", (e) => { if (isBoosting) return; // 暴走状态下锁定滚轮 // 向上滑加速,向下滑减速 const delta = -e.deltaY * 0.002; baseSpeed = Math.max(0.1, Math.min(6.0, baseSpeed + delta)); // 更新 slider sliderSpeed.value = baseSpeed.toFixed(1); sliderSpeedText.textContent = baseSpeed.toFixed(1); targetSpeed = baseSpeed; }, { passive: true }); // 鼠标长按跃迁逻辑 function activateBoost() { isBoosting = true; targetSpeed = 16.0; // 狂暴跃迁! valEngine.textContent = "WARP BOOST"; valEngine.style.color = "#ff1744"; flash.style.opacity = "0.2"; // 跃迁瞬间闪烁感 boostPrompt.classList.add("warp-active"); setTimeout(() => { flash.style.opacity = "0"; // 极速消退闪烁 }, 120); } function deactivateBoost() { isBoosting = false; targetSpeed = baseSpeed; valEngine.textContent = "CRUISE"; valEngine.style.color = "#00e676"; boostPrompt.classList.remove("warp-active"); } window.addEventListener("mousedown", (e) => { // 排除用户点击控制板或切换按钮的情况 if (hudPanel.contains(e.target) || toggleHud.contains(e.target)) return; activateBoost(); }); window.addEventListener("mouseup", () => { if (isBoosting) { deactivateBoost(); } }); // 支持触屏控制跃迁 window.addEventListener("touchstart", (e) => { if (hudPanel.contains(e.target) || toggleHud.contains(e.target)) return; activateBoost(); }); window.addEventListener("touchend", () => { if (isBoosting) { deactivateBoost(); } }); // HUD 显隐切换 toggleHud.addEventListener("click", () => { hudPanel.classList.toggle("minimized"); }); // Sliders 参数联动绑定 sliderSpeed.addEventListener("input", (e) => { baseSpeed = parseFloat(e.target.value); sliderSpeedText.textContent = baseSpeed.toFixed(1); if (!isBoosting) { targetSpeed = baseSpeed; } }); sliderFov.addEventListener("input", (e) => { fov = parseInt(e.target.value); sliderFovText.textContent = fov; valFov.textContent = fov; }); sliderCount.addEventListener("input", (e) => { numStars = parseInt(e.target.value); sliderCountText.textContent = numStars; initStars(); }); </script> </body> </html>
实时渲染沙盒视窗 (Sandboxed Sandbox)
实时可交互