From ac79db7e6c047c6eead338f69ff994937c73ee8a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Apr 2026 23:48:15 +0000 Subject: [PATCH 1/2] fix: add +N pop animations to Your Tab (Running) strip Agent-Logs-Url: https://github.com/nitrocode/token-deathclock/sessions/dbfaddc2-7472-496f-98bd-384cbe7f5bc7 Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com> --- src/js/18-scary-features.js | 24 ++++++++++++++++++++++++ styles/counter-milestones.css | 7 +++++++ styles/scary-features.css | 2 ++ 3 files changed, 33 insertions(+) diff --git a/src/js/18-scary-features.js b/src/js/18-scary-features.js index a66efaf..e09c13d 100644 --- a/src/js/18-scary-features.js +++ b/src/js/18-scary-features.js @@ -97,6 +97,9 @@ // ── PRD 4: Your Tab (Running) strip ────────────────────────── + // Per-item throttle timestamp for the floating +N pop animations. + let _lastTabPop = 0; + function updateSessionTabStrip() { const now = Date.now(); const elapsed = Math.max(1, (now - pageLoadTime) / 1000); @@ -131,6 +134,27 @@ if (treesEl) treesEl.textContent = fmtSmall(trees); if (chargeEl) chargeEl.textContent = fmtSmall(charges); if (metresEl) metresEl.textContent = fmtSmall(metres); + + // Floating "+N" pops — once per second, showing the per-second increment for each stat. + if (now - _lastTabPop >= 1000) { + _lastTabPop = now; + const impactPerSec = calculateEnvironmentalImpact(rate); + const coffeesPerSec = impactPerSec.waterL / 0.2; + const treesPerSec = impactPerSec.treesEquivalent; + const chargesPerSec = impactPerSec.kWh / 0.015; + const metresPerSec = impactPerSec.co2Kg / 0.000171; + const MIN_TAB_POP_THRESHOLD = 0.005; + [ + { el: waterEl, val: coffeesPerSec }, + { el: treesEl, val: treesPerSec }, + { el: chargeEl, val: chargesPerSec }, + { el: metresEl, val: metresPerSec }, + ].forEach(({ el, val }) => { + if (!el || val < MIN_TAB_POP_THRESHOLD) return; + const item = el.closest('.session-tab-item'); + spawnPop(item, '+' + fmtSmall(val), 'token-pop--tab'); + }); + } } function initSessionTabStrip() { diff --git a/styles/counter-milestones.css b/styles/counter-milestones.css index c48061a..a3b07e6 100644 --- a/styles/counter-milestones.css +++ b/styles/counter-milestones.css @@ -95,6 +95,13 @@ font-size: 0.7rem; } +/* Your Tab (Running) pop — orange, matches .sti-val colour */ +.token-pop--tab { + color: var(--accent-2); + text-shadow: 0 0 8px rgba(255,136,0,0.5); + font-size: 0.7rem; +} + @keyframes token-pop-float { 0% { opacity: 0; transform: translateX(-50%) translateY(0); } 15% { opacity: 1; } diff --git a/styles/scary-features.css b/styles/scary-features.css index d4b8b14..59f1017 100644 --- a/styles/scary-features.css +++ b/styles/scary-features.css @@ -134,6 +134,8 @@ padding: 0.5rem 0.75rem; font-size: 0.78rem; color: var(--text-dim); + position: relative; + overflow: visible; } .sti-icon { font-size: 1.1rem; flex-shrink: 0; } From 10f8e1592b069131724ac2a7158ab04d9233852a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Apr 2026 23:49:36 +0000 Subject: [PATCH 2/2] refactor: extract tab strip conversion constants to avoid duplication Agent-Logs-Url: https://github.com/nitrocode/token-deathclock/sessions/dbfaddc2-7472-496f-98bd-384cbe7f5bc7 Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com> --- src/js/18-scary-features.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/js/18-scary-features.js b/src/js/18-scary-features.js index e09c13d..bf3dbe1 100644 --- a/src/js/18-scary-features.js +++ b/src/js/18-scary-features.js @@ -100,6 +100,11 @@ // Per-item throttle timestamp for the floating +N pop animations. let _lastTabPop = 0; + // Conversion constants shared between session totals and per-second pop deltas. + const WATER_PER_COFFEE_L = 0.2; // litres of water per cup of coffee + const KWH_PER_CHARGE = 0.015; // kWh per smartphone charge + const CO2_PER_METRE_KG = 0.000171; // kg CO₂ per metre driven (171 g/km) + function updateSessionTabStrip() { const now = Date.now(); const elapsed = Math.max(1, (now - pageLoadTime) / 1000); @@ -108,13 +113,13 @@ const impact = calculateEnvironmentalImpact(tokens); // Cups of coffee (200 mL per cup, water use) - const coffees = Math.max(0, impact.waterL / 0.2); + const coffees = Math.max(0, impact.waterL / WATER_PER_COFFEE_L); // Trees needed for a year const trees = Math.max(0, impact.treesEquivalent); // Smartphone charges (0.015 kWh per charge) - const charges = Math.max(0, impact.kWh / 0.015); + const charges = Math.max(0, impact.kWh / KWH_PER_CHARGE); // Metres driven (171 g CO2/km = 0.000171 kg/m) - const metres = Math.max(0, impact.co2Kg / 0.000171); + const metres = Math.max(0, impact.co2Kg / CO2_PER_METRE_KG); function fmtSmall(n) { if (n >= 1e6) return (n / 1e6).toFixed(1) + 'M'; @@ -139,10 +144,10 @@ if (now - _lastTabPop >= 1000) { _lastTabPop = now; const impactPerSec = calculateEnvironmentalImpact(rate); - const coffeesPerSec = impactPerSec.waterL / 0.2; + const coffeesPerSec = impactPerSec.waterL / WATER_PER_COFFEE_L; const treesPerSec = impactPerSec.treesEquivalent; - const chargesPerSec = impactPerSec.kWh / 0.015; - const metresPerSec = impactPerSec.co2Kg / 0.000171; + const chargesPerSec = impactPerSec.kWh / KWH_PER_CHARGE; + const metresPerSec = impactPerSec.co2Kg / CO2_PER_METRE_KG; const MIN_TAB_POP_THRESHOLD = 0.005; [ { el: waterEl, val: coffeesPerSec },