Repository navigation
feat(appearance): optional pixel shift against image persistence - #337
Conversation
Adds a Pixel shift toggle to the dimming card (household or per-display, off by default). When enabled, the dashboard drifts a few pixels on a slow cycle so static elements never sit on the exact same pixels, helping prevent image persistence on always-on wall displays. Values follow the industry optimum: at most 4px, every 4 minutes (Samsung signage manuals list 0-4px and 1-4 min, optimum 4/4; Philips shifts up to 8px every 80 seconds). Translate-only on the app root, folded into the existing idle timer, so there are no scrollbars and taps still land.
|
Nice small addition. I ran it locally (demo mode, 1600x1000, Playwright clock to skip ahead), with the switch off as the control.
Small: the test sets |
Review feedback (mrramam): a transform on #root made it the containing block for its position:fixed descendants, pushing the dock off screen and dropping fixed layers below MUI dialogs portaled to body. The shift now uses relative left/top offsets on #root, which leave every fixed layer viewport-anchored and create no stacking context. Switching the setting off now resets position, left, top, transition, the marker and the body overflow-x clamp at once (previously the last offset persisted until reload). Horizontal overflow is hidden on <body> while the shift is on, so positive-x steps cannot widen the page. The pixel-shift test no longer clears the offset itself before the off case, so it covers the reset, and it restores the document/window globals it stubs. The setting screenshot is no longer committed; it is attached to the PR instead.
|
Thanks for testing this so thoroughly — all five points addressed in c6c0594:
Small: the test saves and restores the Tests: client 791/791, build clean. |
Port of the jherforth#337 review fix: a transform on #root would make it the containing block for its position:fixed descendants and push the dock off screen, while relative left/top offsets leave every fixed layer viewport-anchored. Positive-x steps hide horizontal overflow on <body> while the shift runs.
|
Let's pick up the "Display dimming" section as a whole and move it to Admin Panel > Displays > This Display. Then break out the sections: Touch, expand widgets, dimming |
Review feedback (jherforth, jherforth#337): pick up the Display dimming section as a whole and move it to Admin Panel > Displays > This Display, then break out the sections Touch, expand widgets, dimming. The dimming section (DisplayDimmingSettings, including the pixel-shift toggle) moves unchanged — it saves only its own field through its own save button — from the Look tab to the end of This Display, after that page's own save button. Touch, expanding widgets, and dimming are now separated by dividers instead of flowing as one list. Client 791/791, build clean. Generated with Muse AI 🤖
|
Done in 7cc47a8 (pushed to this branch):
Client 791/791, build clean. Generated with Muse AI 🤖 |
… card - The dock is position: fixed, so #root's relative offset doesn't move it, yet it's the most static thing on a wall display. The shift now also sets --pixel-shift-x/-y on <html>, which the dock adds to its own transform, and turning the shift off removes them. - Pixel shift moves to the end of the dimming card. It sat between "Dim the display when idle" and "Idle seconds before dimming", splitting two settings that belong together, and it works without dimming. - Its help text says so: "Works whether or not dimming is on." Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
Thanks. This addressed mrramam's points, and the move to This Display reads well. In Edge, with the clock jumped past 4 minutes,
Client tests and CI pass. |
# Conflicts: # client/src/utils/displayDim.js # client/src/utils/displayDim.pixelShift.test.js

Adds a Pixel shift toggle to the Display dimming card (household default or per-display override, off by default). When enabled, the dashboard drifts a few pixels on a slow cycle, so static elements never sit on the exact same pixels — protection against image persistence on always-on wall displays.
Values follow the industry optimum: at most 4px, every 4 minutes. Samsung's signage manuals list 0-4px horizontal/vertical and 1-4 minutes, with 4px / 4 min as the optimum; Philips shifts up to 8px every 80 seconds, the same order of magnitude.
Implementation notes:
Screenshot of the new setting (test instance, Look tab): attached in the comments below.
Testing:
Generated with Muse AI 🤖