Skip to content

Instantly share code, notes, and snippets.

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

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

Select an option

Save carddass2018-svg/d6a54542976fb79c4e3363d7447b872d 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">
<title>龍珠閃卡 - 終極穩定版</title>
<style>
body { background: #000; margin: 0; height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; overflow: hidden; font-family: sans-serif; color: #fff; }
/* 100% 唔會錯過嘅啟動掣 */
#auth-overlay { position: fixed; inset: 0; background: #000; z-index: 9999; display: flex; flex-direction: column; align-items: center; justify-content: center; }
#auth-btn { background: #f1c40f; color: #000; border: none; padding: 20px 40px; border-radius: 12px; font-size: 20px; font-weight: bold; cursor: pointer; }
/* 左上角設置掣 */
#set-btn { position: fixed; top: 20px; left: 20px; z-index: 1000; background: #333; color: #fff; border: 2px solid #555; padding: 10px 15px; border-radius: 8px; cursor: pointer; display: none; }
/* 上傳面板 */
.panel { position: fixed; top: 0; left: 0; width: 100%; background: #1a1a1a; padding: 30px 20px; border-bottom: 2px solid #444; z-index: 999; box-sizing: border-box; transform: translateY(-110%); transition: 0.4s cubic-bezier(0.4, 0, 0.2, 1); }
.panel.active { transform: translateY(0); }
.row { margin-bottom: 15px; text-align: left; }
label { display: block; font-size: 13px; color: #aaa; margin-bottom: 5px; }
input[type="file"] { width: 100%; color: #0f0; font-size: 14px; }
/* 展示區 */
.stage { perspective: 1200px; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; }
#card { width: 85vw; max-width: 320px; aspect-ratio: 1 / 1.4; position: relative; border-radius: 18px; overflow: hidden; background: #111; box-shadow: 0 0 50px #000; }
.layer { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
#c-base { width: 100%; height: 100%; object-fit: cover; z-index: 1; }
/* 核心遮罩:解決 iPhone 唔反應同黑位漏光 */
#foil-wrap {
z-index: 2;
mix-blend-mode: color-dodge;
filter: contrast(800%) brightness(100%); /* 暴力切斷黑位漏光 */
-webkit-mask: url(#m);
mask: url(#m);
}
#c-foil { background-size: cover; background-position: center; opacity: 0.15; }
#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; }
svg { position: absolute; width: 0; height: 0; }
</style>
</head>
<body>
<div id="auth-overlay"><button id="auth-btn" onclick="init()">啟動珍藏閃卡</button></div>
<button id="set-btn" onclick="document.getElementById('p').classList.toggle('active')">⚙️ 設置圖片</button>
<div class="panel" id="p">
<div class="row"><label>1. 揀選卡片原圖</label><input type="file" accept="image/*" onchange="up(event,'b')"></div>
<div class="row"><label>2. 揀選黑白遮罩 (人黑背景白)</label><input type="file" accept="image/*" onchange="up(event,'m')"></div>
<div class="row"><label>3. 揀選閃紋貼圖</label><input type="file" accept="image/*" onchange="up(event,'f')"></div>
<button onclick="document.getElementById('p').classList.remove('active')" style="width:100%; padding:15px; background:#444; color:#fff; border:none; border-radius:8px; font-weight:bold;">完成</button>
</div>
<svg><defs><mask id="m" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox"><image id="m-img" width="1" height="1" preserveAspectRatio="none" /></mask></defs></svg>
<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'), base=document.getElementById('c-base'), mImg=document.getElementById('m-img'), 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 data = ev.target.result;
if(type==='b') base.src = data;
if(type==='f') foil.style.backgroundImage = `url('${data}')`;
if(type==='m') {
mImg.setAttribute('xlink:href', data);
// 強制 iPhone 刷新遮罩
const w = document.getElementById('foil-wrap');
w.style.display='none'; w.offsetHeight; w.style.display='block';
}
};
reader.readAsDataURL(file);
}
function init() {
if (typeof DeviceOrientationEvent!=='undefined' && typeof DeviceOrientationEvent.requestPermission==='function') {
DeviceOrientationEvent.requestPermission().then(res => { if(res==='granted') start(); });
} else { start(); }
}
function start() {
document.getElementById('auth-overlay').style.display='none';
document.getElementById('set-btn').style.display='block';
window.addEventListener('deviceorientation', e => {
let lr=e.gamma||0, fb=(e.beta||45)-45;
foil.style.filter = `hue-rotate(${lr*10}deg) brightness(${0.9 + Math.abs(lr)/60}) contrast(1.5)`;
foil.style.opacity = 0.15 + Math.abs(lr)/100;
shine.style.backgroundPosition = `${50+lr*2}% ${50+fb*2}%`;
});
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment