423 lines
20 KiB
HTML
423 lines
20 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
||
<title>宇森 · Yusen|活的文明系统模拟</title>
|
||
<link rel="stylesheet" href="assets/fonts/yusen-fonts.css" />
|
||
<link rel="icon" type="image/png" sizes="48x48" href="assets/ui/logo_planet_48.png?v=20260723">
|
||
<link rel="icon" type="image/png" sizes="256x256" href="assets/ui/logo_planet_256.png?v=20260723">
|
||
<link rel="apple-touch-icon" href="assets/ui/logo_planet_256.png?v=20260723">
|
||
<link rel="stylesheet" href="assets/common.css" />
|
||
<!-- 首屏 hero 图预加载,提升 LCP -->
|
||
<link rel="preload" as="image" href="assets/slides/01_starry_sky.webp" fetchpriority="high">
|
||
<style>
|
||
/* ===== 首页:全屏 hero 轮播 ===== */
|
||
html,body{height:100%;width:100%;overflow:hidden;}
|
||
.home-main{flex:1;display:flex;flex-direction:column;position:relative;overflow:hidden;}
|
||
|
||
.hero{position:relative;flex:1;border-radius:0;overflow:hidden;min-height:0;}
|
||
.hero .slideshow{position:absolute;inset:0;overflow:hidden;}
|
||
.hero .slide-track{position:absolute;inset:0;display:flex;flex-direction:column;transition:transform 1.25s cubic-bezier(0.4,0,0.2,1);will-change:transform;}
|
||
.hero .slide{flex:0 0 100%;width:100%;height:100%;background-size:cover;background-position:center;position:relative;}
|
||
.hero .slide::before{content:"";position:absolute;inset:0;
|
||
background:linear-gradient(90deg, rgba(8,12,26,.92) 0%, rgba(8,12,26,.70) 22%, rgba(8,12,26,.40) 40%, transparent 58%),
|
||
linear-gradient(180deg, rgba(8,12,26,.55) 0%, transparent 35%);}
|
||
|
||
.hero .copy{position:absolute;left:56px;top:56px;z-index:3;pointer-events:none;}
|
||
.hero .copy h1{font-family:"ZCOOL QingKe HuangYou",sans-serif;font-size:56px;letter-spacing:10px;color:#fff;text-shadow:0 2px 24px rgba(0,0,0,.9),0 0 32px rgba(139,92,246,.7);line-height:1.2;}
|
||
.hero .copy .sub2{font-family:"Press Start 2P",monospace;font-size:11px;color:var(--gold);margin:6px 0 0;letter-spacing:2px;text-shadow:0 1px 8px rgba(0,0,0,.9);}
|
||
.hero .copy .tag{font-size:20px;font-weight:500;color:#e8ecf6;margin-top:4px;text-shadow:0 1px 10px rgba(0,0,0,.85);}
|
||
|
||
/* 轮播文字(左下) */
|
||
.slide-label{position:absolute;left:56px;bottom:72px;z-index:4;pointer-events:none;opacity:0;transform:translateY(16px);transition:opacity .8s ease, transform .8s ease;}
|
||
.slide.active .slide-label{opacity:1;transform:translateY(0);}
|
||
.slide-label .sl-en{font-family:"Press Start 2P",monospace;font-size:13px;color:var(--cyan);letter-spacing:3px;margin-bottom:10px;display:block;text-shadow:0 1px 8px rgba(0,0,0,.9);}
|
||
.slide-label .sl-cn{font-family:"ZCOOL QingKe HuangYou",sans-serif;font-size:46px;letter-spacing:7px;color:#fff;text-shadow:0 2px 22px rgba(0,0,0,.95),0 0 30px rgba(139,92,246,.65);line-height:1.25;}
|
||
.slide-label .sl-desc{font-size:16px;color:#c8d2ec;margin-top:12px;max-width:500px;line-height:1.85;text-shadow:0 1px 8px rgba(0,0,0,.88);}
|
||
|
||
/* 右下指示器 */
|
||
.sl-dots{position:absolute;right:40px;bottom:96px;z-index:5;display:flex;flex-direction:column;gap:14px;pointer-events:auto;}
|
||
.sl-dot{width:12px;height:12px;border-radius:50%;background:rgba(255,255,255,.22);border:1px solid rgba(255,255,255,.4);cursor:pointer;transition:.3s;flex:0 0 auto;}
|
||
.sl-dot:hover{background:rgba(255,255,255,.5);}
|
||
.sl-dot.active{background:var(--gold);border-color:var(--gold);box-shadow:0 0 12px rgba(231,184,92,.6);transform:scale(1.15);}
|
||
|
||
/* 左右箭头 */
|
||
.sl-arrow{position:absolute;top:50%;z-index:6;transform:translateY(-50%);width:44px;height:44px;border-radius:50%;border:1px solid rgba(255,255,255,.15);background:rgba(8,12,26,.55);backdrop-filter:blur(8px);color:#e8ecf6;font-size:22px;cursor:pointer;transition:.2s;display:flex;align-items:center;justify-content:center;}
|
||
.sl-arrow:hover{background:rgba(139,92,246,.25);border-color:rgba(139,92,246,.4);transform:translateY(-50%) scale(1.08);}
|
||
.sl-arrow.prev{left:16px;}
|
||
.sl-arrow.next{right:16px;}
|
||
/* 隐藏左右翻页与轮播点,底层自动轮播/键盘/滑动切换逻辑保留 */
|
||
.sl-arrow, .sl-dots{ display:none !important; }
|
||
|
||
/* 起源历史(右上竖排) */
|
||
.slide-origin{position:absolute;right:72px;top:48px;z-index:4;pointer-events:none;writing-mode:vertical-rl;text-orientation:upright;
|
||
font-family:"Noto Sans SC",sans-serif;font-size:16px;font-weight:500;letter-spacing:3px;line-height:1.55;color:rgba(240,244,252,.94);
|
||
text-shadow:0 1px 3px rgba(0,0,0,.92);max-height:34vh;overflow:hidden;
|
||
opacity:0;transform:translateY(-12px);transition:opacity .9s ease .25s, transform .9s ease .25s;}
|
||
.slide.active .slide-origin{opacity:1;transform:translateY(0);}
|
||
.slide-origin .so-tag{color:var(--gold);font-family:"ZCOOL QingKe HuangYou",sans-serif;font-size:19px;letter-spacing:5px;margin-bottom:7px;text-shadow:0 1px 4px rgba(0,0,0,.92),0 0 10px rgba(231,184,92,.45);}
|
||
|
||
/* 进入游戏按钮(底部) */
|
||
.hero .enter-wrap{position:absolute;left:0;right:0;bottom:32px;display:flex;justify-content:center;z-index:5;}
|
||
.hero .enter-btn{
|
||
font-family:"Noto Sans SC",sans-serif;font-size:17px;font-weight:600;color:#0b1020;
|
||
background:linear-gradient(135deg, #f0d49a, #e7b85c, #f0d49a);
|
||
padding:14px 48px;border-radius:30px;cursor:pointer;border:1px solid rgba(255,255,255,.3);
|
||
box-shadow:0 4px 14px rgba(231,184,92,.35), inset 0 1px 0 rgba(255,255,255,.4);
|
||
letter-spacing:2px;transition:.2s;
|
||
}
|
||
.hero .enter-btn:hover{
|
||
filter:brightness(1.08);transform:translateY(-2px);
|
||
box-shadow:0 6px 20px rgba(231,184,92,.5), inset 0 1px 0 rgba(255,255,255,.5);
|
||
}
|
||
.hero .enter-btn:active{transform:translateY(0);}
|
||
|
||
/* ===== 响应式 ===== */
|
||
@media (max-width:900px){
|
||
.hero .copy h1{font-size:42px;}
|
||
}
|
||
@media (max-width:768px){
|
||
.hero .copy{left:18px;top:28px;}
|
||
.hero .copy h1{font-size:30px;letter-spacing:5px;}
|
||
.hero .copy .tag{font-size:15px;}
|
||
.slide-label{left:18px;bottom:78px;}
|
||
.slide-label .sl-cn{font-size:24px;letter-spacing:3px;}
|
||
.slide-label .sl-desc{font-size:13px;max-width:100%;}
|
||
.sl-dots{right:16px;gap:10px;}
|
||
.hero .enter-btn{font-size:15px;padding:11px 30px;}
|
||
}
|
||
|
||
/* 进游戏开场动画(yuthon 科技感)—— 总时长约 5.2s */
|
||
#introSplash {
|
||
position: fixed; inset: 0; z-index: 600; overflow: hidden;
|
||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||
background:
|
||
radial-gradient(ellipse at 50% 48%, rgba(20,44,78,.55), rgba(3,5,10,.97) 70%),
|
||
#03050a;
|
||
opacity: 0; visibility: hidden; transition: opacity .5s ease;
|
||
}
|
||
#introSplash.show { opacity: 1; visibility: visible; }
|
||
#introSplash.hide { opacity: 0; visibility: hidden; transition: opacity .45s ease; }
|
||
#introSplash .intro-grid {
|
||
position: absolute; inset: -50%;
|
||
background-image:
|
||
linear-gradient(rgba(74,175,255,.09) 1px, transparent 1px),
|
||
linear-gradient(90deg, rgba(74,175,255,.09) 1px, transparent 1px);
|
||
background-size: 44px 44px;
|
||
transform: perspective(440px) rotateX(62deg);
|
||
animation: introGridMove 3.2s linear infinite;
|
||
-webkit-mask-image: radial-gradient(ellipse at 50% 38%, #000 8%, transparent 72%);
|
||
mask-image: radial-gradient(ellipse at 50% 38%, #000 8%, transparent 72%);
|
||
}
|
||
@keyframes introGridMove { from { background-position: 0 0; } to { background-position: 0 44px; } }
|
||
#introSplash .intro-sweep {
|
||
position: absolute; top: 0; bottom: 0; width: 42%; left: -42%;
|
||
transform: skewX(-18deg); z-index: 3; pointer-events: none;
|
||
background: linear-gradient(90deg, transparent, rgba(140,210,255,.20), transparent);
|
||
}
|
||
#introSplash.show .intro-sweep { animation: introSweep 1.8s ease-in-out .6s 1; }
|
||
@keyframes introSweep { 0% { left: -42%; } 100% { left: 110%; } }
|
||
#introSplash .intro-logo {
|
||
position: relative; z-index: 2; margin: 0;
|
||
font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif;
|
||
font-weight: 800; font-size: clamp(48px, 12vw, 132px);
|
||
letter-spacing: .22em; text-indent: .22em; text-transform: lowercase;
|
||
color: #eaf6ff; opacity: 0; transform: scale(.92); filter: blur(8px);
|
||
text-shadow: 0 0 18px rgba(74,175,255,.7), 0 0 42px rgba(74,175,255,.35);
|
||
}
|
||
#introSplash.show .intro-logo { animation: introLogoIn 2s cubic-bezier(.16,1,.3,1) .2s forwards, introHoldPulse 1.6s ease-in-out 3.6s 1 forwards; }
|
||
@keyframes introLogoIn {
|
||
0% { opacity: 0; transform: scale(.92); filter: blur(8px); }
|
||
30% { opacity: 1; transform: scale(1.04); filter: blur(0); text-shadow: 3px 0 rgba(255,46,86,.55), -3px 0 rgba(40,200,255,.55), 0 0 18px rgba(74,175,255,.7); }
|
||
48% { text-shadow: 0 0 18px rgba(74,175,255,.7), 0 0 42px rgba(74,175,255,.35); }
|
||
100% { opacity: 1; transform: scale(1); filter: blur(0); }
|
||
}
|
||
@keyframes introHoldPulse {
|
||
0% { text-shadow: 0 0 18px rgba(74,175,255,.7), 0 0 42px rgba(74,175,255,.35); }
|
||
50% { text-shadow: 0 0 28px rgba(74,175,255,.9), 0 0 72px rgba(74,175,255,.5), 0 0 120px rgba(138,92,246,.25); }
|
||
100% { text-shadow: 0 0 18px rgba(74,175,255,.7), 0 0 42px rgba(74,175,255,.35); }
|
||
}
|
||
#introSplash .intro-line {
|
||
position: relative; z-index: 2; margin-top: 18px; height: 2px; width: 0;
|
||
background: linear-gradient(90deg, transparent, #4af, #a8e6cf, transparent);
|
||
box-shadow: 0 0 12px rgba(74,175,255,.7);
|
||
}
|
||
#introSplash.show .intro-line { animation: introLine 1.4s ease-out 1.4s forwards; }
|
||
@keyframes introLine { to { width: min(320px, 60vw); } }
|
||
#introSplash .intro-sub {
|
||
position: relative; z-index: 2; margin-top: 14px; font-size: 13px;
|
||
letter-spacing: .4em; text-indent: .4em; color: rgba(150,200,255,.55); opacity: 0;
|
||
}
|
||
#introSplash.show .intro-sub { animation: introFade 1.2s ease 2.6s forwards; }
|
||
@keyframes introFade { to { opacity: 1; } }
|
||
</style>
|
||
<link rel="stylesheet" href="assets/story-player.css" />
|
||
</head>
|
||
<body>
|
||
<!-- 进游戏开场动画(yuthon 科技感) -->
|
||
<div id="introSplash">
|
||
<div class="intro-grid"></div>
|
||
<div class="intro-sweep"></div>
|
||
<div class="intro-logo">yuthon</div>
|
||
<div class="intro-line"></div>
|
||
<div class="intro-sub">宇森游戏</div>
|
||
</div>
|
||
<div class="app">
|
||
<header class="topbar">
|
||
<a href="index.html" class="logo"><span class="cn">宇森</span></a>
|
||
<nav class="nav">
|
||
<a href="announce.html">公告</a>
|
||
<a href="background.html">背景</a>
|
||
<a href="rules.html">规则</a>
|
||
<a href="codex.html">图鉴</a>
|
||
<a href="story.html">剧情</a>
|
||
<a href="forum.html" class="auth-only">论坛</a>
|
||
<a href="worlddata.html" class="auth-only">世界数据</a>
|
||
</nav>
|
||
<div class="spacer"></div>
|
||
<div class="user-box" id="userBox"></div>
|
||
</header>
|
||
|
||
<main class="home-main">
|
||
<section class="hero">
|
||
<div class="slideshow" id="slideshow"></div>
|
||
<div class="copy">
|
||
<h1>宇森 · Yusen</h1>
|
||
<div class="sub2">LIVING CIVILIZATION SIMULATOR</div>
|
||
<div class="tag">活的文明系统模拟</div>
|
||
</div>
|
||
<button class="sl-arrow prev" id="slPrev" aria-label="上一张">‹</button>
|
||
<button class="sl-arrow next" id="slNext" aria-label="下一张">›</button>
|
||
<div class="enter-wrap">
|
||
<button class="enter-btn" id="enterGame">⚔ 进入游戏</button>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
</div>
|
||
|
||
<script src="assets/game-api.js"></script>
|
||
<script src="assets/common.js"></script>
|
||
<script>
|
||
// ============ 五层世界图片轮播 ============
|
||
(function(){
|
||
const slides = [
|
||
{ img:'assets/slides/01_starry_sky.webp', en:'STARRY SKY', cn:'星空', desc:'陨石星空带悬浮于世界最外层,是文明触及维度的起点。星轨连通各浮空岛,穹鎏晶体自星尘中凝结。',
|
||
origin:'世界未形,星尘先于万物浮游于虚无。首缕维度自星隙坍缩成形,穹鎏晶体由尘凝就,文明自此仰望苍穹之始。' },
|
||
{ img:'assets/slides/02_sky.webp', en:'SKY', cn:'天空', desc:'云朵地基块托起浮空岛群,灵气复苏的第一缕风拂过。各族初代聚落,在此仰望也更在此扎根。',
|
||
origin:'云基初结,浮空岛群自苍穹垂落凡尘。灵气复苏,初民循风而居,于云上筑城,仰望亦扎根,道统由此萌发。' },
|
||
{ img:'assets/slides/03_earth.webp', en:'EARTH', cn:'大地', desc:'平原与森林铺展成万物生灵的摇篮,玄荒文明于斯鼎盛。城邦林立,征伐与道统在沃土上并行。',
|
||
origin:'沃野铺展为万灵摇篮,玄荒先族自林泉走出。城邦并起,征伐与道统并驰沃土之上,文明于此鼎盛绵延。' },
|
||
{ img:'assets/slides/04_underground.webp',en:'UNDERGROUND',cn:'地下', desc:'溶洞晶矿与暗河在深处低语,冥玉生于幽暗玉石之中。地心工坊调度浅层资源,灯火不熄。',
|
||
origin:'溶洞深开,晶矿与暗河在幽处低语。冥玉生于幽玉深心,地心工坊取浅层之资,灯火长明,匠魂不熄。' },
|
||
{ img:'assets/slides/05_core.webp', en:'CORE', cn:'地心', desc:'熔岩奔流的地心,是世界诞生的本源。元玺在此凝聚,追溯天地初开的那一瞬永恒。',
|
||
origin:'熔岩奔流处,乃世界本源所钟。元玺于亿载炽火中凝聚成形,溯天地初开一瞬,万物归处,亦是起始。' }
|
||
];
|
||
|
||
const container = document.getElementById('slideshow');
|
||
if (!container) return;
|
||
let current = 0, timer = null;
|
||
const INTERVAL = 5500;
|
||
|
||
// 预加载所有图(消除切换空白)
|
||
slides.forEach(s => { const img = new Image(); img.src = s.img; });
|
||
|
||
// 缩略图(保留兼容)
|
||
const track = document.createElement('div');
|
||
track.className = 'slide-track';
|
||
container.appendChild(track);
|
||
|
||
slides.forEach((s,i)=>{
|
||
const el = document.createElement('div');
|
||
el.className = 'slide' + (i===0 ? ' active' : '');
|
||
el.style.backgroundImage = "url('" + s.img + "')";
|
||
el.innerHTML =
|
||
'<div class="slide-label"><span class="sl-en">' + s.en + '</span><div class="sl-cn">' + s.cn + '</div><div class="sl-desc">' + s.desc + '</div></div>' +
|
||
'<div class="slide-origin"><span class="so-tag">起源</span>' + s.origin + '</div>';
|
||
track.appendChild(el);
|
||
});
|
||
const all = track.querySelectorAll('.slide');
|
||
|
||
// 指示器
|
||
const dotsWrap = document.createElement('div');
|
||
dotsWrap.className = 'sl-dots';
|
||
slides.forEach((_,i)=>{
|
||
const d = document.createElement('div');
|
||
d.className = 'sl-dot' + (i===0 ? ' active' : '');
|
||
d.addEventListener('click', ()=> go(i));
|
||
dotsWrap.appendChild(d);
|
||
});
|
||
document.querySelector('.hero').appendChild(dotsWrap);
|
||
const dots = dotsWrap.querySelectorAll('.sl-dot');
|
||
|
||
// 箭头按钮
|
||
const prevBtn = document.getElementById('slPrev');
|
||
const nextBtn = document.getElementById('slNext');
|
||
if (prevBtn) prevBtn.addEventListener('click', ()=> { prev(); resetTimer(); });
|
||
if (nextBtn) nextBtn.addEventListener('click', ()=> { next(); resetTimer(); });
|
||
|
||
function go(idx){
|
||
if (idx<0) idx = slides.length-1;
|
||
if (idx>=slides.length) idx = 0;
|
||
if (idx === current) return;
|
||
all[current].classList.remove('active');
|
||
dots[current].classList.remove('active');
|
||
current = idx;
|
||
track.style.transform = 'translateY(' + (-current*100) + '%)';
|
||
all[current].classList.add('active');
|
||
dots[current].classList.add('active');
|
||
resetTimer();
|
||
}
|
||
function next(){ go((current+1) % slides.length); }
|
||
function prev(){ go((current-1+slides.length) % slides.length); }
|
||
function resetTimer(){ clearInterval(timer); timer = setInterval(next, INTERVAL); }
|
||
|
||
// 滚轮切换
|
||
let lock = false, wAccum = 0;
|
||
document.querySelector('.hero').addEventListener('wheel', (e)=>{
|
||
wAccum += e.deltaY;
|
||
if (lock) return;
|
||
if (Math.abs(wAccum) > 50){
|
||
lock = true;
|
||
wAccum > 0 ? next() : prev();
|
||
wAccum = 0;
|
||
setTimeout(()=> { lock=false; }, 1250);
|
||
}
|
||
}, {passive:true});
|
||
|
||
// 键盘
|
||
document.addEventListener('keydown', (e)=>{
|
||
if (e.key === 'ArrowLeft') prev();
|
||
if (e.key === 'ArrowRight') next();
|
||
});
|
||
|
||
// 触屏
|
||
const hero = document.querySelector('.hero');
|
||
let tx=0, ty=0;
|
||
hero.addEventListener('touchstart', (e)=>{
|
||
const t = e.touches[0];
|
||
tx = t.clientX; ty = t.clientY;
|
||
}, {passive:true});
|
||
hero.addEventListener('touchend', (e)=>{
|
||
const t = e.changedTouches[0];
|
||
const dx = t.clientX - tx, dy = t.clientY - ty;
|
||
if (Math.abs(dy) > Math.abs(dx) && Math.abs(dy) > 50){
|
||
dy > 0 ? prev() : next();
|
||
}
|
||
}, {passive:true});
|
||
|
||
resetTimer();
|
||
})();
|
||
|
||
// ============ 进入游戏 ============
|
||
document.getElementById('enterGame').addEventListener('click', async ()=>{
|
||
try {
|
||
const me = await API.me();
|
||
if (me && me.uid) location.href = 'world.html';
|
||
else location.href = 'login.html?next=world.html';
|
||
} catch(e) {
|
||
location.href = 'login.html?next=world.html';
|
||
}
|
||
});
|
||
</script>
|
||
<script src="assets/story-player.js"></script>
|
||
<script>
|
||
// 进游戏开场动画(yuthon 科技感):首次访问播放,约 5.2s 后自动结束,本会话只播一次
|
||
let _introAudioCtx = null;
|
||
function getIntroAudioCtx() {
|
||
try {
|
||
const AC = window.AudioContext || window.webkitAudioContext;
|
||
if (!AC) return null;
|
||
if (!_introAudioCtx) _introAudioCtx = new AC();
|
||
if (_introAudioCtx.state === 'suspended') _introAudioCtx.resume();
|
||
return _introAudioCtx;
|
||
} catch (e) { return null; }
|
||
}
|
||
function stopIntroSound(master) {
|
||
if (!master) return;
|
||
try {
|
||
const ctx = master.context;
|
||
const t = ctx.currentTime;
|
||
master.gain.cancelScheduledValues(t);
|
||
master.gain.setValueAtTime(Math.max(0.0001, master.gain.value), t);
|
||
master.gain.exponentialRampToValueAtTime(0.0001, t + 0.12);
|
||
} catch (e) {}
|
||
}
|
||
function playIntroSound() {
|
||
// 参考背景音乐设置:读取「音效」开关,关闭时不发声
|
||
if (typeof loadWorldSFXSetting === 'function' && !loadWorldSFXSetting()) return null;
|
||
const ctx = getIntroAudioCtx();
|
||
if (!ctx) return null;
|
||
const now = ctx.currentTime;
|
||
const master = ctx.createGain();
|
||
master.gain.setValueAtTime(0.0001, now);
|
||
master.gain.linearRampToValueAtTime(0.5, now + 0.05);
|
||
master.connect(ctx.destination);
|
||
|
||
// 干净的「铃」音:正弦主音 + 高八度泛音增亮,平滑指数衰减
|
||
function bell(freq, start, dur, vol) {
|
||
const o1 = ctx.createOscillator(); o1.type = 'sine'; o1.frequency.value = freq;
|
||
const o2 = ctx.createOscillator(); o2.type = 'sine'; o2.frequency.value = freq * 2;
|
||
const g1 = ctx.createGain();
|
||
g1.gain.setValueAtTime(0.0001, start);
|
||
g1.gain.exponentialRampToValueAtTime(vol, start + 0.012);
|
||
g1.gain.exponentialRampToValueAtTime(0.0001, start + dur);
|
||
const g2 = ctx.createGain();
|
||
g2.gain.setValueAtTime(0.0001, start);
|
||
g2.gain.exponentialRampToValueAtTime(vol * 0.3, start + 0.012);
|
||
g2.gain.exponentialRampToValueAtTime(0.0001, start + dur * 0.55);
|
||
o1.connect(g1).connect(master); o1.start(start); o1.stop(start + dur + 0.05);
|
||
o2.connect(g2).connect(master); o2.start(start); o2.stop(start + dur + 0.05);
|
||
}
|
||
|
||
// 开场:极轻星光一闪(光点感)
|
||
bell(1046.50, now + 0.2, 0.45, 0.06);
|
||
// 揭示「叮咚」门铃:高音 ding -> 低音 dong
|
||
bell(1567.98, now + 3.6, 0.55, 0.22); // G6 叮
|
||
bell(1046.50, now + 4.25, 0.95, 0.22); // C6 咚
|
||
|
||
return master;
|
||
}
|
||
function playIntro(done) {
|
||
const el = document.getElementById('introSplash');
|
||
if (!el) { done && done(); return; }
|
||
try {
|
||
if (sessionStorage.getItem('introPlayed')) { el.remove(); done && done(); return; }
|
||
} catch (e) {}
|
||
el.classList.add('show');
|
||
let soundMaster = null;
|
||
try { soundMaster = playIntroSound(); } catch (e) { console.warn('intro音效异常', e); }
|
||
let finished = false;
|
||
const finish = () => {
|
||
if (finished) return; finished = true;
|
||
try { stopIntroSound(soundMaster); } catch (e) {}
|
||
try { sessionStorage.setItem('introPlayed', '1'); } catch (e) {}
|
||
el.classList.remove('show'); el.classList.add('hide');
|
||
setTimeout(() => { el.remove(); done && done(); }, 480);
|
||
};
|
||
setTimeout(finish, 5200);
|
||
}
|
||
|
||
// 首页首次访问:先播 yuthon 开场动画,再播剧情漫画
|
||
(function() {
|
||
if (localStorage.getItem('seen_intro_part1')) return;
|
||
const btn = document.getElementById('enterGame');
|
||
if (btn) btn.style.display = 'none';
|
||
playIntro(() => {
|
||
playIntroStory([
|
||
'assets/story/story_01_transmigration.jpg',
|
||
'assets/story/story_02_awakening.jpg'
|
||
]).then(() => {
|
||
localStorage.setItem('seen_intro_part1', '1');
|
||
if (btn) btn.style.display = '';
|
||
}).catch(e => {
|
||
console.warn('首页剧情播放异常', e);
|
||
localStorage.setItem('seen_intro_part1', '1');
|
||
if (btn) btn.style.display = '';
|
||
});
|
||
});
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|