Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
| start [2026/06/11 21:08] – jumpstartadmin | start [2026/06/11 21:28] (current) – jumpstartadmin | ||
|---|---|---|---|
| Line 57: | Line 57: | ||
| .js-card: | .js-card: | ||
| - | .js-label { position: absolute; left: 0; width: 100%; z-index: 3; padding: 16px; font-family: | + | .js-label { position: absolute; left: 0; width: 100%; z-index: 3; padding: 16px; font-family: |
| .js-card: | .js-card: | ||
| Line 97: | Line 97: | ||
| } | } | ||
| - | .js-title-sub { font-family: | + | .js-title-sub { font-family: |
| - | .js-title-main { font-family: | + | .js-title-main { font-family: |
| .js-title-divider { display: flex; align-items: | .js-title-divider { display: flex; align-items: | ||
| Line 121: | Line 121: | ||
| .js-card: | .js-card: | ||
| - | /* Non-hovered cards — VHS chromatic aberration, JS controlled */ | + | /* VHS chromatic aberration |
| .js-card { | .js-card { | ||
| position: relative; | position: relative; | ||
| Line 127: | Line 127: | ||
| overflow: hidden; | overflow: hidden; | ||
| text-decoration: | text-decoration: | ||
| - | transition: filter 0.6s ease !important; | + | transition: filter 0.25s ease !important; |
| } | } | ||
| .js-card.js-fading { | .js-card.js-fading { | ||
| - | filter: saturate(0.5) brightness(0.9) blur(0.4px) !important; | + | filter: saturate(0.55) brightness(0.92) !important; |
| } | } | ||
| - | /* Red channel bleed — shifts right */ | + | /* Scanline overlay on fading |
| - | .js-card.js-fading::before { | + | |
| - | content: '' | + | |
| - | position: absolute !important; | + | |
| - | inset: -2px !important; | + | |
| - | z-index: 10 !important; | + | |
| - | pointer-events: | + | |
| - | background: inherit !important; | + | |
| - | mix-blend-mode: | + | |
| - | transform: translateX(3px) !important; | + | |
| - | filter: saturate(3) hue-rotate(-30deg) opacity(0.18) !important; | + | |
| - | animation: none !important; | + | |
| - | } | + | |
| - | + | ||
| - | /* Blue channel bleed — shifts left + scanlines | + | |
| .js-card.js-fading:: | .js-card.js-fading:: | ||
| content: '' | content: '' | ||
| position: absolute !important; | position: absolute !important; | ||
| inset: 0 !important; | inset: 0 !important; | ||
| - | z-index: | + | z-index: |
| pointer-events: | pointer-events: | ||
| - | background: | + | background: repeating-linear-gradient( |
| - | | + | 0deg, |
| - | 0deg, | + | transparent 0px, |
| - | transparent 0px, | + | transparent |
| - | transparent | + | rgba(0, 0, 0, 0.08) 3px, |
| - | rgba(100, 140, 255, 0.06) 1px, | + | rgba(0, 0, 0, 0.08) 4px |
| - | rgba(100, 140, 255, 0.06) 2px, | + | ) !important; |
| - | transparent 2px, | + | |
| - | transparent 4px, | + | |
| - | rgba(255, 60, 60, 0.04) 4px, | + | |
| - | rgba(255, 60, 60, 0.04) 5px | + | |
| - | ) !important; | + | |
| - | | + | |
| - | animation: vhsDrift 6s linear infinite !important; | + | |
| - | transform: translateX(-2px) !important; | + | |
| } | } | ||
| - | @keyframes vhsDrift | + | /* RGB canvas overlay */ |
| - | 0% { background-position: 0 0; } | + | .js-rgb-canvas |
| - | | + | |
| + | inset: | ||
| + | z-index: 11; | ||
| + | pointer-events: | ||
| + | opacity: 0; | ||
| + | transition: opacity 0.6s ease; | ||
| + | } | ||
| + | .js-card.js-fading .js-rgb-canvas | ||
| + | opacity: 1; | ||
| + | } | ||
| + | |||
| + | /* Block card hover effects when title zone is active */ | ||
| + | .js-wrap.js-title-active .js-card:hover video { | ||
| + | transform: scale(1) !important; | ||
| + | filter: brightness(0.6) saturate(0.8) !important; | ||
| + | } | ||
| + | .js-wrap.js-title-active .js-card: | ||
| + | | ||
| + | } | ||
| + | .js-wrap.js-title-active .js-card: | ||
| + | top: 50% !important; | ||
| + | transform: translateY(-50%) !important; | ||
| + | letter-spacing: | ||
| + | color: #EDE8F5 !important; | ||
| + | text-shadow: 0 1px 0 rgba(0, | ||
| + | opacity: 0.7 !important; | ||
| + | } | ||
| + | .js-wrap.js-title-active .js-card: | ||
| + | transform: translateX(-50%) scaleX(0) !important; | ||
| + | } | ||
| + | .js-wrap.js-title-active .js-card: | ||
| + | opacity: 0 !important; | ||
| } | } | ||
| Line 323: | Line 332: | ||
| < | < | ||
| - | // VHS chromatic aberration | + | // VHS RGB chromatic aberration |
| (function() { | (function() { | ||
| const cards = document.querySelectorAll(' | const cards = document.querySelectorAll(' | ||
| + | const wrap = document.querySelector(' | ||
| + | const titleEl = document.querySelector(' | ||
| let activeCard = null; | let activeCard = null; | ||
| let fadeTimeout = null; | let fadeTimeout = null; | ||
| - | | + | |
| + | const animFrames = new Map(); | ||
| - | | + | |
| - | const rect = card.getBoundingClientRect(); | + | cards.forEach(card => { |
| - | const zoneX = rect.width | + | const canvas = document.createElement(' |
| - | const zoneY = rect.height * 0.125; | + | canvas.className = ' |
| - | const x = e.clientX | + | card.appendChild(canvas); |
| - | const y = e.clientY | + | canvases.set(card, |
| - | return | + | }); |
| + | |||
| + | function drawRGB(card) { | ||
| + | const canvas = canvases.get(card); | ||
| + | const video = card.querySelector(' | ||
| + | if (!video || !canvas) return; | ||
| + | |||
| + | const w = card.offsetWidth; | ||
| + | const h = card.offsetHeight; | ||
| + | canvas.width | ||
| + | canvas.height = h; | ||
| + | const ctx = canvas.getContext(' | ||
| + | |||
| + | function frame() { | ||
| + | if (!card.classList.contains(' | ||
| + | ctx.clearRect(0, 0, w, h); | ||
| + | animFrames.delete(card); | ||
| + | return; | ||
| + | } | ||
| + | ctx.clearRect(0, | ||
| + | |||
| + | ctx.save(); | ||
| + | ctx.globalCompositeOperation = ' | ||
| + | ctx.globalAlpha = 0.18; | ||
| + | ctx.filter = ' | ||
| + | ctx.drawImage(video, | ||
| + | ctx.restore(); | ||
| + | |||
| + | ctx.save(); | ||
| + | ctx.globalCompositeOperation = ' | ||
| + | ctx.globalAlpha = 0.14; | ||
| + | ctx.filter = ' | ||
| + | ctx.drawImage(video, | ||
| + | ctx.restore(); | ||
| + | |||
| + | animFrames.set(card, | ||
| + | } | ||
| + | |||
| + | if (!animFrames.has(card)) { | ||
| + | animFrames.set(card, | ||
| + | } | ||
| + | } | ||
| + | |||
| + | function isTitleZone(e) { | ||
| + | const sub = document.querySelector(' | ||
| + | const main = document.querySelector(' | ||
| + | const divider | ||
| + | if (!sub || !main) return false; | ||
| + | const top = sub.getBoundingClientRect().top - 20; | ||
| + | const bottom = (divider || main).getBoundingClientRect().bottom + 20; | ||
| + | const left = main.getBoundingClientRect().left - 40; | ||
| + | const right = main.getBoundingClientRect().right + 40; | ||
| + | return | ||
| + | | ||
| + | } | ||
| + | |||
| + | function setTitleGlow(on) { | ||
| + | if (!titleEl) return; | ||
| + | if (on) { | ||
| + | titleEl.style.transition = 'text-shadow 0.3s ease'; | ||
| + | titleEl.style.textShadow = '0 0 120px rgba(184, | ||
| + | titleEl.style.color = '# | ||
| + | } else { | ||
| + | titleEl.style.transition = ' | ||
| + | titleEl.style.textShadow = ''; | ||
| + | titleEl.style.color = ''; | ||
| + | } | ||
| } | } | ||
| Line 342: | Line 420: | ||
| if (activeCard === hoveredCard) return; | if (activeCard === hoveredCard) return; | ||
| activeCard = hoveredCard; | activeCard = hoveredCard; | ||
| + | setTitleGlow(false); | ||
| + | wrap.classList.remove(' | ||
| cards.forEach(card => { | cards.forEach(card => { | ||
| if (card !== hoveredCard) { | if (card !== hoveredCard) { | ||
| card.classList.add(' | card.classList.add(' | ||
| - | | + | |
| } else { | } else { | ||
| card.classList.remove(' | card.classList.remove(' | ||
| - | card.classList.add(' | ||
| } | } | ||
| }); | }); | ||
| Line 355: | Line 434: | ||
| function clearFading() { | function clearFading() { | ||
| activeCard = null; | activeCard = null; | ||
| - | | + | |
| - | card.classList.remove(' | + | wrap.classList.remove(' |
| - | card.classList.remove(' | + | |
| - | }); | + | |
| } | } | ||
| - | cards.forEach(card => { | + | |
| - | | + | activeCard = ' |
| - | if (isInCenterZone(card, e)) { | + | setTitleGlow(true); |
| - | clearTimeout(fadeTimeout); | + | wrap.classList.add(' |
| - | // Only trigger after staying in center zone for 200ms | + | |
| - | | + | } |
| - | entryTimeout | + | |
| - | setFading(card); | + | wrap.addEventListener(' |
| - | | + | if (isTitleZone(e)) { |
| - | }, 200); | + | clearTimeout(fadeTimeout); |
| - | } | + | if (activeCard |
| - | } else { | + | |
| - | | + | } |
| - | entryTimeout | + | |
| - | // Only clear after leaving for 400ms | + | // Find which card the mouse is over |
| - | | + | let overCard |
| - | | + | |
| + | const rect = card.getBoundingClientRect(); | ||
| + | if (e.clientX >= rect.left && e.clientX <= rect.right && | ||
| + | | ||
| + | overCard = card; | ||
| } | } | ||
| }); | }); | ||
| - | | + | |
| - | clearTimeout(entryTimeout); | + | |
| - | entryTimeout = null; | + | |
| clearTimeout(fadeTimeout); | clearTimeout(fadeTimeout); | ||
| - | | + | |
| - | }); | + | } |
| + | }); | ||
| + | |||
| + | wrap.addEventListener(' | ||
| + | clearTimeout(fadeTimeout); | ||
| + | fadeTimeout = setTimeout(clearFading, | ||
| }); | }); | ||
| })(); | })(); | ||
| </ | </ | ||
| </ | </ | ||