From f7e649ce265d0ecb3780cd25a4b915be73402520 Mon Sep 17 00:00:00 2001 From: John Bampton Date: Mon, 26 Jan 2026 18:09:52 +1000 Subject: [PATCH] Surprise me hover glow; screenshot mode --- src/_includes/footer.njk | 8 ++++ src/_includes/header.njk | 8 ++-- src/assets/css/style.css | 96 +++++++++++++++++++++++++++++++--------- src/assets/js/script.js | 79 ++++++++++++++++++++++++++------- 4 files changed, 151 insertions(+), 40 deletions(-) diff --git a/src/_includes/footer.njk b/src/_includes/footer.njk index 71de0b1b..e32ddde7 100644 --- a/src/_includes/footer.njk +++ b/src/_includes/footer.njk @@ -72,6 +72,14 @@ +1 LVL + +
{% endif %} diff --git a/src/assets/css/style.css b/src/assets/css/style.css index 947fb47d..76a4eb88 100644 --- a/src/assets/css/style.css +++ b/src/assets/css/style.css @@ -42,38 +42,36 @@ html, body { /** * 2. USER CARDS - DYNAMIC & STATIC */ -.user-card h2 { - /* Dynamic color from theme logic */ - color: var(--accent) !important; - font-weight: 800; - transition: color 0.3s ease; /* Only animate the color fade, not movement */ - margin-bottom: 0.5rem; -} - -/* Hover state: No movement, just a slight brightness shift */ -.user-card:hover h2 { - filter: brightness(1.1); -} - /** - * 3. PROFILE LINKS - THEMED + * DYNAMIC COLORING (NO ANIMATION) */ +.user-card h2, .profile-link, -.user-card a[href*="github"], -.user-card a[href*="linkedin"] { +.user-card a { color: var(--accent) !important; - font-weight: 700; + font-weight: 800; text-decoration: none; - transition: opacity 0.2s ease; - display: inline-flex; - align-items: center; - gap: 0.4rem; + /* Animate ONLY the color property when theme changes */ + transition: color 0.4s ease, opacity 0.2s ease; +} + +/* Static Hover: No movement */ +.user-card:hover h2 { + filter: brightness(1.2); } .profile-link:hover, .user-card a:hover { text-decoration: underline; - opacity: 0.8; /* Subtle visual feedback instead of moving */ + opacity: 0.8; +} + +/* Button to trigger Screenshot Mode in the Dev Panel */ +.screenshot-btn { + border-color: var(--text-muted) !important; + color: var(--text-muted) !important; + font-size: 0.6rem !important; + margin-top: 10px; } /* If your links look like tags/pills */ @@ -291,3 +289,57 @@ html body #dev-tools[data-lock="true"] { } .konami-roll { animation: konami-barrel-roll 2s cubic-bezier(0.45, 0.05, 0.55, 0.95); } + +/** + * FANCY USER SELECTION EFFECT + */ +@keyframes fancy-ping { + 0% { + box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0.7); + } + 70% { + box-shadow: 0 0 0 20px rgba(var(--accent-rgb), 0); + } + 100% { + box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0); + } +} +/* Ensure the card can show the trace glow */ +.user-card.selected-fancy { + z-index: 50; + overflow: visible !important; + transform: scale(1.02); + transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); +} + +.border-trace { + position: absolute; + inset: -2px; /* Slightly outside the card border */ + width: calc(100% + 4px); + height: calc(100% + 4px); + pointer-events: none; + fill: none; +} + +.border-trace rect { + stroke-width: 4px; + stroke-linecap: round; + /* Perimeter length - 2500px is a safe bet for these cards */ + stroke-dasharray: 2500; + stroke-dashoffset: 2500; + animation: retrace-sequence 7.5s linear forwards; +} + +@keyframes retrace-sequence { + 0% { + stroke-dashoffset: 2500; + stroke: var(--accent); + filter: drop-shadow(0 0 8px var(--accent)); + } + 100% { + stroke-dashoffset: 0; + /* Cycle through colors while drawing */ + stroke: var(--accent); + filter: drop-shadow(0 0 12px var(--accent)) hue-rotate(360deg); + } +} diff --git a/src/assets/js/script.js b/src/assets/js/script.js index e029411f..6fcf44a8 100644 --- a/src/assets/js/script.js +++ b/src/assets/js/script.js @@ -193,8 +193,8 @@ function applyTheme(theme) { html.style.setProperty('--bg-footer', `hsl(${h}, 40%, 5%)`); // Deepest html.style.setProperty('--text-main', `hsl(${h}, 20%, 95%)`); // Near White html.style.setProperty('--text-muted', `hsl(${h}, 15%, 70%)`); // Softened - html.style.setProperty('--accent', `hsl(${h}, 90%, 65%)`); // Vivid Pop - html.style.setProperty('--accent-light', `hsla(${h}, 90%, 65%, 0.15)`); + html.style.setProperty('--accent', `hsl(${h}, 95%, 70%)`); // Vivid Pop + html.style.setProperty('--accent-light', `hsla(${h}, 95%, 70%, 0.2)`); html.style.setProperty('--border-color', `hsl(${h}, 30%, 20%)`); if (heart) { @@ -439,32 +439,81 @@ window.startSelfDestruct = function() { function scrollToRandomUser() { playSound('click'); - // 1. Secret Unlock Logic surpriseClickCount++; if (surpriseClickCount >= 5) { surpriseClickCount = 0; - // This triggers the Matrix overlay triggerSecretUnlock('matrix'); + return; } - // 2. Scrolling Logic const cards = document.querySelectorAll('.user-card'); - if (cards.length === 0) { - console.warn("No .user-card elements found to scroll to."); - return; - } + if (cards.length === 0) return; - // Clear previous highlights - cards.forEach(c => c.classList.remove('highlight-pulse')); + // Clean up previous selection + cards.forEach(c => { + c.classList.remove('selected-fancy'); + const oldTrace = c.querySelector('.border-trace'); + if (oldTrace) oldTrace.remove(); + }); - // Pick a random card and scroll const randomCard = cards[Math.floor(Math.random() * cards.length)]; - randomCard.scrollIntoView({ behavior: 'smooth', block: 'center' }); // Changed to center for better visibility + randomCard.scrollIntoView({ behavior: 'smooth', block: 'center' }); + + setTimeout(() => { + playSound('levelUp'); + randomCard.classList.add('selected-fancy'); + + // Inject the Tracing SVG + const svgNamespace = "http://www.w3.org/2000/svg"; + const svg = document.createElementNS(svgNamespace, "svg"); + const rect = document.createElementNS(svgNamespace, "rect"); + + svg.setAttribute("class", "border-trace"); + rect.setAttribute("fill", "none"); + rect.setAttribute("width", "100%"); + rect.setAttribute("height", "100%"); + + svg.appendChild(rect); + randomCard.appendChild(svg); - // Add the pulse animation - randomCard.classList.add('highlight-pulse'); + // Remove trace and fancy class after the 7.5s animation ends + setTimeout(() => { + randomCard.classList.remove('selected-fancy'); + svg.remove(); + }, 7500); + }, 400); } +/** + * UTILITY: SCREENSHOT MODE + */ +window.toggleScreenshotMode = function() { + const devPanel = document.getElementById('dev-tools'); + const header = document.querySelector('header'); + const footer = document.querySelector('footer'); + const gameStats = document.getElementById('game-stats'); + + // Hide everything + [devPanel, header, footer, gameStats].forEach(el => { + if(el) el.style.opacity = '0'; + if(el) el.style.pointerEvents = 'none'; + }); + + // Show a tiny notification that it's active + const toast = document.createElement('div'); + toast.style.cssText = "position:fixed; bottom:20px; left:50%; transform:translateX(-50%); color:var(--text-muted); font-family:monospace; font-size:10px; z-index:9999;"; + toast.innerText = "SCREENSHOT MODE ACTIVE - RESTORING IN 5S"; + document.body.appendChild(toast); + + setTimeout(() => { + [devPanel, header, footer, gameStats].forEach(el => { + if(el) el.style.opacity = '1'; + if(el) el.style.pointerEvents = 'auto'; + }); + toast.remove(); + }, 5000); +}; + /** * 8. INITIALIZATION */