Created
April 30, 2026 09:59
-
-
Save carddass2018-svg/f181f73187bb283bffb6529ba6f56d71 to your computer and use it in GitHub Desktop.
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="zh-Hant"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |
| <style> | |
| body { background: #000; margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; overflow: hidden; font-family: sans-serif; } | |
| #settings-btn { position: fixed; top: 15px; left: 15px; z-index: 1000; background: rgba(0,0,0,0.6); color: #0f0; border: 1px solid #0f0; padding: 10px; border-radius: 50%; width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; font-size: 20px; } | |
| .panel { position: fixed; top: 0; left: 0; width: 100%; background: #111; padding: 20px; border-bottom: 2px solid #333; z-index: 999; box-sizing: border-box; transform: translateY(-100%); transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1); } | |
| .panel.active { transform: translateY(0); } | |
| .upload-row { margin-bottom: 15px; } | |
| input[type="file"] { font-size: 13px; color: #0f0; } | |
| .stage { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; perspective: 1200px; } | |
| #card { | |
| width: 82vw; max-width: 320px; aspect-ratio: 1 / 1.4; | |
| position: relative; border-radius: 16px; overflow: hidden; | |
| background: #000; box-shadow: 0 0 50px rgba(0,0,0,1); | |
| will-change: transform; | |
| } | |
| .layer { position: absolute; inset: 0; pointer-events: none; } | |
| #c-base { width: 100%; height: 100%; object-fit: cover; z-index: 1; } | |
| /* 強化閃紋層:找回明顯的質感 */ | |
| #foil-wrap { | |
| z-index: 2; | |
| mix-blend-mode: color-dodge; | |
| opacity: 0.25; /* 提高基礎亮度 */ | |
| -webkit-mask-size: 100% 100%; | |
| mask-size: 100% 100%; | |
| will-change: filter, opacity; | |
| } | |
| #c-foil { | |
| background-size: cover; | |
| background-position: center; | |
| filter: contrast(1.8) saturate(1.5); /* 預設高對比,讓閃紋更突出 */ | |
| } | |
| #c-shine { | |
| z-index: 3; | |
| background: linear-gradient(110deg, transparent 40%, rgba(255,255,255,0.4) 50%, transparent 60%); | |
| background-size: 250% 250%; | |
| mix-blend-mode: overlay; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="settings-btn" onclick="document.getElementById('ui-panel').classList.toggle('active')">⚙️</div> | |
| <div class="panel" id="ui-panel"> | |
| <div class="upload-row"><label style="font-size:12px;color:#888">1. 原圖</label><br><input type="file" accept="image/*" onchange="up(event, 'base')"></div> | |
| <div class="upload-row"><label style="font-size:12px;color:#888">2. 遮罩 (人唔閃)</label><br><input type="file" accept="image/*" onchange="up(event, 'mask')"></div> | |
| <div class="upload-row"><label style="font-size:12px;color:#888">3. 閃紋貼圖</label><br><input type="file" accept="image/*" onchange="up(event, 'foil')"></div> | |
| <button onclick="document.getElementById('ui-panel').classList.remove('active')" style="width:100%; padding:12px; background:#004400; color:#0f0; border:none; border-radius:8px;">完成</button> | |
| </div> | |
| <div class="stage"> | |
| <div id="card"> | |
| <img id="c-base" src="https://asobi-center.com"> | |
| <div id="foil-wrap" class="layer"> | |
| <div id="c-foil" class="layer"></div> | |
| </div> | |
| <div id="c-shine" class="layer"></div> | |
| </div> | |
| </div> | |
| <script> | |
| const foil = document.getElementById('c-foil'); | |
| const wrap = document.getElementById('foil-wrap'); | |
| const base = document.getElementById('c-base'); | |
| const shine = document.getElementById('c-shine'); | |
| function up(e, type) { | |
| const file = e.target.files[0]; | |
| if (!file) return; | |
| const reader = new FileReader(); | |
| reader.onload = (ev) => { | |
| const res = ev.target.result; | |
| if (type === 'base') base.src = res; | |
| if (type === 'foil') foil.style.backgroundImage = `url('${res}')`; | |
| if (type === 'mask') { | |
| wrap.style.maskImage = `url('${res}')`; | |
| wrap.style.webkitMaskImage = `url('${res}')`; | |
| } | |
| }; | |
| reader.readAsDataURL(file); | |
| } | |
| let ticking = false; | |
| window.addEventListener('deviceorientation', (e) => { | |
| if (!ticking) { | |
| window.requestAnimationFrame(() => { | |
| let lr = e.gamma || 0; | |
| let fb = (e.beta || 45) - 45; | |
| // 恢復適度的變色與亮度,但限制計算頻率 | |
| let hue = lr * 8; | |
| let intensity = (Math.abs(lr) + Math.abs(fb)) / 80; | |
| // 應用濾鏡 | |
| wrap.style.filter = `hue-rotate(${hue}deg) brightness(${1 + intensity})`; | |
| wrap.style.opacity = 0.2 + intensity * 0.5; | |
| // 玻璃掃影 | |
| shine.style.backgroundPosition = `${50 + lr * 1.8}% ${50 + fb * 1.8}%`; | |
| ticking = false; | |
| }); | |
| ticking = true; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment