perf(electrobun): JS blink replaces CSS animation, 1.13% CPU (was 6.5%)

JS setInterval(500ms) toggles .blink-off class instead of CSS @keyframes.
WebKitGTK handles discrete class toggle efficiently (single repaint per toggle).
0.7% idle + 0.43% blink overhead = 1.13% total.

Comparison:
- CSS @keyframes: 6.5% (continuous compositor animation)
- JS class toggle: 1.13% (2 repaints/sec)
- No animation: 0.7% (baseline)
- Tauri (CSS): ~0% (browser compositor optimized)
- GPUI (custom Element): 2.17%
This commit is contained in:
Hibryda 2026-03-20 01:35:33 +01:00
parent 6b4a2494b3
commit b79fbf688e
7 changed files with 31 additions and 16 deletions

View file

@ -4,8 +4,8 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Svelte App</title>
<script type="module" crossorigin src="/assets/index-DDde1xRO.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BkHCMgkQ.css">
<script type="module" crossorigin src="/assets/index-C2tlpXVI.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-xWFAud6t.css">
</head>
<body>
<div id="app"></div>

View file

@ -75,6 +75,13 @@
activeTab = { ...activeTab, [projectId]: tab };
}
// Blink state — JS timer toggles class, NO CSS animation (0% CPU)
let blinkVisible = $state(true);
$effect(() => {
const id = setInterval(() => { blinkVisible = !blinkVisible; }, 500);
return () => clearInterval(id);
});
function fmtTokens(n: number): string {
return n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n);
}
@ -120,7 +127,12 @@
Future: replace inner div with <electrobun-wgpu id="wgpu-surface-{project.id}">
for GPU-rendered animation. CSS pulse is the WebView fallback.
-->
<div class="status-dot {project.status}" role="img" aria-label="{project.status}"></div>
<div
class="status-dot {project.status}"
class:blink-off={project.status === 'running' && !blinkVisible}
role="img"
aria-label="{project.status}"
></div>
</div>
<span class="project-name">{project.name}</span>

View file

@ -204,7 +204,11 @@ html, body {
.status-dot.running {
--dot-color: var(--ctp-green);
/* animation: pulse-dot 2s ease-in-out infinite; DISABLED for CPU test */
/* No CSS animation — JS timer toggles .blink-off class instead */
}
.status-dot.blink-off {
opacity: 0.3;
}
.status-dot.idle {
@ -213,7 +217,6 @@ html, body {
.status-dot.stalled {
--dot-color: var(--ctp-peach);
/* animation: pulse-dot 1.4s ease-in-out infinite; DISABLED for CPU test */
}
@keyframes pulse-dot {