Files
home-frontend/src/scripts/sections/hero.js

149 lines
5.4 KiB
JavaScript

import { qs, isMobileViewport } from '../utils/dom.js';
import { copyToClipboard, flashFeedback, flashClass } from '../utils/clipboard.js';
import { typewriterReveal } from '../animations/typewriter.js';
import { initFluidByteField } from '../animations/fluid-byte-field.js';
import { DISCORD_LOADER_SCRIPT, COPY_FEEDBACK_DURATION_MS } from '../config/constants.js';
const HERO_GREETING = 'Vyla Home';
function initVideoColorExtraction() {
const videos = document.querySelectorAll('.hero-atmosphere-video');
if (videos.length === 0) return;
console.log('Video color extraction initialized, found', videos.length, 'videos');
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });
let animationFrameId;
let frameCount = 0;
let currentVideoColor = 'rgb(0, 0, 0)';
function extractColors() {
const video = videos[0];
if (video.readyState < 2) {
console.log('Video not ready, readyState:', video.readyState);
animationFrameId = requestAnimationFrame(extractColors);
return;
}
try {
canvas.width = 64;
canvas.height = 64;
ctx.drawImage(video, 0, 0, 64, 64);
const imageData = ctx.getImageData(0, 0, 64, 64);
const data = imageData.data;
let r = 0, g = 0, b = 0;
let count = 0;
for (let i = 0; i < data.length; i += 4) {
r += data[i];
g += data[i + 1];
b += data[i + 2];
count++;
}
r = Math.round(r / count);
g = Math.round(g / count);
b = Math.round(b / count);
currentVideoColor = `rgb(${r}, ${g}, ${b})`;
const dominantColorTransparent = `rgba(${r}, ${g}, ${b}, 0.5)`;
document.documentElement.style.setProperty('--video-dominant-color', currentVideoColor);
document.documentElement.style.setProperty('--video-dominant-color-transparent', dominantColorTransparent);
if (window.scrollY === 0) {
document.documentElement.style.setProperty('--color-bg', currentVideoColor);
}
frameCount++;
if (frameCount % 30 === 0) {
console.log('Frame', frameCount, '- Extracted color:', currentVideoColor);
console.log('CSS variable set:', getComputedStyle(document.documentElement).getPropertyValue('--video-dominant-color'));
}
} catch (e) {
console.error('Error extracting video colors:', e);
}
animationFrameId = requestAnimationFrame(extractColors);
}
function handleScroll() {
const scrollY = window.scrollY;
const heroHeight = window.innerHeight;
const scrollProgress = Math.min(scrollY / (heroHeight * 0.5), 1);
const videoColorRGB = currentVideoColor.match(/\d+/g);
if (videoColorRGB) {
const r = Math.round(parseInt(videoColorRGB[0]) * (1 - scrollProgress));
const g = Math.round(parseInt(videoColorRGB[1]) * (1 - scrollProgress));
const b = Math.round(parseInt(videoColorRGB[2]) * (1 - scrollProgress));
const fadedColor = `rgb(${r}, ${g}, ${b})`;
document.documentElement.style.setProperty('--color-bg', fadedColor);
}
}
animationFrameId = requestAnimationFrame(extractColors);
window.addEventListener('scroll', handleScroll, { passive: true });
handleScroll();
videos.forEach(video => {
video.addEventListener('pause', () => {
console.log('Video paused, stopping color extraction');
cancelAnimationFrame(animationFrameId);
});
video.addEventListener('play', () => {
console.log('Video playing, starting color extraction');
animationFrameId = requestAnimationFrame(extractColors);
});
});
}
function initHeroTitle() {
const heroTitle = qs('.hero-title');
if (heroTitle) typewriterReveal(heroTitle, HERO_GREETING);
}
function initDiscordCopyBar() {
const copyBtn = document.getElementById('copy-discord-btn');
const copyLabel = document.getElementById('copy-discord-label');
const copyIcon = document.getElementById('copy-discord-icon');
if (!copyBtn) return;
copyBtn.addEventListener('click', async () => {
await copyToClipboard(DISCORD_LOADER_SCRIPT);
if (copyIcon) flashClass(copyIcon, 'copied', COPY_FEEDBACK_DURATION_MS);
});
}
function initHeroCopyButton() {
const heroCopyScriptBtn = document.getElementById('hero-copy-script-btn');
if (!heroCopyScriptBtn) return;
heroCopyScriptBtn.addEventListener('click', async () => {
await copyToClipboard(DISCORD_LOADER_SCRIPT);
flashFeedback(heroCopyScriptBtn, 'Copied!', COPY_FEEDBACK_DURATION_MS);
});
}
function initCtaCopyButton() {
const ctaCopyScriptBtn = document.getElementById('cta-copy-script-btn');
if (!ctaCopyScriptBtn) return;
ctaCopyScriptBtn.addEventListener('click', async () => {
await copyToClipboard(DISCORD_LOADER_SCRIPT);
flashFeedback(ctaCopyScriptBtn, 'Copied!', COPY_FEEDBACK_DURATION_MS);
});
}
export function initHeroSection() {
initHeroTitle();
initDiscordCopyBar();
initHeroCopyButton();
initCtaCopyButton();
initVideoColorExtraction();
initFluidByteField('hero-byte-overlay');
initFluidByteField('cta-byte-overlay');
}