飞机视角地貌认知系统 · English
一个从飞机舷窗视角认知地球的纪录片式 Web 应用:在三维地球上飞到巡航高度, 看清一处地方最标志性的地物,配合成段的地理讲解,把它真正"看懂、记住"。
先读这一段再看内容:本项目的文字与数据是依据公开资料整理生成的,没有经过 人工逐条审核,其中确实存在过、也仍然会存在事实错误。已知的错误类型、已经修掉的 例子和现有的自动防线,都记在
docs/known-errors.md; 请勿把这里的任何数字、航班号、机场名当作可直接引用的权威信息。详见下面 「数据可靠性」一节。
不是 GIS 仪表盘,不是飞行模拟器,也不是游戏。
两种模式(顶栏一键切换,localStorage 记住):
| 模式 | 面向的问题 | 内容 |
|---|---|---|
| 学习模式 | "这片是什么地形?怎么形成的?" | 地形地貌图鉴 —— 1402 处地貌 + 6 板块讲解 |
| 旅游出行模式 | "到了这个陌生城市,衣食住行要注意什么?" | 城市概览 —— 地理格局 / 衣食住行 / 人文习俗 / 出行提示 |
两套内容系统平行、互不影响。
当前范围(node --experimental-strip-types scripts/check-regions.ts /
check-places.ts / check-routes.ts 每次运行都会打印准确计数——这三行数字随内容持续
增长,这里的数字如果对不上,以脚本输出为准;按国家的详细分布见 CLAUDE.md
"范围"一节,那里随每次扩展同步更新,本文件不重复维护第二份、避免又和实际脱节):
- 学习模式 —— 亚洲 · 欧洲 · 非洲 · 北美洲 · 南美洲 · 大洋洲共 53 个国家,1402 处地貌,中英双语
- 旅游模式 —— 覆盖学习模式已上线国家中的 53 个,共 53 个国家概览 + 961 座城市,中英双语; 303 条航线(国内 + 国际,每条附机场/地形航点 + 学习/旅游两套双语解说)—— 其中 289 条有经核实后可展示的航班信息,见下面「数据可靠性」
规划:继续逐国扩展全球地形覆盖 + 按旅游热度扩展各国旅游模式覆盖城市。
- 1402 处地貌统一注册在
lib/terrain-registry.ts,14 类:mountain_system/plateau/basin/plain/hills/desert/lake/river/valley/gorge/island/grassland/coast/inselberg。 - 每处记录锚点(主峰 / 主湖 / 枢纽城市 + 经纬度 + 海拔)、边界框、走向轴、 中英名、数据来源。侧边栏、地图标签、相机、区域高亮全部由这一份注册表驱动。
- 选取标准与分类判据见
docs/terrain-taxonomy.md(T1 骨架 / T2 地貌省 / T3 标志地点;settlement人文层的收录方法)—— 勿凭感觉加条目。
- 城市与国家概览注册在
lib/places-registry.ts: 经纬度 / 级别(capital / major / notable)/ 机场 / 来源。 - 讲解为 6 段
TravelGuide(lib/travel-lesson.ts): 概览 / 地理与格局 / 衣食住行 / 人文与习俗 / 看什么·体验什么 / 何时去·提示。 - 内容写在
lib/travel-content.{zh,en}.ts,依据各国官方旅游机构 / 气象机构气候平均值 / 入境信息 / 通行旅行指南共识总结,去比较性与主观评价。 - 地图上只显示城市点 + 机场(
CityMarkers.tsx,按相机高度分级)。 - 自检:
node --experimental-strip-types scripts/check-places.ts。
点击任意地形 → computeTerrainCamera() 从边界框规模 + 走向轴
推导 { 目标点, 朝向, 俯角, 距离 },让相机停在能清楚看到该地形最标志地物的位置,
锚点落在画面中部,模拟舷窗视角。
- 朝向由地形走向 + 可选的
viewFrom(相机在锚点哪一侧,编辑决策)推导。 - 俯角 / 距离由地形尺度推导;大面积高原 / 大盆地 / 大平原 / 大沙漠在注册表的
WIDE_VIEW里 给viewScale,取景放宽到能看出"一整片高地 / 盆地"的地貌特征,而非锚点周边一个局部景物。 - 几何自检:
node --experimental-strip-types scripts/check-terrain-camera.ts(1402/1402)。
hover 或选中某地形时,在该地形范围上画一条很细、很淡的暖色轮廓 (定高度 polyline,非贴地,任意视角含俯视都能看清地块范围)。不是任何官方地理边界, 只是"当前就是这一块"的提示,因此刻意做得不夸张、不遮挡地表细节。
- 42 处地形使用 Natural Earth 提取的真实边界多边形(
public/data/gis/exports/*.geojson), 其余用边界框八边形。 - hover 命中走
scene.drillPick,在重叠地块里取面积最小(最具体)的那个。 - 旅游模式下地形拾取与高亮整体关闭。
HTML 标签层(CesiumOverlayLabels.tsx):
- 用
EllipsoidalOccluder剔除地球背面的标签,缩小看地球时不堆叠。 - 按 zoom 分级展开(大陆 → 国家 → 区域 → POI),字号随 zoom 缩放。
- hover / 选中时标签与地块高亮联动;中英双语跟随语言切换。
- Edge TTS(中文
zh-CN-XiaoxiaoNeural,英文en-US-AvaMultilingualNeural), word-boundary 精确同步逐句高亮。 - Edge TTS 失败自动回退浏览器 TTS,按字数估时推进高亮。
- 中英双语一键切换,语音与讲解文本同步切换。
学习模式讲解分 6 个通用板块(lib/lesson.ts LESSON_SECTION_ORDER):
| 板块 | 内容 |
|---|---|
| 概述 | 是什么、在哪、为什么重要、从空中的整体印象 |
| 地貌特征 | 形态、尺度、组成、成因 |
| 从空中怎么看 | 关键观测点、标志物、颜色与纹理 |
| 与相似地形的区分 | 对比要点(秦岭 vs 南岭、塔里木 vs 准噶尔…) |
| 地理知识 | 为什么算这类地形、常见误区(云贵高原海拔低仍是高原、柴达木海拔高仍是盆地…) |
| 历史与人文 | —— |
- 内容写在
lib/terrain-content.{zh,en}.ts(getTerrainContent(id, lang)), 参照中国国家地理 / 中科院 / 自然资源部 / Geoscience Australia / Parks Australia / UNESCO 等公开资料整理而成,不是文学化旁白,但也不是逐条核过的权威资料。 - 1402 处全部有中英双语讲解。写作口径:去比较性 / 主观评价,有争议的加限定或并列,
查不到宁可删,数字尽量对齐权威口径;新增国家优先查该国官方地质 / 国家公园 / 地名机构。
这是写作时的自我要求,不等于事后有人逐条验收过。
source字段留了痕,但只有 部分条目点名了可复核的具体来源,其余写的是"概略"或笼统的机构名;个别条目明确标注 "概略坐标 / 待实测"。这些字段是审计线索、不是质检认证——引用具体数字前请自行复核。 - 已知会出错的地方(表述被简化成事实错误、未加限定的最高级、人口/面积数字缺年份与口径)
与已修掉的实例,见
docs/known-errors.md。 lib/terrain-lesson.tsresolveLesson(id, lang)一处决定用哪份讲解。
- 303 条航线(
data/routes/*.json,含国内航线与 中国—他国国际航线),每条 = 一对真实通航的城市 + 出发到达机场 + 沿途地形航点, 数据里在核实得到时另存航司 / 航班号 / 机型。 不要把航班字段当成实时航班表:它们只是checkedOn当天的快照;无法可靠核实的航线 只保留地理路线,不展示航班号、机型或时长。 - 一次 ≤3 分钟:镜头立即摆到起点机场上空 → 立刻开始播这条航线专属的一段连贯解说
(
lib/route-narration.ts,中英,教材区域地理口径)→ 镜头同时沿航点匀速飞完。 - 一条航线两套解说,跟随当前模式:
ROUTE_NARRATION[id].{study, travel}。 - 自检:
node --experimental-strip-types scripts/check-routes.ts。 - 航班号/机型只有核实过才对外显示:
FlightRoute.source(ref/checkedOn/status)是核实留痕,lib/routes.ts的isFlightVerified()是唯一出口——没有留痕、 或留痕结论为wrong的航线,界面、搜索、解说里都不出现航班号与机型,航线照常 可飞、地理解说照常播。npm run check:routes会硬性拦截"未核实航线的解说里点名机型 或航班号"。 - 现状:303 条均有机器可读的来源状态——289 条可展示核实后的航班信息;
5 条已查明原信息有误、9 条只能确认航点关系,后 14 条不显示航班号或机型。
2026-09-07 的首轮 280 条审计结果是 91 条属实、163 条有误已改正、26 条有误且找不到可靠替代。
逐条核下来 189 条至少有一处错,占 68%;冰岛、挪威、法国、意大利、西班牙、
葡萄牙、丹麦、蒙古八国的国内线错误率是 100%。另有 15 条现实中根本没有不经停航班
的航线已整条移除(295 → 280)。
错法以"这个航班号根本不飞这条航线"和机型漂移为主。即便是核对属实的那些,也只是
checkedOn那天的快照,航司改期换机不会自动同步——出行请以航司官网或 OTA 的 实时信息为准。
这个项目的文字量很大(1402 处地形 × 6 板块 + 961 座城市 × 7 段 + 303 条航线 × 2 套解说, 中英双语),它是依据公开资料整理生成的,没有人逐条审核过。已经发现并修掉的事实错误 不在少数,还没被发现的一定也有。下面写清楚哪些是可查的、哪些不可信、以及靠什么防线兜着。
| 内容 | 可信程度 | 说明 |
|---|---|---|
| 地形的位置与范围 | 较高 | 逐条查过来源并留在 source 字段;相机几何有自检 |
| 地形的讲解文字 | 中 | 参照公开资料整理,写作时避开比较级与争议表述,但没有事后逐条验收 |
| 城市的坐标 / IATA / 机场 | 较高 | check:places 强制齐全;机场更名等变动靠人工发现后修(见 known-errors) |
| 城市的运转与生活描述 | 中 | 同地形讲解;人口/面积一类数字很多没有写年份和口径 |
| 航线的城市对与机场 | 较高 | 都是真实通航的城市对 |
| 航线的航班号 / 机型 | 中(有来源状态) | 289 条可展示核实信息;5 条 wrong + 9 条 flight-unknown 不显示航班号或机型 |
npm run check # 一次跑完下面全部
npm run check:regions # 大洲/次区域/国家 ↔ 地形计数一致性
npm run check:camera # 相机几何(1402/1402)
npm run check:places # 城市坐标 / IATA / 来源 / 双语内容齐全
npm run check:routes # 航点单调性、解说时长、机型与数据是否自相矛盾、
# 未核实航线的解说不得点名机型或航班号
npm run check:flight # 镜头运动断言(地速/高度比、加速度、转向、干飞时长)
npm run check:anchors # 解说逐句锚点表与解说句数一致、镜头滞后统计
npm run check:claims # 易过期断言扫描:人口数字缺年份、主观最高级、排名断言缺口径
npm run verify:report -- <findings.json> # 把一轮核实结果落地:开/关 issue + 记台账这些脚本只能查"自相矛盾"和"不该出现的表述",查不了"写的内容对不对"。 对不对要靠联网核实,流程见下。
新增地形 / 城市 / 航线之后,用内置的核实流程把这批内容拿去和权威来源比对:
/verify-content # 核实自上次以来所有新增/改动的条目
/verify-content cities kul-lgk kch-myy # 或指定范围
它做四件事:算出这轮改了哪些条目(git diff + 核实台账)→ 分批交给
content-verifier 子代理逐条联网核实(官方来源优先,拿不准就报 unknown,
不许补一个看起来合理的答案)→ 事实错误当场改掉 → 结论交给
npm run verify:report 自动落地:
- 当场修掉的 → 之前若为它开过 issue,评论写清怎么修的 + 来源,然后关掉
- 没修掉的(查明有误但找不到替代值)→ 自动开 issue,正文埋去重键, 重复跑不会重复开;已关闭的若问题重现会自动重开
- 每一轮 → 在对应的总 issue 下留进度评论 + 往
docs/verification-ledger.md追加一行
规则见 .claude/skills/verify-content/SKILL.md。
请开一个 issue(标签 data-error)。已知错误类型、根因、修法与现有防线
都在 docs/known-errors.md——新发现的错误先归到那里的某一类,
归不进去说明是新类型,要同时补一条防线。
- Next.js 16(App Router,
--webpack)+ React 19 + TypeScript 5 - CesiumJS 1.141 —— 三维地球、相机系统、地形高程采样
- Tailwind CSS v4 · Newsreader 衬线(编辑式排版)
- edge-tts-universal —— Edge TTS
npm install
cp .env.example .env.local
# 编辑 .env.local,至少填入 NEXT_PUBLIC_CESIUM_ION_TOKEN
npm run dev浏览器打开 http://localhost:3000
| 变量 | 必填 | 说明 |
|---|---|---|
NEXT_PUBLIC_CESIUM_ION_TOKEN |
强烈建议 | Cesium Ion Token(免费注册)。不填时地球为平坦椭球,无山脊起伏。 |
TTS_REMOTE_CACHE_URL |
部署时建议 | 预热好的语音缓存所在的公开 URL 前缀(如 R2 公开桶 https://…/tts)。本机 .tts-cache/ 不进仓库、线上读不到;设了它,未命中本机缓存时按 <url>/<key>.json 取,取不到才现场合成。同步方式:npm run warm:tts 之后把 .tts-cache/ 整个上传到该前缀(如 rclone copy .tts-cache r2:bucket/tts)。 |
npm run dev # 开发(webpack)
npm run build # 生产构建
npm run lint # ESLint
npm run typecheck # tsc --noEmit
npm run check:regions # 大洲/次区域/国家地形计数一致性自检
npm run check:camera # 相机几何自检(1402/1402)
npm run check:places # 旅游地点自检(城市坐标/IATA/来源/双语内容齐全)
npm run check:routes # 航线自检(waypoint 单调性、解说时长、核实留痕、机型一致性)
npm run check:flight # 镜头运动自检(地速/高度比、加速度、转向、干飞时长)
npm run check:anchors # 解说逐句锚点表自检 + 镜头滞后统计
npm run check:claims # 易过期断言扫描(人口/面积缺年份、未加限定的最高级)
npm run check # 依次跑完上面全部(typecheck + lint + 自检)
node scripts/extract-ne-landforms.mjs # 重新提取地形边界app/
api/tts/ — Edge TTS(PROSODY 按语言分)
page.tsx layout.tsx globals.css
components/
ExplorerApp.tsx — 主编排器(模式 / 讲解 / 航线 / 语音链路 + 组合 UI)
CesiumMap.tsx — 三维地球、相机、区域轮廓高亮、appMode / focusCity
CesiumOverlayLabels.tsx — HTML 地形标签层(zoom 自适应,学习模式)
CityMarkers.tsx — 地图城市点(旅游模式,按相机高度分级)
ContinentIntro.tsx — 首屏大陆滑动卡片(学习/旅游模式共用,数地貌数还是城市数由调用方传入)
IndexRail.tsx — 左侧目录(学习:次区域 → 国家 → 地形;旅游:国家 → 省/州 → 城市,
省/州分组按拼音/字母序,标题旁彩色圆点提示所属大区)
ReadingPanel.tsx — 右侧单一阅读面板(卡片态 ⇄ 文章态,逐句高亮)
JourneyBar.tsx — 底部航线胶片条
StructuredLesson.tsx — 板块讲解渲染(6 板块 lesson / 通用段列表 sections)
ModeToggle.tsx — 顶栏 学习 / 旅游 切换
RegionSelector.tsx — 顶栏大洲 / 次区域两级切换
lib/
terrain-registry.ts — 【单一真实源】1402 处地形的锚点/范围/走向/中英名/来源
terrain-camera.ts — computeTerrainCamera() 数据驱动相机推导
terrain-content.{zh,en}.ts— 权威 6 板块讲解内容(中/英)
terrain-lesson.ts — resolveLesson(id, lang):一处决定用哪份讲解
terrain-label-registry.ts — 标签(由注册表生成,含 nameEn)
lesson.ts — 讲解板块顺序 / 标题 / 拼接
routes.ts / route-narration.ts — 航线(当前 303 条,国内+国际;航班号仅在核实过时对外显示)
+ 每条学习/旅游两套连贯解说
app-mode.ts — AppMode 类型 + localStorage 读写
places-registry.ts — 【旅游模式单一真实源】城市 + 国家概览
travel-content.{zh,en}.ts — 旅游模式 6 段 TravelGuide 中英内容
travel-lesson.ts — resolveTravelGuide + travelGuideToSections
travel-rail.ts — 旅游模式左侧目录
regions.ts — 大洲 + 次区域(M49) 配置 + 国家归属 + 辅助函数 + DEFAULT_REGION_ID
subregion-geo.ts — 次区域地形数量 / 地理重心(供顶栏二级下拉飞行)
terrain-tier.ts — terrainTier(id) → T1/T2/T3 + categoryOrder(目录排序)
speech.ts — TTS 系统(Edge TTS + 浏览器回退,跟随 language)
i18n.ts / i18n-stories.ts — UI 国际化 / 早期讲解翻译
features/
china-core-features.ts — 早期核心地形定义(GeographicFeature)
china-northwest-features.ts — 早期核心地形定义(中国西北:天山 / 昆仑 / 阿尔泰 等)
data/
*.json — 早期地形数据(坐标现由 terrain-registry 覆盖)
routes/ — 航线定义(当前 303 条,国内+国际,含 source 核实留痕)
gis/ — Natural Earth 原始 shp/dbf(不入库)
public/data/gis/exports/ — 提取出的 42 个地形边界 geojson
scripts/
check-terrain-camera.ts — 相机几何自检
check-routes.ts — 航线自检
check-places.ts — 旅游地点自检
extract-ne-landforms.mjs — 从 Natural Earth 提取地形边界
copy-cesium.mjs — 拷贝 Cesium 静态资源(postinstall)
TerrainEntry(注册表:锚点 landmark + bbox + axis + viewFrom)
→ computeTerrainCamera() 推导 { target, heading, pitch, range }
→ flyToTerrainAndWait(payload, { heading, pitch })
→ Cesium camera.flyTo
调参常量集中在 lib/terrain-camera.ts 顶部
(FRAME_HALF_ANGLE_DEG / PITCH_* / SHOW_KM_MAX / RANGE_MAX / LANDMARK_SCREEN_FRAC),
视觉取景需在真实浏览器中校准。
学习模式:
lib/terrain-registry.ts加地形条目(regionId),坐标逐个查权威来源,source留痕lib/regions.ts加 / 开启 regionlib/terrain-content.{zh,en}.ts写双语 6 板块讲解lib/terrain-label-registry.ts补重要度scripts/check-terrain-camera.ts通过
旅游模式:
lib/places-registry.ts加城市 +COUNTRY_OVERVIEWS加国家概览lib/travel-content.{zh,en}.ts写 6 段TravelGuide中英内容scripts/check-places.ts通过(坐标 / IATA / 来源 / 双语内容齐全)
选取标准见 docs/terrain-taxonomy.md。
| 文档 | 内容 |
|---|---|
CLAUDE.md |
产品定位、架构、开发规范、禁止事项 |
docs/terrain-taxonomy.md |
地形集选取标准与分类定义 |
docs/routes.md |
航线选取理由与覆盖分析( |
docs/architecture-metrics.md |
项目健康度指标、模块耦合度( |
docs/project-status-2026-09-04.md |
2026-09-04 时间点快照:已知不足评估、当次修复记录、给下一个任务的起点建议(不是持续维护的活文档) |
docs/known-errors.md |
已犯过的错误台账:错误类型、真实例子、根因、怎么修的、现在有没有防线接住 |
docs/verification-ledger.md |
内容核实台账:哪些条目核过、什么时候核的、结论是什么 |
DESIGN.md |
UI / 视觉设计规范 |
| 数据 | 来源 |
|---|---|
| 地形边界 | Natural Earth 10m Geography Regions |
| 卫星影像 | Bing Maps(Cesium Ion) |
| 地形高程 | Cesium World Terrain |
| 地形讲解 | 参照中国国家地理 / 中科院 / 自然资源部 / Geoscience Australia / Parks Australia / UNESCO 等公开资料整理生成,未经人工逐条审核 |
| 旅游讲解 | 参照各国官方旅游机构 / 气象机构气候平均值 / 入境信息 / 通行旅行指南整理生成,未经人工逐条审核 |
| 航班号 / 机型 | 303 条均有来源状态;289 条可展示,5 条 wrong + 9 条 flight-unknown 不对外显示;其余也只是核实当日的快照,航司改期换机不会自动同步 |
版权所有 © 2026 Audrey Yang。保留所有权利。
未经版权所有人书面许可,不得复制、修改、分发、再授权或商业使用本项目。详见 LICENSE。