十一长假我贬低了一张地图
十一长假,一位老友说开始用workbuddy尝试做地图,虽然是第一次,但毕竟不用自己写代码。

我们都做空间信息这一行,只是专注的业务不一样。老友做软件,极海做数据监测。他十一没有假期,趁着短暂的休息用 WorkBuddy 做了一个交互地图,想练练自己驾驭 AI 的手感。
我看了不到一分钟。数据别扭,界面挤,手指一滑,菜单就跟地图打架。我跟了一句让人不舒服的话。大意是,workbuddy就是不行。
话出口我就知道有点伤人。他在练手。我在用成品的标准砸一份练习,虽然我贬低的是workbuddy。更难堪的是,我平时老跟别人说,自己做成一件小事,比仰着头看新工具重要。轮到别人真做成一件小事,我先挑刺。
既然嘴这么快,就得自己做一张。正好,假期一直在用 Muse 抓数据,我想试试 Muse 这种个人助理,能不能把一个地图应用从空目录扛到能打开,而且正好与workbuddy类似,都算是免费的吧。结果是:壳,它能写个大概;账,它算的糊弄。改到最后,我都有点火冒三丈了!按照目前大模型的智能水平,我甚至都开始骂Muse——你这个傻子。不得不在 GitHub 上建了仓库,把 Grok bot拉进来,又让它去叫 Opus 5.5,才有了一个我愿意挂上版本号的站点:map.kowa88.net。
站点今天我还在更新,但自己也不觉得它有多大意义。今天把这段体验写下来的,不是又多了一个好看的世界地图,是这几天把「画得出来」和「敢标日期」看的更透彻了一点。

会变色的山,不是新画的山
我是不想不浪费任何一次做地图时候的尝新机会。假期前,我看到一张图。Bert Spaan 的 Relief。Google Maps Mania 在 10 月给它起了个标题,Providing Global Relief。FlowingData 也写了。地形的渲染随着镜头的拉近拉远而变化。你把地图从荷兰拖到青藏高原,颜色会跟着变,低地的几米高差不会被珠峰压成一种蓝。


很多人第一眼会以为,这是一张画得更细的山影。不是。
传统山影瓦片是一张烤好的图片。颜色在服务器上就已经死了。全球用同一套色标,珠峰占住最深的那一档,华北平原、荷兰圩田只好挤在最浅的一档里。你放大,看到的还是那张烤死的图,只是像素变大。
这个山影的实践反过来。它用的是 Mapterhorn 的全球高程。瓦片里不存颜色,存每个格子的海拔。荷兰局部还换了更高分辨率的 AHN。浏览器拿到高度以后,按你当前视野临时上色,再算阴影。所以山是活的。数据没变,色带变了。
在这个网页上你可以在「当前视野」和「绝对高程」之间切换,锁住色带,反色,开等高线,把海底也铺上。GEBCO 那套海深一接,海沟和山峰才在同一张图里。这是 2026 年秋天一张值得看的地图。有了这个技术,就不必提前生产各个级别的瓦片,还可以切换任意色带。
借着这个机会,我在自己站点的「地形」页做的是它的一个收窄版。渲染那一下,Muse一次就写出来了。转到球体上,某些角度瓦片会消失,俯仰角也会乱,后面又补了几轮。虽然后面的bug不是Muse改的,但也算完成首次交付就顺利出功能了。

我把它叫做视域分位高程瓦片
先把名字放下,免得后文绕。
视域分位高程瓦片。
它不是一种新的文件格式。文件仍是高程编码栅格瓦片,业内叫 Terrarium。新的是用法:颜色不烘在瓦片里,而按当前视野的海拔分位,在浏览器里现算。
地图瓦片其实就三家邻居。
影像瓦片,像素是颜色。卫星图、烤好的山影,都算这一家。烤完就死。
矢量瓦片,里面是点、线、面。国界、铁路、港口,走这一家。OpenFreeMap 的底图就是它。
高程瓦片,像素是高度。Mapterhorn 发的是 512 像素的 webp,全球大约 30 米一格。一个像素的红、绿、蓝拼成米数:红 × 256 + 绿 + 蓝 / 256 − 32768。减掉 32768,是为了让海平面附近落在中间,深海和高山都能写下。
视域分位,是高程瓦片的一种活法。预渲染山影是把高程提前烤成影像瓦片。烤完,荷兰永远是那种绿。
我这次做的时候,有四件不能省的事。
第一,海和陆不是同一张表。Mapterhorn 的海里是 0 米,它不负责海底。所以陆地缩放到 8 级以上用 Mapterhorn,更小的比例尺和海底用 AWS 那套老 Terrarium,海深主要来自 GEBCO。欧洲海域放到 10 级以上,改用 EMODnet,大约 115 米,取不到就退回 AWS。海深贴上去之后,还得做低通和双三次插值,不然海底是一块一块的格子。
第二,阴影不能在瓦片边上断开。山影要看相邻格子的高差。每块瓦片向邻居借 1 个像素,接缝才连得上。加载慢的时候,先用上一层或下一层顶着,不能让屏幕空一块。
第三,颜色按视野拉,但不能被一座尖峰绑架。当前屏幕里的陆地海拔,取 0 到 99.5% 分位,再留 5% 余量。海洋取 1% 到 98%。数字会平滑,免得你一拖地图,颜色就跳。另外有一道刹车:陆地色带的顶端,不许超过这个海拔在全球绝对色标上该有的颜色。一座几百米的丘陵不该假装自己是雪山。
第四,手机和老浏览器会失败。浮点纹理、着色器,不是台台都有。失败了就退回 MapLibre 自带的山影。总览页用的是同一套机器的灰度模式,平地和海透明,只把阴影压在矢量底图上。没有这层退路,演示在别人手机上就是一块黑。

原创网站Relief 比我这页完整。它还有等高线、色带动画、探索按钮。我没有把别人的交互再做一遍。我要确认的是:这种活的高程,一个助手能不能一次放进可发布的页面。能。难的从不在这里。
一小时的壳,我在里面说的脏话
我后来跟自己说,一个展示性质的 GIS 应用,一小时可以搞定。这句话容易听成吹牛。拆细了看,一小时搞定的是壳,不是数据监测。
壳里至少有这些。
矢量瓦片负责底图和注记。点、线、面不在浏览器里现画全世界,只取你视野里的那几块。这是成熟技术。这次多出来的,就是上面那种视域分位高程瓦片。一个运几何,一个运高度。别混成一种。
边界有两种,别谈成一件事。一种是瓦片接缝,借 1 个像素就能补。一种是政区边界。我们用 Natural Earth 的陆地国界做示意,但咱们国家的边界主张要画对,另外还要做南海十段线,底图还有一层很小的过滤,在第一批矢量瓦片解析之前就放进去。晚了,MapLibre 会把已经加载的瓦片全部重新解析一遍,手机上就能感到卡。页上写明了:国界是示意,不作划界依据。软件做得到的是把线放对、把不该混的注记滤掉。软件做不到的是让一条示意线变成法律。
符号化是把数变成能看的差别。首都的点按人口分级,用的是 Natural Earth 的都市区估算,不是最新普查,所以不能在弹窗里装成统计局数字。集装箱港按 2024/2025年的标准箱分级。货物港按吨。两套口径并排时必须写清,吨和箱不能加在一起。晶圆厂分最难,想找全了不太可能,先分三档精度:厂址、园区、城市。点的样子可以一样,旁边的字不能一样。

截图不是按一下系统截屏。当前图层如果还在懒加载,截出来的图会少一块,标题上的数字也会空。所以先等这一页要用的数据到齐,再画进画布,导出 PNG。手机上走系统分享,让人存到相册。一张发不出去的地图,在微信里等于没有。
过滤和多设备更不起眼,也更要命。图层要能关。底图过滤要赶在瓦片前面。页面高度用整屏,避开浏览器那一条地址栏。顶部和底部让出刘海和横条。按钮的点击区域不能跟地图抢手指。老友的演示,就是拉胯在这里。我后来补上了,也不觉得光荣。只是不用成品标准去砸别人之前,自己得先被手机砸一次。
壳做完,站点能转,能换中英文,能导出。到这一步,它仍然只是一个展览。
真正的来回,发生在坐标和日期上
仓库比网站诚实。
10 月 6 日,线上第一次被完整收进 GitHub。之后三天,数据版本号从 20261005d 走到 20261008b。好看的地形没有再改原理。改的是点能不能放上去。
晶圆厂最典型。第一轮,Grok 调 Opus,把 176 处原先落在城市中心的点挪到厂址或园区,弹窗里留下来源链接。然后 Muse 上的 GLM 5.3 逐条核验,改了 146 条:128 条把精度往下降,18 条动了坐标。听起来很负责。Grok 对着来源再核了一遍,只采纳了 2 处降级,其余 126 处维持原来有出处的数。第四轮又把剩下的城市级点位往厂区推。冲电气八王子那 8 条产线,2013 年就关了,不画。
你看,模型不是不会改坐标。它太会改了。没有来源、没有版本、没有下一轮否决,一次「逐条核验」就是一次整齐的误伤。
别的层也是同样的脾气。世界遗产官方名录里有 3 处没有坐标,不画。热门景点本来想做,访客量没有基准年份,整层拿掉。4F 机场只写已查明的,并标明不是全球全集,证据还分了强弱。集装箱港和货物港的年份不一样,中国货物港用的是交通运输部 2025 年的数,有的境外港只能拿到上一财年,页上分开写。美军基地的整理日期和源头报告的年份不是同一年,就两个都留下,临时演习地点不收。
看这些总结的句子很无聊。无聊才是专业。
演示问的是:能不能跑。专业应用问的是:这条点准到厂还是准到城,年份是 2024 还是 2025,关了的还画不画,没有坐标的要不要编一个。AI 现在很擅长把看见的东西画上去。它不擅长决定什么时候该从地图上拿掉。
生成不掉的,是这本账
所以我才觉得 map.kowa88.net 这种网站,做成了也还浅。
它证明了一件已经不稀奇的事:矢量瓦片、动态高程、导出、手机适配,都可以在一个假期里被助手拼出来。拼出来的是一台观看仪器。读者打开它,能看见首都、铁路、港口、核电站,也能看见一座会随视野变色的山。然后呢。他不能问:这个品牌上个月在哪些县净增了店,哪些店是真的关了,不是网站抽风。
极海这些年做的是后一个问题。2025 年 4 月我们写过一个里程碑,品牌监测收录的连锁品牌超过 1.5 万个,在营门店超过 150 万家。数字还会变,变的方式比数字重要。小程序和官网来的门店,是每天在看的那一部分。当天没看见,不立刻写成关店,先标暂停营业。这种情况超过 30 天,才把最后一次看见的日期写成停业日期。补充来的、门店变化慢的品牌,按季度看,不跟每天更新的那些搅在一个口径里。
这和「2013 年关闭的产线不画」「没有基准年的热度不画」是同一条纪律。差别只是,地图展览可以做完就停。监测不能停。停一天,暂停和关店就会混。混一次,后面所有「净增」「撤退」「下沉」都是故事,不是账。
AI 把观看变得很便宜。测量没有一起变便宜。模型可以在一小时里写出着色器,也可以在十分钟里给你一份「全国门店分布」的自信回答。你要是不追问年份、坐标精度、没看见的那天怎么记账,那份回答比没有地图更危险。没有地图,人知道自己不知道。一份干净的错误地图,会让决策变得很果断。
缰绳比聊天窗口重要,账本比缰绳重要
这次也把助手的差别看清了。
Muse 能把地形渲染一次写出来,这点我不抹杀。它扛不住的是整条链:仓库、预览、数据版本、来源链接、下一轮把上一轮打回去。WorkBuddy 在这份假期作业里更不像一个能交付的环境。从数据到界面,尤其是手机上的手指,都还停在「生成了一个页面」。
Grok、Claude Code、pi 这一类强一些,不是因为聊天更会说。是因为它们肯把活拴在一个仓库里。推上去有预览,错了能撤回,模型不够用时可以再叫一个更强的去核对来源。大家管这个叫做 harness,缰绳。没有缰绳的助手,偶尔能写出惊人的一段着色器,然后在坐标表上悄悄发挥。
有缰绳也不够。缰绳保证过程留得下。留得下的东西若没有日期、精度和删除规则,仍然是一个更好看的展览。Opus 把厂址找回来,GLM 把一批点降级,Grok 再按来源否决大部分降级。这三步都发生了,站点才从「能打开」变成「我敢把口径写在图例里」。
回到假期那一幕。
老友想练的事是对的。AI 这东西,不亲手驾驭一次,永远停在传闻里。我用移动端体验去蛐蛐他,贬低的是成品,不是练习。这句贬低,傲慢,不合时宜。收回。
另一半不收回。空间信息这一行,如果接下来比的是谁先做出一个能转的地球,那会越来越热闹,也越来越不值钱。软件会被一小时生成。观看会被一小时生成。不会被生成掉的,是一本还在每天翻的账:看见了记一笔,没看见先别写成关店,超过期限再落日期,口径不同的数不许加总。
山可以随你的视野变色。店不会。店开关的那一天,不会因为你把地图拖到了一个好看的角度,就自己出现。