A clean, minimal desktop Timer & Stopwatch app (inspired by Microsoft Clock). Built with Electron Forge (webpack) and React + Tailwind. Timers persist locally in SQLite and the app can speak a message when a timer finishes. Download
- Screenshots
- Features
- Tech stack
- Install & run
- Scripts
- Preload / IPC API (exact names)
- SQLite schema
- Project structure (high-level)
- How it works (high-level)
- Roadmap / TODO
- Release
- License
- Create / edit / delete timers
- Timers can include an optional message that will be spoken via TTS (
say) when the timer finishes - Default ringtone plays when a timer finishes
- Multithreading with Web Worker API to manage timers and stopwatch
- Stopwatch with Start / Pause / Reset and Lap marking
- Local persistence using SQLite (
better-sqlite3) - Secure IPC via a
preloadbridge (contextBridge.exposeInMainWorld) - TypeScript + Node ESM in the main process
Planned (future): Settings screen, Alarm screen, custom ringtones, export laps.
- Electron (Electron Forge + webpack)
- React (frontend)
- Tailwind CSS (styling)
- TypeScript (renderer & main)
- Node ESM (
"type": "module"inpackage.json) better-sqlite3for local storagesayfor text-to-speech
git clone https://github.com/LH-10/ItsTime-ElectronProject.git
cd ItsTime-ElectronProject
npm install
npm run dev:start # or: npm startBuild / package:
npm run package
npm run makeYour package.json scripts:
"scripts": {
"dev:start": "electron-forge start",
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make",
"publish": "electron-forge publish",
"lint": "eslint --ext .ts,.tsx ."
}npm install will install dependencies; use npm run dev:start or npm start to run the app in development.
In preload.ts you expose the API as: #this code is there in preload folder timerpreload file
contextBridge.exposeInMainWorld('timeApi', {
timer: {
addNewTimer: /* function */,
editTimer: /* function */,
deleteTimer: /* function */,
}
});- The exposed object name is
timeApi. - Timer APIs live at
timeApi.timer.*. - Recommended: implement these functions using
ipcRenderer.invoke(...)inside the preload so they returnPromises (main process handles DB operations).
Timers are stored in a local SQLite table. The fields are:
id— unique identifier for each timer, INTEGER PRIMARY KEY AUTOINCREMENTseconds— total duration in seconds (INTEGER)title— human-readable title for the timer (TEXT)message— optional message to be spoken when the timer ends (TEXT)
Example conceptual CREATE statement: #Its included in the index.ts file
CREATE TABLE IF NOT EXISTS timers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
seconds INTEGER NOT NULL,
title TEXT,
message TEXT
);Notes:
- All create / update / delete operations are performed in the main process and persisted with
better-sqlite3. - On app startup the main process reads the
timerstable and serves data to the renderer through the preload API.
The-app/
├─ src/
│ ├─ alarms/ # future alarm logic
│ ├─ app-assets/
│ ├─ database/ # sqlite wrappers and schema (timers table)
│ ├─ ipc/ # ipc channel definitions / handlers (main)
│ ├─ preload/ # preload.ts - exposes timeApi
│ ├─ React/ # React app (components, pages)
│ ├─ types/ # shared TS types
│ ├─ ui-assets/
│ ├─ index.css
│ ├─ index.html
│ ├─ index.ts # Electron main (ESM)
│ ├─ preload.ts
│ ├─ renderer.ts
│
├─ .eslintrc.json
├─ forge.config.ts
├─ package.json
- Persistence: timers data is stored locally in SQLite (
better-sqlite3). The main process accesses the DB. - IPC & Security:
preload.tsexposestimeApiviacontextBridge.exposeInMainWorld. Renderer callstimeApi.timer.*to request create / update / delete operations from the main process. Renderer does not accessipcRendererdirectly. - Timer finish: when a timer reaches zero the app plays the default ringtone and uses
sayto speak the timermessage(if provided). - Syncing: main process handles DB changes and returns results to the renderer so UI stays in sync.
- Settings screen (app preferences)
- Alarm screen (scheduled alarms, repeats)
- Allow custom ringtones
- Export / save stopwatch laps locally
- Add tests and CI
- Accessibility and keyboard shortcuts
Download the App Installer
You can download the app installer from this link: Installer Link
This project is licensed under the MIT License.

