Adding intro to the app with a skip button

This commit is contained in:
Zakaria
2026-05-21 09:38:27 -04:00
parent 69ed1c78ad
commit 166eacdbfd
6 changed files with 1053 additions and 6 deletions
+138
View File
@@ -17,6 +17,9 @@ let authProfile = null
let leaderboardScope = "hour"
let latestLeaderboardRows = []
let lastDefinition = null
let introDismissed = false
let pendingInteractionStart = false
let introTimers = []
const WORD_LENGTH = 5
const MAX_GUESSES = 6
@@ -26,6 +29,25 @@ const STATS_KEY = "fancy-wordle-stats-v2"
const LOCAL_ROUND_KEY = "fancy-wordle-hourly-round-v1"
const PLAY_INTERVAL_MS = 60 * 60 * 1000
const GUESS_TIMEOUT_MS = 10000
const INTRO_DURATION_MS = 5200
const INTRO_LETTER_SETS = [
["D", "E", "S", "I", "G", "N"],
["C", "A", "M", "E", "R", "A"],
["A", "S", "P", "E", "C", "T"],
["W", "O", "R", "D", "L", "E"]
]
const INTRO_STATUS_SETS = [
["wrong", "wrong", "wrong", "wrong", "wrong", "wrong"],
["wrong", "misplaced", "wrong", "misplaced", "wrong", "wrong"],
["misplaced", "wrong", "misplaced", "wrong", "wrong", "misplaced"],
["correct", "correct", "correct", "correct", "correct", "correct"]
]
const INTRO_SOUND_EVENTS = [
[280, "flip-start"],
[1280, "misplaced-pass"],
[2460, "answer-lock"],
[3720, "logo-lock"]
]
const KEY_ROWS = ["QWERTYUIOP", "ASDFGHJKL", "ZXCVBNM"]
const FALLBACK_TARGET_WORDS = [
"about",
@@ -102,6 +124,10 @@ const guessBars = document.getElementById("guess-bars")
const statsDefinition = document.getElementById("stats-definition")
const resetStatsButton = document.getElementById("reset-stats")
const shareResultsButton = document.getElementById("share-results")
const introOverlay = document.getElementById("intro-overlay")
const introSkipButton = document.getElementById("intro-skip")
const introTileRow = document.getElementById("intro-tiles")
const introTiles = Array.from(document.querySelectorAll(".intro-tile"))
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initializeGame, { once: true })
@@ -113,6 +139,7 @@ async function initializeGame() {
if (hasInitialized) return
hasInitialized = true
initializeIntro()
createBoard()
createKeyboard()
restoreTheme()
@@ -132,6 +159,111 @@ async function initializeGame() {
await startHourlyRound()
}
function initializeIntro() {
if (!introOverlay || introTiles.length === 0) {
introDismissed = true
document.body.classList.remove("intro-active")
return
}
if (introOverlay.dataset.initialized) return
introOverlay.dataset.initialized = "true"
introDismissed = false
document.body.classList.add("intro-active")
introSkipButton?.addEventListener("click", dismissIntro)
if (prefersReducedMotion()) {
setIntroFrame(INTRO_LETTER_SETS.length - 1, false)
introTileRow?.classList.add("is-solved", "is-logo")
introTimers.push(setTimeout(dismissIntro, 700))
return
}
scheduleIntroSequence()
introTimers.push(setTimeout(dismissIntro, INTRO_DURATION_MS))
}
function prefersReducedMotion() {
return window.matchMedia?.("(prefers-reduced-motion: reduce)").matches
}
function setIntroTile(tile, letter, status) {
const letterElement = tile.querySelector(".intro-letter")
tile.dataset.status = status
if (letterElement) letterElement.textContent = letter
}
function flipIntroTile(tile, letter, status, delay) {
introTimers.push(setTimeout(() => {
tile.classList.add("is-flipping")
introTimers.push(setTimeout(() => setIntroTile(tile, letter, status), 130))
introTimers.push(setTimeout(() => tile.classList.remove("is-flipping"), 285))
}, delay))
}
function setIntroFrame(frameIndex, animate = true) {
introTiles.forEach((tile, index) => {
const letter = INTRO_LETTER_SETS[frameIndex][index]
const status = INTRO_STATUS_SETS[frameIndex][index]
if (animate) {
flipIntroTile(tile, letter, status, index * 58)
return
}
tile.classList.remove("is-flipping")
setIntroTile(tile, letter, status)
})
if (frameIndex === INTRO_LETTER_SETS.length - 1) {
introTimers.push(setTimeout(() => introTileRow?.classList.add("is-solved"), 420))
introTimers.push(setTimeout(() => introTileRow?.classList.add("is-logo"), 1180))
}
}
function dispatchIntroSoundCue(name) {
window.dispatchEvent(new CustomEvent("wordleIntro:soundCue", { detail: { name } }))
}
function scheduleIntroSequence() {
clearIntroTimers()
introTileRow?.classList.remove("is-solved", "is-logo")
setIntroFrame(0, false)
const frameTimes = [880, 1720, 2580]
frameTimes.forEach((time, index) => {
introTimers.push(setTimeout(() => setIntroFrame(index + 1, true), time))
})
INTRO_SOUND_EVENTS.forEach(([time, name]) => {
introTimers.push(setTimeout(() => dispatchIntroSoundCue(name), time))
})
}
function clearIntroTimers() {
introTimers.forEach(clearTimeout)
introTimers = []
}
function dismissIntro() {
if (introDismissed) return
introDismissed = true
clearIntroTimers()
setIntroFrame(INTRO_LETTER_SETS.length - 1, false)
introTileRow?.classList.add("is-solved", "is-logo")
introOverlay?.classList.add("is-dismissing")
document.body.classList.remove("intro-active")
setTimeout(() => {
if (introOverlay) introOverlay.hidden = true
}, 540)
if (pendingInteractionStart && !gameFinished) {
pendingInteractionStart = false
startInteraction()
}
}
async function loadWordLists() {
targetWords = await loadWordList("targetWords")
@@ -755,6 +887,12 @@ async function signOut() {
}
function startInteraction() {
if (!introDismissed) {
pendingInteractionStart = true
return
}
pendingInteractionStart = false
stopInteraction()
document.addEventListener("click", handleMouseClick)
document.addEventListener("keydown", handleKeyPress)