🌩️ 构建闹鬼天气应用:一次进入 3D Web 开发的惊悚之旅
Source: Dev.to
(请提供您希望翻译的正文内容,我将为您翻译成简体中文,同时保留原始的格式、Markdown 语法和技术术语。)
Introduction
当雾气弥漫、闪电划破天际时,你会知道自己已经不在堪萨斯了。我想打造一种将氛围视觉与实用功能相结合的东西——一个带有恐怖氛围的天气应用。于是诞生了 Eerie Weather App,这是一款 3D 天气可视化应用,漂浮的闹鬼小屋会根据全球各城市的实时天气做出反应。雨天会使天空变暗并出现雨滴,雷暴会释放锯齿状的闪电,每种天气类型都有其独特的粒子系统和环境音效。
设计
配色方案
- 背景色:
#1a1a2e(深蓝紫)—— 如暴风雨前的天空。 - 强调色:
#460809→#f4320b(悬停时)—— 血红色的高亮。 - 文字发光: 以飘渺的红色并配以脉动的文字阴影。
h3 {
color: #ff6b6b;
text-shadow: 0 0 10px rgba(255, 107, 107, 0.5);
}
排版
“October Crow” 字体营造出锯齿状、手绘的感觉。
@font-face {
font-family: "October Crow";
src: url("/fonts/October Crow.ttf") format("truetype");
}
body {
font-family: "October Crow", Arial, sans-serif;
}
自定义按钮
按钮使用内联 SVG 背景进行样式化,看起来像风化的石板。
/* Example background image */
background-image: url('data:image/svg+xml,');
Three.js 设置
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a2e);
scene.fog = new THREE.Fog(0x1a1a2e, 10, 50);
雾效增加了深度感,并营造出一种“有什么东西潜伏”的氛围。
鬼屋模型
loader.load("models/forest_house.glb", (gltf) => {
house = gltf.scene;
house.userData.centerY = -center.y - 2.5;
scene.add(house);
});
// Animation loop
house.position.y = house.userData.centerY + Math.sin(time * 0.5) * 0.2;
房子轻轻上下摇摆,随天气变化而响应。
灯光
const ambientLight = new THREE.AmbientLight(0x9999cc, 0.4); // Moonlit base
const directionalLight = new THREE.DirectionalLight(0xaaaadd, 0.3); // Soft moonlight
const rimLight = new THREE.DirectionalLight(0x6666aa, 0.2); // Subtle backlight
闪电效果
function createLightningBolt(startX, startY, startZ, endX, endY, endZ) {
const points = [];
const segments = 8 + Math.floor(Math.random() * 6);
for (let i = 0; i < segments; i++) {
// generate jittered points between start and end
const t = i / (segments - 1);
const x = THREE.MathUtils.lerp(startX, endX, t) + (Math.random() - 0.5) * 0.5;
const y = THREE.MathUtils.lerp(startY, endY, t) + (Math.random() - 0.5) * 0.5;
const z = THREE.MathUtils.lerp(startZ, endZ, t) + (Math.random() - 0.5) * 0.5;
points.push(new THREE.Vector3(x, y, z));
}
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0xffffff, linewidth: 2 });
const line = new THREE.Line(geometry, material);
scene.add(line);
// Fade out after a short duration
setTimeout(() => scene.remove(line), 200);
}
天气数据集成
const url = `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}¤t=temperature_2m,weather_code...`;
const data = await fetch(url).then(r => r.json());
将 Open‑Meteo 天气代码映射到恐怖效果:
let condition;
if ([95, 96, 99].includes(weatherCode)) condition = "Thunderstorm";
else if ([61, 63, 65].includes(weatherCode)) condition = "Rain";
else if ([71, 73, 75].includes(weatherCode)) condition = "Snow";
用户界面
- 搜索栏 – 查找任意城市,观看天气实时变化。
- 底部栏 – 快速访问按钮:
- 🏠 首页 – 重置相机。
- ℹ️ 关于 – 打开一个包含应用信息和致谢的模态框。
document.getElementById("home-btn").addEventListener("click", () => {
camera.position.copy(initialCameraPosition);
controls.target.copy(initialCameraTarget);
controls.update();
});
面板可以最小化:
function togglePanel(panelId) {
const panel = document.getElementById(panelId);
panel.classList.toggle("minimized");
}
故障排除
| 问题 | 解决方案 |
|---|---|
| 闪电导致“Computed radius is NaN”错误 | 在创建几何体之前验证坐标:`if (isNaN(startX) |
快速的天气变化触发 play()/pause() 冲突 | 跟踪当前声音,仅暂停其他声音:Object.values(weatherSounds).forEach(s => { if (s !== sound) { s.pause(); s.currentTime = 0; } }); |
| 城市搜索覆盖手动天气选择 | 使用在显示新 API 数据之前重置的 manualOverride 标志:manualOverride = false; displayWeatherInfo(data); |
结论
Eerie Weather App 已上线。搜索你的城市,调高雷暴强度,让闪电照亮你的屏幕。无论你是想寻找 Three.js 灵感,还是仅仅想要最戏剧性的天气查询方式,这款应用都能满足你的需求。