feat: growing token rate + floating +N pop animation on total counter#76
Conversation
- Add getDynamicRate() to death-clock-core.js with 30% annual growth after BASE_DATE - Add RATE_GROWTH_PER_YEAR constant (0.30) - Update getCurrentTokens() to integrate the exponential rate for accuracy - Use getDynamicRate() in 02-counter.js for rate display and session tokens - Update rate subtitle to show "and growing" beyond BASE_DATE - Add spawnTokenPop(): spawns a "+N" floating element on the total counter every second - Add .token-pop CSS with @Keyframes tokenPopFloat (float up 56px, fade out over 1.5s) - Change .counter-box overflow to visible so pops can float above the box - Add 9 unit tests for getDynamicRate and RATE_GROWTH_PER_YEAR - All 262 unit tests pass at 100% coverage; all 68 E2E tests pass Agent-Logs-Url: https://github.com/nitrocode/token-deathclock/sessions/1579b618-82e8-4125-b282-8ddddafa27eb Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
- Extract POP_LEFT_BASE/POP_LEFT_SPREAD named constants - Rename k → continuousGrowthRate for clarity - Add source citation comment for RATE_GROWTH_PER_YEAR - Add explanatory comment on counter-box overflow: visible change Agent-Logs-Url: https://github.com/nitrocode/token-deathclock/sessions/1579b618-82e8-4125-b282-8ddddafa27eb Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
📝 WalkthroughWalkthroughUpdates site version to 1.4.0, prepends structured changelog entries for v1.4.0–v1.1.0, adds an exponential dynamic token-rate model and exported growth constant, switches token accumulation to continuous exponential growth, updates counter UI to use dynamic rates and spawn a floating token increment, and adds tests for the new rate API. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Counter as Counter (02-counter.js)
participant State as State (00-state.js)
participant Core as Core (death-clock-core.js)
participant DOM as DOM/UI
User->>Counter: Tick / interval
Counter->>State: getCurrentTokens()
State->>Core: getDynamicRate(now)
Core->>Core: Compute exponential rate from BASE_DATE
Core-->>State: Return dynamic rate
State->>Counter: Return total tokens
Counter->>Counter: Compute increment since last
Counter->>DOM: Update display
Counter->>DOM: Spawn .token-pop with +increment
DOM->>DOM: Animate float & fade, then remove
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
@copilot merge main to this branch and regenerate styles.css |
…visualization # Conflicts: # styles.css Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
Merge origin/main (mobile fixes from #74, #75) into branch, then rebuild styles.css from source so it contains both the mobile layout fixes and the token-pop animation styles. Agent-Logs-Url: https://github.com/nitrocode/token-deathclock/sessions/aedeb8a9-2599-40ef-a1a4-aa6d47261123 Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
👁️ PR Preview
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #76 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 1 1
Lines 233 242 +9
Branches 107 109 +2
=========================================
+ Hits 233 242 +9
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/js/02-counter.js (1)
51-53: Avoid cloning/reversingRATE_SCHEDULEon every frame.I pity the fool who burns cycles in
requestAnimationFrame— precompute a reversed schedule once outsideupdateCounters()and reuse it.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/js/02-counter.js` around lines 51 - 53, The code currently clones and reverses RATE_SCHEDULE inside updateCounters() every frame when computing rateEntry; move the reversed schedule creation out of the hot path by computing a single reversed array (e.g., REVERSED_RATE_SCHEDULE) once at module load time and then use REVERSED_RATE_SCHEDULE.find(...) inside updateCounters() instead of [...RATE_SCHEDULE].reverse(), ensuring any code that mutates RATE_SCHEDULE is instead done by replacing the array reference so the precomputed reversed copy stays correct.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@changelog-data.js`:
- Around line 5-133: You edited the generated artifact changelog-data.js
(contains SITE_VERSION and CHANGELOG_RELEASES) directly; instead update the
source CHANGELOG.md with your v1.4.0 release notes, then run the changelog
generator (npm run build:changelog) to regenerate changelog-data.js so
SITE_VERSION and CHANGELOG_RELEASES are produced correctly, and commit both the
updated CHANGELOG.md and the regenerated changelog-data.js together.
In `@src/js/02-counter.js`:
- Line 19: The current cleanup relies solely on
el.addEventListener('animationend', () => el.remove(), { once: true }) which can
leave .token-pop nodes if animations are interrupted; update the token-pop
teardown to also listen for 'animationcancel' and schedule a fallback timeout
(e.g., animationDuration + small buffer) that removes el if still in the DOM,
and ensure both the event listeners and the timeout clear each other to avoid
double removals; target the existing el variable and the addEventListener call
so you add an additional listener for 'animationcancel' and a cleanup timeout
alongside the existing 'animationend' handler.
In `@styles/counter-milestones.css`:
- Around line 64-83: The new .token-pop rule fails stylelint: change the
font-family value in .token-pop (currently 'Orbitron', monospace) to use the
project-preferred quoting (e.g. "Orbitron", monospace) to satisfy
font-family-name-quotes, and rename the `@keyframes` tokenPopFloat to a
lint-compliant kebab-case name (e.g. token-pop-float) and update the animation
reference in .token-pop (animation: token-pop-float 1.5s ease-out forwards;) so
the keyframes-name-pattern rule is satisfied; ensure both the `@keyframes`
declaration and any usages (animation/animation-name) use the new kebab-case
identifier.
---
Nitpick comments:
In `@src/js/02-counter.js`:
- Around line 51-53: The code currently clones and reverses RATE_SCHEDULE inside
updateCounters() every frame when computing rateEntry; move the reversed
schedule creation out of the hot path by computing a single reversed array
(e.g., REVERSED_RATE_SCHEDULE) once at module load time and then use
REVERSED_RATE_SCHEDULE.find(...) inside updateCounters() instead of
[...RATE_SCHEDULE].reverse(), ensuring any code that mutates RATE_SCHEDULE is
instead done by replacing the array reference so the precomputed reversed copy
stays correct.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 569eff41-ad09-4fb9-a9c9-950e77e85777
📒 Files selected for processing (8)
changelog-data.jsdeath-clock-core.jsscript.jssrc/js/00-state.jssrc/js/02-counter.jsstyles.cssstyles/counter-milestones.csstests/death-clock.test.js
…ata.js - changelog-data.js: reset to base and regenerate via npm run build:changelog so the file is properly derived from CHANGELOG.md, not edited directly - spawnTokenPop: add animationcancel listener + fallback timeout (1500+200ms) with a shared 'removed' flag so cleanup never double-fires - styles/counter-milestones.css: use double-quotes for "Orbitron" font-family and rename @Keyframes tokenPopFloat → token-pop-float (kebab-case) - updateCounters: hoist [...RATE_SCHEDULE].reverse() to module-level REVERSED_RATE_SCHEDULE constant, out of the per-frame hot path Agent-Logs-Url: https://github.com/nitrocode/token-deathclock/sessions/fedaea6d-9cc7-4df9-a304-fbde3025a7ec Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
styles/counter-milestones.css (1)
64-68:⚠️ Potential issue | 🟠 MajorDrop the quotes from Orbitron at Line 67 to clear stylelint.
I pity the fool who ships a red lint check — Line 67 still violates
font-family-name-quotes.🛠️ Suggested patch
.token-pop { position: absolute; bottom: 55%; - font-family: "Orbitron", monospace; + font-family: Orbitron, monospace; font-size: 0.8rem; font-weight: 700;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@styles/counter-milestones.css` around lines 64 - 68, The .token-pop CSS rule uses a quoted font-family token "Orbitron" which triggers stylelint's font-family-name-quotes; remove the quotes so the declaration reads font-family: Orbitron, monospace; to satisfy the font-family-name-quotes rule and clear the lint error in the .token-pop selector.
🧹 Nitpick comments (1)
src/js/02-counter.js (1)
4-4: Precompute schedule timestamps to trim frame-loop churn.I pity the fool who reparses dates every frame — Line 66 can use precomputed epoch values.
♻️ Suggested refactor
-const REVERSED_RATE_SCHEDULE = [...RATE_SCHEDULE].reverse(); +const REVERSED_RATE_SCHEDULE = [...RATE_SCHEDULE] + .map((r) => ({ ...r, epochMs: new Date(r.date).getTime() })) + .reverse(); ... -const rateEntry = REVERSED_RATE_SCHEDULE.find( - (r) => now >= new Date(r.date).getTime() -); +const rateEntry = REVERSED_RATE_SCHEDULE.find( + (r) => now >= r.epochMs +);Also applies to: 65-67
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/js/02-counter.js` at line 4, Precompute epoch timestamps for the rate schedule to avoid reparsing dates each frame: extend the existing REVERSED_RATE_SCHEDULE (created from RATE_SCHEDULE) to map each entry to include a numeric epoch (e.g., timestamp or startEpoch) once at module init, then update the frame-loop code that currently calls Date.parse/new Date/getTime each frame (the code referenced around line 66) to use the precomputed epoch field instead of reparsing; keep the original RATE_SCHEDULE/REVERSED_RATE_SCHEDULE identifiers and only change consumers to read the new epoch property.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@styles/counter-milestones.css`:
- Around line 64-68: The .token-pop CSS rule uses a quoted font-family token
"Orbitron" which triggers stylelint's font-family-name-quotes; remove the quotes
so the declaration reads font-family: Orbitron, monospace; to satisfy the
font-family-name-quotes rule and clear the lint error in the .token-pop
selector.
---
Nitpick comments:
In `@src/js/02-counter.js`:
- Line 4: Precompute epoch timestamps for the rate schedule to avoid reparsing
dates each frame: extend the existing REVERSED_RATE_SCHEDULE (created from
RATE_SCHEDULE) to map each entry to include a numeric epoch (e.g., timestamp or
startEpoch) once at module init, then update the frame-loop code that currently
calls Date.parse/new Date/getTime each frame (the code referenced around line
66) to use the precomputed epoch field instead of reparsing; keep the original
RATE_SCHEDULE/REVERSED_RATE_SCHEDULE identifiers and only change consumers to
read the new epoch property.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: bda68672-d2ae-4809-9d05-1455bd612ac6
📒 Files selected for processing (4)
script.jssrc/js/02-counter.jsstyles.cssstyles/counter-milestones.css
- Resolve add/add conflicts for all 11 conflicted files - Use origin/main base for workflow files, .gitignore, AGENTS.md, package.json - Merge our branch additions into death-clock-core.js: RATE_GROWTH_PER_YEAR, getDynamicRate(), exponential getCurrentTokens() integration - Merge our branch additions into src/js/02-counter.js: REVERSED_RATE_SCHEDULE, spawnTokenPop() with animationend/animationcancel/fallback cleanup - Merge our branch .token-pop CSS into styles/counter-milestones.css - Merge our getDynamicRate unit tests into tests/death-clock.test.js - Run git rm --cached for 5 generated files now excluded by .gitignore - All 262 tests pass with 100% coverage Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
git rm --cached