旅行日记
将旅行原始素材转化为一个滚动叙事网站:每张卡片对应一天,显示在固定卫星地图上; 移动段落(房车、汽车、自行车、徒步、渡轮、船屋)绘制在地图上;照片和视频标注在拍摄位置; 沿途信息点(“Unterwegs” / “中途”)配有维基共享资源图片;以及每天的回放功能, 以3D方式飞越路线,显示统计数据、海拔剖面图,照片会在拍摄位置弹出。
template/中的模板是一个Vite + TypeScript + MapLibre项目(无框架,无API密钥)。
用户无需接触代码:一个本地设置Web应用通过拖放收集语言、旅行数据、每日文本和文件;
其余工作由构建脚本完成。
哪种模式?
| 用户说 | 模式 | 转到 |
|---|---|---|
| “新建旅行日记”,“设置一个旅行网站”,尚无项目 | init | §1 |
| “新照片 / GPX / 时间线 / 日记文本”,“添加第N天”,项目已存在 | day | §2 |
| “部署”,“发布”,“生成单个文件”,“上线” | deploy | §3 |
一个项目是旅行日记项目,当它包含data/trip.json和scripts/build-timeline.mjs时。
1. init – 脚手架新项目
- 仅询问(或从消息中获取)两件事:目标文件夹以及用户是否更愿意在浏览器应用中回答设置问题(默认,更友好)还是在聊天中回答。其余内容由应用询问。
- 运行脚手架:
node <skill-dir>/scripts/init.mjs <target-folder>。它会复制template/,运行npm install,并打印下一条命令。 - 启动设置应用:在项目内运行
npm run setup(端口5180),并告诉用户打开http://localhost:5180。如果浏览器面板可用,请使用`preview_start`打开该URL。应用引导用户完成:语言(de/en)→ 标题、副标题、日期、时区、交通工具、输出类型、强调色 → 每天一个条目(日期、标题、Markdown格式的日记文本)→ 照片、视频、GPX、Google时间线的拖放区域。应用会写入data/trip.json、content/tagebuch.md和raw/文件夹。用户可随时重新打开。 - 当用户返回(“done”,“fertig”,或直接粘贴素材)时,继续进行day。
如果用户改为在聊天中回答,请自行编写data/trip.json(模式见references/data-formats.md),并将日记写入content/tagebuch.md(## Tag N – <weekday, date> – <title> / ## Day N – …)。
2. day – 处理新素材
在会话中首次运行前阅读references/day-workflow.md;其中包含准确的顺序、约定和陷阱。简要版本:
- 盘点
raw/下新增的内容(find raw -newer public/data/photos.json),以及日记是否包含新的天数。如果Claude Docs连接器和文档链接可用,将文档作为Markdown导出到content/tagebuch.md;否则由设置应用/用户维护该文件。 - 结构化
data/trip.json:每天一个days[]条目(n、date、title、GPX的tracks[]、飞越片段的video、无时间线时的legs[])。将GPX文件重命名为YYYY-MM-DD_slug.gpx。 - 时间线标签:运行
npm run data:timeline,读取控制台显示的段落列表,并为每个段落分配一个人工标签,写入trip.json → timeline.labels(键为本地开始时间YYYY-MM-DDTHH:MM)。修正timeline.kinds中误检测的类型(例如电动自行车上的SKIING →ebike,朋友的汽车 →car)。向places添加停车点,使停靠点显示名称而非“Pause”。 - 构建:
npm run data(内容 → 轨迹 → 时间线 → 兴趣点 → 照片)。公共路线/高程/共享资源服务器有速率限制;脚本会暂停并缓存,不会循环请求。 - 查看照片:构建新照片的联系表(脚本见参考文档),阅读它们,并为每张照片在
data/captions.json中写一个简短的句子。当照片位置(打印在每张照片旁)可识别时,命名地点和山脉;说“Ortler group”而非猜测山峰。将模糊或意外拍摄的照片放入data/exclude.json。 - 兴趣点:对于用户经过但自己没有好照片的著名地点(隧道、知名湖泊、城堡),在
data/pois.json中添加条目,包含2–3句事实性描述和一个共享资源搜索词;运行npm run data:pois获取一张自由许可的图片及其归属信息。在联系表中检查所选图片,如果第一个结果不佳(版画、地图),则手动指定更好的file。 - 验证:运行
npm run dev,打开新的一天,检查线条、图钉、说明文字,并至少播放一次回放。 - 部署(§3),如果项目是git仓库,则提交。
保持项目中的CLAUDE.md最新(它是下一次会话的交接文档)。
3. deploy
trip.json → output指定用户的选择;详细信息和确切命令见references/hosting.md。
- single:
npm run build:single→ 生成一个HTML文件,位于项目旁,包含数据、照片和视频(大型自有视频被省略并附注)。用户注意:在某些手机上,从文件系统打开文件会阻止地图的web worker;托管更可靠。 - web:
npm run deploy:web→ 构建,生成.htaccess+.htpasswd(基本认证),并通过SSH上传变更文件(tar管道,通过哈希清单增量更新)。需要.env.web(主机、用户、目录、登录信息)。 - nas:
npm run deploy→ tar管道到Synology nginx容器;配置在nas/default.conf中。
值得了解的事情
- 照片需要EXIF时间和GPS(手机都提供)。视频的时间从文件名获取(
PXL_YYYYMMDD_HHMMSS),位置从时间线、GPX、停靠点或最近的照片获取。 - GPX优先于时间线:与GPX轨迹重叠的时间线活动被丢弃。
- 没有Google Timeline时,驾车路线通过
days[].legs在已命名地点之间路由。 - 船屋旅行:类型
boat沿OSM河流/运河路由(scripts/waterway.mjs,可选timeline.waterways白名单),并使用照片EXIF位置作为路点——见references/day-workflow.md。 - 桌面端(≥ 900 px):地图占左侧50%,故事占右侧50%并带有大照片网格;回放在右侧显示照片卡片,并将15分钟内拍摄的照片(最多6张)分组到一张卡片上(移动端不变)。
- 高速公路隧道上的海拔剖面显示上方地形;这就是为什么海拔增益只计算自行车/徒步。
- 所有UI文本位于
src/i18n.ts(de,en);添加一种语言只需增加一个字典。