前言

相册工具通常会把照片排成时间线、瀑布流或文件夹列表。这样的方式足够高效,但总觉得少了一点“重新进入那段记忆”的仪式感。

时光星图 Time Atlas 想做的是另一种体验:把本地照片目录变成一片可以探索的 3D 记忆星河。一个文件夹是一座星系,一张照片是一颗星辰,用户可以在星图全貌、焦点航行、星系内部和照片浏览之间层层进入,把一次旅行、一个纪念日、一段日常重新展开。

访问地址https://junly.top/time-atlas

时光星图首页

它解决什么问题

时光星图不是为了替代系统相册,也不是为了做云端照片管理。它更像一个专注“沉浸式回看”的本地记忆浏览器。

它适合这些场景:

  • 想把旅行、纪念日、家庭日常等照片按主题重新组织。
  • 想在大屏、投影或触控设备上用更有氛围的方式展示照片。
  • 想体验摄像头手势浏览照片,但又不希望照片上传到服务器。
  • 想把文件夹里的照片快速变成一个可演示、可分享思路的 3D 互动页面。

核心设计原则很简单:照片留在本地,交互变得更有空间感。

核心功能

1. 本地照片目录导入

进入页面后,可以点击“选择照片目录”导入本地照片根目录。时光星图会按照目录结构自动生成星河:

1
2
3
4
5
6
7
8
9
10
11
我们的照片/
├─ 2024-巴黎旅行/
│ ├─ 01.jpg
│ ├─ 02.jpg
│ └─ 街景/
│ └─ 03.png
├─ 纪念日/
│ ├─ dinner.webp
│ └─ gift.jpg
└─ 日常/
└─ weekend.jpg

其中:

  • 根目录下的一级文件夹会成为独立星系。
  • 文件夹内各层级图片会成为该星系中的记忆星辰。
  • 如果只是想先体验效果,可以直接使用“演示模式”进入内置示例数据。

导入完成后,系统会统计星系数量和照片数量,并根据文件夹名称、照片顺序、图片数量生成一片可探索的 3D 星图。这个过程不要求用户整理数据库,也不需要额外填写描述信息,只要本地目录结构是清晰的,时光星图就能把它变成可浏览的空间结构。

2. 演示模式

如果暂时没有准备照片,首页可以直接点击“演示模式”。演示模式会生成一组内置旅行主题星系,例如巴黎、东京、京都、冰岛、威尼斯等,每个星系里都有若干颗模拟照片星辰。

演示模式适合用来快速体验完整业务流程:

  • 从首页进入星图。
  • 查看螺旋星河全貌。
  • 选择某个星系进入焦点航行。
  • 进入星系内部查看照片星辰。
  • 打开记忆浏览和照片全屏。
  • 尝试鼠标、键盘和手势控制。

它的价值是降低体验门槛:即使没有本地照片,也能先理解时光星图的交互方式。

3. 3D 记忆星河

导入照片后,页面会进入螺旋星图全貌。星系按照空间坐标分布在一片深色星空中,每个星系带有自己的颜色、名称和照片数量。

浏览路径分成五层:

1
2
3
4
5
螺旋星图全貌
-> 焦点航行
-> 星系内部
-> 记忆浏览
-> 照片全屏

这种层级设计让照片浏览不再只是“下一张、上一张”,而是先看整体,再进入某段记忆,最后聚焦到具体照片。

螺旋星图全貌

这是进入照片宇宙后的第一层。用户会看到一片由多个星系组成的螺旋星图,可以通过拖动观察整体结构,也可以缩放视角查看更远或更近的星系。

这一层主要解决“从整体上看我的照片被分成了哪些记忆主题”的问题。它不是列表,而是一张空间地图。

焦点航行

当用户选中某个星系后,视角会进入焦点航行状态。此时页面会围绕当前星系组织镜头,用户可以切换上一个或下一个星系,也可以确认进入当前星系。

焦点航行像是在星系之间巡航,适合快速浏览不同文件夹主题,决定接下来要进入哪一段记忆。

星系内部

进入星系后,文件夹里的照片会被转换成一颗颗记忆星辰,围绕星系中心分布。用户可以环绕观察、缩放星系,也可以点击某颗照片星进入具体照片。

这一层保留了 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 星河里,再用手势、鼠标和键盘把它串起来。对于旅行回忆、纪念日照片、家庭影像或个人作品集展示,这种形式会比传统列表更有情绪,也更适合被分享和演示。

后续如果继续迭代,我希望它可以加入更多照片元数据能力,比如按拍摄时间自动形成时间轨道、按地点生成空间节点,甚至把照片说明、音乐和故事线组合成一段完整的“记忆航行”。