Skip to content

yuanzihao/Gaze20

Repository files navigation

远眺 Gaze20

一款本地优先、低打扰的 Windows 桌面护眼提醒工具

按 20-20-20 法则帮你科学用眼:每用眼约 20 分钟,抬头远眺 20 英尺(6 米)外 20 秒。 它会感知你是否真的在看屏幕、会在开会/全屏时自动让路,并把用眼、提醒、症状自评沉淀成本地、可追溯的趋势数据。

平台 技术栈 许可证


目录


它解决什么问题

长时间盯着屏幕会导致数字视疲劳(Digital Eye Strain):眼干、视物模糊、头痛、肩颈僵硬。眼科普遍推荐的缓解方法是 20-20-20 法则——每 20 分钟,看向 20 英尺(约 6 米)外的物体,持续 20 秒,让睫状肌放松、并通过完整眨眼补充泪膜。

市面上的提醒软件大多有两个毛病:

  1. 机械计时——不管你是在专注敲代码,还是早就离开了座位,它都照样弹窗,久而久之让人反感、直接关掉。
  2. 粗暴打断——一弹就是全屏黑幕盖住整个桌面,把"提醒"做成了"强制"。

远眺 Gaze20 针对这两点重新设计:只在你真正用眼时计时只用一张屏幕中央的小卡片温柔提示,并且在每块显示器上同步出现


核心特性

特性 说明
🧠 活动感知计时 通过系统空闲时间 + 前台窗口判断你是在敲键盘、在阅读、还是已离开,按权重累计"有效用眼时间",而非死板的墙上时钟。
🖥️ 多屏同步提醒 有几块显示器,就在几块显示器的正中央同时弹出提醒卡片,倒计时、按钮状态和操作结果同步。
🌿 温柔不霸屏 提醒是约屏幕 1/10 的小卡片,带呼吸式倒计时环和轻量入场动画;四周桌面照常可见——是提醒,不是遮挡。
🤫 自动让路 检测到全屏/会议/演示(Zoom、Teams、PPT 放映、OBS、播放器、游戏等)时,到点的微休息会自动延后而不是打断你。
⏱️ 微休息 + 深休息 微休息(远眺 20 秒)防急性疲劳;深休息(起身 3–5 分钟)防久坐,二者独立计时。
🎚️ 三档强度 保守 / 平衡 / 激进,对应不同的提醒间隔与时长,按你的工作强度选。
📈 本地趋势统计 用眼时长、远眺完成率、风险评分、每小时用眼热力图、按 App 用眼用眼构成(主动/阅读/会议)、症状趋势,全部本地留存、可回溯。
🩺 症状自评 记录眼睛红血丝、眼干、模糊、头痛、肩颈 5 项评分;弹窗会根据严重程度切换表情,且在休息提醒进行中会自动延后。
🔕 勿扰与暂停 一键勿扰、暂停记录、延后 5 分钟、立即远眺;托盘常驻,最小化运行。
🧪 工程模式 设置页内置隐藏工程工具,可手动预览微休息、深休息、症状自评弹窗,调节眼睛分数并开启快速演示模式。
💾 稳健的数据层 本地 SQLite(WAL)+ 显式 schema 迁移链 + 迁移前自动备份 + 损坏自动恢复 + 原始活动事实层 + 导出/导入迁移。
🔐 本地优先 所有数据只存在你自己的电脑上,不联网上传、不采集摄像头画面、不记录窗口标题。

隐私承诺

护眼软件不该成为隐私黑洞。远眺 Gaze20 的设计原则:

  • 不采集摄像头画面。 用眼检测完全基于系统空闲时间和前台进程名,不读取任何图像。
  • 不持久化窗口标题。 前台窗口标题仅在内存中用于"是否会议/全屏"的关键词判断,绝不写入磁盘、绝不显示;落地与展示的只有进程名(如 chrome.exe)。
  • 不联网。 数据全部存在本地 SQLite,没有云同步、没有遥测。(仅"检查更新"在你手动点击时才会访问你自行配置的更新地址。)
  • 数据随时可带走。 设置页可一键导出全部数据为 JSON,换机/重装时再导入(幂等去重,不覆盖本机数据)。

详见源码 src-tauri/src/lib.rsvisible_process_label() 的隐私注释。


工作原理

核心是一个纯逻辑状态机src-tauri/src/engine.rs),由 Rust 端每秒驱动一次:

                 每 1 秒
  ┌───────────────────────────────────────────────────────────┐
  │  采集活动快照 (Win32)        推进状态机          执行副作用   │
  │  ─────────────────          ──────────         ──────────  │
  │  · 系统空闲秒数              · 累计有效用眼      · 弹出提醒卡 │
  │  · 前台进程 / 全屏          · 判断微/深休息到点  · 写事件日志 │
  │  · 会议/全屏 → 该让路吗     · 计算风险评分       · 落地聚合表 │
  │            │                      │                  │      │
  │            └──── eye_weight ──────┴──── Decision ─────┘      │
  └───────────────────────────────────────────────────────────┘

有效用眼时间不是简单的开机时长,而是按活动状态加权累计:

状态 判断依据 计时权重
键鼠活跃 空闲 ≤ 60 秒 ×1.0(满额计时)
疑似阅读 无输入但在浏览器/编辑器/PDF 等,且未超过"阅读宽限" ×0.7
全屏/会议中阅读 同上但正在放映/会议 ×0.45(轻量计时并延后提醒)
已离开 空闲 ≥ "离开判定"分钟 ×0(暂停累计)

三档强度预设:

模式 微休息间隔 深休息间隔 远眺时长 深休息时长
保守 30 分钟 90 分钟 20 秒 3 分钟
平衡(默认) 20 分钟 60 分钟 20 秒 3 分钟
激进 15 分钟 45 分钟 30 秒 5 分钟

风险评分(0–100) 综合连续用眼时长、当日总时长、微休息完成率、远眺达成度、当前用眼压力和当天症状自评六项,映射为"眼睛状态"评分与配图,让你对疲劳程度一目了然。

状态机是纯函数、与 Tauri/数据库解耦,因此可被单元测试覆盖(见 engine.rs 末尾的测试)。它的状态会持久化,重启后能恢复当天进度

提醒弹窗由 public/overlay.html 渲染,Rust 侧的 OverlayCoordinator 负责协调弹窗优先级:休息提醒优先显示;如果症状自评刚好到点,会等休息提醒结束后再弹,避免多屏场景下出现两个弹窗互相覆盖。


界面一览

  • 今日概览:眼睛状态、实时用眼评分、当前连续专注时长、下次提醒倒计时、今日用眼时间轴、今日建议。
  • 提醒中心:今日提醒记录(完成 / 延后 / 跳过 / 自动延后)。
  • 趋势统计:多日用眼时长、远眺完成率、风险评分趋势、每小时用眼热力图、风险构成、症状趋势和趋势洞察。
  • 症状记录:眼睛红血丝 / 眼干 / 模糊 / 头痛 / 肩颈五项自评打分与历史,支持单独导出。
  • 设置:强度模式、检测参数(阅读宽限、离开判定)、勿扰、开机自启、检查更新、数据导出/导入、保留天数、每日症状提醒、工程模式。
  • 提醒卡片(独立窗口):屏幕中央的小卡片,带 3D 感倒计时点、入场动效、开始休息 / 完成休息 / 延后 / 跳过。
  • 症状自评弹窗(独立窗口):5 项评分 + 表情状态卡;越严重表情越难过,提交后写入本地 SQLite。

安装与使用

方式一:直接安装(推荐普通用户)

  1. Releases 下载最新的 远眺 Gaze20_x.y.z_x64-setup.exe(NSIS 安装包)、远眺 Gaze20_x.y.z_x64_zh-CN.msi,或免安装版 远眺_Gaze20_x.y.z_portable_x64.zip
  2. 双击安装。首次运行后程序常驻系统托盘,最小化时仍在后台计时。
  3. 右键托盘图标可:打开主界面 / 立即远眺 / 暂停记录 / 退出。

⚠️ 当前安装包尚未代码签名,Windows SmartScreen 可能提示"未知发布者"。签名方案见 doc/RELEASE.md。建议优先用安装包安装(而非直接拷贝 exe),否则系统通知(toast)可能因缺少开始菜单快捷方式而不弹。

方式二:从源码构建

见下方 本地开发构建与发布

平台说明:活动感知依赖 Windows API(GetLastInputInfo、前台窗口、注册表自启),目前仅完整支持 Windows 10/11。非 Windows 平台可编译运行 UI,但活动检测为模拟桩。


数据与文件位置

所有数据都在你本机的应用数据目录下:

文件 路径 说明
主数据库 %APPDATA%\com.gaze20.desktop\gaze20.db SQLite(WAL),全部用眼/提醒/症状/聚合数据
数据库备份 同目录 gaze20.db.bak* 迁移前备份 + 滚动 24h 备份
运行日志 %LOCALAPPDATA%\com.gaze20.desktop\logs\gaze20.log 排障用
旧版数据 %APPDATA%\com.gaze20.desktop\gaze20-data.json 旧 JSON,首启自动迁移进 SQLite 后备份为 .json.bak

卸载后如需彻底清除,删除上述 com.gaze20.desktop 目录即可。


技术架构

┌──────────────────────────── 前端 (WebView2) ────────────────────────────┐
│  React 18 + TypeScript + Vite                                            │
│  · 主窗口  index.html → src/App.tsx(概览/趋势/症状/设置)               │
│  · 提醒卡  public/overlay.html(独立窗口,纯 HTML/CSS/JS,无框架)        │
└───────────────▲───────────────────────────────────────▲────────────────┘
                │  invoke 命令 / 监听 engine-state 事件     │  overlay-action
                │                                          │  overlay-start
┌───────────────┴──────────────── Rust 核心 (Tauri 2) ─────┴────────────────┐
│  engine.rs   纯状态机:计时、微/深休息判定、风险评分(单元测试覆盖)       │
│  lib.rs      1 秒权威循环、Win32 活动快照、托盘、命令、多屏提醒与弹窗调度 │
│  db.rs       SQLite:迁移链 / 事实表 / 聚合表 / 备份 / 恢复 / 导出         │
│  插件        single-instance · notification · log · updater              │
└───────────────────────────────────▲─────────────────────────────────────┘
                                     │
                          ┌──────────┴──────────┐
                          │  gaze20.db (SQLite) │
                          └─────────────────────┘

技术选型:

  • Tauri 2 —— 体积小、内存占用低,复用系统 WebView2,无需打包 Chromium。
  • Rust 拥有状态机与数据 —— 计时与判定不依赖前端是否打开,重启不丢上下文,关键逻辑可单测。
  • SQLite(rusqlite,bundled) —— SQLite 编译进二进制,免去系统依赖;WAL 模式 + 显式迁移链保证数据可演进、可恢复。
  • 独立 overlay.html 提醒窗 —— 与主应用解耦的轻量卡片,多屏各一份、逻辑像素居中、不透明不霸屏,并支持休息提醒与症状自评两种模式。
  • OverlayCoordinator 弹窗协调器 —— 休息提醒优先,症状自评自动排队,避免同一时间多屏弹窗互相覆盖或误关。

数据库表(SCHEMA_VERSION = 7): app_metasettingsactivity_sessionsreminder_eventsreminder_sessionssymptom_recordsdaily_statshourly_stats。其中 symptom_records 已包含 redness(眼睛红血丝)维度,并通过当天最新自评参与风险评分。


项目结构

Gaze20/
├─ index.html                 主窗口入口
├─ src/                       前端 (React + TS)
│  ├─ App.tsx                 全部页面与组件
│  ├─ main.tsx                React 挂载
│  └─ styles.css              样式
├─ public/
│  ├─ overlay.html            提醒卡片(独立窗口)
│  └─ eyes/                   眼睛状态配图 (webp,构建产物用)
├─ src-tauri/                 Rust + Tauri
│  ├─ src/
│  │  ├─ lib.rs               主逻辑:循环/命令/托盘/活动快照/提醒窗/弹窗调度
│  │  ├─ engine.rs            纯状态机(含单元测试)
│  │  ├─ db.rs                SQLite 数据层(含单元测试)
│  │  ├─ native_reminder.rs   备用的原生 GDI 渲染器(当前未启用)
│  │  └─ main.rs              入口
│  ├─ capabilities/           Tauri 权限能力
│  ├─ tauri.conf.json         应用与打包配置
│  └─ Cargo.toml
├─ scripts/                   构建辅助(图标生成、眼图优化)
├─ CHANGELOG.md               版本发布记录
├─ doc/                       发布与产品化文档
│  ├─ RELEASE.md              代码签名 + 自动更新配置
│  └─ PRODUCTION-READINESS.md 产品化待办清单
└─ .github/workflows/         Windows 构建与发版 CI

本地开发

前置要求: Node.js ≥ 18、Rust stable、Windows 上需 WebView2 运行时(Win10/11 一般已内置)。

# 安装前端依赖
npm install

# 开发模式(热重载;同时起 Vite 与 Tauri)
npm run tauri dev

# 仅跑前端(浏览器里调 UI)
npm run dev:web

运行测试:

# Rust 单元测试(状态机 + 数据库 + 弹窗调度,当前 26 个)
cargo test --manifest-path src-tauri/Cargo.toml

# 前端类型检查
npx tsc --noEmit

# Rust 静态检查(CI 同步执行)
cargo clippy --manifest-path src-tauri/Cargo.toml --all-targets -- -D warnings

# 前端生产构建
npm run build

自检提醒卡片(无需等到点):设置环境变量 GAZE20_SELF_TEST_REMINDER=1 后启动,程序会在 ~1.5 秒后弹出休息卡片;设置 GAZE20_SELF_TEST_SYMPTOM=1 可直接弹出症状自评卡片。设置页里的“工程模式”也能手动预览微休息、深休息和症状自评。


构建与发布

# 产出 Release 可执行文件 + MSI + NSIS 安装包
npm run tauri build
# 产物位于 src-tauri/target/release/ 及 bundle/{msi,nsis}/

CI(.github/workflows/build.yml)会在向 main / develop 推送、提交 PR 或手动触发时,于 windows-latest 上执行 tsccargo testclippy -D warnings 和 Tauri release 构建,并上传 exe 与安装包产物。发布记录见 CHANGELOG.md

代码签名自动更新的脚手架已接好,但证书、更新签名私钥、更新服务器属于你自己的基础设施,需自行补齐——完整步骤见 doc/RELEASE.md

⚠️ 自动更新私钥绝不能提交进 git


已知限制与路线图

当前版本(0.3.0)是一个功能完整、可日常使用的版本,但作为面向大众的成熟产品仍有打磨空间。完整的产品化待办见 doc/PRODUCTION-READINESS.md,要点:

  • 未代码签名 / 自动更新未配真实服务端 —— 安装会触发 SmartScreen 警告;更新链路就绪但指向占位地址。
  • 风险模型仍是启发式模型 —— 已纳入症状自评,但权重仍来自产品判断,后续需要更多真实使用数据校准。
  • 前端仍是单文件主应用 —— App.tsx 已承载多页面和数据转换,后续应拆分成页面、hooks 与 Tauri 命令层。
  • 仅支持简体中文、无障碍能力有限 —— 暂无 i18n 与完整键盘导航。
  • 仅 Windows —— 活动检测依赖 Win32,跨平台需补适配。

欢迎按 PRODUCTION-READINESS.md 的优先级提 issue / PR。


许可证

Apache License 2.0

作者:yuanzihao

About

远眺 Gaze20 — 护眼提醒软件

Resources

License

Stars

3 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors