时光星图 Time Atlas:把本地照片变成一片可以探索的 3D 记忆星河
前言
相册工具通常会把照片排成时间线、瀑布流或文件夹列表。这样的方式足够高效,但总觉得少了一点“重新进入那段记忆”的仪式感。
时光星图 Time Atlas 想做的是另一种体验:把本地照片目录变成一片可以探索的 3D 记忆星河。一个文件夹是一座星系,一张照片是一颗星辰,用户可以在星图全貌、焦点航行、星系内部和照片浏览之间层层进入,把一次旅行、一个纪念日、一段日常重新展开。
它解决什么问题
时光星图不是为了替代系统相册,也不是为了做云端照片管理。它更像一个专注“沉浸式回看”的本地记忆浏览器。
它适合这些场景:
- 想把旅行、纪念日、家庭日常等照片按主题重新组织。
- 想在大屏、投影或触控设备上用更有氛围的方式展示照片。
- 想体验摄像头手势浏览照片,但又不希望照片上传到服务器。
- 想把文件夹里的照片快速变成一个可演示、可分享思路的 3D 互动页面。
核心设计原则很简单:照片留在本地,交互变得更有空间感。
核心功能
1. 本地照片目录导入
进入页面后,可以点击“选择照片目录”导入本地照片根目录。时光星图会按照目录结构自动生成星河:
1 | 我们的照片/ |
其中:
- 根目录下的一级文件夹会成为独立星系。
- 文件夹内各层级图片会成为该星系中的记忆星辰。
- 如果只是想先体验效果,可以直接使用“演示模式”进入内置示例数据。
导入完成后,系统会统计星系数量和照片数量,并根据文件夹名称、照片顺序、图片数量生成一片可探索的 3D 星图。这个过程不要求用户整理数据库,也不需要额外填写描述信息,只要本地目录结构是清晰的,时光星图就能把它变成可浏览的空间结构。
2. 演示模式
如果暂时没有准备照片,首页可以直接点击“演示模式”。演示模式会生成一组内置旅行主题星系,例如巴黎、东京、京都、冰岛、威尼斯等,每个星系里都有若干颗模拟照片星辰。
演示模式适合用来快速体验完整业务流程:
- 从首页进入星图。
- 查看螺旋星河全貌。
- 选择某个星系进入焦点航行。
- 进入星系内部查看照片星辰。
- 打开记忆浏览和照片全屏。
- 尝试鼠标、键盘和手势控制。
它的价值是降低体验门槛:即使没有本地照片,也能先理解时光星图的交互方式。
3. 3D 记忆星河
导入照片后,页面会进入螺旋星图全貌。星系按照空间坐标分布在一片深色星空中,每个星系带有自己的颜色、名称和照片数量。
浏览路径分成五层:
1 | 螺旋星图全貌 |
这种层级设计让照片浏览不再只是“下一张、上一张”,而是先看整体,再进入某段记忆,最后聚焦到具体照片。
螺旋星图全貌
这是进入照片宇宙后的第一层。用户会看到一片由多个星系组成的螺旋星图,可以通过拖动观察整体结构,也可以缩放视角查看更远或更近的星系。
这一层主要解决“从整体上看我的照片被分成了哪些记忆主题”的问题。它不是列表,而是一张空间地图。
焦点航行
当用户选中某个星系后,视角会进入焦点航行状态。此时页面会围绕当前星系组织镜头,用户可以切换上一个或下一个星系,也可以确认进入当前星系。
焦点航行像是在星系之间巡航,适合快速浏览不同文件夹主题,决定接下来要进入哪一段记忆。
星系内部
进入星系后,文件夹里的照片会被转换成一颗颗记忆星辰,围绕星系中心分布。用户可以环绕观察、缩放星系,也可以点击某颗照片星进入具体照片。
这一层保留了 3D 空间感:照片不是直接摊成网格,而是作为星系内部的节点存在。
记忆浏览
打开照片后,会进入记忆浏览视图。页面左侧是缩略图索引,中间是当前照片,底部或周围会展示照片名称、所属星系和当前位置。
这一层回到更清晰的照片阅读模式,适合连续查看同一个文件夹下的照片。用户可以点击缩略图、方向键切换,也可以用手势切换上一张和下一张。
照片全屏
点击主照片后会进入全屏查看。全屏模式支持缩放、拖动平移、双击还原和退出。对于合照、风景照、截图这类需要看细节的图片,全屏模式会比普通浏览更舒服。
4. 多种输入方式
时光星图同时支持鼠标、键盘、触摸和摄像头手势。不同输入方式共享同一套交互状态,不会出现“鼠标选中一套、手势又选中另一套”的割裂感。
常用操作包括:
| 场景 | 鼠标 / 键盘 / 触摸 | 摄像头手势 |
|---|---|---|
| 星图全貌 | 拖动旋转,滚轮缩放,点击星系预览 | 右手移动指针,左手捏合进入 |
| 焦点航行 | 滚轮或方向键切换星系,Enter 进入 | 左手张掌 / V 手势切换,捏合进入 |
| 星系内部 | 拖动观察,点击照片星打开 | 右手指向照片星,左手捏合打开 |
| 记忆浏览 | 点击缩略图或方向键切换照片 | 左手张掌下一张,V 手势上一张 |
| 照片全屏 | 滚轮缩放,拖动平移,Esc 退出 | 张掌放大,V 手势缩小,握拳返回 |
手势交互采用“右手指针、左手动作”的分工:右手负责指向目标,左手负责确认、返回、缩放和切换。这能减少确认目标时的误触,也更符合实际使用中的身体动作习惯。
5. 照片浏览与全屏查看
进入某个星系后,可以查看照片星辰,也可以进入记忆浏览视图。浏览视图左侧有缩略图索引,中间展示当前照片,并显示照片名称、所属星系和当前位置。
点击主照片后会进入全屏查看。全屏模式支持:
- 滚轮或双指缩放,最高可放大到 500%。
- 放大后拖动平移,查看照片细节。
- 双击或点击“重置”恢复默认比例。
Esc、背景点击或关闭按钮退出全屏。
这些事件会由顶层照片视图接管,不会误操作背后的 3D 场景。
手势功能详解
时光星图的手势设计不是把鼠标操作生硬搬到摄像头前,而是重新定义了一套适合空中操作的动作语义。它采用固定双手分工:
- 右手:只负责移动虚拟指针,用来指向星系或照片星辰。
- 左手:负责确认、返回、缩放、切换等业务动作。
这样设计有一个明显好处:选择目标和执行动作由两只手分开完成。右手先把指针移动到目标上,左手再做捏合确认,确认时指针会被锁定,减少“刚要点击目标却飘走”的误操作。
基础手势语义
| 摄像头手势 | 作用 |
|---|---|
| 右手单食指移动 | 移动虚拟指针,用来指向星系、照片星或界面目标 |
| 左手捏合 | 锁定目标、确认选择、进入星系或打开照片 |
| 左手握拳 | 取消当前操作,或返回上一级 |
| 左手 V 手势 | 在可缩放场景中缩小;在切换场景中切到上一个 |
| 左手张掌 | 在可缩放场景中放大;在切换场景中切到下一个 |
| 左手单食指朝向 | 根据食指方向旋转场景或平移照片 |
手势识别更偏向稳定手型,而不是依赖挥动距离。也就是说,系统更关心“你当前摆出了什么明确姿态”,而不是要求用户做夸张的大幅挥手动作。
星图全貌中的手势
在螺旋星图全貌中,用户面对的是整个记忆宇宙。
| 功能 | 手势操作 | 效果 |
|---|---|---|
| 移动选择目标 | 右手单食指移动 | 屏幕上出现虚拟指针,跟随右手移动 |
| 预览星系 | 右手指向星系并停留 | 星系被高亮,显示星系名称和照片数量 |
| 进入星系 | 左手捏合 | 锁定当前指向的星系并进入焦点航行或星系内部 |
| 旋转星图 | 左手单食指朝向 | 按指向调整观察角度 |
| 缩小星图 | 左手 V 手势 | 拉远视角,查看更多星系 |
| 放大星图 | 左手张掌 | 拉近视角,观察局部星系 |
| 返回 | 左手握拳 | 如果已经在根层,会提示当前已是最外层 |
这一层的关键是“右手找目标,左手确认”。用户不需要碰鼠标,也能像在空中指向某颗星一样选择一个照片主题。
焦点航行中的手势
焦点航行用于在不同星系之间切换。这个场景里,手势更像遥控器:
| 功能 | 手势操作 | 效果 |
|---|---|---|
| 上一个星系 | 左手 V 手势 | 镜头切换到上一个星系 |
| 下一个星系 | 左手张掌 | 镜头切换到下一个星系 |
| 进入当前星系 | 左手捏合 | 确认进入当前聚焦的星系 |
| 小角度观察 | 左手单食指朝向 | 对当前星系做轻微角度调整 |
| 返回全貌 | 左手握拳 | 回到螺旋星图全貌 |
焦点航行中的滚轮和手势都偏向“切换星系”,不会再做自由缩放。这能避免用户本来想切换下一个星系,却把镜头缩放乱了。
星系内部中的手势
进入某个星系后,照片会变成星系内部的星辰。此时右手重新承担指向目标的作用:
| 功能 | 手势操作 | 效果 |
|---|---|---|
| 指向照片星 | 右手单食指移动 | 虚拟指针移动到某颗照片星上 |
| 打开照片 | 左手捏合 | 打开当前指向的照片 |
| 环绕观察 | 左手单食指朝向 | 围绕星系观察照片星辰 |
| 缩小星系 | 左手 V 手势 | 拉远,查看更多照片星 |
| 放大星系 | 左手张掌 | 拉近,查看当前局部 |
| 返回焦点航行 | 左手握拳 | 退出当前星系内部 |
这一层没有把“上一张、下一张”强行绑定到右手指向,因为照片星本身已经是空间目标。用户想看哪张,就直接指向哪张,再捏合打开。
记忆浏览中的手势
打开照片后,会进入更传统的照片浏览界面。此时用户通常更关心连续翻看,所以手势也会切换成翻页语义:
| 功能 | 手势操作 | 效果 |
|---|---|---|
| 下一张照片 | 左手张掌 | 切换到下一张照片 |
| 上一张照片 | 左手 V 手势 | 切换到上一张照片 |
| 打开全屏 | 左手捏合 | 将当前照片放大到全屏查看 |
| 返回星系内部 | 左手握拳 | 回到照片星辰视图 |
记忆浏览层会接管滚轮和手势事件,不会让操作穿透到背后的 3D 场景。这样用户翻照片时,不会误把后面的镜头也一起转动或缩放。
照片全屏中的手势
照片全屏是看细节的场景,因此手势重点放在缩放和平移:
| 功能 | 手势操作 | 效果 |
|---|---|---|
| 放大照片 | 左手张掌 | 放大当前照片 |
| 缩小照片 | 左手 V 手势 | 缩小当前照片 |
| 平移照片 | 左手单食指朝向 | 放大后移动查看不同区域 |
| 快速还原 | 左手捏合 | 将照片恢复到默认比例和位置 |
| 退出全屏 | 左手握拳 | 关闭全屏,回到记忆浏览 |
全屏缩放范围为 100%–500%。当照片被放大后,平移操作可以用来查看局部细节;当照片恢复默认比例后,平移会自动归位,避免视图停留在奇怪的位置。
手势不可用时怎么办
摄像头手势需要浏览器授权摄像头,并加载 MediaPipe Hands 相关资源。实际使用中,如果遇到摄像头不可用、权限被拒绝、光线不足或网络无法加载识别模型,时光星图会保留鼠标和键盘操作。
也就是说,手势是增强体验,不是唯一入口。即使不用摄像头,仍然可以完成:
- 导入照片目录。
- 浏览星图全貌。
- 切换和进入星系。
- 打开照片。
- 缩放、平移和全屏查看。
- 返回上一级。
隐私设计
时光星图是纯前端应用,照片文件和摄像头画面都在浏览器本地处理。页面上的“本地沙箱环境”不是一句装饰文案,而是这个项目的边界:
- 照片不会上传到服务器。
- 摄像头画面只用于浏览器内的手势识别。
- 目录扫描依赖浏览器文件访问能力。
- 摄像头不可用或权限被拒绝时,鼠标和键盘仍可完成核心流程。
需要注意的是,摄像头手势依赖 MediaPipe Hands,相关脚本和模型默认从 CDN 加载。因此在严格离线环境下,手势识别可能不可用,但照片浏览本身不受影响。
技术实现
项目使用 Vue 3 组织界面状态,用 Pinia 管理星系、照片、焦点、返回栈和手势状态;3D 场景由 Three.js 渲染;动画和过渡使用 GSAP;手势识别基于 MediaPipe Hands。
代码结构上,大致可以分成几层:
| 模块 | 作用 |
|---|---|
WelcomeScreen |
首页、照片目录导入、演示模式入口 |
SpaceEngine |
Three.js 场景、镜头、拾取和星河渲染 |
InteractionController |
把鼠标、键盘、触摸和手势统一成业务动作 |
GestureManager |
摄像头手势识别与姿态状态 |
PhotoViewer |
记忆浏览、缩略图、照片全屏与缩放 |
universe store |
星系、星辰、当前层级和交互状态管理 |
我比较喜欢这个项目的一点是:它没有把“手势”当成单独的一套特殊逻辑,而是把所有输入都翻译成统一动作。这样后续增加遥控器、游戏手柄或其他输入设备时,也可以沿用同一套业务状态。
体验总结
时光星图的价值不在于“更快找到某张照片”,而在于让照片浏览重新带上空间感和探索感。
普通相册解决的是管理效率,时光星图解决的是回看体验。它把文件夹、照片、缩略图、全屏查看这些常见功能放进一个 3D 星河里,再用手势、鼠标和键盘把它串起来。对于旅行回忆、纪念日照片、家庭影像或个人作品集展示,这种形式会比传统列表更有情绪,也更适合被分享和演示。
后续如果继续迭代,我希望它可以加入更多照片元数据能力,比如按拍摄时间自动形成时间轨道、按地点生成空间节点,甚至把照片说明、音乐和故事线组合成一段完整的“记忆航行”。



