openvibers/openvibe.live Commits

Hero stats: measure the settled height before animating the swap

OP OpenVibers committed 16 Sept 2026 · 24fd425810 · 2 files, +9 −5

The chips start at 0 and count up, and a chip reading 70,172 is taller than one reading 0 once
its label wraps — so the height measured at click time was several hundred pixels short of where
the board settles, and the expand finished with a visible jump. The final text is written before
measuring now, then the count-up runs over the top of it.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CMxJm1dB8rdsaMSgNjVa82

Changes

ddiff --git a/public/index.html b/public/index.html
iindex ab1e6e3d..ea26d358 100644
---- a/public/index.html
++++ b/public/index.html
@@@ -5130,7 +5130,7 @@ curl -s https://openvibe.media/live/@Goosely/chat-insight.json | jq ".chat_insig
<script src="/live-notify.js?v=3" defer></script>
<script src="/js/ov-skeleton.js?v=1" defer></script>
<script src="/js/ov-odometer.js?v=3" defer></script>
--<script src="/js/app.js?v=155" defer></script>
++<script src="/js/app.js?v=156" defer></script>
<script src="/js/stream-player.js?v=22" defer></script>
<script src="/js/stream-pip.js?v=1" defer></script>
<script src="/js/chat-shared.js?v=3" defer></script>
ddiff --git a/public/js/app.js b/public/js/app.js
iindex edde86ed..f8cf2171 100644
---- a/public/js/app.js
++++ b/public/js/app.js
@@@ -1534,11 +1534,15 @@ function renderHeroStats(stats) {
};
btn.addEventListener('click', () => {
++ // The board's chips start showing "0" and count up, and a chip reading "70,172" is taller
++ // than one reading "0" once its label wraps — so the height measured at click time was
++ // several hundred pixels short of where the board actually settles, and the animation
++ // finished with a jump. Write the final text first, measure, animate, then count up from
++ // zero over the top of it.
++ const pending = full.hidden ? [...full.querySelectorAll('.hero-stat-num:not([data-counted])')] : [];
++ pending.forEach(el => { el.textContent = _heroStatFmt(parseInt(el.dataset.n, 10) || 0); });
swap();
-- // Count the numbers up the first time they are actually looked at.
-- if (!full.hidden) full.querySelectorAll('.hero-stat-num:not([data-counted])').forEach(el => {
-- el.setAttribute('data-counted', '1'); _heroCountUp(el, parseInt(el.dataset.n, 10) || 0);
-- });
++ pending.forEach(el => { el.setAttribute('data-counted', '1'); _heroCountUp(el, parseInt(el.dataset.n, 10) || 0); });
});
wrap.querySelectorAll('.hero-stat-strip .hero-stat-num').forEach(el => {
el.setAttribute('data-counted', '1');