Spaces:
Sleeping
Sleeping
Download script.js from Samfredoly/live-20: direct link, hf CLI and curl.
- Browser
- Download file 5.36 kB
-
https://huggingface.co/spaces/Samfredoly/live-20/resolve/main/script.js
- Command line
-
hf download hf://spaces/Samfredoly/live-20/script.js
-
curl -L -o script.js https://huggingface.co/spaces/Samfredoly/live-20/resolve/main/script.js
5.36 kB
| const introScreen = document.querySelector('#introScreen'); | |
| const holdScreen = document.querySelector('#holdScreen'); | |
| const completeScreen = document.querySelector('#completeScreen'); | |
| const openButton = document.querySelector('#openButton'); | |
| const replayButton = document.querySelector('#replayButton'); | |
| const sendBackButton = document.querySelector('#sendBackButton'); | |
| const sendBackNote = document.querySelector('#sendBackNote'); | |
| const letterButton = document.querySelector('#letterButton'); | |
| const letterPanel = document.querySelector('#letterPanel'); | |
| const letterClose = document.querySelector('#letterClose'); | |
| const heartHold = document.querySelector('#heartHold'); | |
| const holdMeterFill = document.querySelector('#holdMeterFill'); | |
| const holdStatusText = document.querySelector('#holdStatusText'); | |
| const holdInstruction = document.querySelector('#holdInstruction'); | |
| const topbarNote = document.querySelector('#topbarNote'); | |
| const HOLD_DURATION = 3200; | |
| let holdStartedAt = 0; | |
| let holdFrame = null; | |
| let isHolding = false; | |
| let hasCompleted = false; | |
| const holdLines = [ | |
| 'I’m right here', | |
| 'A little closer…', | |
| 'That’s it, Pookie', | |
| 'You are so, so loved', | |
| 'I’ve got you' | |
| ]; | |
| function showScreen(screen) { | |
| [introScreen, holdScreen, completeScreen].forEach((item) => { | |
| const active = item === screen; | |
| item.classList.toggle('is-active', active); | |
| item.setAttribute('aria-hidden', String(!active)); | |
| }); | |
| } | |
| function resetHold() { | |
| cancelAnimationFrame(holdFrame); | |
| isHolding = false; | |
| holdStartedAt = 0; | |
| heartHold.classList.remove('is-holding'); | |
| heartHold.style.setProperty('--progress', '0%'); | |
| holdMeterFill.style.width = '0%'; | |
| holdStatusText.textContent = 'I’m right here'; | |
| holdInstruction.textContent = 'Press and hold the heart to feel how much I love you.'; | |
| } | |
| function beginExperience() { | |
| resetHold(); | |
| showScreen(holdScreen); | |
| topbarNote.textContent = 'hold close'; | |
| window.setTimeout(() => heartHold.focus(), 60); | |
| } | |
| function updateHold(now) { | |
| if (!isHolding) return; | |
| const elapsed = now - holdStartedAt; | |
| const progress = Math.min(elapsed / HOLD_DURATION, 1); | |
| const percent = `${Math.round(progress * 100)}%`; | |
| heartHold.style.setProperty('--progress', percent); | |
| holdMeterFill.style.width = percent; | |
| const lineIndex = Math.min(Math.floor(progress * holdLines.length), holdLines.length - 1); | |
| holdStatusText.textContent = holdLines[lineIndex]; | |
| if (progress >= 1) { | |
| completeHug(); | |
| return; | |
| } | |
| holdFrame = requestAnimationFrame(updateHold); | |
| } | |
| function startHolding(event) { | |
| if (hasCompleted || isHolding) return; | |
| if (event?.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return; | |
| if (event?.cancelable) event.preventDefault(); | |
| isHolding = true; | |
| holdStartedAt = performance.now(); | |
| heartHold.classList.add('is-holding'); | |
| holdInstruction.textContent = 'Keep holding… let the warmth find you.'; | |
| holdFrame = requestAnimationFrame(updateHold); | |
| } | |
| function stopHolding(event) { | |
| if (event?.type === 'keyup' && event.key !== ' ' && event.key !== 'Enter') return; | |
| if (event?.cancelable) event.preventDefault(); | |
| if (!isHolding || hasCompleted) return; | |
| cancelAnimationFrame(holdFrame); | |
| isHolding = false; | |
| heartHold.classList.remove('is-holding'); | |
| holdStatusText.textContent = 'Almost… stay with me'; | |
| holdInstruction.textContent = 'You can hold a little longer for the full hug.'; | |
| } | |
| function completeHug() { | |
| cancelAnimationFrame(holdFrame); | |
| isHolding = false; | |
| hasCompleted = true; | |
| heartHold.classList.remove('is-holding'); | |
| heartHold.style.setProperty('--progress', '100%'); | |
| holdMeterFill.style.width = '100%'; | |
| holdStatusText.textContent = 'Hug complete'; | |
| topbarNote.textContent = 'made of warmth'; | |
| window.setTimeout(() => { | |
| showScreen(completeScreen); | |
| window.setTimeout(() => replayButton.focus(), 80); | |
| }, 420); | |
| } | |
| function replayHug() { | |
| hasCompleted = false; | |
| sendBackNote.textContent = ''; | |
| letterPanel.hidden = true; | |
| beginExperience(); | |
| } | |
| function openLetter() { | |
| letterPanel.hidden = false; | |
| letterButton.setAttribute('aria-expanded', 'true'); | |
| window.setTimeout(() => letterClose.focus(), 60); | |
| } | |
| function closeLetter() { | |
| letterPanel.hidden = true; | |
| letterButton.setAttribute('aria-expanded', 'false'); | |
| letterButton.focus(); | |
| } | |
| function sendHugBack() { | |
| sendBackNote.textContent = 'I felt that, Pookie. Keeping it close.'; | |
| sendBackButton.innerHTML = '<span aria-hidden="true">♥</span> Hug sent'; | |
| window.setTimeout(() => { | |
| sendBackButton.innerHTML = '<span aria-hidden="true">♡</span> Send another hug back'; | |
| }, 2600); | |
| } | |
| openButton.addEventListener('click', beginExperience); | |
| replayButton.addEventListener('click', replayHug); | |
| sendBackButton.addEventListener('click', sendHugBack); | |
| letterButton.addEventListener('click', openLetter); | |
| letterClose.addEventListener('click', closeLetter); | |
| heartHold.addEventListener('pointerdown', startHolding); | |
| heartHold.addEventListener('pointerup', stopHolding); | |
| heartHold.addEventListener('pointercancel', stopHolding); | |
| heartHold.addEventListener('pointerleave', stopHolding); | |
| heartHold.addEventListener('keydown', startHolding); | |
| heartHold.addEventListener('keyup', stopHolding); | |
| heartHold.addEventListener('blur', stopHolding); | |
| window.addEventListener('contextmenu', (event) => { | |
| if (event.target === heartHold) event.preventDefault(); | |
| }); | |