From 84d6208bc9dd51c8dc24816aca6cadb044750a74 Mon Sep 17 00:00:00 2001 From: nick2000713 Date: Mon, 29 Jun 2026 11:06:13 +0200 Subject: [PATCH] perf: add Max Performance mode + stop password-manager autofill storm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two CPU regressions surfaced in software-rendered / no-GPU containers (Docker), where transform/opacity and canvas radial-gradient fills rasterize on the CPU instead of a compositor: 1. Worker-orbs canvas + decorative motion saturate a core and freeze the UI. A new opt-in "Max Performance" mode is the nuclear low-power switch: body.max-performance CSS kills blur/shadow/filter AND all animation/transition (spinners go static), and JS halts every canvas loop (orbs, particles, cursor-glow, API sparks) via window._maxPerfActive. Reduce Visual Effects is now decoupled from the orbs — they follow their own toggle; only Max Performance force-kills them. While Max Performance is on, the Orbs/Particles/Reduce-Effects checkboxes lock + grey out, and save reads the runtime flags so prefs aren't clobbered. 2. Password managers (Bitwarden et al.) rebuild their autofill overlay on every DOM mutation; a captured trace showed Bitwarden using ~6x the CPU of the whole app (~400 setupOverlayOnField/sec). suppressPasswordManager- Autofill() tags non-credential inputs with data-bwignore / data-1p-ignore / data-lpignore / data-form-type=other so the managers skip them; real login/PIN fields are left alone. Wired through: web_server.py (_initial_appearance_context), index.html (inline flag + body class + checkbox), init.js (applyMaxPerformance + bootstrap + listener + autofill suppression), settings.js (load/save), worker-orbs.js / particles.js / api-monitor.js (gates), style.css. Co-Authored-By: Claude Opus 4.8 --- web_server.py | 2 + webui/index.html | 12 ++- webui/static/api-monitor.js | 4 +- webui/static/init.js | 145 +++++++++++++++++++++++++++++++++++- webui/static/particles.js | 6 +- webui/static/settings.js | 20 ++++- webui/static/style.css | 32 ++++++++ webui/static/worker-orbs.js | 13 ++-- 8 files changed, 217 insertions(+), 17 deletions(-) diff --git a/web_server.py b/web_server.py index 83e88a87..b335fc05 100644 --- a/web_server.py +++ b/web_server.py @@ -387,6 +387,7 @@ def _initial_appearance_context(): _request_is_firefox(), ) reduce_effects = config_manager.get('ui_appearance.reduce_effects', False) is True + max_performance = config_manager.get('ui_appearance.max_performance', False) is True r, g, b = _hex_to_rgb(accent) hue, saturation, lightness = _rgb_to_hsl(r, g, b) light = _hsl_to_rgb(hue, saturation, min(lightness + 0.16, 0.95)) @@ -399,6 +400,7 @@ def _initial_appearance_context(): 'initial_particles_enabled': particles_enabled, 'initial_worker_orbs_enabled': worker_orbs_enabled, 'initial_reduce_effects': reduce_effects, + 'initial_max_performance': max_performance, } diff --git a/webui/index.html b/webui/index.html index 5e5a1580..5565a794 100644 --- a/webui/index.html +++ b/webui/index.html @@ -24,11 +24,12 @@ window._particlesEnabled = {{ initial_particles_enabled|tojson }}; window._workerOrbsEnabled = {{ initial_worker_orbs_enabled|tojson }}; window._reduceEffectsActive = {{ initial_reduce_effects|tojson }}; + window._maxPerfActive = {{ initial_max_performance|tojson }}; {{ vite_assets('head')|safe }} - + diff --git a/webui/static/api-monitor.js b/webui/static/api-monitor.js index 7b793e68..9f5ce8d0 100644 --- a/webui/static/api-monitor.js +++ b/webui/static/api-monitor.js @@ -386,8 +386,8 @@ function _renderEqualizerBars(grid, data) { // Call embers: tiny accent sparks rise off the fill tip, spawned per // socket update in proportion to REAL traffic — motion strictly means // API calls are happening right now. Suppressed during cooldown and - // under reduced-effects. - if (!window._reduceEffectsActive && !cooling && realPct > 0.03) { + // under reduced-effects / max-performance. + if (!window._reduceEffectsActive && !window._maxPerfActive && !cooling && realPct > 0.03) { _spawnEmbers(bar, pct, realPct > 0.6 ? 3 : realPct > 0.25 ? 2 : 1); } diff --git a/webui/static/init.js b/webui/static/init.js index 0b49db46..e8ccc58c 100644 --- a/webui/static/init.js +++ b/webui/static/init.js @@ -179,6 +179,14 @@ function initAccentColorListeners() { applyReduceEffects(reduceEffectsCheckbox.checked); }); } + + // Max Performance toggle — apply immediately on change + const maxPerfCheckbox = document.getElementById('max-performance-enabled'); + if (maxPerfCheckbox) { + maxPerfCheckbox.addEventListener('change', () => { + applyMaxPerformance(maxPerfCheckbox.checked); + }); + } } function applyReduceEffects(enabled) { @@ -211,6 +219,67 @@ function applyReduceEffects(enabled) { } } +// Max Performance overrides Worker Orbs / Particles / Reduce Effects, so while it's +// on we lock those checkboxes (greyed + visually off) and restore them when it's +// off. We never fire their change handlers, so the user's real saved prefs +// (window._workerOrbsEnabled / _particlesEnabled / the reduce-effects localStorage) +// stay intact — saving reads those, not these forced-off boxes. +function _syncMaxPerfDependentToggles(maxPerfOn) { + const ids = ['worker-orbs-enabled', 'particles-enabled', 'reduce-effects-enabled']; + ids.forEach(id => { + const cb = document.getElementById(id); + if (!cb) return; + const group = cb.closest('.form-group'); + if (maxPerfOn) { + cb.disabled = true; + cb.checked = false; + if (group) group.classList.add('setting-overridden'); + } else { + cb.disabled = false; + if (group) group.classList.remove('setting-overridden'); + // Restore each box to the user's real per-device preference. + if (id === 'worker-orbs-enabled') cb.checked = window._workerOrbsEnabled !== false; + else if (id === 'particles-enabled') cb.checked = window._particlesEnabled === true; + else if (id === 'reduce-effects-enabled') cb.checked = localStorage.getItem('soulsync-reduce-effects') === '1'; + } + }); +} + +// Max Performance — the nuclear low-power switch for software-rendered / no-GPU +// setups (e.g. Docker). Superset of Reduce Visual Effects: body.max-performance CSS +// kills the expensive GPU properties AND all animation/transitions, while here we +// halt every JS canvas loop (particles + worker orbs; cursor-glow + API sparks gate +// on window._maxPerfActive themselves). +function applyMaxPerformance(enabled) { + if (enabled) { + document.body.classList.add('max-performance'); + } else { + document.body.classList.remove('max-performance'); + } + window._maxPerfActive = enabled; + localStorage.setItem('soulsync-max-performance', enabled ? '1' : '0'); + + const pcanvas = document.getElementById('page-particles-canvas'); + if (enabled) { + if (window.pageParticles) window.pageParticles.stop(); + if (pcanvas) pcanvas.style.display = 'none'; + if (window.workerOrbs) window.workerOrbs.setPage('_disabled'); + } else { + // Restore whatever the user's own toggles (and reduce-effects) still allow. + const reduce = window._reduceEffectsActive === true; + const activePage = document.querySelector('.page.active'); + const activeId = activePage ? activePage.id.replace('-page', '') : null; + if (!reduce && window._particlesEnabled !== false) { + if (pcanvas) pcanvas.style.display = ''; + if (window.pageParticles && activeId) window.pageParticles.setPage(activeId); + } + if (window._workerOrbsEnabled !== false && window.workerOrbs && activeId) { + window.workerOrbs.setPage(activeId); + } + } + _syncMaxPerfDependentToggles(enabled); +} + // Bootstrap accent and reduce-effects from localStorage instantly (prevents flash) (function () { // Auto performance mode on likely-weak hardware. Only acts when this device has @@ -264,6 +333,19 @@ function applyReduceEffects(enabled) { } else if (window._reduceEffectsActive) { document.body.classList.add('reduce-effects'); } + // Max Performance — device-scoped (localStorage wins over the server default, + // same as reduce-effects). The window flag is seeded server-side in index.html + // for a flash-free first paint; localStorage reconciles it here. + const maxPerfSaved = localStorage.getItem('soulsync-max-performance'); + if (maxPerfSaved === '1') { + document.body.classList.add('max-performance'); + window._maxPerfActive = true; + } else if (maxPerfSaved === '0') { + document.body.classList.remove('max-performance'); + window._maxPerfActive = false; + } else if (window._maxPerfActive) { + document.body.classList.add('max-performance'); + } const saved = localStorage.getItem('soulsync-accent'); if (saved) applyAccentColor(saved); // Bootstrap particles setting from localStorage — OFF by default (continuous @@ -319,6 +401,66 @@ async function bootstrapServerAppearanceSettings() { bootstrapServerAppearanceSettings(); +// ── Password-manager autofill suppression ────────────────────────────── +// Bitwarden / 1Password / LastPass etc. attach an inline autofill overlay to +// every /