Skip to content

feat: growing token rate + floating +N pop animation on total counter#76

Merged
nitrocode merged 6 commits into
mainfrom
copilot/enhance-rate-visualization
Apr 26, 2026
Merged

feat: growing token rate + floating +N pop animation on total counter#76
nitrocode merged 6 commits into
mainfrom
copilot/enhance-rate-visualization

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 26, 2026

  • Previous code review fixes (animationcancel, CSS lint, changelog regen)
  • Merge origin/main (includes PR chore: exclude generated files from git to eliminate merge conflicts #80: exclude generated files from git)
  • Resolve all 11 add/add merge conflicts
  • Untrack committed generated files (script.js, styles.css, changelog-data.js, milestones-data.js, project-stats-data.js) via git rm --cached
  • Rebuild generated files on disk, all 262 tests pass at 100% coverage

Copilot AI and others added 2 commits April 26, 2026 12:36
- 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>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

📝 Walkthrough

Walkthrough

Updates 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

Cohort / File(s) Summary
Changelog & Version
changelog-data.js
Bumped SITE_VERSION to 1.4.0 and prepended release objects for 1.4.01.1.0 with new headings and item entries.
Core Rate Model
death-clock-core.js
Added RATE_GROWTH_PER_YEAR and getDynamicRate(date) to compute exponential growth for future dates while preserving legacy schedule for historical dates.
State & Token Calculation
src/js/00-state.js
Replaced linear accumulation with continuous exponential growth in getCurrentTokens; now imports RATE_GROWTH_PER_YEAR and getDynamicRate from window.DeathClockCore.
Counter & UI Behavior
src/js/02-counter.js, styles/counter-milestones.css
Counter now uses getDynamicRate() for currentRate, updates subtitle to "and growing · tokens/sec" after base date, and spawns a throttled floating +<n> token-pop element. CSS: .counter-box overflow made visible; added .token-pop styles and keyframe animation.
Tests
tests/death-clock.test.js
Added tests for getDynamicRate() and RATE_GROWTH_PER_YEAR: base-date equality, year-over-year growth (with tolerance), historical compatibility, input fallbacks, and numeric constraints.

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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • nitrocode
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly summarizes the two main features added: exponential token rate growth and a floating animation that displays token increments on the counter UI.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch copilot/enhance-rate-visualization

Comment @coderabbitai help to get the list of available commands and usage tips.

@nitrocode
Copy link
Copy Markdown
Owner

@copilot merge main to this branch and regenerate styles.css

Copilot AI and others added 2 commits April 26, 2026 12:45
…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>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 26, 2026

@copilot merge main to this branch and regenerate styles.css

Done — merged origin/main (mobile fixes from #74 and #75) and rebuilt styles.css from the source files in styles/. The regenerated CSS includes both the mobile layout fixes and the token-pop animation styles. Commit: c5d6563.

Copilot AI requested a review from nitrocode April 26, 2026 12:46
@nitrocode nitrocode marked this pull request as ready for review April 26, 2026 15:03
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 26, 2026

👁️ PR Preview

🚀 Open Preview

Deployed from commit 8c59b1e · Updates on every push to this PR
(Preview is removed automatically when the PR is closed.)

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (fd1cb0d) to head (8c59b1e).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##              main       #76   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            1         1           
  Lines          233       242    +9     
  Branches       107       109    +2     
=========================================
+ Hits           233       242    +9     
Flag Coverage Δ
unit 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
death-clock-core.js 100.00% <100.00%> (ø)

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fd1cb0d...8c59b1e. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/js/02-counter.js (1)

51-53: Avoid cloning/reversing RATE_SCHEDULE on every frame.

I pity the fool who burns cycles in requestAnimationFrame — precompute a reversed schedule once outside updateCounters() 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

📥 Commits

Reviewing files that changed from the base of the PR and between a0b3ce4 and c5d6563.

📒 Files selected for processing (8)
  • changelog-data.js
  • death-clock-core.js
  • script.js
  • src/js/00-state.js
  • src/js/02-counter.js
  • styles.css
  • styles/counter-milestones.css
  • tests/death-clock.test.js

Comment thread changelog-data.js Outdated
Comment thread src/js/02-counter.js Outdated
Comment thread styles/counter-milestones.css
…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>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
styles/counter-milestones.css (1)

64-68: ⚠️ Potential issue | 🟠 Major

Drop 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

📥 Commits

Reviewing files that changed from the base of the PR and between c5d6563 and ce70c22.

📒 Files selected for processing (4)
  • script.js
  • src/js/02-counter.js
  • styles.css
  • styles/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>
@nitrocode nitrocode merged commit bce2b8b into main Apr 26, 2026
11 checks passed
@nitrocode nitrocode deleted the copilot/enhance-rate-visualization branch April 26, 2026 16:09
github-actions Bot added a commit that referenced this pull request Apr 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants