Skip to content

Instantly share code, notes, and snippets.

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

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

Select an option

Save carddass2018-svg/7317e929703055f0b6201d9e160cc9ed 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,maximum-scale=1,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 50px; border-radius: 15px; font-size: 22px; font-weight: bold; cursor: pointer; }
#set-btn { position: fixed; top: 15px; left: 15px; z-index: 1000; background: rgba(0,0,0,0.6); color: #fff; border: 1px solid #555; padding: 10px; border-radius: 50%; width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; cursor: pointer; 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(-110%); transition: 0.3s; color: #fff; max-height: 80vh; overflow-y: auto; }
.panel.active { transform: translateY(0); }
.row { margin-bottom: 12px; font-size: 13px; border-bottom: 1px solid #222; padding-bottom: 8px; }
.status { font-size: 10px; margin-left: 10px; color: #555; }
.ready { color: #0f0 !important; }
input[type="file"] { width: 100%; margin-top: 5px; color: #0f0; }
/* 卡片容器 */
#card { width: 82vw; 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; }
/* 1. 一般閃紋層 */
#foil-wrap { z-index: 2; mix-blend-mode: color-dodge; }
#c-foil { background-size: cover; background-position: center; opacity: 0.55; filter: contrast(2.7) saturate(2.2) brightness(1.1); }
/* 2. 燙金層 (Gold Foil) - 獨立層次 */
#gold-wrap { z-index: 3; mix-blend-mode: color-dodge; }
#c-gold {
background-size: cover; background-position: center; opacity: 0;
filter: contrast(3) saturate(1.5) brightness(1.5) sepia(1) hue-rotate(5deg);
/* 預設金色濾鏡: sepia 加上黃色調 */
}
/* 3. 玻璃高光 */
#c-shine { z-index: 4; background: linear-gradient(110deg, transparent 40%, rgba(255,255,255,0.7) 50%, transparent 60%); background-size: 200% 200%; mix-blend-mode: overlay; }
canvas { display: none; }
</style>
</head>
<body>
<div id="auth-overlay"><button id="auth-btn" onclick="init()">進入龍珠珍藏館</button></div>
<div id="set-btn" onclick="document.getElementById('p').classList.toggle('active')">⚙️</div>
<div class="panel" id="p">
<div class="row">1. 原圖: <span id="s-b" class="status">未選取</span><input type="file" accept="image/*" onchange="ld(this,'b')"></div>
<div class="row">2. 閃紋遮罩: <span id="s-m" class="status">未選取</span><input type="file" accept="image/*" onchange="ld(this,'m')"></div>
<div class="row">3. 閃紋貼圖: <span id="s-f" class="status">未選取</span><input type="file" accept="image/*" onchange="ld(this,'f')"></div>
<div class="row" style="background: #221a00;">4. 燙金遮罩 (可選): <span id="s-g" class="status">未選取</span><input type="file" accept="image/*" onchange="ld(this,'g')"></div>
<button id="gen-btn" onclick="processAll()" style="width:100%; padding:12px; background:#444; color:#888; border:none; border-radius:8px; font-weight:bold; cursor:not-allowed;">請先選取圖片</button>
</div>
<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="gold-wrap" class="layer"><div id="c-gold" class="layer"></div></div>
<div id="c-shine" class="layer"></div>
</div>
<canvas id="cvs"></canvas>
<script>
let imgM, imgF, imgG;
const foil = document.getElementById('c-foil'), gold = document.getElementById('c-gold'), base = document.getElementById('c-base'), shine = document.getElementById('c-shine'), cvs = document.getElementById('cvs'), ctx = cvs.getContext('2d', { willReadFrequently: true });
function ld(input, type) {
if (!input.files || !input.files[0]) return;
const status = document.getElementById('s-' + type);
status.innerText = "讀取中...";
const reader = new FileReader();
reader.onload = (e) => {
const img = new Image();
img.onload = () => {
if (type === 'b') base.src = img.src;
if (type === 'm') imgM = img;
if (type === 'f') imgF = img;
if (type === 'g') imgG = img;
status.innerText = "已就緒 ✓";
status.classList.add('ready');
checkReady();
};
img.src = e.target.result;
};
reader.readAsDataURL(input.files[0]);
}
function checkReady() {
if (imgM && imgF) {
const btn = document.getElementById('gen-btn');
btn.style.background = "#f1c40f"; btn.style.color = "#000"; btn.style.cursor = "pointer"; btn.innerText = "⚡ 生成強化閃卡";
}
}
// 封裝像素運算邏輯
function createMaskedImg(mask, texture) {
const maxLimit = 800;
let scale = Math.min(1, maxLimit / Math.max(mask.width, mask.height));
cvs.width = mask.width * scale; cvs.height = mask.height * scale;
ctx.clearRect(0, 0, cvs.width, cvs.height);
ctx.drawImage(mask, 0, 0, cvs.width, cvs.height);
let mData = ctx.getImageData(0, 0, cvs.width, cvs.height);
ctx.clearRect(0, 0, cvs.width, cvs.height);
ctx.drawImage(texture, 0, 0, cvs.width, cvs.height);
let tData = ctx.getImageData(0, 0, cvs.width, cvs.height);
for (let i = 0; i < mData.data.length; i += 4) {
if (mData.data[i] < 230) tData.data[i + 3] = 0;
}
ctx.putImageData(tData, 0, 0);
return cvs.toDataURL('image/png');
}
function processAll() {
if (!imgF || !imgM) return;
// 生成一般閃紋
foil.style.backgroundImage = `url('${createMaskedImg(imgM, imgF)}')`;
// 如果有選燙金圖,生成燙金效果
if (imgG) {
gold.style.backgroundImage = `url('${createMaskedImg(imgG, imgF)}')`;
gold.style.opacity = "0.7"; // 燙金層基礎透明度
} else {
gold.style.backgroundImage = "";
gold.style.opacity = "0";
}
document.getElementById('p').classList.remove('active');
}
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 = 'flex';
let lastLR = 0, lastFB = 0;
const lerp = 0.2;
window.addEventListener('deviceorientation', e => {
window.requestAnimationFrame(() => {
let currentLR = e.gamma || 0;
let currentFB = (e.beta || 45) - 45;
lastLR += (currentLR - lastLR) * lerp;
lastFB += (currentFB - lastFB) * lerp;
let intensity = Math.abs(lastLR) / 45;
// 一般閃紋:虹彩變色
foil.style.filter = `hue-rotate(${lastLR * 15}deg) brightness(${1.0 + intensity * 0.4}) contrast(2.7) saturate(2.2)`;
foil.style.opacity = Math.min(0.55 + intensity * 0.3, 0.85);
// 燙金層:固定金色,僅改變亮度
if (imgG) {
gold.style.filter = `brightness(${1.2 + intensity * 0.8}) contrast(2.7) saturate(1.5) sepia(1) hue-rotate(5deg)`;
gold.style.opacity = Math.min(0.7 + intensity * 0.3, 1.0);
}
shine.style.backgroundPosition = `${50 + lastLR * 3}% ${50 + lastFB * 3}%`;
});
});
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment