Skip to content

Commit 57dcac7

Browse files
committed
i
1 parent a79b99b commit 57dcac7

8 files changed

Lines changed: 70 additions & 44 deletions

File tree

dist/bundle-31946.css

Lines changed: 0 additions & 2 deletions
This file was deleted.

dist/bundle-31946.js

Lines changed: 0 additions & 2 deletions
This file was deleted.

dist/bundle-650e6.css

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/bundle-650e6.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

src/css/style.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ canvas {
2424
opacity: 1;
2525
}
2626
#header-verse {
27+
display: none;
2728
position: absolute;
2829
left: 6%;
2930
top: -.75em;

src/js/bible-verses.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
if (!isMobile) {
2-
32
function constructVerseURL(verse) {
43
const [book, chapter_verse] = verse.split(' ');
54
const [chapter, verse_range] = chapter_verse.split(':');
65
const formatted_book = book.toLowerCase().substring(0, 3);
76
return `https://www.blb.org/csb/${formatted_book}/${chapter}/${verse_range}`;
87
}
98
function displayRandomBibleVerse() {
9+
const headerVerse = document.getElementById('header-verse');
10+
headerVerse.style.display = 'block';
1011
shuffle(bibleVerses);
1112
let currentIndex = 0;
1213
let remainingTime = 0;
@@ -32,23 +33,23 @@ function displayRandomBibleVerse() {
3233
}
3334
function tick() {
3435
if (isWindowActive && !document.querySelector('header').classList.contains('scrolled-down')) {
36+
headerVerse.style.display = 'block';
3537
remainingTime -= tickInterval;
3638
if (remainingTime <= 0) {
3739
displayVerse();
3840
} else {
3941
timerPause = setTimeout(tick, tickInterval);
4042
}
4143
} else {
44+
headerVerse.style.display = 'none';
4245
timerPause = setTimeout(tick, tickInterval);
4346
}
4447
}
4548
tick();
4649
}
4750
displayVerse();
4851
}
49-
const headerVerse = document.getElementById('header-verse');
5052
document.addEventListener("DOMContentLoaded", function() {
51-
5253
if (isInitialLoad) {
5354
displayRandomBibleVerse();
5455
}

src/js/color-change.js

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
if (!isMobile) {
2-
31
const hoverShift = document.querySelectorAll('button, a, .article-nav-bottom, footer');
42
const alwaysShift = document.querySelectorAll('header, #site-title, #toolbar, nav .col a, .article-header, .article-title, .section-nav, footer');
53

64
function getRandomDegree() {
7-
// More uniform distribution and efficient rounding
85
return Math.random() < 0.5
96
? -45 - Math.floor(Math.random() * 270)
107
: 46 + Math.floor(Math.random() * 224);
@@ -48,72 +45,99 @@ function startShift(element, interval, isHover = false) {
4845
element.style.filter = filterValue;
4946
}
5047

51-
function animate(time) {
48+
function animateColors(time) {
5249
if (!isRunning) return;
5350
if (isWindowActive && isElementInViewport(element)) {
5451
const deltaTime = time - lastTime;
5552
lastTime = time;
5653
progress += deltaTime / interval;
57-
5854
if (progress >= 1) {
5955
targetDegree = getRandomDegree();
6056
targetSaturation = Math.random() * 35 + 90; // 90-125
6157
targetContrast = Math.random() * (isHover ? 90 : 40) + 80;
6258
targetBrightness = Math.random() * (isHover ? 50 : 20) + (isHover ? 85 : 90);
6359
progress = 0;
6460
}
65-
6661
const t = () => metaRecursiveEaseNoise(progress);
67-
6862
currentDegree += Math.round((targetDegree - currentDegree) * t() * Math.random() * 0.07);
6963
currentSaturation += Math.round((targetSaturation - currentSaturation) * t() * Math.random());
7064
currentContrast += Math.round((targetContrast - currentContrast) * t() * Math.random());
7165
currentBrightness += Math.round((targetBrightness - currentBrightness) * t() * Math.random());
72-
7366
updateFilter();
7467
}
75-
76-
if (isRunning) requestAnimationFrame(animate);
68+
if (isRunning) requestAnimationFrame(animateColors);
7769
}
7870

79-
requestAnimationFrame(animate);
80-
71+
// Initial filter apply (starts from random state)
72+
updateFilter();
73+
requestAnimationFrame(animateColors);
8174
return () => {
8275
isRunning = false;
8376
element.style.filter = 'none';
8477
};
8578
}
8679

87-
function handleDisengage(element, stopAnimationFunction) {
88-
if (stopAnimationFunction) {
89-
stopAnimationFunction();
80+
function handleDisengage(element, stopAnim) {
81+
if (stopAnim) {
82+
stopAnim();
9083
}
9184
element.style.filter = 'none';
9285
}
9386

94-
// Initialize alwaysShift elements with throttled animations
95-
alwaysShift.forEach(element => {
96-
element.animateFunction = throttle(() => startShift(element, getRandomInterval()), 30)();
87+
// Viewport-lazy with light staggering: Observe in batches for gradual init
88+
const observerOptions = {
89+
threshold: 0,
90+
rootMargin: '200px',
91+
};
92+
93+
const animationObserver = new IntersectionObserver((entries) => {
94+
entries.forEach(entry => {
95+
const element = entry.target;
96+
if (entry.isIntersecting && !element._isAnimating) {
97+
element._stopper = startShift(element, getRandomInterval());
98+
element._isAnimating = true;
99+
}
100+
});
101+
}, observerOptions);
102+
103+
// Stagger .observe() calls lightly (~20ms batches) for perf ramp-up
104+
let observeDelay = 0;
105+
const observeBatchSize = 10;
106+
alwaysShift.forEach((element, index) => {
107+
setTimeout(() => {
108+
animationObserver.observe(element);
109+
}, observeDelay);
110+
if (index % observeBatchSize === observeBatchSize - 1) {
111+
observeDelay += 20; // Tune: 10-50ms for balance
112+
}
97113
});
98114

99-
// Initialize hoverShift elements with event handlers and throttle/debounce control
100-
hoverShift.forEach(element => {
101-
let stopAnimationFunction = null;
102-
let disengageTimeout = null;
103-
104-
const startAnim = throttle(() => {
105-
if (stopAnimationFunction) stopAnimationFunction();
106-
stopAnimationFunction = startShift(element, getRandomInterval(), true);
107-
}, 30);
108-
109-
element.addEventListener('mouseover', startAnim);
110-
element.addEventListener('click', startAnim);
111-
element.addEventListener('touchstart', () => {
112-
if (stopAnimationFunction) stopAnimationFunction();
113-
stopAnimationFunction = startShift(element, getRandomInterval(), true);
114-
disengageTimeout = setTimeout(() => handleDisengage(element, stopAnimationFunction), 888);
115+
// Cleanup on unload
116+
window.addEventListener('beforeunload', () => {
117+
alwaysShift.forEach(element => {
118+
if (element._stopper) {
119+
element._stopper();
120+
element._stopper = null;
121+
}
115122
});
116-
element.addEventListener('mouseout', debounce(() => handleDisengage(element, stopAnimationFunction), 30));
123+
animationObserver.disconnect();
117124
});
118125

119-
}
126+
if (!isMobile) {
127+
hoverShift.forEach(element => {
128+
let stopAnim = null;
129+
let disengageTimeout = null;
130+
const startAnim = throttle(() => {
131+
if (stopAnim) stopAnim();
132+
stopAnim = startShift(element, getRandomInterval(), true);
133+
}, 30);
134+
element.addEventListener('mouseover', startAnim);
135+
element.addEventListener('click', startAnim);
136+
element.addEventListener('touchstart', () => {
137+
if (stopAnim) stopAnim();
138+
stopAnim = startShift(element, getRandomInterval(), true);
139+
disengageTimeout = setTimeout(() => handleDisengage(element, stopAnim), 888);
140+
});
141+
element.addEventListener('mouseout', debounce(() => handleDisengage(element, stopAnim), 30));
142+
});
143+
}

0 commit comments

Comments
 (0)