一款開源的離線溫習計時 PWA(漸進式網頁應用)。把「倒數計時」「番茄工作法」「階段提示音」與「自選背景音樂」整合在一起,自動記錄每日學習時長,幫你專心溫習、也知道「今天溫習了多久」。
- 四個分頁:計時 / 日曆 / 音樂 / 設定
- 平台:Android 手機(Chrome)+ Windows 電腦(Chrome / Edge)
- 技術形態:PWA,可「加到主畫面」當 App,可安裝到桌面,斷網也能用
溫習時常遇到的痛點:
- 想專心一段固定時間,但手機計時器不會自動記錄「今天累計溫習多久」。
- 番茄工作法能逼自己有規律地學,但原生鬧鐘沒有「階段輪流 + 自動統計專注時數」且休息不計入。
- 想邊聽自己喜歡的音樂邊溫習,又不想每次重開 App 都重新選檔。
- 隱私與離線:不想登入、不想上傳任何資料到雲端,所有數據只存在自己設備上。
- 手機放後台 / 被系統清掉記憶體後,計時不準甚至歸零。
這個 App 把上述全部做成一個本地、離線、無登入的工具:計時準(用牆上時鐘追趕)、記錄自動累計、音樂一次存入、數據只存本機,且兩台設備各自獨立(靠匯出 / 匯入手動搬移)。
| 模塊 | 功能 |
|---|---|
| 倒數計時 | 自由設時長(分 / 秒);開始、暫停 / 繼續、重置、結束;快捷 25 / 45 / 60 分;結束播提示音 + 通知;進行中時間計入日曆。 |
| 番茄工作法 | 專注 / 短休息 / 長休息 / 循環數全部可調;自動輪流切換;切換播對應提示音;顯示「第 X/Y 個番茄 · 專注中」與進度;可跳過 / 提前結束;只有專注階段計入學習時長,休息不計。 |
| 提示音效 | 內置 4 款離線合成音效(輕快上行 / 溫和下行 / 鈴聲 / 單音叮),「開始學習」與「休息結束」可分別選;音量調節;手機可震動。 |
| 學習日曆 | 月曆每天顯示總時長(顏色深淺表示久短);點某天看明細(時段 + 來源:倒數 / 番茄專注);頂部顯示今日 / 本週 / 本月 / 連續天數。 |
| 音樂播放器 | 首次啟動自動播種 9 首 AI 生成預設音樂;亦可從設備加入自己的音檔(以 Blob 存 IndexedDB,重開不丟);播放 / 暫停 / 上一首 / 下一首 / 循環 / 隨機;音量;與計時聯動(專注自動播、休息自動停,可關)。 |
| 設定 | 所有時間參數、提示音、主題(淺色 / 深色 / 像素二次元)、音樂聯動,全存本機,即時生效;匯出 / 匯入記錄。 |
| 後台計時準確 | 計時一律用 Date.now() 差值;每次狀態變更把執行快照寫入 localStorage;App 回到前景(visibilitychange)或重啟時,依牆上時鐘追趕後台期間流逝的時間,並重播已完成的番茄階段——放後台 / 被殺再回來,剩餘時間依然準確。 |
| 離線 / 安裝 | Service Worker 預緩存全部資源,包含 9 首 mp3;可「加到主畫面」當 App,斷網照常使用。 |
兩個計時模塊完全獨立:切換倒數 / 番茄只換顯示,不會重置或互相干擾——另一個模塊會繼續在背景計時。
- Node.js 18+(僅開發 / 打包需要;打包出的純靜態檔在手機上不需要 Node)
- npm(隨 Node 附帶)
git clone https://github.com/youyou9179/study-timer.git study-timer
cd study-timer
npm install| 指令 | 說明 |
|---|---|
npm run dev |
啟動本地開發伺服器(預設 http://localhost:5173),即時預覽 |
npm run build |
打包成靜態檔到 dist/(含 PWA manifest + service worker) |
npm run preview |
本地預覽打包結果(http://localhost:4173) |
npm run test |
執行全部單元測試(Vitest) |
npm run test:watch |
測試監看模式 |
npm run build產出dist/。- 把
dist/部署到任意靜態託管(GitHub Pages / Netlify / Cloudflare Pages 等,需 HTTPS)。- 本專案
base設為./,可直接放在https://youyou9179.github.io/study-timer/這類子路徑。
- 本專案
- 手機用 Chrome 開啟網址 → 選單「加到主畫面」;電腦用 Chrome / Edge 開啟 → 網址列「安裝」圖示。
- 安裝後即為獨立 App,且完全離線運作,資料只存在該設備。
託管只用作「安裝入口」與靜態檔下載;App 執行時不發出任何網路請求、不上傳資料,不違反「無雲端」約束。
開啟 App 後預設進入計時分頁。
- 頂部切換
倒數/番茄。 - 倒數:點
25 / 45 / 60設時長(或到設定改預設值)→ 按開始;可暫停 / 繼續、重置。 - 番茄:按
開始後自動輪流專注 → 短休息 → …;可跳過當前階段、結束整組。 - 切換分頁或放後台都不影響計時;回到 App 會立即依真實時間校正。
- 看當月每天學習時長(顏色越深代表越久)。
- 點某天看該日明細(時段與來源:倒數 / 番茄專注)。
- 頂部顯示今日 / 本週 / 本月總時長與連續天數。
- 用
‹›切換月份。
- 首次啟動已有 9 首預設音樂,直接播放 / 暫停 / 上一首 / 下一首。
- 點「加入音樂」從設備選自己的音檔(支援多選),會存入本機資料庫、下次免重選。
- 切換循環 / 隨機、調音量;可刪除曲目釋放空間。
- 設定中的「專注自動播 / 休息自動停」開關控制與計時聯動。
- 倒數預設、番茄(專注 / 短休 / 長休 / 幾個後長休):即時生效。
- 提示音:開始學習 / 休息結束分別選音效、音量、震動開關。
- 外觀:淺色 / 深色 / 像素二次元。
- 備份:
匯出記錄下載一份study-timer-backup.json;匯入記錄選該檔還原(會覆蓋本機記錄)。
輸入(設定倒數預設 25 分,或點快捷 25):
倒數預設 = 25 分
過程與輸出(大字顯示逐秒倒數):
25:00 → 24:59 → … → 00:01 → 00:00
結束時:播放「休息結束」提示音 → 彈系統通知「溫習完成:呢節倒數計時完成啦!」→ 把這 25 分鐘寫入當日日曆(來源:倒數)。
輸入(設定:專注 25 / 短休 5 / 長休 15 / 4 個後長休):
pomodoro = { focusSec: 25*60, shortSec: 5*60, longSec: 15*60, cyclesBeforeLong: 4 }
自動輪流(每階段切換播對應提示音):
第 1 個番茄 · 專注中 (25:00 倒數) → 短休息 (05:00) →
第 2 個番茄 · 專注中 → 短休息 →
第 3 個番茄 · 專注中 → 短休息 →
第 4 個番茄 · 專注中 → 長休息 (15:00) → 回到第 1 個番茄 …
統計規則:只有「專注」階段的秒數計入學習時長;短休 / 長休不計。
| 呼叫 | 輸出 |
|---|---|
formatTime(1500) |
"25:00" |
formatTime(3661) |
"01:01:01" |
formatDuration(1800) |
"30 分" |
formatDuration(3900) |
"1 小時 5 分" |
formatDuration(45) |
"45 秒" |
今日 1 小時 5 分
本週 4 小時 20 分
本月 12 小時 0 分
連續 6 天
點某天明細示例:
2026-08-30
總時長:1 小時 5 分
- 倒數 · 25 分
- 番茄專注 · 40 分
{
"version": 1,
"exportedAt": "2026-08-30T11:00:00.000Z",
"settings": {
"countdownDefaultSec": 1500,
"pomodoro": { "focusSec": 1500, "shortSec": 300, "longSec": 900, "cyclesBeforeLong": 4 },
"sound": { "startStudy": "chime-up", "breakOver": "chime-down", "volume": 0.7, "vibrate": true },
"theme": "light",
"musicLink": true,
"playlistOrder": ["default_lofi_piano", "t_123456_abc"]
},
"sessions": [
{ "date": "2026-08-30", "totalSec": 3900, "entries": [
{ "startTs": 1756543200000, "endTs": 1756544700000, "source": "countdown", "sec": 1500 },
{ "startTs": 1756545000000, "endTs": 1756547400000, "source": "pomodoro-focus", "sec": 2400 }
] }
],
"music": [
{ "id": "default_lofi_piano", "name": "Lo-fi 鋼琴 Lo-fi Piano", "mime": "audio/mpeg", "data": "<base64>" },
{ "id": "t_123456_abc", "name": "我的歌.mp3", "mime": "audio/mpeg", "data": "<base64>" }
],
"playlistOrder": ["default_lofi_piano", "t_123456_abc"]
}| 曲名 | 檔案 |
|---|---|
| 木吉他 Acoustic Guitar | music/acoustic_guitar.mp3 |
| 環境節拍 Ambient Beats | music/ambient_beats.mp3 |
| 舒緩鋼琴 1–5 Chill Piano 1–5 | music/chill_piano_1.mp3 … chill_piano_5.mp3 |
| 古典鋼琴 Classical Piano | music/classical_piano.mp3 |
| Lo-fi 鋼琴 Lo-fi Piano | music/lofi_piano.mp3 |
播種只在每個設備發生一次(由
meta.seededDefaultMusic標記保證);你刪掉預設曲也不會自動補回。
AI 生成音樂標註:以上 9 首預設背景音樂均由 ACE-Step 1.5(MIT) 於本機生成,其來源、授權狀態與免責聲明詳見
public/music/MUSIC_CREDITS.md。
study-timer/
├─ index.html # 單頁入口,掛載 #app
├─ package.json
├─ vite.config.js # 含 vite-plugin-pwa 設定(manifest + service worker)
├─ public/
│ ├─ music/ # 9 首預設音樂 mp3(離線預緩存)
│ └─ icons/ # PWA 圖標 192 / 512 / maskable
├─ src/
│ ├─ main.js # 啟動、分頁路由、主題套用、前景同步
│ ├─ state/
│ │ ├─ db.js # IndexedDB 封裝:settings / sessions / music / meta
│ │ └─ store.js # 中央狀態:設定、計時、音樂、後台追趕、匯出匯入
│ ├─ timer/
│ │ ├─ engine.js # 計時核心(timestamp 精準、可序列化)
│ │ ├─ countdown.js # 倒數模式
│ │ └─ pomodoro.js # 番茄模式(自動輪流 + 階段切換 + 追趕)
│ ├─ audio/
│ │ ├─ sounds.js # WebAudio 合成內置提示音 + 音量
│ │ ├─ notify.js # 系統通知 + 震動
│ │ ├─ musicPlayer.js # 本地音樂播放器
│ │ └─ defaultMusic.js # 預設音樂清單 + 首次播種
│ ├─ modules/
│ │ ├─ timerView.js # 計時分頁
│ │ ├─ calendarView.js # 日曆分頁
│ │ ├─ musicView.js # 音樂分頁
│ │ └─ settingsView.js # 設定分頁
│ ├─ utils/
│ │ ├─ time.js # 時間格式化、日期鍵、streak 計算
│ │ └─ backup.js # 匯出 / 匯入(JSON + Blob base64)
│ └─ styles/
│ └─ main.css # 主題變數、排版、手機/電腦響應式
└─ (sw.js 由 vite-plugin-pwa 自動生成,勿手改)
- 不登入、不聯網、無雲端:App 執行期間不發出任何網路請求,無上傳行為。
- 數據全存本機:學習記錄、設定、音樂檔皆存於設備的 IndexedDB(等同本地檔);計時執行快照存 localStorage 以支援後台追趕。
- 兩台設備各自獨立:手機與電腦不會自動同步;跨設備搬移唯一方式是設定頁的「匯出 / 匯入」。
npm run test涵蓋:計時核心(倒數 / 番茄)、後台真實時間追趕、模式獨立、預設音樂播種、提示音、日曆統計、備份匯出匯入、建置產物驗證等。
- PWA 無法像原生 App 那樣在通知欄常駐一條通知;本專案以「牆上時鐘追趕」保證計時準確(而非常駐通知)。
- 預設音樂共 9 首(約 26MB),會隨網站一併預緩存;若想減小體積可改為外部連結或壓縮。
- 手機安裝 PWA 需要 HTTPS;離線可用,但部分瀏覽器在長時間完全斷網後可能需重新整理一次以更新 service worker 快取。
- 程式碼以 MIT License 釋出,詳見 LICENSE。
- 預設背景音樂由 ACE-Step 1.5(MIT) 於本機生成,其授權與免責聲明見 public/music/MUSIC_CREDITS.md;音樂素材授權與程式碼授權獨立,使用時請另行保留該聲明。
- 本專案為離線、無雲端工具;若你自行部署,託管服務僅作靜態檔下載與安裝入口之用。