Last active
March 11, 2026 06:41
-
-
Save HoughIO/3ea501592a59a5504bdd90b8b9075471 to your computer and use it in GitHub Desktop.
Trading cards with back button
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Pet Trading Cards</title> | |
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css"> | |
| <style> | |
| * { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { | |
| min-height: 100vh; | |
| background: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 50%, #16213e 100%); | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; | |
| overflow-x: hidden; | |
| } | |
| .header { | |
| text-align: center; | |
| padding: 2rem 1rem; | |
| color: white; | |
| } | |
| .header h1 { | |
| font-size: 2.5rem; | |
| background: linear-gradient(90deg, #ffd700, #ff8c00, #ff6b6b, #ff8c00, #ffd700); | |
| background-size: 200% auto; | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| animation: shine 3s linear infinite; | |
| margin-bottom: 0.5rem; | |
| } | |
| .header p { | |
| color: rgba(255,255,255,0.6); | |
| font-size: 1rem; | |
| } | |
| .back-btn { | |
| display: inline-block; | |
| color: #ffd700; | |
| text-decoration: none; | |
| font-size: 0.9rem; | |
| margin-bottom: 1rem; | |
| padding: 0.5rem 1rem; | |
| border: 1px solid rgba(255,215,0,0.3); | |
| border-radius: 2rem; | |
| transition: all 0.3s; | |
| } | |
| .back-btn:hover { | |
| background: rgba(255,215,0,0.1); | |
| border-color: #ffd700; | |
| } | |
| @keyframes shine { | |
| to { background-position: 200% center; } | |
| } | |
| /* Filter buttons */ | |
| .filters { | |
| display: flex; | |
| justify-content: center; | |
| gap: 1rem; | |
| margin-bottom: 2rem; | |
| flex-wrap: wrap; | |
| padding: 0 1rem; | |
| } | |
| .filter-btn { | |
| background: rgba(255,255,255,0.1); | |
| border: 1px solid rgba(255,255,255,0.2); | |
| color: white; | |
| padding: 0.5rem 1.5rem; | |
| border-radius: 2rem; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| font-size: 0.9rem; | |
| } | |
| .filter-btn:hover, .filter-btn.active { | |
| background: linear-gradient(135deg, #ffd700, #ff8c00); | |
| border-color: transparent; | |
| color: black; | |
| transform: scale(1.05); | |
| } | |
| /* Swiper */ | |
| .swiper { | |
| width: 100%; | |
| padding: 2rem 0 4rem; | |
| } | |
| .swiper-slide { | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| width: 320px; | |
| } | |
| .swiper-pagination-bullet { | |
| background: rgba(255,255,255,0.5); | |
| } | |
| .swiper-pagination-bullet-active { | |
| background: #ffd700; | |
| } | |
| .swiper-button-next, .swiper-button-prev { | |
| color: #ffd700; | |
| } | |
| /* Card Styles */ | |
| :root { | |
| --pointer-x: 50%; | |
| --pointer-y: 50%; | |
| --card-opacity: 0; | |
| --rotate-x: 0deg; | |
| --rotate-y: 0deg; | |
| } | |
| .card-container { | |
| perspective: 1500px; | |
| width: 280px; | |
| } | |
| .card { | |
| position: relative; | |
| width: 100%; | |
| aspect-ratio: 0.714; | |
| border-radius: 4.5% / 3.2%; | |
| transform-style: preserve-3d; | |
| transform: rotateY(var(--rotate-x)) rotateX(var(--rotate-y)); | |
| transition: transform 0.15s ease-out, box-shadow 0.3s; | |
| cursor: grab; | |
| box-shadow: | |
| 0 0 5px -1px rgba(255,255,255,0.5), | |
| 0 0 10px 1px rgba(255,215,0,0.3), | |
| 0 0 20px 3px rgba(255,215,0,0.2), | |
| 0px 30px 60px -15px rgba(0,0,0,0.8); | |
| } | |
| .card:hover { | |
| box-shadow: | |
| 0 0 10px 0px rgba(255,255,255,0.8), | |
| 0 0 20px 3px rgba(255,215,0,0.5), | |
| 0 0 40px 8px rgba(255,215,0,0.3), | |
| 0px 40px 80px -20px rgba(0,0,0,0.9); | |
| } | |
| .card__image { | |
| position: absolute; | |
| inset: 0; | |
| border-radius: inherit; | |
| overflow: hidden; | |
| background: #1a1a2e; | |
| } | |
| .card__image img { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: cover; | |
| object-position: top; | |
| } | |
| .card__shine { | |
| position: absolute; | |
| inset: 0; | |
| border-radius: inherit; | |
| background: | |
| repeating-linear-gradient( | |
| 82deg, | |
| hsl(53, 65%, 60%) 0%, | |
| hsl(93, 56%, 50%) 8%, | |
| hsl(176, 54%, 49%) 16%, | |
| hsl(228, 59%, 55%) 24%, | |
| hsl(283, 60%, 55%) 32%, | |
| hsl(326, 59%, 51%) 40%, | |
| hsl(326, 59%, 51%) 48%, | |
| hsl(283, 60%, 55%) 56%, | |
| hsl(228, 59%, 55%) 64%, | |
| hsl(176, 54%, 49%) 72%, | |
| hsl(93, 56%, 50%) 80%, | |
| hsl(53, 65%, 60%) 88% | |
| ); | |
| background-size: 400% 900%; | |
| background-position: | |
| calc(10% + (var(--pointer-x) * 0.8)) | |
| calc(10% + (var(--pointer-y) * 0.8)); | |
| filter: brightness(0.8) contrast(2.5) saturate(0.8); | |
| mix-blend-mode: color-dodge; | |
| opacity: var(--card-opacity); | |
| pointer-events: none; | |
| } | |
| .card__glare { | |
| position: absolute; | |
| inset: 0; | |
| border-radius: inherit; | |
| background: radial-gradient( | |
| farthest-corner circle at var(--pointer-x) var(--pointer-y), | |
| hsla(0, 0%, 100%, 0.8) 10%, | |
| hsla(0, 0%, 100%, 0.4) 30%, | |
| hsla(0, 0%, 0%, 0.5) 90% | |
| ); | |
| mix-blend-mode: overlay; | |
| opacity: var(--card-opacity); | |
| pointer-events: none; | |
| } | |
| .card__sparkle { | |
| position: absolute; | |
| inset: 0; | |
| border-radius: inherit; | |
| background-image: | |
| radial-gradient(circle at 20% 30%, rgba(255,255,255,0.9) 0%, transparent 2%), | |
| radial-gradient(circle at 80% 20%, rgba(255,255,255,0.7) 0%, transparent 1.5%), | |
| radial-gradient(circle at 40% 70%, rgba(255,255,255,0.8) 0%, transparent 1.8%), | |
| radial-gradient(circle at 70% 60%, rgba(255,255,255,0.6) 0%, transparent 1.2%), | |
| radial-gradient(circle at 30% 50%, rgba(255,255,255,0.7) 0%, transparent 1.5%), | |
| radial-gradient(circle at 60% 40%, rgba(255,255,255,0.8) 0%, transparent 1.7%), | |
| radial-gradient(circle at 85% 75%, rgba(255,255,255,0.6) 0%, transparent 1.3%), | |
| radial-gradient(circle at 15% 80%, rgba(255,255,255,0.7) 0%, transparent 1.4%); | |
| opacity: calc(var(--card-opacity) * 0.9); | |
| pointer-events: none; | |
| animation: sparkle 2.5s ease-in-out infinite; | |
| } | |
| @keyframes sparkle { | |
| 0%, 100% { opacity: calc(var(--card-opacity) * 0.6); } | |
| 50% { opacity: var(--card-opacity); } | |
| } | |
| .card__label { | |
| position: absolute; | |
| bottom: 0; | |
| left: 0; | |
| right: 0; | |
| background: linear-gradient(transparent, rgba(0,0,0,0.9)); | |
| padding: 3rem 1rem 1rem; | |
| color: white; | |
| text-align: center; | |
| border-radius: 0 0 inherit inherit; | |
| } | |
| .card__name { | |
| font-size: 1rem; | |
| font-weight: bold; | |
| background: linear-gradient(90deg, #ffd700, #fff, #ffd700); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| margin-bottom: 0.25rem; | |
| } | |
| .card__theme { | |
| font-size: 0.75rem; | |
| text-transform: uppercase; | |
| letter-spacing: 2px; | |
| color: rgba(255,255,255,0.6); | |
| } | |
| /* Mobile touch hint */ | |
| .touch-hint { | |
| text-align: center; | |
| color: rgba(255,255,255,0.4); | |
| font-size: 0.8rem; | |
| padding: 1rem; | |
| padding-bottom: 100px; | |
| } | |
| @media (min-width: 768px) { | |
| .touch-hint { display: none; } | |
| } | |
| /* Bottom tabs */ | |
| .tabs { | |
| position: fixed; | |
| bottom: 0; | |
| left: 0; | |
| right: 0; | |
| display: flex; | |
| background: #0a0a0a; | |
| border-top: 1px solid rgba(255,255,255,0.08); | |
| padding-bottom: env(safe-area-inset-bottom); | |
| z-index: 100; | |
| } | |
| .tab { | |
| flex: 1; | |
| padding: 12px; | |
| text-align: center; | |
| color: rgba(255,255,255,0.5); | |
| font-size: 0.75rem; | |
| cursor: pointer; | |
| text-decoration: none; | |
| display: block; | |
| } | |
| .tab.active { | |
| color: #ff6b6b; | |
| } | |
| .tab-icon { | |
| font-size: 1.4rem; | |
| display: block; | |
| margin-bottom: 4px; | |
| } | |
| .swiper { | |
| padding-bottom: 100px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="header"> | |
| <a href="index.html" class="back-btn">β Back to Cam</a> | |
| <h1>π΄ Pet Trading Cards π΄</h1> | |
| <p>Swipe to browse β’ Hover for holographic effect</p> | |
| </div> | |
| <div class="filters"> | |
| <button class="filter-btn active" data-filter="all">All Cards</button> | |
| <button class="filter-btn" data-filter="kevin">π± Kevin</button> | |
| <button class="filter-btn" data-filter="todd">π± Todd</button> | |
| <button class="filter-btn" data-filter="simba">π Simba</button> | |
| </div> | |
| <div class="swiper"> | |
| <div class="swiper-wrapper" id="cards-wrapper"> | |
| <!-- Cards injected by JS --> | |
| </div> | |
| <div class="swiper-pagination"></div> | |
| <div class="swiper-button-prev"></div> | |
| <div class="swiper-button-next"></div> | |
| </div> | |
| <div class="touch-hint">π Tap and drag cards to feel the holo effect</div> | |
| <!-- Bottom nav to match main app --> | |
| <nav class="tabs"> | |
| <a href="index.html" class="tab"><span class="tab-icon">πΊ</span>Live</a> | |
| <a href="index.html#clips" class="tab"><span class="tab-icon">π¬</span>Clips</a> | |
| <a href="trading-cards.html" class="tab active"><span class="tab-icon">π΄</span>Cards</a> | |
| <a href="index.html#activity" class="tab"><span class="tab-icon">π</span>Activity</a> | |
| </nav> | |
| <script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script> | |
| <script> | |
| const CARDS = [ | |
| // Kevin | |
| { pet: 'kevin', name: 'Kevin', theme: 'Samurai', image: 'trading-cards/batch-001/kevin-samurai.png' }, | |
| { pet: 'kevin', name: 'Kevin', theme: 'Space Captain', image: 'trading-cards/batch-001/kevin-space-captain.png' }, | |
| { pet: 'kevin', name: 'Kevin', theme: 'Vampire', image: 'trading-cards/batch-001/kevin-vampire.png' }, | |
| { pet: 'kevin', name: 'Kevin', theme: 'Chef', image: 'trading-cards/batch-001/kevin-chef.png' }, | |
| { pet: 'kevin', name: 'Kevin', theme: 'Disco', image: 'trading-cards/batch-001/kevin-disco.png' }, | |
| { pet: 'kevin', name: 'Kevin', theme: 'Sopranos', image: 'trading-cards/batch-001/kevin-sopranos.png' }, | |
| { pet: 'kevin', name: 'Kevin', theme: 'Classical', image: 'trading-cards/batch-001/kevin-classical.png' }, | |
| // Todd | |
| { pet: 'todd', name: 'Todd', theme: 'Samurai', image: 'trading-cards/batch-001/todd-samurai.png' }, | |
| { pet: 'todd', name: 'Todd', theme: 'Space Captain', image: 'trading-cards/batch-001/todd-space-captain.png' }, | |
| { pet: 'todd', name: 'Todd', theme: 'Vampire', image: 'trading-cards/batch-001/todd-vampire.png' }, | |
| { pet: 'todd', name: 'Todd', theme: 'Chef', image: 'trading-cards/batch-001/todd-chef.png' }, | |
| { pet: 'todd', name: 'Todd', theme: 'Disco', image: 'trading-cards/batch-001/todd-disco.png' }, | |
| { pet: 'todd', name: 'Todd', theme: 'Sopranos', image: 'trading-cards/batch-001/todd-sopranos.png' }, | |
| { pet: 'todd', name: 'Todd', theme: 'Classical', image: 'trading-cards/batch-001/todd-classical.png' }, | |
| // Simba | |
| { pet: 'simba', name: 'Simba', theme: 'Samurai', image: 'trading-cards/batch-001/simba-samurai.png' }, | |
| { pet: 'simba', name: 'Simba', theme: 'Space Captain', image: 'trading-cards/batch-001/simba-space-captain.png' }, | |
| { pet: 'simba', name: 'Simba', theme: 'Vampire', image: 'trading-cards/batch-001/simba-vampire.png' }, | |
| { pet: 'simba', name: 'Simba', theme: 'Chef', image: 'trading-cards/batch-001/simba-chef.png' }, | |
| { pet: 'simba', name: 'Simba', theme: 'Disco', image: 'trading-cards/batch-001/simba-disco.png' }, | |
| { pet: 'simba', name: 'Simba', theme: 'Sopranos', image: 'trading-cards/batch-001/simba-sopranos.png' }, | |
| { pet: 'simba', name: 'Simba', theme: 'Classical', image: 'trading-cards/batch-001/simba-classical.png' }, | |
| ]; | |
| let currentFilter = 'all'; | |
| let swiper; | |
| function createCardHTML(card) { | |
| return ` | |
| <div class="swiper-slide" data-pet="${card.pet}"> | |
| <div class="card-container"> | |
| <div class="card"> | |
| <div class="card__image"> | |
| <img src="${card.image}" alt="${card.name} - ${card.theme}" loading="lazy"> | |
| </div> | |
| <div class="card__shine"></div> | |
| <div class="card__glare"></div> | |
| <div class="card__sparkle"></div> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| } | |
| function renderCards(filter = 'all') { | |
| const wrapper = document.getElementById('cards-wrapper'); | |
| const filtered = filter === 'all' ? CARDS : CARDS.filter(c => c.pet === filter); | |
| wrapper.innerHTML = filtered.map(createCardHTML).join(''); | |
| if (swiper) { | |
| swiper.destroy(); | |
| } | |
| swiper = new Swiper('.swiper', { | |
| effect: 'coverflow', | |
| grabCursor: true, | |
| centeredSlides: true, | |
| slidesPerView: 'auto', | |
| coverflowEffect: { | |
| rotate: 15, | |
| stretch: 0, | |
| depth: 200, | |
| modifier: 1, | |
| slideShadows: true, | |
| }, | |
| pagination: { | |
| el: '.swiper-pagination', | |
| clickable: true, | |
| }, | |
| navigation: { | |
| nextEl: '.swiper-button-next', | |
| prevEl: '.swiper-button-prev', | |
| }, | |
| keyboard: true, | |
| loop: filtered.length > 3, | |
| }); | |
| initCardEffects(); | |
| } | |
| function initCardEffects() { | |
| document.querySelectorAll('.card').forEach(card => { | |
| const handleMove = (clientX, clientY) => { | |
| const rect = card.getBoundingClientRect(); | |
| const x = clientX - rect.left; | |
| const y = clientY - rect.top; | |
| const percentX = (x / rect.width) * 100; | |
| const percentY = (y / rect.height) * 100; | |
| const centerX = percentX - 50; | |
| const centerY = percentY - 50; | |
| card.style.setProperty('--pointer-x', percentX + '%'); | |
| card.style.setProperty('--pointer-y', percentY + '%'); | |
| card.style.setProperty('--rotate-x', (centerX / 4) + 'deg'); | |
| card.style.setProperty('--rotate-y', (-centerY / 4) + 'deg'); | |
| card.style.setProperty('--card-opacity', '0.75'); | |
| }; | |
| const handleEnd = () => { | |
| card.style.setProperty('--rotate-x', '0deg'); | |
| card.style.setProperty('--rotate-y', '0deg'); | |
| card.style.setProperty('--card-opacity', '0'); | |
| }; | |
| // Mouse | |
| card.addEventListener('mousemove', e => handleMove(e.clientX, e.clientY)); | |
| card.addEventListener('mouseleave', handleEnd); | |
| // Touch | |
| card.addEventListener('touchmove', e => { | |
| if (e.touches.length === 1) { | |
| handleMove(e.touches[0].clientX, e.touches[0].clientY); | |
| } | |
| }); | |
| card.addEventListener('touchend', handleEnd); | |
| }); | |
| } | |
| // Filter buttons | |
| document.querySelectorAll('.filter-btn').forEach(btn => { | |
| btn.addEventListener('click', () => { | |
| document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active')); | |
| btn.classList.add('active'); | |
| renderCards(btn.dataset.filter); | |
| }); | |
| }); | |
| // Initial render | |
| renderCards(); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment