Skip to content

Instantly share code, notes, and snippets.

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

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

Select an option

Save carddass2018-svg/1097ebd6b5fc62afb47a8bfe4b49595c 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; align-items: center; justify-content: center; overflow: hidden; font-family: sans-serif; }
/* 啟動層 */
#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; border: none; padding: 20px 40px; border-radius: 12px; font-size: 20px; font-weight: bold; }
/* 設定面板 */
#set-btn { position: fixed; top: 15px; left: 15px; z-index: 1000; background: rgba(0,0,0,0.7); color: #fff; border: 1px solid #555; padding: 10px; border-radius: 8px; display: none; }
.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; color: #fff; }
.panel.active { transform: translateY(0); }
.row { margin-bottom: 12px; font-size: 13px; }
input[type="file"] { width: 100%; margin-top: 5px; color: #0f0; }
/* 卡片展示區 */
.stage { perspective: 1200px; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; }
#card { width: 82vw; max-width: 320px; aspect-ratio: 1 / 1.4; position: relative; border-radius: 18px; overflow: hidden; background: #000; 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; }
/* 強化遮罩層:加入暴力對比切斷 */
#foil-wrap {
z-index: 2;
mix-blend-mode: color-dodge;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
-webkit-mask-repeat: no-repeat;
/* 核心:將遮罩黑白化到極致,完全切斷灰色漏光 */
filter: contrast(1000%) brightness(100%);
will-change: filter;
}
#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; }
</style>
</head>
<body>
<div id="auth-overlay">
<button id="auth-btn" onclick="initMotion()">啟動 iPhone 零漏光版</button>
</div>
<button id="set-btn" onclick="document.getElementById('p').classList.toggle('active')">⚙️ 設定</button>
<div class="panel" id="p">
<div class="row">1. 選擇原圖: <input type="file" accept="image/*" onchange="up(event,'b')"></div>
<div class="row">2. 選擇遮罩: <input type="file" accept="image/*" onchange="up(event,'m')"></div>
<div class="row">3. 選擇閃紋: <input type="file" accept="image/*" onchange="up(event,'f')"></div>
<button onclick="document.getElementById('p').classList.remove('active')" style="width:100%; padding:12px; background:#333; border:none; border-radius:8px; color:#fff;">完成欣賞</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>
<!-- 隱形畫布用作處理圖片 -->
<canvas id="cvs" style="display:none;"></canvas>
<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');
const cvs = document.getElementById('cvs');
const ctx = cvs.getContext('2d');
function up(event, type) {
const file = event.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (e) => {
const img = new Image();
img.onload = () => {
// 將圖片畫入 Canvas 轉化為穩定數據流
cvs.width = img.width;
cvs.height = img.height;
ctx.drawImage(img, 0, 0);
const dataUrl = cvs.toDataURL('image/png');
if(type === 'b') base.src = dataUrl;
if(type === 'f') foil.style.backgroundImage = `url('${dataUrl}')`;
if(type === 'm') {
// iPhone Safari 必須強制重新套用 webkit 屬性
wrap.style.webkitMaskImage = `url('${dataUrl}')`;
wrap.style.maskImage = `url('${dataUrl}')`;
}
};
img.src = e.target.result;
};
reader.readAsDataURL(file);
}
function initMotion() {
if (typeof DeviceOrientationEvent !== 'undefined' && typeof DeviceOrientationEvent.requestPermission === 'function') {
DeviceOrientationEvent.requestPermission().then(res => {
if (res === 'granted') startApp();
});
} else { startApp(); }
}
function startApp() {
document.getElementById('auth-overlay').style.display = 'none';
document.getElementById('set-btn').style.display = 'block';
window.addEventListener('deviceorientation', (e) => {
let lr = e.gamma || 0;
let 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 = Math.min(0.15 + (Math.abs(lr)/100), 0.6);
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