perf: пауза шейдера на главной при скролле >1000px
This commit is contained in:
1 parent
8eeeb9eb0a
commit
276c447567
1 file changed
+51
-1
@@ -29,6 +29,26 @@ function paletteFromTheme(root) {
|
||||
];
|
||||
}
|
||||
|
||||
// Статичный CSS-fallback фона. Переписывает --page-bg напрямую, чтобы
|
||||
// обновляться при смене акцента даже если WebGL отключён (мобильные).
|
||||
function setStaticPageBg(root) {
|
||||
const h = parseFloat(root.style.getPropertyValue("--theme-h")) || 210;
|
||||
const s = parseFloat(root.style.getPropertyValue("--theme-s")) || 90;
|
||||
const l = parseFloat(root.style.getPropertyValue("--theme-l")) || 40;
|
||||
const isDark = root.dataset.theme === "dark";
|
||||
const mixAndStop = isDark ? [[52, 62], [44, 64], [36, 68]] : [[38, 62], [32, 64], [26, 68]];
|
||||
const hueShift = isDark ? 180 : 90; // тёмная: accent-square-3/+180, светлая: +90
|
||||
const hues = [h + hueShift, h + 90, h + 270].map(x => ((x % 360) + 360) % 360);
|
||||
const bg = `color-mix(in srgb, var(--bg) 100%, transparent)`;
|
||||
let bgStr = "";
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const [mix, stop] = mixAndStop[i];
|
||||
const color = `hsl(${Math.round(hues[i])} calc(${s}% * 1) calc(${Math.round(l)}% * 1))`;
|
||||
bgStr += `radial-gradient(calc(48% * 1) calc(56% * 1) at var(--mesh-a-x) var(--mesh-a-y), color-mix(in srgb, ${color}, ${bg}) ${mix}%, transparent ${stop}%)${i < 2 ? "," : ""}`;
|
||||
}
|
||||
root.style.setProperty("--page-bg", bgStr);
|
||||
}
|
||||
|
||||
function colorVec4Array(colors) {
|
||||
// Шейдер ждёт u_colors как vec4[10] → массив из 10 под-массивов [r,g,b,a].
|
||||
// setUniformValues сам flatten'ит массив массивов в uniform4fv.
|
||||
@@ -62,6 +82,25 @@ function disposeMount() {
|
||||
}
|
||||
}
|
||||
|
||||
function updateCanvasVisibility(root) {
|
||||
const host = root.querySelector(".page-mesh-bg canvas");
|
||||
if (!host) return;
|
||||
const shouldHide = root.dataset.meshBg === "off" || document.body.dataset.scrollHidden === "1";
|
||||
host.style.visibility = shouldHide ? "hidden" : "visible";
|
||||
}
|
||||
|
||||
function handleScroll(root) {
|
||||
// Шэйдер закрывается, когда прокручено больше 1000px — в дизайне
|
||||
// mesh-bg перекрывается фоном секций и всё равно не виден.
|
||||
// Это освобождает GPU на весь остальной скролл.
|
||||
if (document.body.scrollTop > 1000 || document.documentElement.scrollTop > 1000) {
|
||||
root.dataset.scrollHidden = "1";
|
||||
} else {
|
||||
delete root.dataset.scrollHidden;
|
||||
}
|
||||
updateCanvasVisibility(root);
|
||||
}
|
||||
|
||||
function buildMount(host, root) {
|
||||
const sizing = () => ({
|
||||
u_fit: ShaderFitOptions[defaultObjectSizing.fit],
|
||||
@@ -115,11 +154,17 @@ function buildMount(host, root) {
|
||||
// Обновляем палитру при смене акцента/темы.
|
||||
onTheme = () => {
|
||||
const next = paletteFromTheme(root);
|
||||
if (!next || !mount) return;
|
||||
if (!next || !mount) {
|
||||
setStaticPageBg(root);
|
||||
updateCanvasVisibility(root);
|
||||
return;
|
||||
}
|
||||
mount.setUniforms({
|
||||
u_colors: colorVec4Array(next),
|
||||
u_colorsCount: next.length,
|
||||
});
|
||||
setStaticPageBg(root);
|
||||
updateCanvasVisibility(root);
|
||||
};
|
||||
window.addEventListener("site-theme-applied", onTheme, { passive: true });
|
||||
}
|
||||
@@ -138,6 +183,11 @@ export function initPageMeshShader() {
|
||||
|
||||
buildMount(host, document.documentElement);
|
||||
|
||||
// Скролл-контроль видимости canvas: при скролле >1000px фон перекрывается
|
||||
// секциями и не виден — закрываем canvas, чтобы не тратить GPU.
|
||||
window.addEventListener("scroll", () => handleScroll(document.documentElement), { passive: true });
|
||||
handleScroll(document.documentElement);
|
||||
|
||||
// Чистим ресурсы при нормальном уходе со страницы.
|
||||
if (!pagehideBound) {
|
||||
pagehideBound = true;
|
||||
|
||||
Reference in new issue
Block a user