Skip to content

Instantly share code, notes, and snippets.

@carddass2018-svg
Created April 30, 2026 09:59
Show Gist options
  • Select an option

  • Save carddass2018-svg/f181f73187bb283bffb6529ba6f56d71 to your computer and use it in GitHub Desktop.

Select an option

Save carddass2018-svg/f181f73187bb283bffb6529ba6f56d71 to your computer and use it in GitHub Desktop.
<!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