本项目目前已成功部署上线,可点击链接查看 Demo 网站,也可以前往 GitHub 仓库查看源代码。
一、项目简介 #
Global Ethnography 是一个以 3D 地球与 2D 地图为入口的世界民族志档案。目前,它可以将民族志作品、版本、作者、田野地点、研究时间、研究主题与阅读札记等信息聚合在同一套可探索界面里,致力于可视化人类学与民族学学生的阅读经验,在此基础上形成兼具整体性和特殊性的知识库。
最初本项目主要是参考 Radio Garden 的 3D 地球形态构建 UI,但具体的项目功能则是在与其他项目的比较分析上得到明确(这一点会在「项目缘起」中具体展开)——用户可以在显示详细地理信息的地图上标记阅读过的民族志。而随着使用和迭代,项目逐渐形成了一条更完整的功能逻辑闭环。
在 3D 地球或 2D 平面地图上探索地点
→ 搜索、悬停或点击一个地理区域
→ 新建 / 查看民族志档案
→ 记录作品版本、作者、国籍、田野时间、标签与 Markdown 札记
→ 从时间图谱、研究网络与主题图层重新观察档案
→ 将私人数据导出、导入或恢复
在开发本项目的过程中,我参考了多类相似项目,尝试进行竞品分析,在与 Codex 的协作中独立发起并主导问题定义、需求拆解、架构组织、交互设计、数据模型、测试迭代、验收与部署上线。
由于这是我与 AI 协作开发的第一个项目,因而也可说是相对完整地体验了一次从 0 到 1 的 Vibe Coding 流程,开发时间在 2026.06.29 — 2026.07.30,用时一个月左右。需要指出的是,本项目主要从个人学术学习需求兼具开发练习出发,因而并不具备市场化产品所需的各种特性。但我更在意的是在开发本项目的过程中通过与 Codex 进行协作,既能满足个人提高日常工作学习效率的需求,也能训练我把领域兴趣转译成需求、数据结构、交互和可验收产品的能力。
项目 Demo 的实现栈如下:
-
前端应用层选取了 React、TypeScript 和 MapLibre GL JS:
- React 负责 UI 渲染、交互状态管理和组件组织
- TypeScript 负责类型约束、领域模型定义和编译期检查
- MapLibre GL JS 负责 3D 地球、2D 地图、地图图层及地图交互
-
本地数据持久化层选取了 Dexie 和 IndexedDB:
- IndexedDB 是浏览器提供的底层本地数据库,用于持久保存用户的私人档案
- Dexie 是 IndexedDB 的封装库,用于简化数据库定义、查询、事务和版本升级等操作
-
构建与部署层使用 Vite 和 Cloudflare Pages:
- Vite 负责开发环境以及将项目构建为
dist静态资源 - Cloudflare Pages 是当前 Demo 的主要托管平台,负责托管和分发 Vite 构建生成的静态站点
- 项目没有业务服务端;私人档案默认保存在用户浏览器的 IndexedDB 中,不会上传至 Cloudflare Pages
- Vite 负责开发环境以及将项目构建为
当前版本已经实现的功能和进度如下:
- 支持 3D 地球与 2D 平面地图切换,并让两种视图共享同一套地点、档案与研究轨迹数据
- 支持按国家、一级行政区、城市乃至乡村建立档案,并通过树形地点索引重新进入
- 区分原始版本与中文译本,记录作者国籍、田野时间、出版信息、标签、封面与 Markdown 阅读札记
- 提供地点书架、中文搜索、时间图谱、研究者 / 国籍网络与动态主题图层
- 将私人档案保存在设备本地,同时提供只读公开演示档案、JSON 导出、合并导入、覆盖恢复与清空保护
- 建立 45 项单元测试与 5 条桌面 / 移动端浏览器流程,并通过 GitHub Actions 持续检查
- 完成依赖清理、安全响应头、公开演示数据与 Cloudflare Pages 部署
二、项目缘起 #
从狭义上来说,人类学是一门研究文化的学科,其最独特的特征莫过于被称为「民族志」(Ethnography)的研究成果。但需要指出的是,「民族志」的前缀「民族」在中文语境中往往带有特定的含义,指的是一个自身有着明确身份认同的历史文化共同体。但 Ethnography 本身并非只是记录这样的群体,它既可以研究过去生活在南美洲厄瓜多尔原始部落的阿丘阿尔人,可以研究中国境内的 55 个少数民族,也可以研究当代城市中工厂车间里的工人和热衷于整容手术的中产阶级妇女,又或者是街头帮派、宗教信徒等。
换而言之,所谓民族志,其研究对象可以被简单理解为一个内部存在关联性的人群,即便没有形成稳定的自我认同,但只要被某个关键事物松散地连接起来亦可。而无论民族志研究的是怎样的对象,都脱离不开在特定的地点进行田野调查,因而从传统人类学到现代人类学,不同阶段的人类学产出的民族志都与世界上的地理位置具有密不可分的关联性——尤其是积累丰厚的传统人类学,可以说伴随着地理大发现和殖民扩张而出现与发展。
我个人在学习人类学时,读过的民族志便分散在不同国家、历史阶段与理论问题中。民族志书名可以记录在清单里,读书笔记也可以写在 Markdown 中,但这些记录很难回答几类更接近人类学的问题:
- 这些民族志分别在什么地方开展田野?我真的对这些地点产生印象了吗?比如,我读过《暮光之矛》后知道研究地点在南美洲的厄瓜多尔,但我仍然对这一地点没有具体、直观的空间感
- 田野发生的时间与作品出版、译介的时间有何差异?
- 同一位研究者、同一国籍的研究者都曾前往哪些地区?
- 看似相隔遥远的民族志研究材料,是否在讨论相近的社会关系与世界观?
我尝试比较和分析了 Radio Garden 和 World Ethnography 两个地图产品。前者证明 3D 地球本身可以成为一种低门槛的探索入口,后者则让我看到「将民族志标记在地图上」的直观价值。然而后者这一项目却存在两个很明显的限制,也正是这两个限制让我认为该项目并不具备可持续性。
- 地图严重缺失详细的地理信息,无法在 3D 地球上看到具体的地名,只有一个又一个标记点。那么即便录入的民族志数据足够多,对于使用者而言也只是一个又一个孤立的点,无法形成在空间上彼此关联的地理网络
- 如果地图只是负责展示民族志研究地点,那么短暂的视觉新鲜感过后,项目内容可能便沦为机械的书目材料罗列——用人类学家埃德蒙·利奇的话来说,分类以后,还剩下什么?
基于上述问题,本项目希望可以回应两个问题:
- 如何让使用者可以通过使用本项目,对各民族志研究的地点产生具体的空间感?
- 在 1 的基础上,如何把分散的民族志阅读,从一份书单变成可以在空间、时间、人物和研究关系之间来回切换的个人知识档案?
虽然本项目源于我个人的学科学习需求,没有经过市场调研,暂且也想不出其商业价值,但在我看来,对以上两个问题的解决会让「世界民族志档案」这样的项目具备从私人性转向公共性的可能,随着迭代的进行或许可以发展为公共的知识库。
三、项目定位 #
结合项目的发起原因,我将本项目的定位落于——先服务一个真实用户,也就是我自身,之后再验证能否扩展。
1. 目标使用对象与场景 #
首版 Demo 的核心用户是我自己,也可以扩展到有相似需求的人类学学生或研究者。典型场景是,当阅读者读完或正在阅读一部民族志时,希望可以将民族志放回真实的田野地点与历史时间中。另外,如果以后再从项目网站中的某一个地点、某一位作者、某一个年代或一个主题数据进入,还可以重新发现自己曾经阅读过的材料。
需要指出的是,这一定位目前只来自自身持续使用与多次迭代的验收,还没有经过正式用户访谈或规模化可用性测试。因此,推测潜在的目标使用对象并不绝对包括人类学学生或研究者。
2. 可能的 PRD #
我没有写过 PRD 文档。事实上,在本次项目的开发过程中,我也主要是让 Codex 在规划方案后进行执行,而后我再根据脑海中的需要不断要求 Codex 进行修改调试。这里根据项目反向尝试拟一份简单的文稿。
| 项目 | 定义 |
|---|---|
| 用户问题 | 如何建立民族志地理空间分布网络; 书目、地点、田野时间与阅读札记彼此分散,难以形成可回看的知识关系 |
| 产品目标 | 让用户完成「发现地点—建立档案—重新检索—比较观察—安全保存」的闭环 |
| 核心对象 | 民族志作品、出版版本、作者、田野经历、地点、标签与阅读札记 |
| 首版载体 | 浏览器中的单用户地图应用 |
| 首版成功标准 | 能建立、编辑、搜索与重开档案; 地图信息不被错误改写; 刷新后数据仍在; 私人数据可备份恢复; 首次访问不为空白 |
| 明确不做 | 账号、多人协作、公共投稿、云端同步、付费体系、AI 自动生成学术关系 |
由于期望的第一版 Demo 是能快速实现地理信息关联的功能,因此没有搭建完整的后端数据库。如果第一版期望的功能都可以实现,并且能得到一定数量的使用对象认可,可以在之后进行扩展,而非提前为了想象中的市场,过早承担认证、权限、内容审核、版权、重复条目和云成本。
当前:单用户本地优先 Demo
↓ 有跨设备需求证据后
多用户私有档案
↓ 有贡献与审核机制后
公共共建知识库
3. 六条项目原则 #
下面是对开发项目过程提炼出的几项约束大模型的原则。
- 真实信息优先于视觉效果。 地理边界、行政层级与研究路线不能为了「好看」或更丰富的功能而被随意编造,扭曲真实信息。
- 一份数据,多种观察方式。 地球、平面、时间、网络与主题都应是同一批档案的不同投影(3D 与 2D)。
- 先完成闭环,再扩展功能。 每一轮都先保证录入、查看、检索和恢复可用,再增加分析性入口。
- 私人数据边界必须可理解。 本地保存不等于永久安全,也不等于云端同步;项目需要主动解释并提供备份能力。
- 结构化实体与自由表达并存。 作者、国籍、田野经历需要结构化;个人阅读札记仍保留 Markdown 的开放性。
- AI 加速执行,但不替代产品判断。 需求优先级、事实口径、体验取舍与最终验收仍由开发者负责。
四、核心体验 #
1. 「在哪里」——从地图进入知识 #
用户可以在项目的 3D 地球与 2D 平面地图之间进行切换。两种视图没有复制两套数据和交互逻辑,而是复用同一个 MapLibre 实例、同一组数据源与图层,仅仅改变了投影和视图状态。
3D 与 2D 地图都可以随着缩放展示不同层级的信息,并支持:
- 在大洲、国家、一级行政区、城市、乡镇等具体地点建立档案
- 在搜索栏中搜索项目中的地点、已录入作品或作者
- 点击地点后可以选择「新建档案」,或者是打开该地已有的作品列表
- 悬停已录入过民族志档案的区域时,项目界面侧边会显示「民族志书架」
- 在项目界面右侧的地点档案中,可以按照「大洲—国家—一级行政区—地点—民族志」逐层进入,看到一本民族志归属的一级又一级地理信息
2. 「记录什么」——从点位升级为档案 #
在 Demo 的最早形态中,数据对象只是一个可以增加和删除的城市点点。迭代了一次后,我把它重构为一条民族志档案,并逐步加入以下要素:
- 民族志原文书名、中文书名与不同出版版本
- 民族志作者与作者国籍
- 田野地点、开始时间与结束时间
- 民族志原版与译本的出版社、出版时间、译者与 ISBN
- 民族志书封、作者图片、简介、阅读者、完成阅读时间
- 多标签与 Markdown 阅读札记。
这里有一个细节,民族志的作者的信息录入不可以被压缩为一个逗号字符串,因为每位作者还需要分别关联国籍与田野经历。标签和译者则使用可规范化的简单列表。
3. 「何时、由谁、围绕什么」——从收集走向观察 #
当档案结构稳定后,项目则增加了三种分析入口:
- 时间图谱:在田野时间、作品首次出版与中文译本出版之间切换,用时间轴或自动播放观察档案如何出现
- 研究网络:按研究者或研究者国籍查看田野地点,并用带时间标签的研究轨迹表达关系
- 主题图层:从现有档案动态汇总标签,支持多选筛选,不要求每次新增标签都修改代码
这些功能刚好可以对应几个问题:
在哪里研究? → 地球 / 平面地图 / 地点档案
何时发生? → 时间图谱
谁在研究? → 研究网络
研究什么? → 主题图层
另外,研究网络经历过一次语义修正。如果将不同作者的田野点按时间串成一条路径,界面会暗示「同一个人从 A 移动到 B」。当前方案让国籍国家作为共同起点,分别连向不同田野点,并在 3D 球面与 2D 地图采用各自更易读的路线规则。
4. 「如何不丢」——把本地数据风险变成产品能力 #
目前,项目最为适合的使用场景是私人档案,因而数据主要保存在本地浏览器的 IndexedDB 中,无需要账号和服务器,有利于降低维护成本。当然,这也意味着一旦清理浏览器站点数据,此前在本地录入的私人档案数据也会被清除,无法恢复。
为此,Demo 上线前补充了下列内容:
- 一份随网站发布、只读且与私人数据隔离的公开演示档案
- 带
schemaVersion、应用版本和导出时间的 JSON 备份格式 - 导入前的完整结构、日期、经纬度、图片与重复 ID 校验
- 「合并」与「覆盖」两种恢复方式,并通过事务保证写入完整性
- 清空私人档案前的明确确认,且永远不删除公开演示数据
- 图片类型、5 MB 大小限制与 HTTPS 外链限制
五、架构思维 #
这个项目让我第一次比较完整地理解「架构」在产品中的含义。要实现架构规划,停留在画一张复杂技术图远远不够,还需要能做到提前决定哪些变化应该影响哪些部分、哪些事实只能有一个来源、未来替换一层时是否需要重写全部产品。
当前架构可以概括为以下内容:
体验层
├─ 3D 地球 / 2D 平面地图
├─ 搜索、地点档案与民族志详情
└─ 时间图谱、研究网络、主题图层
↓
领域模型
├─ EthnographyArchive:作品与阅读档案
├─ EthnographyEdition:原版与译本
├─ ArchiveAuthor:作者与国籍
├─ FieldworkLeg:作者、地点与时间
└─ PlaceSnapshot:保存当时的地理上下文
↓
数据层
├─ 公共演示档案:随代码发布、只读
├─ ArchiveRepository:统一数据访问接口
└─ Dexie / IndexedDB:当前设备的私人档案
地图侧
├─ Natural Earth:国家与一级行政区基础边界
├─ 本地城市与地点索引
└─ OpenStreetMap / OpenFreeMap:在线地图样式与瓦片
其中几项关键选择是:
(1)Repository 隔离存储
项目界面不直接读写 IndexedDB,而是调用 ArchiveRepository。首版 Demo 实现是 LocalArchiveRepository,未来如果真实用户需要账号与跨设备同步,再增加云端实现,但不必重写地图和档案界面。
(2)地点快照保护历史语境
每条档案既保存地点 ID,也保存名称、层级、国家代码与经纬度快照。这样即使以后底图或地理数据源变化,已录入档案仍能保留当时上下文。对旧档案,则通过版本迁移逐步补全结构化作者与田野数据。
(3)单一数据源驱动多种视图
3D 地球与 2D 平面地图不是两个产品,时间、网络与主题也不是各自维护的数据副本。它们都由档案派生展示状态,因此切换视图、清除筛选和删除轨迹不会修改原始档案。
(4) 静态部署与运行时数据分离
网站本身是无服务器静态应用,适合 GitHub 与 Cloudflare Pages 持续部署。私人数据仍留在访问者设备,运行时会请求地图样式与瓦片,但不会自动上传用户的民族志档案。
六、测试迭代 #
迭代一:从 Radio Garden 复现到自己的产品语言 #
Demo 最早设计出来的 UI 是采用暗色卫星地球、荧光绿点与动态星空。它可以快速建立「可拖动的世界」这一核心体验,但从外观来看更像地图技术实验,和民族志阅读之间的联系感很弱,甚至是带着几分割裂。
我随后将视觉方向从「宇宙中的科技地球」调整为「档案室中的交互地图」,具体来说,移除星空,背景改为均匀的羊皮纸色与低强度纸浆纹理,地图改为灰绿海洋、旧纸陆地、深褐文字和陶土红点位,面板、按钮和阅读页则共享一套档案纸张语言。
UI 设计很关键,乍一看变化的似乎主要是色彩,但不同的色彩组合反而是产品定基立调的关键。在第一次迭代中,通过不断调整色彩,我认为项目所追求的复古感应来自排版、材质和信息秩序,而不是堆叠指南针、卷轴、航海线等符号。
迭代二:从城市点位到结构化民族志档案 #
早期的项目 Demo 只允许地球吸附真实城市并保存一个绿点。随着多次使用,我发现真正需要管理的是「一部作品在何处、由谁、何时开展田野」,而不是点位本身。
于是我将数据从 SavedPoint 调整为 EthnographyArchive,存储从 localStorage 升级到 IndexedDB,并通过 Repository 统一访问。此后,地点只负责提供入口,作品、版本、作者和田野经历转而成为产品中的核心实体。
从这里或许可以看出,产品的数据模型不是技术人员在需求完成后补上的表结构,它本身就决定了用户能提出什么问题。
迭代三:从「按地点分类」到时间、人物与主题 #
在项目档案数量增加后,只按大洲和国家展开目录仍然只是分类。受「哲学家星图」这一项目的启发,我加入了「3D 地球 / 2D 平面地图」的切换功能,后来还加入了地点书架、时间图谱、研究网络与主题图层,让同一份材料可以被重新排列。
项目的主题图层没有采用封闭词表。系统会去除首尾空格、合并多余空格并忽略大小写进行匹配,同时保留用户原始文字用于展示。这样既允许新主题自然出现,又为未来增加别名表保留空间。
迭代四:从修一个 Bug 到修一类数据问题 #
地理产品最危险的问题是界面看起来合理,然而实际表达出现错误。
在本项目的开发过程中,我先后发现以下影响真实地理信息的 Bug:
- 新加坡被重叠的简化边界误判为马来西亚
- 沿海城市点落在简化边界外,导致国家或一级行政区缺失
- Natural Earth 的
Seven seas (open ocean)技术分类被错误显示成「七海地区」1 - 27 条与父级同名的占位行政区进入搜索,造成重复候选
- 美属萨摩亚等领地可以悬停,却无法稳定选择建档
这些问题没有通过逐项隐藏来解决,处理方式包括:审计上游字段语义、建立明确的七大洲映射、增加边界面积与邻近判断、剔除通用占位记录、保留合法同名层级并在搜索端消歧,最后用数据测试锁定规则。
迭代五:删除偏离主线的设计 #
项目曾有书籍与作者图片轮播、动态星图、坐标玫瑰、旧 Three.js 地球实现与多组未使用资源。不过考虑再三以后,我认为这些资源或功能实际只会抢夺使用者的注意力,同时还增加了代码和性能成本,并不能很好地服务于项目的核心功能,因此有选择性地进行了删除精简。
项目部署上线前,我主要选择删除轮播、星空与遗留渲染链路,保留真正服务于「地点—档案—关系」的部分。
我认为可持续性与可维护性是项目开发中的重中之重,而前述的两种特性正来自明确的边界和删除低价值复杂度——不是所有的尝试都有必要留在代码中。
七、评测:「我觉得不错」→可操作指标 #
目前项目的验证以工程质量、数据正确性与形成性体验检查为主,但还没有正式的用户研究,因此需要明确已验证的内容与缺少的指标。
| 要验证的问题 | 当前方法与证据 | 缺少 |
|---|---|---|
| 核心闭环是否可用 | 45 项单元测试;5 条桌面 / 移动端浏览器流程;生产构建与线上冒烟验证 | 面向目标用户的任务成功率、完成时间与误触记录 |
| 地理信息是否可靠 | 七大洲口径测试、特殊地区映射、重复行政区清洗、沿海与重叠边界回归测试 | 更完整的数据版本策略与外部领域专家复核 |
| 私人数据能否恢复 | 备份格式校验、合并 / 覆盖事务、损坏数据恢复、清空后公开演示保留 | 大规模档案、跨版本与跨设备迁移测试 |
| 桌面与移动体验是否稳定 | 1440×900 与 Pixel 7 浏览器流程;地图切换、筛选、导入导出回归 | 更多浏览器、低性能设备、弱网与无障碍测试 |
| 产品是否解决真实需求 | 自己持续使用、同专业朋友讨论、逐轮体验验收 | 正式访谈、可用性测试、复访与迁移意愿 |
相比于询问使用者「你是否喜欢这一项目」,不如让几位人类学学生完成以下几项具体任务,之后根据反馈进行调整。
- 找到一个田野地点并理解其层级
- 建立一条包含作者、时间和札记的档案
- 从时间或研究网络重新找到档案
- 导出数据、清空并成功恢复
- 解释个人在哪一步犹豫、哪些字段不符合真实研究习惯
只有明确任务完成率、首次建档时间、搜索与地图误触、恢复成功率,以及用户是否愿意迁移现有书目,才能开始尝试判断是否具有潜在的使用价值和商业价值。
八、我如何与 AI 协作 #
Global Ethnography 不是一个以大模型为核心功能的 AI 产品,但它是一项完整的 AI 协作开发实践,经由此次实践,我完整地体验了一次(并不正规的) Vibe Coding 过程。
| 我的职责 | AI 协助的部分 | 共同完成 |
|---|---|---|
| 提出领域问题与真实使用需求 | 调研地图、数据源、存储与部署方案 | 将模糊想法拆成范围、状态与验收条件 |
| 确定产品定位、优先级与非目标 | 实现代码、迁移逻辑与自动化测试 | 根据真实页面和测试结果持续迭代 |
| 判断地理与人类学语义是否合理 | 扫描同类数据问题、定位技术根因 | 形成可复用的规则而非一次性补丁 |
| 验收、拒绝、回退或删除方案 | 维护变更记录、构建与部署检查 | 在产品价值、风险和成本之间取舍 |
提出问题与领域约束
→ 先讨论产品与技术方案
→ 拆成可验收的小阶段
→ AI 协助实现和测试
→ 我在真实界面体验与复核
→ 修正、删除、回退或进入下一轮
有意思的是,在项目开发早期,我经常使用「更有高级感」「像古典档案馆」这类难以执行的描述来让 AI 写代码。随着协作深入,我逐渐开始主动补充状态、数据边界、成功条件与不允许改变的事实。例如,「轨迹更清晰」可以被拆为起点语义、球面大圆、平面单画面路线、箭头位置和时间标签这样的术语,「保护数据」被拆成仓储接口、迁移、备份格式、导入事务和异常测试这样更精确的描述。
我认为这应当算是 Vibe Coding 的精髓。
总结一下,Vibe Coding 或与 AI 协作的能力并不只笼统于「会写 Prompt」这样的表述,更重要的是能给 AI 足够但不过量的上下文,将目标、约束、非目标和验收标准分开,识别模型建议中的事实风险与过度设计,通过测试、版本和真实体验形成反馈闭环,以及知道什么时候应该停止继续加功能。
九、当前局限与下一步 #
Global Ethnography 项目已经部署上线,可供体现,但还有一些局限:
- 目前只有一条随网站发布的公开演示档案,还不足以展示大规模知识关系
- 私人档案仍是设备本地数据,不会自动跨浏览器、域名或设备同步
- 当前作品仍有一个主要归档地点,虽然
fieldwork[]已能保存结构化田野经历,但对真正的多点民族志还没有完整录入与呈现 - 作者身份仍嵌在各条档案中,同一人物跨作品的稳定实体需要进一步抽离
- 标签能完成筛选,但还不能解释「两部作品为什么相关」
- 主界面与地图组件仍然较大,后续需要按领域继续拆分
- 没有正式用户研究、行为埋点和业务指标,不能证明市场需求与长期留存
所以,该项目之后应当会优先完成以下步骤:
- 先做用户验证:观察目标用户怎样建档、检索、恢复,以及地图是否真的优于通用笔记工具
- 支持多点民族志:将作品、田野项目与多个地点改成明确的多对多关系,区分比较、移动、分布式研究与文本涉及地
- 建立「有证据的连接」:不直接生成一个黑箱相似度,而是让每条档案亲和、影响、比较或争议关系都拥有类型、解释、出处与可修订状态
- 决定是否上云:只有跨设备和协作需求成立后,再考虑是否引入账户、数据库与对象存储
- 继续工程拆分与性能验证:拆分大型组件,补充弱网、低性能设备、无障碍与地图服务降级测试。
回到利奇所问的,分类以后还剩下什么?我希望这一项目不会只是停留在对各本民族志的分布进行排列,只能回答「人类学发生在哪里」,更希望可以据此发现不同地方的民族志材料是否存在关联,为什么可以比较、思想如何在文本与田野之间迁移,以及一段民族志怎样动摇我们习以为常的世界分类。