chrome extension · dark theme engine

Dark mode that beats the site to the paint.

DarkShift applies a dynamic dark theme to any page — without the white flash every other dark-mode extension makes you sit through. Two-layer engine, per-site cache, zero telemetry.

 typical dark-mode extension
white flash
~400ms
 DarkShift
instant shell
<5ms

document_start vs. waiting for the page — measured, not marketing.

how it works

Two layers, in order

Most dark-mode extensions wait for the page to render, then repaint it — that's the flash. DarkShift splits the work into a layer that's cheap enough to run before anything is visible, and a layer that takes its time to get colors right.

Instant Shell
A coarse dark layer applied synchronously at document_start, before first paint.
< 5ms
Precise Theme
Transforms actual CSS colors while preserving hue, replaces the shell once ready.
< 300ms p95
measured, not claimed

What the engine actually costs

Every number below is a budget enforced in CI, not an aspiration. Per-site theme results are cached, so repeat visits skip straight to Instant Shell speed.

Dark paint — cached siterevisit, theme already computed
< 50ms
Dark paint — first visitp95, cold theme computation
< 300ms
Live setting changesslider → repaint
< 100ms
zero telemetry zero network requests per-site exclude list Manifest V3
install

Not on the Web Store yet

DarkShift is distributed directly for now — Chrome won't install a downloaded .zip in one click, so it's a short manual load:

Download the .zip above and unzip it anywhere on disk.

Open chrome://extensions in a new tab.

Turn on Developer mode (top-right toggle).

Click Load unpacked and select the unzipped folder.

changelog

What changed

0.2.0 2026-09-28 current

Fixed

  • Dark text stayed dark on design-token sites. A colour kept in a CSS custom property was always darkened, whichever way the page used it — so text set through var(--text) became dark-on-dark and vanished. The engine now infers what each custom property is for from how the page consumes it: lightened when it feeds color/fill/stroke, darkened when it feeds a background or a border. A property used both ways gets a second, lightened twin, and foreground declarations are rewritten to read that one. Definition chains (--a: var(--b)) inherit the role.
  • Enabled / Mode in “All sites” scope only affected the current site. The Scope select steered the sliders alone; the mode always wrote a per-site entry.
  • Changing the global settings needed a manual reload. A write from the Options page reached storage but no open tab. The background now broadcasts the change, and tabs apply it themselves — switching to Off strips the injected styles without a reload at all.
  • Removing a site in Options left its stale theme cached. The cache entry is invalidated together with the setting.
  • Report problem still opened a 404. The 0.1.2 fix pointed the button at a repository that is not public. It now opens a report page on this landing. The site and version travel in the URL fragment, which browsers never send to a server — so composing a report tells the server nothing about where you were.

Perf gate re-run with a design-token fixture (300 custom properties + var() usages): 1.1ms against the 300ms first-visit budget.

0.1.2 2026-08-20

Fixed

  • Report problem opened a GitHub 404. The issue URL pointed at a placeholder organisation that does not exist.
  • Enabled / Mode changes needed a manual refresh. Two code paths re-registered the content script at the same time; one rejected with a duplicate-ID error and aborted the message router before it could tell the tab to reload. Registration runs are now serialized and can no longer reject into the router.
  • Filter mode ignored the sliders until a reload. The mode baked brightness and contrast into its CSS as literals and dropped saturation, warmth and dim entirely. Both modes now drive the same custom properties, so a slider repaints immediately.
  • Filter mode left backgroundless pages white. A page that sets no background of its own gave the invert nothing to act on — a no-white-flash violation. The root now gets an explicit ground colour that the site's own background still overrides.
  • Dragging a slider exceeded the storage quota. Persisting on every input event blew past Chrome's sync-storage write limit and threw in the popup. Dragging now only previews; the write happens once, debounced, on release.

Added

  • Extension icons (16/32/48/128) — earlier builds shipped none, so Chrome fell back to a grey placeholder tile.
0.1.1 2026-07-20

Added

  • Site fix for habr.com: darken cross-origin cards, lighten #333 text.
  • External stylesheets that load after document_start are now themed.

Fixed

  • Snapshot self-poisoning: the engine's own stylesheets were included in the style snapshot and could trigger a native-dark false positive.
0.1.0 2026-07-09

Initial release

  • Instant dark paint, dynamic theme generation, per-site theme cache, mutation pipeline for SPAs, popup and options UI, bundled site fixes.
для тестировщика

Что проверить в 0.2.0

Сборка прогнана через автотесты (движок, расширение, e2e в реальном Chrome) и перф-гейт. От тебя нужно только поставить и посмотреть глазами. Ничего собирать и запускать в терминале не надо.

Установка — 3 шага, около минуты

  1. Скачай DarkShift 0.2.0 кнопкой вверху страницы и распакуй архив в любую папку. Внутри должен лежать manifest.json — это и есть расширение.
  2. Открой в Chrome адрес chrome://extensions и включи справа вверху «Режим разработчика».
  3. Нажми «Загрузить распакованное расширение» и выбери папку, куда распаковал (ту, где лежит manifest.json).
Иконку DarkShift удобно закрепить на панели: значок пазла → «булавка». В этой версии у расширения впервые своя иконка — тёмная плитка с бирюзовым кольцом. Видишь серый квадрат с буквой «D» — значит поставилась старая сборка.

Прицельно — то, что чинили в этой версии

Общий проход по сайтам

Дополнительно пройди десяток живых сайтов — например Gmail, GitHub, Wikipedia, YouTube, Amazon, Twitter/X, Reddit, StackOverflow, NYTimes, Notion.

Чего в этой версии ещё нет — не надо репортить

Что писать в отчёте

На каждую проблему: адрес сайта + что не так + скриншот. Сломанные сайты на старте — это нормально, они чинятся точечными фиксами; главное их зафиксировать.