返回项目列表
Analemma 标志

Analemma

允许从任何地理位置可视化太阳和月亮轨迹的 Web 工具。

天文学自动化

一个用于自动化摄影采集并以交互方式可视化太阳与月亮“8”字轨迹(analemma)的完整系统。

该项目自动、定期地从公共网络摄像头采集图像,生成能够呈现太阳和月亮随时间视运动的序列(延时摄影)。图像通过 GitHub Actions 在精确的天文时刻采集,随后由高性能的现代 Web 查看器(PWA)加以呈现。整个系统无需传统数据库,而是依托 Git 仓库自身的文件系统运行。


软件架构

为保持代码的可维护性、可扩展性与可测试性,摄影编排器的核心(src/)严格遵循 Clean Architecture 与 Domain-Driven Design (DDD) 的原则进行构建。

1. 领域层(Domain Layer)

这是软件的核心。这里存放纯粹的业务规则,独立于任何框架或外部基础设施:

  • 实体(Location、Camera):Location 封装地理数据(国家、州/省、城市)并生成动态标识符。Camera 关联到某个 Location,并保存其朝向方位。
  • 值对象(Value Objects):例如 CelestialObject,用于统一领域词汇。
  • 契约(接口):例如 ScheduleRepository,定义领域期望如何获取或持久化数据的抽象。

2. 应用层(Application Layer)

包含主要用例。它作为编排者,协调领域层与基础设施层以满足系统需求。

  • Scheduler:负责检查每个 Location 的计划时间。如果当前执行时间与某次计划采集相符(或处于阈值范围内),它会协调相应的采集服务获取图像。

3. 基础设施层(Infrastructure Layer)

代码在此与外部服务、I/O 和框架进行交互:

  • 采集服务:使用 Puppeteer(PuppeteerCaptureService)访问公共网络摄像头网页,等待多媒体组件加载完成,并从视频流或 canvas 中干净地提取画面(截图),不包含网页界面。
  • ConfigScheduleRepository:一个动态仓库,根据配置计算 src/config/locations.ts 中登记的每个 Location 坐标处的精确采集时间。

编排周期

编排器设计为通过 GitHub Actions 周期性运行,并借助定时任务(cronjob)优化资源使用。

sequenceDiagram
    participant GH as GitHub Actions (Cron)
    participant App as Scheduler
    participant Repo as ConfigScheduleRepository
    participant Cam as PuppeteerCaptureService
    participant FS as File System / Git

    GH->>App: 执行每小时周期(第 0 分钟)
    App->>Repo: 查询当天的采集时间
    Repo-->>App: 返回 { sun: '12:05', moon: '03:45' }
    App->>App: 判断系统时间(America/La_Paz)是否匹配

    alt 在阈值内匹配太阳事件
        App->>Cam: 启动 Puppeteer Headless
        Cam-->>App: 提取并返回图像缓冲区(截图)
        App->>FS: 将文件保存至 'captures/sun/{location}/{camera}/{YYYY-MM-DD}.jpg'
        GH->>FS: 执行 Git Commit 并 Push 到仓库
    end

配置与环境变量

系统依赖集中式配置,运行所需的条件很少,其中最关键的是时间同步。

变量说明
TZ关键: 确保时区配置为 America/La_Paz(UTC-4)。应用以此为基准,将预期的天文时间表与每小时的定时任务进行同步和比较。

Web 查看器

这是一个交互式 Web 应用,专门用于流畅地浏览由项目主编排器生成的数以万计的摄影采集(延时摄影),呈现太阳和月亮在长时间跨度内的运行轨迹。


UI 架构与用户体验(UX)

该 Web 应用旨在提供出色的性能,尤其是在处理大量高分辨率图像时,不会占用过多内存或影响浏览器的流畅度。

流畅的过渡

应用实现了一种导航机制:拦截用户点击,并在不重新加载整个页面的情况下将下一页动态载入 DOM。这确保了界面状态(例如视觉主题或主导航)保持连续。

深色模式持久化

深色/浅色配色方案从系统中检测,并在用户的各次会话之间保持一致。得益于与页面过渡的同步,在不同视图之间导航时不会出现视觉闪烁。


查看器的核心:播放器

在浏览数千张图像时(例如,一年的 Analemma 包含 365 帧高分辨率画面),一个关键挑战是终端用户设备的内存可能耗尽。为此,图像播放器采用了轻量且经过优化的架构:

stateDiagram-v2
    [*] --> Initialization: 加载数据集 URL
    Initialization --> BufferedLoading: 预加载第一张图像(预览)
    BufferedLoading --> BackgroundLoading: 渐进式批量加载
    BackgroundLoading --> Ready: 达到最低阈值(例如 20%)
    Ready --> Playback: 用户开始播放
    Playback --> Tick: 根据 FPS 更新图像
    Tick --> UpdateFrame: 渲染下一帧
    UpdateFrame --> Playback: 如有更多帧则循环

1. 异步缓冲加载(Buffered Loading)

播放器不会强制浏览器在允许交互之前下载全部图像,而是启动一个后台进程,以小批量异步方式下载图像。当本地已有最低比例的帧可用时即启用播放,从而避免画面卡顿。

2. 动态速度控制

用户可以完全控制播放速度,并可实时调整。播放器会即时重新计算帧之间的切换间隔(FPS),且不会中断播放。


无需关系型数据库的索引

整个系统的设计无需 SQL 或 NoSQL 数据库等复杂基础设施。

取而代之的是,Web 查看器在构建过程中直接为存放图像的静态目录结构(captures/)建立索引:

graph LR
    A["构建过程"] -->|读取文件系统| B(静态目录 'captures/')
    B --> C{解析层级结构}
    C -->|按地点和摄像头分类| D[对摄影序列进行分组]
    D --> E[生成 JSON 元数据索引]
    E -.->|为 Web 视图提供数据| F(渲染与 UI 筛选)

Web 界面使用这一轻量索引,可在客户端执行快速、精确的筛选,而无需额外的网络请求或产生延迟。


面向移动设备与离线使用

Web 查看器具备多项高级功能,以扩大其适用范围:

  • 优化的元数据,确保在社交网络上分享的链接包含具有代表性的图像和描述。
  • 配置为 Progressive Web App (PWA),可直接安装到设备上。
  • 基础离线模式,通过 Service Worker 实施缓存策略,即使在网络不稳定时也能提供连续的体验。
  • 自托管字体,避免额外的加载时间或对外部服务器的依赖。

拖动可移动图示。按 + 和 − 缩放,方向键移动,0 重置视图。

一起合作

软件工程师、高级全栈开发工程师,常驻玻利维亚Santa Cruz,远程办公。欢迎新的工作机会。