尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
我用华为云码道 CodeArts 做了个「地球心跳」:33 项测试全绿,把实时地震跑成一颗会跳的星球
我用华为云码道 CodeArts 做了个「地球心跳」33 项测试全绿把实时地震跑成一颗会跳的星球**一键开通华为云码道 CodeArts 代码智能体 **https://developer.huaweicloud.com/codeartsco.html?sourcedmzntgwatomgit1sourceaddmzntgwatomgithd作品介绍「地球心跳 / Terra Pulse」是一个纯前端网页它把 USGS 的全球实时地震数据和 NOAA 的地磁指数翻译成一颗会跳动、能听见、还能逐拍重放的星球。地震越密、磁暴越强它心跳就越快越重没什么动静的时候会慢到 40 多像睡着了。整站零第三方运行时依赖纯 ESM Canvas Web Audioclone 下来npm run serve就能跑核心逻辑全部写成纯函数33 项自动化测试全绿还配了一个联网取证脚本能证明「同一份数据快照重放多少次节拍都一模一样」。这也是我整个项目最想守住的一条底线画面可以好看但每一处好看都得能追溯到一条真实记录。一、为什么做「地球心跳」而不是又一个炫酷地球刷到过不少「实时数据可视化」的地球转得花里胡哨配个暗色背景加几圈光晕看着挺唬人。我手贱扒过其中两个的源码结果挺无语——数据全是写死的假数组画面就是拿一个requestAnimationFrame的假时钟在那儿空转跟真实世界没半毛钱关系。你把它挂一晚上它「震」的还是那几条 2019 年的旧记录。好看是好看但假。这类东西看多了我对「实时可视化」这四个字都有点PTSD了。所以我就较上劲了做一个反过来的东西屏幕上每一处跳动都能对上一条真实发生过的记录。挑中地震是因为它骗不了人——USGS 官方接口免费、免注册、浏览器还能直接跨域读地震本身就是这颗星球实打实的「抽一下」是那种你不需要任何解释就能感受到「它在动」的信号。再把地磁活动掺进来当「情绪」把这两样翻译成心跳哪怕完全不懂技术的我妈扫一眼也能看出它现在是踏实还是在紧张。这个选题还有个隐藏的好处它能让「算法」这件事硬起来。密度怎么映射成心率、能量怎么算、可不可重放每一样都能拿真值去验不是堆特效糊弄眼睛。这也是我最后死磕「可重放」的根源。二、先跑起来看上面这张是此刻的真实截图不是渲染图。点阵世界地图上每一个发光的白点都是过去几个小时里真震过的一次右边那列「最近地震」是中文清单——几级、在哪、几分钟前、多深写得明明白白底下那条蓝线是它的「心电图」右上角的 58 就是它现在一分钟跳多少下。整个界面就四个实时读数BPM心率、地磁 Kp、事件数、快照 SHA-256 指纹。球面版把一张 180×90 的陆地格用正交投影投到球面上只画朝向你的那一面随自转缓缓转震中按新近度画扩散的冲击环越近越亮越久越淡。背景是一层缓慢视差的星野地球边缘有一圈随 BPM 收缩的辉光——「心跳」这件事你得能看见。能拖拽旋转、滚轮缩放、球面平面切换、一键静音断网也不慌它会自动退回我打包进仓库的那份离线快照继续跳绝不给你看白板。三、提示词把「可重放」钉死到函数级我没跟码道说「给我做个地球」——那种一句话需求它一定给你糊一个华而不实的东西出来。我是把需求拆到函数级一轮一轮喂每轮都给很硬的判据。最关键那段提示词长这样policy / heart / sources 三层必须是纯函数不 fetch、不读系统时钟、 不用 Math.randomnowMs 一律作参数传入。 sanKp(kp) 非有限值归零bpm clamp(44 9*ratePerMin 3.2*kp, 44, 168) energy magSq/(magSq60)同一 (events,kp,nowMs) 调用两次输出必须逐字段相等。为什么要钉这么死因为「可重放」这个卖点是从「纯函数」这个约束里长出来的。只要核心层不碰任何外部状态网络、时钟、随机那给定同样的输入它必然吐同样的输出——这件事就能被测试死死钉住。把「可重放」写进约束而不是等它写完再想办法证明这是整篇最关键的一个决策。我的经验是AI 只会执行你钉死的规矩不会替你把「可信」这件事想周全。你含糊它就自由发挥你含糊的地方就是它翻车的地方。四、架构六层纯函数层不碰 I/O整个项目我切成六层依赖是严格单向的src/ landmask.js 180×90 陆地点阵world-atlas 离线栅格化运行时零依赖 policy.js 数据清洗/校验坏数据一律拒绝、域名白名单 heart.js 心跳模型eventskpnow → bpm/energy/beats纯函数 sources.js 数据适配USGS/NOAA 解析 SHA-256 快照指纹 render.js 表现层3D 点阵地球 / 平面地图 / 冲击波 / 中文洲名 ecg.js 底部心电图波形 audio.js Web Audiolub-dub 双心音合成 app.js 装配层状态机 idle→fetching→beating→degraded依赖方向app → {render, ecg, audio, sources} → heart → policy。这么切有三个好处。第一渲染和音频只读数据、绝不改数据所以画面永远只是数据的一个「投影」不会出现「画面上震了但数据里没有」这种事。第二数据层不碰界面任何一层单独拎出来都能测。第三出了问题能一眼定位到层——是清洗放过了脏数据还是心跳算错了还是渲染画错了边界清楚。有一条纪律我钉得最死纯函数层policy / heart / sources 的解析部分不碰任何 I/O。这是「可重放」能成立的唯一前提。五、核心算法密度怎么变成心跳整颗星球的心率就这几行算出来的。取近一小时的地震事件数算密度再掺一点地磁 Kp压进 44 到 168 这个人体能接受的区间exportfunctionvitalSigns(events,kp,nowMs){letcount0,magSq0;constwindowStartnowMs-VITAL_WINDOW_MS;// 只看最近 1 小时for(constevofevents){if(evnull||!Number.isFinite(ev.timeMs))continue;if(ev.timeMswindowStart||ev.timeMsnowMs)continue;count1;if(Number.isFinite(ev.mag))magSqev.mag*ev.mag;}constratePerMincount/60;constbpmclamp(449*ratePerMin3.2*kp,BPM_MIN,BPM_MAX);constenergymagSq/(magSq60);// 震级平方和饱和归一return{ratePerMin,bpm,energy,magSq,count};}几个数字是这么定的基线 44 是「地球很安静时」的静息心率系数 9 让全球一小时几十次小震能把心率抬到六七十的正常区间3.2 是地磁每一点 Kp 的抬升磁暴时地球「紧张」心率自然快。上限 168 是怕极端震群把数字顶到失真。energy这里我特意盯着它别用「事件数」得用「震级平方和」——一次 7 级大地震本来就该比十次 3 级小震让这颗星球跳得更使劲。这种把物理常识塞进公式的细节是验收时我逼它改的第一版它偷懒用了 count。六、渲染与声音让它「活」起来球面投影是正交的把经纬度转成单位球面点叠上自转角 rot 和俯仰角 tilt只画正面functionprojectGlobe(lonRad,latSin,latCos,radius,cx,cy,rot,tilt){constlolonRadrot;constxlatCos*Math.sin(lo);constylatSin*Math.cos(tilt)-latCos*Math.cos(lo)*Math.sin(tilt);constzlatSin*Math.sin(tilt)latCos*Math.cos(lo)*Math.cos(tilt);return{sx:cxx*radius,sy:cy-y*radius,z};// z0 是背面不画}底部那条心电图是两簇高斯脉冲叠出来的 lub-dubBPM 越高扫得越快当前拍处一个冷蓝亮点functiongauss(x,cx,w){constd(x-cx)/w;returnMath.exp(-d*d);}// 主峰 稍晚的次峰 lub-dub亮点跟着当前拍走声音用 Web Audio 合成不加载任何音频文件lub 是低频冲击dub 稍高稍弱能量决定音高和轻重地磁 Kp 驱动一条极慢的次声「呼吸」基线constisLubphaselub;constfreq(isLub?LUB_FREQ_BASE:DUB_FREQ_BASE)energy*(isLub?LUB_FREQ_RANGE:DUB_FREQ_RANGE);constamp(0.160.5*energy)*(isLub?1:0.55)*Math.max(0.05,weight);因为浏览器不让自动播声音所以音频要等用户第一次点击/按键后才解锁——这个坑我第一次没注意页面加载就new AudioContext()结果被挂起后来才改成手势后 resume。七、安全三条红线分开写红线一只连官方域名。只放行 https 且主机精确匹配仿冒域名、后缀混淆、带账号密码的 URL 全挡外头——这段是我主动要求加的AI 可不会替你操心 SSRFexportfunctionassertAllowedUrl(url){if(typeofurl!string||url.length0)returnfalse;letparsed;try{parsednewURL(url);}catch{returnfalse;}if(parsed.protocol!https:)returnfalse;if(parsed.username!||parsed.password!)returnfalse;returnALLOWED_HOSTS[parsed.hostname.toLowerCase()]true;}红线二坏数据一律拒绝绝不产出 NaN。清洗层对每条地震做坐标/时间校验任何异常直接返回 null宁可丢一条也不污染下游if(!Number.isFinite(lon)||!Number.isFinite(lat))returnnull;if(lon-180||lon180||lat-90||lat90)returnnull;if(!Number.isFinite(timeMs)||timeMs0)returnnull;我还专门写了个 fuzz 测试喂 200 个随机脏对象进去断言清洗层零异常、输出零 NaN。红线三不碰用户隐私。全程只读公开的 USGS/NOAA 数据不采集访客 IP 和位置断网退回内置快照、不外发任何请求。这条听着虚但「一个会读你麦克风的网页」本来就该把「音频只在本地分析、绝不上传」写死。八、测试33 项全绿重放用 SHA-256 指纹锚定用 AI 写代码我有个心病——它当场跑对是真对了还是碰巧所以我把「可重放」做成可断言的同一份真实 USGS 快照跑两遍逐拍比对每次取数算一个 SHA-256 指纹。assert.ok(first.beats.length0,真实快照应能产生节拍);assert.equal(first.beats.length,second.beats.length,两次心跳节拍数必须一致);for(leti0;ifirst.beats.length;i){assert.deepEqual(first.beats[i],second.beats[i],第${i}拍必须逐字段相等);}取证脚本真联网跑一次[evidence] 白名单校验通过 ✓ [evidence] 联网拉取成功USGS sha2567514699d8d8a… { sha256: 7514699d…, kp: 3.67, vitals: { bpm: 56.19, energy: 0.0969 }, count: 227 } [evidence] beats 逐拍一致 → 重放一致 ✓33 项测试覆盖黄金重放逐拍相等、BPM 对事件密度单调不减且恒在 [44,168]、坏数据 fuzz 200 例零异常零 NaN、域名白名单拒绝 http/仿冒/后缀混淆、快照指纹同输入恒定异输入不同。我每一轮都不是「它说绿就绿」而是 clone 到本地独立跑一遍node --test。这活儿 AI 替不了你——它报绿了你也得亲眼再看一遍。九、真实的坑它写对了九成剩下一成得我来过程一点都不顺举三个真实的坑一加拖拽那轮把 3D 球面点阵改没了。本来好好的加完「鼠标拖动旋转」后大陆全消失、只剩一片星空。我让它拿还能正常工作的平面版当参照回修——这个坑我到现在还没完全填平见第十一节。坑二它中途开始「只讲不做」。做到加特效那轮它突然不写文件了在对话框里噼里啪啦写了一大篇「我打算怎么改 render.js」仓库一个字没动。给我整乐了直接一句「别描述了建文件提交」才把它拽回来。长对话到后面这个毛病挺常见。坑三地名翻译很糙。为了让普通人看得懂我让它把 USGS 英文地点转中文。它的逻辑其实很朴素——一张国家/海域映射表能匹配就换、匹配不上留原文exportfunctiontranslatePlace(place){letoutplace;for(constkofSORTED_KEYS){if(out.indexOf(k)!-1)outout.split(k).join(COUNTRY_CN[k]);}returnout.replace(/\s{2,}/g, ).trim();}所以国家名基本对了菲律宾、夏威夷、西班牙可一到复合词就露馅offshore Costa Rica被翻成「近shore 哥斯达黎加」——国家对了前缀漏了。这种脏活得我自己再兜一层不能全信它。十、提效数据到底省了多少事环节我纯手写估摸码道实际六层代码 33 项测试两三天约 2 小时多轮累计3D 点阵地球 底图生成一天起步topojson 得自己啃一轮连离线栅格化一起Web Audio 心跳合成半天一轮README 取证脚本两小时一轮全程我真正逐字敲的代码不到一成剩下都是它写、我 clone 到本地跑测试复核。码道每轮底下还会自己贴一行运行数据比如核心层那轮「耗时 4m33s输入 90.1K token输出 12.2K token任务 9 已完成」底图那轮「耗时 9m41s输入 318.1K token」——不用我盯着问进度它自己报账。所以别信什么「AI 全自动躺赢」。快是真快但功夫全花在盯着它别跑偏上了那三个坑每一个都得我一眼看出来再拽回来。十一、五维自检对照评审维度架构设计六层单向依赖、纯函数层不碰 I/O任何一层可单独验。代码质量33 项测试全绿 联网重放逐拍一致 SHA-256 指纹可溯源。安全合规域名白名单防 SSRF、坏数据 fuzz 零 NaN、不采集用户 IP/位置、断网降级。UI/UX深色高级感 冷蓝点缀、球面/平面/中国特写/悬停联动、断网不白屏。博文内容真实截图 真实代码 实测数据 诚实写了没修完的坑。十二、本地怎么跑以及我希望你亲自点的三下git clone https://atomgit.com/azhiqiu/earth-pulse.git cd earth-pulse node --test # 33 项全绿 node tools/evidence.cjs # 联网取证 重放一致性 npm run serve # 打开 http://localhost:8080打开后我建议你亲手做三件事比看我说一百句都直观对着麦克风吹口气或哼个调看 BPM 和冲击环跟着变点一下右侧「最近地震」任意一行看地图上对应震中高亮把网断了刷新一次看它退回离线快照、还在跳、没白屏。十三、写在最后人定架构AI 分块实现折腾下来最大的体会AI 智能体能跑多快全看你给它的约束有多硬。我全程没让它自由发挥而是把「纯函数、可重放、白名单、逐轮验收」这套框钉死它就在框里又快又稳地长肉。它负责把想法变成能跑的代码我负责判断它跑没跑对——这活儿谁也替不了谁。还没做好的地方我也不藏3D 球面那个 bug 我发完这篇就回去修地名翻译对冷门复合词还漏下一步想加条时间轴能拖着回看过去一周这颗星球的心跳曲线把「可重放」这个能力真正用到界面上。数据源与致谢地震数据 USGS Earthquake Hazards Program地磁 NOAA SWPC Planetary K-index底图 world-atlas land-110m开发工具 华为云码道 CodeArts 代码智能体AtomGit。MIT 开源仓库就是第十二节 clone 命令里那个地址。你平时用 AI 写东西是更爽于「它一把梭帮我搞定」还是更在意「每一步我都能验、能重来」我属于后者所以这次死磕「可重放」。评论区聊聊你的看法。
RELATED

相关推荐

Markdown从入门到进阶:语法、工具链与转换工作流全指南

Markdown从入门到进阶:语法、工具链与转换工作流全指南

这次话题有点“老生常谈”,但正因为它老,我反而想把Markdown从头到尾彻底捋一遍。起因很简单:前阵子帮同事整理一套交付文档,发现连“换行”这种最基础的细节都能争论半天——有人按一次回车以为就是换行,有人把表格从…

📅 2026/10/5 14:04:10
插件加载失败排查指南:plugin.json配置与TypeScript SDK实战

插件加载失败排查指南:plugin.json配置与TypeScript SDK实战

1. 从"plugins"这个标题说起:插件系统到底在解决什么问题"plugins"这个词单独拎出来,信息量其实非常有限。但结合热搜词里反复出现的cursor、plugin.json、TypeScript SDK、CLI、harness failed to load plugins这些关键词&#xff…

📅 2026/10/5 14:04:10
CentOS 7.6上Zabbix 6.0 LTS从零部署实战指南

CentOS 7.6上Zabbix 6.0 LTS从零部署实战指南

直接把整套环境从零开始搭出来的完整过程写出来,包括我踩过的坑和最后沉淀下来的操作清单。如果手里拿到的是一台全新或者已经运行业务的 CentOS 7.6 服务器,下面的内容可以让你少走至少两三个小时的弯路。 先交代一下我这边的环境背景:操作…

📅 2026/10/5 14:04:10
MORE NEWS

更多资讯

📰

从Demo到生产:AI应用平台的Agent编排、MCP与RAG实战拆解

过去两年我一直在折腾 AI 应用开发。最早的项目很简单,一个聊天窗口接上大模型 API,再丢几篇文档进向量库,一天就能看到效果。可等你想把它从“能跑的 Demo”变成“团队每天都在用的生产系统”,问题立刻就变味了:Agent…

📰

零售数仓实战:促销敏感度与评论敏感度建模全解析

做了不少零售行业的数仓项目,说实话,像“促销敏感度”和“评论敏感度”这类需求,几乎每个做电商或品牌方数据团队都会接到。老板们通常不会直接说“我要建个模型”,而是扔过来几个很现实的问题:为什么这波满减发出去&a…

📰

树莓派离线唤醒方案:snowboy安装与实战踩坑指南

前阵子帮朋友折腾树莓派语音助手,需求很朴素:不能依赖外网,最好本地就能实现“喊一嗓子唤醒设备”。市面上唤醒词方案不少,但很多要么需要注册账号、在线拉模型,要么在树莓派这种ARM小机器上跑起来很吃力。绕了一圈&am…

📰

RAG文本分块与层级索引:从Splitter选型到父子块实战

先说一个结论:RAG 系统里的“分块”,从来不是为了把文本切碎,而是为了让“找回”这一步更接近“命中”。我见过太多团队在 Embedding 模型、向量库选型上反复折腾,最后发现检索效果差,问题根源居然出在分块上——不是切…

📰

AI Agent工程化七要素:Goal到Loop的可落地实践

1. 这不是概念炒作,是工程师每天要填的七个坑“AI Agent”这个词最近半年在技术社区里炸开了锅,从早会PPT到招聘JD,从投资人尽调清单到实习生答辩稿,几乎无处不在。但你有没有发现一个奇怪的现象:聊得越热闹&#xff0…

📰

轻型AI中台落地实践:消除重复录入与财务对账难题

前阵子帮一家成长型公司落地了一套“轻型AI中台”,目标是解决两个让他们头疼很久的问题:业务数据重复录入、财务月度对账困难。项目周期不到两个月,用的全是开源和轻量工具,没有搞那种大而全的企业级中台。这篇文章就把整个项目的…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬