A Browser Extension That Knows When You Actually Left Your Desk
Foreword
How are your lower back and neck doing?
I basically spend over 8 hours a day staring at a screen now. A sore neck and back pain have become routine X﹏X
One morning, I woke up and my neck suddenly couldn't move — it hurt whenever I tried. I went to the hospital and got an X-ray......
The doctor took one look and asked: Are we in the same profession?
Me: I work in computers.
Doctor: That explains it. We both have jobs that require sitting for long periods. Aren't we practically colleagues?
The diagnosis said it was typical cervical spine straightening and lumbar muscle strain caused by prolonged sitting! The advice was to stand up and move around at regular intervals. The logic is easy to understand; the hard part is actually doing it. It's not that I don't want to stand up, I genuinely forget every time. Once I get busy, two or three hours have flown by before I even realize it.....
I really needed a tool to remind me to do this thing I "want to do but always forget."
So what exactly should I use for reminders? I thought about phone alarms and smartwatches, but both have drawbacks. A phone on silent sitting on a desk is inaudible, and I don't wear a watch that often.
Then one day while working late, I was staring blankly at the screen when it suddenly hit me: I spend more time with my computer every day than with anyone else. The first thing I do when I start work is turn on the computer; the last thing I do when I finish is close it. Isn't this thing the companion that's always with me? Instead of finding a new tool to remind me, why not just let the computer do it itself?
Why a browser extension?
- Not everyone has a smartwatch, and even those who do might not wear it while working.
- Installing software on a company computer often requires approval, which is a hassle.
- The browser is always in use, and extensions load and run instantly.
- It has the lowest barrier to entry and is the fastest to get running.
As long as the browser is open during work, it can quietly guard my lumbar spine and cervical spine.
Repeatedly Discussing Product Requirements
To be honest, this extension didn't look like this from the start.
I talked about requirements with several friends who also sit for long periods, understanding their real office habits. Then we discussed user habits, product form, and interaction models. It went through many revisions before gradually taking its current shape.
After all those discussions, I realized that "reminding" is not just about setting a timer — locking the screen, meetings, rushing deadlines, taking breaks..... each scenario hides a different need. Core features like "Do Not Disturb when busy," "Lock screen equals rest," and "Continuous overtime tracking" were all added gradually.
How is it different from a regular timer?
In one sentence: It knows whether you've actually left your seat.
Think about your work habits — you lock the screen when going to the bathroom, getting water, or eating. Even if you forget to lock the screen, the computer will naturally enter an idle state after you leave. The extension captures these two signals to determine if you've stood up:
| Scenario | Regular Timer | Sedentary Reminder |
|---|---|---|
| Bathroom break, screen locked for 1 min | ❌ Unaware, pops up on schedule | ✅ Lock screen = rest, count +1, countdown resets |
| Get water, back in 20 secs | ❌ Pops up on schedule | ✅ Below threshold, continues accumulating |
| Go to a meeting, screen locked | ❌ Timer keeps running | ✅ Idle = rest, starts from 0 again upon return |
| Computer idle for 5 mins | ❌ Timer keeps running | ✅ Detects idle → treated as rested, count +1 |
| Rushing a deadline | ❌ Forcefully interrupts with popup | ✅ "Busy now" mode, no interruption but persistent warning |
| Computer shut down overnight | ❌ Shows 1440 minutes the next day | ✅ Auto-corrects, restarts |
| Changing work interval | ❌ Starts over from scratch | ✅ Retains accumulated time, new interval takes effect immediately |
Simply put: The moment the computer enters an idle state, it's treated as you having stood up — screen lock, timeout with no operation, all count. The instant idle is detected, the rest count automatically +1, and the countdown resets to zero; a new timing cycle only begins once you return and become active again. Both thresholds are adjustable.
Feature Overview
📊 Toolbar Popup
Click the icon to see the full picture:
- Real-time sit/stand timer + progress bar
- Precise countdown to the next reminder
- Consecutive usage days ("Goodbye Sedentary · Day X")
- Segmented text: Just starting → Focused → Get ready to move → Overtime → Severe overtime
- Today's statistics cards
- One-click operations: Pause / Rest Now / Reset
- Light / Dark theme toggle
- Menu button
Today's Statistics: Four Core Metrics at a Glance
At the bottom of the popup are four statistics cards, reflecting your sedentary status for the day in real-time:
| Metric | Meaning | How it's derived |
|---|---|---|
| 🕐 Today's Work | Total accumulated time in front of the computer today | Automatically sums sitting duration for each work cycle; idle periods are excluded |
| 🔄 Rest Count | Number of times you stood up and moved today | Auto +1 when computer enters idle/lock screen, or manual +1 by clicking "Start Rest" |
| 📏 Longest Sit | The longest single continuous sitting session today | Takes the max of the current sitting duration and the historical max upon each idle entry |
| 💯 Health Score | A comprehensive assessment from 0-100 | Calculated in real-time based on rest count and longest sit (details below) |
These four data points are interconnected: Work Duration determines the expected number of times you "should stand up," Rest Count shows how well you've met that, and Longest Sit reflects your worst single performance. All three feed into the Health Score algorithm to produce the final score.
Key implementation detail — the timing of updates for rest count and longest sit:
// When chrome.idle.onStateChanged detects idle/lock screen
let currentSitDuration = runtimeState.accumulatedWork || 0
if (runtimeState.workStartTime) {
currentSitDuration += Math.floor((Date.now() - runtimeState.workStartTime) / 1000)
}
// Update today's longest sit (take historical max)
const newMaxSitDuration = Math.max(runtimeState.todayMaxSitDuration || 0, currentSitDuration)
// Accumulate today's total work time
const newTodayWorkTotal = (runtimeState.todayWorkTotal || 0) + currentSitDuration
// Rest count +1
const newRestCount = runtimeState.todayRestCount + 1
await updateRuntimeState({
accumulatedWork: 0, // Countdown reset
todayRestCount: newRestCount,
todayWorkTotal: newTodayWorkTotal,
todayMaxSitDuration: newMaxSitDuration,
})
All data is stored in chrome.storage.local and automatically clears at midnight each day to start a new day's statistics.
🧘 Scheduled Reminder: Not an Alarm, but a Dialogue
When the time is up, a centered popup window and a system notification appear simultaneously (you can choose which one you want in settings).
Browser Popup
System Notification
| Button | Effect |
|---|---|
| 🛋️ Start Rest | Enters rest countdown, closes popup |
| ⏰ Wait 10 more minutes | Delays reminder, pops up again after 10 minutes (adjustable) |
| ✅ Just rested | Marks as false reminder, resets timer |
| 📌 Busy now, keep working | Do Not Disturb mode, no more popups but retains overtime warning |
Key Point: When you're rushing a deadline, you don't want to be interrupted, but you also don't want to pretend the health issue doesn't exist. After clicking "Busy now":
- The popup no longer appears
- But the timer does not stop, continuously accumulating overtime
- The toolbar badge turns red showing
! - The progress bar turns red + displays "Overtime X minutes" in real-time
- It only clears once you actually stand up (lock screen/idle exceeds threshold) or actively rest
This way, you always know how long you've been over time, and you can go move as soon as you finish the task at hand.
🖥️ Speaking of this full-screen reminder popup — its color scheme also took quite a while to adjust 🫥 The reminder window has a dark background with a red warning bar and a blue "Start Rest" button. On my original screen, the dark background looked dull. It wasn't until I switched to the RD270Q that I realized it was a screen color accuracy issue — it's factory-calibrated, has a coding mode (with a colored paper mode) and zonal contrast. The color layers in dark themes were instantly elevated, and I no longer had to repeatedly use DevTools to pick colors when adjusting CSS. The panel's anti-reflective coating is also handy — during the day when someone opens a window next to my desk, or at night when the desk lamp shines on it, the dark popup doesn't blur into a patch of glare ✌️✌️✌️.
📈 Health Score
A health score from 0-100 is automatically calculated daily, using a weighted two-dimensional model based on the day's actual work duration (fair even if you start in the afternoon):
- Rest Frequency Score (out of 60) — More rests mean a higher score; positive reinforcement carries greater weight.
- Sedentary Penalty Score (out of 40) — Longer overtime means more points deducted (linear ratio: a 1-minute overtime is immediately visible in the score drop).
Design philosophy: Encourage standing > Punish sitting. Standing up one extra time shows a noticeable score increase, providing strong positive feedback.
Special handling:
- Grace Period: Within the first full work cycle (e.g., < 45 minutes), before any reminder has triggered → directly 100 points, no premature anxiety.
- Just Started Today: No work data for the day yet → displays "🕐 Just started today," not misjudged as a rest day.
- Rest Day: Historical records show work less than half a cycle → marked as "😴 Rest Day," excluded from scoring.
Score Levels: 🏆≥90 Excellent | 💚≥80 Good | 💛≥60 Average | 🟠≥40 Poor | 🔴<40 Needs Improvement
📊 Health Log
A daily snapshot is automatically saved at midnight:
- A 7-day trend line chart (three parallel lines: stand count + work duration + health score)
- Paginated history table (rest days automatically marked as "😴 Rest Day," meaningless 0 scores are not displayed)
- Daily rating + personalized improvement suggestions
📦 Data Export / Import
No data loss when switching computers; one-click backup of all health records:
| Export Content | Description |
|---|---|
| Health Log | All historical dailyLog data (up to 90 days) |
| User Settings | All configurations: work interval, rest duration, reminder method, theme, etc. |
| Usage Days | The starting timestamp for "Goodbye Sedentary · Day X" |
Safety strategy during import:
- Log data: Does not overwrite existing local records (local data takes precedence)
- Configuration: Overwrites (import = restore preferences)
- Usage days: Takes the earlier date (protects your continuous record)
Exported as a standard JSON file, highly readable, ready for backup and restoration anytime.
⚙️ Flexible Configuration
| Config Item | Description |
|---|---|
| Work Interval | 1-120 minutes, default 45 |
| Rest Duration | 1-30 minutes, default 5 |
| Idle Threshold | 1-20 minutes, default 5 |
| Reminder Method | System Notification / Full-screen Popup / Both |
| Lock Screen Reset Threshold | How many seconds of screen lock counts as standing, default 30 secs |
| Theme | Light / Dark |
| Language | Chinese / English |
| Delay Reminder | 5-30 minutes adjustable, default 10 |
🖥️ Side note: Eyes dry after staring at the screen all day? It might not just be the sitting ಠಿ_ಠ When I was writing this extension, I switched to a BenQ RD270Q coding monitor. I originally just wanted a bigger screen, but I found that looking at code for long periods was surprisingly less tiring on the eyes (⊙o⊙). Especially when rushing a project late into the night, switching to night mode, combined with automatic smart brightness adjustment and low blue light, my eyes no longer felt as dry and sore as before.
Panoramic View
Night Mode
Low Blue Light
Technical Features
Entirely based on native technologies, zero build, zero dependencies, zero servers:
- Chrome Manifest V3 — Latest extension architecture
- Idle Equals Rest — Detecting idle immediately counts as one rest, countdown resets; new cycle starts only after becoming active again
- Multi-Signal Fusion Detection — Dual-channel judgment via lock screen + idle; either trigger counts as standing
- Precise One-Shot Alarm — Fires exactly on time, no polling; short time differences compensated with setTimeout for second-level accuracy
- Platform Adaptation — macOS system notification compatibility (automatically skips unsupported buttons/priority/requireInteraction fields) + Dock icon bounce alert
- Popup Anti-Duplication — Dual protection against tick and alarm race conditions; two reminder windows will never appear
- Timestamp Difference Timing — Not afraid of Service Worker being suspended
- Wake-Up Correction — Shutting down overnight won't display "Sat for 840 minutes"
- Hot Configuration Update — Changing work interval doesn't interrupt current timing; new duration takes effect immediately
- Health Score — 60/40 weighted model + linear overtime penalty; overtime is immediately perceptible, with a focus on positive reinforcement
- Smart Rest Day Identification — Distinguishes "just started today" from "confirmed rest day"; days with zero work hours in history are automatically marked as rest days, not polluting the score trend
- Continuous Overtime Tracking — Timer doesn't stop after reminder pops up; displays overtime duration in real-time
- Full Data Export/Import — One-click backup of logs + settings + usage days; seamless migration when switching devices
- Completely Offline — All data stored locally only, no network connection
Let's dive into a few core technical points below.
Core 1: Idle Equals Rest — No need to manually click "Start Rest"
Most sedentary reminder tools only manage timing and popups, without caring whether you've actually stood up. My approach is to monitor the system idle state; once it detects you've left, it immediately counts it as a rest:
// Listen for system idle/lock screen events
chrome.idle.onStateChanged.addListener(async (newState) => {
const runtimeState = await getRuntimeState()
if (runtimeState.state === STATE.PAUSED) return
if (runtimeState.state === STATE.RESTING) return
if (newState === 'active') {
// User is back: directly start a new countdown cycle (rest was already counted upon entering idle)
if (runtimeState.state === STATE.IDLE) {
await updateRuntimeState({
state: STATE.WORKING,
accumulatedWork: 0, // Start new cycle from 0
workStartTime: Date.now(),
restCountedInCurrentCycle: false,
})
await scheduleReminderAlarm()
}
} else {
// idle or locked: treated as rest, rest count +1, countdown reset
if (runtimeState.state !== STATE.IDLE) {
let currentSitDuration = runtimeState.accumulatedWork || 0
// Also include the time from workStartTime until now that hasn't been saved yet
if (runtimeState.state === STATE.WORKING && runtimeState.workStartTime) {
currentSitDuration += Math.floor((Date.now() - runtimeState.workStartTime) / 1000)
}
const newRestCount = runtimeState.restCountedInCurrentCycle
? runtimeState.todayRestCount
: runtimeState.todayRestCount + 1
await updateRuntimeState({
state: STATE.IDLE,
accumulatedWork: 0, // Countdown reset
todayRestCount: newRestCount, // Rest count +1
lastStandTime: Date.now(),
restCountedInCurrentCycle: true,
})
await chrome.alarms.clear(ALARM_REMINDER_FIRE)
}
}
})
The state flow is one sentence: Idle → Count rest + Reset → Active → Start timing again.
Going to the bathroom and locking the screen, getting water, leaving for a meeting — as long as the computer enters idle, it automatically counts as you having stood up. After you come back and unlock, a new countdown starts from 0.
Core 2: Precise One-Shot Alarm — Fires on time, no polling
MV3's Service Worker can be suspended at any time; relying on setInterval polling is simply unreliable. My approach is to directly calculate how many seconds are left until the target time and create a one-shot alarm:
async function scheduleReminderAlarm() {
await chrome.alarms.clear(ALARM_REMINDER_FIRE)
const [runtimeState, config] = await Promise.all([getRuntimeState(), getConfig()])
// Busy Do Not Disturb mode: no more auto-popups
if (runtimeState.reminderDismissed) return
// Only schedule in working state (idle state is already resting, no reminder needed)
if (runtimeState.state !== STATE.WORKING) return
const workDurationSeconds = config.workDuration * 60
const accumulated = runtimeState.accumulatedWork || 0
const elapsed = runtimeState.workStartTime ? Math.floor((Date.now() - runtimeState.workStartTime) / 1000) : 0
const remainingSeconds = workDurationSeconds - accumulated - elapsed
if (remainingSeconds <= 0) {
await fireReminderNow(config) // Already due: trigger immediately
return
}
// chrome.alarms minimum delay is 30 seconds; if longer, set by calculated delay
const delayInMinutes = Math.max(remainingSeconds / 60, 0.5)
chrome.alarms.create(ALARM_REMINDER_FIRE, { delayInMinutes })
// When remaining < 30 seconds, alarm will be clamped; use setTimeout as immediate compensation
if (remainingSeconds < 30) {
setTimeout(() => fireReminderNow(), remainingSeconds * 1000)
}
}
Any operation that changes the remaining duration (rest, pause, resume, config modification) calls this function to reschedule, ensuring precise triggering at the target time.
Core 3: Busy Do Not Disturb — "Busy now, keep working!"
When rushing a deadline, you don't want to be interrupted, but you also don't want to pretend the health issue doesn't exist. After clicking "Busy now," the timer doesn't stop, continuously accumulating overtime:
case 'DISMISS_REMINDER': {
const dismissState = await getRuntimeState();
// Calculate real sitting duration (including overtime part)
let currentSitDuration = dismissState.accumulatedWork || 0;
if (dismissState.state === STATE.WORKING && dismissState.workStartTime) {
currentSitDuration += Math.floor((Date.now() - dismissState.workStartTime) / 1000);
}
await chrome.alarms.clear(ALARM_REMINDER_FIRE);
await updateRuntimeState({
reminderDismissed: true,
accumulatedWork: currentSitDuration, // Don't reset! Keep real accumulated time
workStartTime: Date.now(),
});
// Note: does not increase todayRestCount, does not update lastStandTime (user hasn't actually stood up)
}
Behavior during dismissed state:
- Popup no longer appears
- Toolbar badge turns red showing
! - Progress bar turns red + displays "Overtime X minutes" in real-time
- Only clears once you actually stand up (system detects idle) or actively click rest
Development Anecdotes: From "a timer" to a 1100+ line state machine
Honestly, I initially thought it was just this timer — setTimeout for 45 minutes, pop a notification, done.
Then I discovered one edge case after another:
- How to handle timing when the screen is locked?
- Does
setIntervalstill run when the Service Worker is suspended? - What if shutting down overnight shows "Sat for 1440 minutes" the next day?
- Isn't it annoying to pop up when the user is busy?
- Won't users complain if changing settings resets the countdown from scratch?
Every solved problem introduced two new ones. In the end, service-worker.js grew to over 1100 lines, essentially a complete finite state machine: WORKING → IDLE → WORKING (normal cycle), WORKING → RESTING → WORKING (active rest), WORKING → PAUSED → WORKING (pause and resume)…… Each state transition needs to handle timing, notifications, icons, and storage synchronization.
🖥️ Around line 800, I started questioning my life choices, then looked up at the code — luckily the screen was big enough (●'◡'●)~ During that time, I was also tinkering with monitors. Previously, I coded on a laptop screen, scrolling back and forth through long files, constantly switching pages. When rushing projects late into the night, it was a real test of eyesight. Later, after switching to the BenQ RD270Q coding monitor, the strain on my eyes and neck from long coding sessions lessened somewhat. The RD270Q is a 27-inch 2K 3:2 productivity square screen (with a very high usable resolution). Using its companion software, I could split the editor into left and right columns, viewing
service-worker.json one side andpopup.json the other, finally eliminating the need to constantly Cmd+Tab between files. Before, writing this kind of cross-file state synchronization logic on a laptop screen, just switching windows would make me dizzy (◎﹏◎).....Reading long code is even better ^o^/! You can rotate it with one hand, directly turning it vertical. One screen can display over a hundred lines of code, no more frantic mouse wheel scrolling QAQ~
Core 4: Health Score Algorithm — Encourage standing > Punish sitting
The health score is calculated based on the day's actual work duration (fair even if you start in the afternoon), using a 60/40 weighted model:
function calcHealthScore(todayWorkTotalSeconds, restCount, maxSitDuration, workDurationMinutes) {
const workDurationSeconds = (workDurationMinutes || 45) * 60
// Grace period: Within the first full work cycle, before any reminder has triggered, no judgment
if (todayWorkTotalSeconds < workDurationSeconds) return 100
// Dimension 1: Rest Frequency Score (out of 60) — Current cycle is exempt; only require rests for past cycles
const completedCycles = Math.floor(todayWorkTotalSeconds / workDurationSeconds)
const expectedRests = Math.max(1, completedCycles - 1)
const restRatio = Math.min(1, restCount / expectedRests)
const restScore = restRatio * 60
// Dimension 2: Longest Sit Penalty (out of 40) — More overtime means faster deduction
let sitScore = 40
if (maxSitDuration > workDurationSeconds) {
const overRatio = Math.min(1, (maxSitDuration - workDurationSeconds) / workDurationSeconds)
// Linear penalty: Overtime ratio directly maps to deduction
sitScore = 40 * (1 - overRatio)
}
return Math.min(100, Math.max(0, Math.round(restScore + sitScore)))
}
Why linear instead of non-linear?
- 1 minute overtime → ~1 point deducted (immediately perceptible, score no longer stays static)
- 5 minutes overtime → ~5 points deducted (time to pay attention)
- 10 minutes overtime → ~10 points deducted (noticeable drop)
- A full cycle overtime → 40 points deducted (all gone, severely exceeding limits)
The effect of positive reinforcement: Standing up one extra time shows a noticeable score increase, which changes behavior more effectively than negative prompts like "You've been sitting too long again."
Core 5: Wake-Up Correction — No false alarms after shutting down overnight
After the Service Worker is suspended or the computer is shut down, workStartTime might point to several hours ago or even yesterday. If not handled, opening it the next day would display "Continuously sat for 840 minutes."
async function sanitizeStateOnWakeup(runtimeState, config) {
const workDurationSeconds = (config.workDuration || 45) * 60
const abnormalThresholdSeconds = workDurationSeconds * 2 // Exceeding 2x work duration = abnormal
const updates = {}
// If time since last stand exceeds 2x work duration → treat as just stood up (shut down/lunch break)
if (runtimeState.lastStandTime) {
const sinceLastStand = Math.floor((Date.now() - runtimeState.lastStandTime) / 1000)
if (sinceLastStand >= abnormalThresholdSeconds) {
updates.lastStandTime = Date.now()
}
}
// If workStartTime is more than 5 minutes ago → reset (prevents tick from calculating abnormally large elapsed time)
if (runtimeState.workStartTime) {
const sinceWorkStart = Math.floor((Date.now() - runtimeState.workStartTime) / 1000)
if (sinceWorkStart > 300) {
updates.workStartTime = Date.now()
}
}
if (Object.keys(updates).length > 0) {
await updateRuntimeState(updates)
}
}
This function is called every time the Service Worker activates and during every tick heartbeat, ensuring the timing is reasonable whether you shut down overnight or come back from lunch.
Core 6: Hot Configuration Update — Changing settings doesn't lose progress
If you change the work interval (e.g., from 45 minutes to 40 minutes), the 20 minutes you've already sat won't be lost:
case 'UPDATE_CONFIG': {
await chrome.storage.sync.set(payload);
if (payload.workDuration !== undefined) {
// Don't reset accumulatedWork, let the ongoing countdown continue
await updateRuntimeState({ reminderDismissed: false });
await initAlarms(); // Reschedule reminder alarm based on new duration
}
}
Already sat for 20 minutes + new interval of 40 minutes = 20 minutes left until reminder. If the time already sat exceeds the new interval, the alarm triggers immediately.
Privacy Statement
This extension does not connect to the internet:
- ❌ No backend server
- ❌ No data upload
- ❌ No third-party SDKs
- ✅ All data is stored locally only
Works exactly the same offline.
Final Words
Honestly, the reason for making this extension wasn't technical interest, but because my body had already raised a red flag.
Cervical spine straightening, lumbar muscle strain... I used to think these terms were far removed from me, until the moment I got the examination report and realized: the damage from prolonged sitting is irreversible, and it had already happened without me even noticing.
Health is the 1; everything else is the 0s that follow. Without your body, writing more code or doing more projects means nothing. We always think, "I'll stand up as soon as I finish writing this bit," and then two or three hours slip by. Day after day, by the time the body sounds the alarm, it's already too late.
🖥️ One last serious note: If you stare at a screen for over 8 hours a day, besides standing up regularly, you should also protect your eyes~ Why not choose a monitor specifically designed for programmers ( •̀ ω •́ )y. During the few weeks I spent writing this extension, I was sitting in front of the RD270Q, then being reminded to stand up by my own extension. Cervical spine issues can't be solved just by standing up; screen height, angle, and lighting all have an impact (⊙o⊙). This monitor's stand can be raised, lowered, and rotated (I turn it vertical for long files, over a hundred lines on one screen without scrolling back and forth). It has a built-in ambient light sensor for automatic brightness adjustment, a dedicated coding mode, a dark theme and colored paper mode designed for black backgrounds, and a light theme for white backgrounds. I quite like this colored paper mode; when turned on, characters are exceptionally clear, and it doesn't feel uncomfortable to look at for long periods. Combined with the anti-reflective panel, it's really comfortable. It can significantly help alleviate the soreness and strain on our necks and eyes from staring intently at the screen for long periods~
One-key switching via hotkeys, very convenient OSD joystick settings entry, no need to navigate through layers of menus 😭; Five TÜV Rheinland eye-care certifications, the fatigue from staring at code for long periods is indeed much lighter ╰(°▽°)╯!
Also, the Flow feature in the companion software Display Pilot 2, simply put, lets the monitor automatically switch modes following your rhythm, eliminating the need to constantly press monitor buttons. A few points I find quite nice:
- Auto scene switching: Open Trae to write code, the monitor automatically jumps to 'Coding - Light Theme'; switch to the browser to view design drafts, it automatically switches to True Color...... No manual adjustment, seamless switching, hassle-free.
- One-click selection for common modes: Focus Max, Work, True Color, Game, Movie — switch with one click.
- Scheduled activation: For example, I set a work period 10:00–19:00, it automatically takes effect on time and exits after work, super suitable for working folks.
What this tool does is very simple — remind you when you forget to stand up. It won't forcefully interrupt when you're busy, nor will it pop up unnecessarily when you've already stood up. It just quietly stays there, gently reminding you when needed: Time to stand up and move around~
I hope everyone like me who sits in front of a computer for long hours every day can take their health seriously. Don't wait until your body sounds the alarm to start taking action.
Looking back over these few weeks, the extension grew from a setTimeout timer into a 1100+ line state machine, and the RD270Q accompanied me through every late night when things wouldn't compile. I quite agree with BenQ's approach to this coding monitor — not just stacking specs, but considering coding display, eye care, and ergonomics from the moment a developer sits down to write code. Empowering developers, helping us write code longer and more steadily, it takes this seriously.
I've been using this extension for about three weeks now, and my experience is that it has greatly improved things. Actually, going to the bathroom takes about 1-2 minutes. Although the time is short, standing itself is very beneficial for the body; you don't have to maintain one posture all the time.
This extension will be open-sourced later; those interested can follow for updates.
It's currently still in the testing and optimization phase. Before that, everyone is welcome to leave comments and exchange ideas — anything that needs optimization, features you want, you can mention in the comments section. I will read them one by one and work together to make it better.
If this article was helpful to you, don't forget to give a 👍 and ⭐~
The BenQ RD270Q used in the article is a 27-inch 2K coding monitor, 3:2 productivity square screen, 144Hz high refresh rate, supporting coding mode (colored paper mode), zonal contrast, Owl mode, MoonHalo smart halo, five TÜV Rheinland eye-care certifications, ergonomic stand, suitable for developers who code for long hours.