320 lines
14 KiB
HTML
320 lines
14 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<script>
|
||
/* ======================= 加载页配置(在此调整) =======================
|
||
* logo : 标志图片(白底会被自动抠成透明并做霓虹发光)
|
||
* target : 加载动画结束后跳转的目标页
|
||
* speed : 全局速度倍率,>1 更快、<1 更慢
|
||
* collapseIn : 结尾“向正中心坍缩”的时长(秒)
|
||
* holdBeforeCollapse : 主体动画结束到开始坍缩之间的停顿(秒)
|
||
* once : true = 同一浏览器会话内仅播放一次(跨标签页共享,关闭浏览器后再进入会重新播放)
|
||
* title / icon : 浏览器标签标题 / 图标;icon 留空则使用 logo
|
||
* ==================================================================== */
|
||
window.LOGO_CONFIG = {
|
||
logo: 'assets/img/logo.jpg',
|
||
target: 'index.php',
|
||
speed: 1.4,
|
||
collapseIn: 0.55,
|
||
holdBeforeCollapse: 0.25,
|
||
once: true,
|
||
title: '',
|
||
icon: ''
|
||
};
|
||
</script>
|
||
<script>
|
||
/* 本会话已播放过:立即跳转目标页(脚本置于最前,尽量缩短空白/闪烁)。
|
||
* 使用“会话级 Cookie”:同一会话内所有标签页共享,关闭浏览器后自动失效。 */
|
||
(function () {
|
||
try {
|
||
var C = window.LOGO_CONFIG || {};
|
||
if (C.once !== false && /(^|;\s*)hp_intro=1(;|$)/.test(document.cookie)) {
|
||
window.__hpIntroSkip = true; /* 已播放过:跳过动画脚本,直接跳转 */
|
||
location.replace(C.target || 'index.php');
|
||
}
|
||
} catch (e) { }
|
||
})();
|
||
</script>
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>加载中…</title>
|
||
<noscript><meta http-equiv="refresh" content="0;url=index.php"></noscript>
|
||
<style>
|
||
:root{--neon:#00ff41;--neon2:#a6ffb8;--bg:#000;}
|
||
*{margin:0;padding:0;box-sizing:border-box;}
|
||
html,body{width:100%;height:100%;overflow:hidden;background:var(--bg);}
|
||
body{font-family:"Consolas","Menlo","Courier New",monospace;color:#7dffa0;}
|
||
|
||
/* 背景层 */
|
||
#rain{position:fixed;inset:0;z-index:0;opacity:0;pointer-events:none;}
|
||
.grid{position:fixed;inset:0;pointer-events:none;opacity:.5;background-image:
|
||
linear-gradient(rgba(0,255,65,.06) 1px,transparent 1px),
|
||
linear-gradient(90deg,rgba(0,255,65,.06) 1px,transparent 1px);background-size:44px 44px;
|
||
-webkit-mask-image:radial-gradient(ellipse at center,#000 18%,transparent 78%);
|
||
mask-image:radial-gradient(ellipse at center,#000 18%,transparent 78%);}
|
||
.scan{position:fixed;inset:0;pointer-events:none;opacity:.35;
|
||
background:repeating-linear-gradient(0deg,rgba(0,0,0,.4) 0 1px,transparent 1px 3px);}
|
||
.vig{position:fixed;inset:0;pointer-events:none;
|
||
background:radial-gradient(ellipse at center,transparent 45%,rgba(0,0,0,.85) 100%);}
|
||
.corner{position:fixed;width:40px;height:40px;pointer-events:none;
|
||
border:2px solid rgba(0,255,65,.5);}
|
||
.corner.tl{top:18px;left:18px;border-right:0;border-bottom:0;}
|
||
.corner.tr{top:18px;right:18px;border-left:0;border-bottom:0;}
|
||
.corner.bl{bottom:18px;left:18px;border-right:0;border-top:0;}
|
||
.corner.br{bottom:18px;right:18px;border-left:0;border-top:0;}
|
||
.hud{position:fixed;pointer-events:none;font-size:12px;letter-spacing:2px;
|
||
color:rgba(0,255,65,.75);white-space:nowrap;}
|
||
.hud.tl{top:22px;left:66px;} .hud.tr{top:22px;right:66px;}
|
||
/* 移动端:两行 HUD 文案较长,窄屏下会相互重叠并溢出;改为缩小字号/字距,
|
||
并将两行上下堆叠于左上角,超长时省略,避免遮挡与横向溢出 */
|
||
@media (max-width:767px){
|
||
.hud{font-size:10px;letter-spacing:1px;max-width:calc(100vw - 84px);overflow:hidden;text-overflow:ellipsis;}
|
||
.hud.tl{top:20px;left:66px;}
|
||
.hud.tr{top:38px;left:66px;right:auto;}
|
||
}
|
||
|
||
/* 动画层(结尾坍缩) */
|
||
#animLayer{position:fixed;inset:0;z-index:10;overflow:hidden;background:var(--bg);
|
||
transform-origin:50% 50%;transition-property:transform,opacity;
|
||
transition-timing-function:cubic-bezier(.7,0,.84,0),ease-in;
|
||
transition-duration:.9s;will-change:transform,opacity;}
|
||
#animLayer.collapse{transform:scale(.02);opacity:0;}
|
||
|
||
/* 舞台 */
|
||
.center{position:fixed;inset:0;display:flex;flex-direction:column;align-items:center;
|
||
justify-content:center;gap:22px;pointer-events:none;}
|
||
svg#logoStage{width:min(56vw,300px);height:auto;overflow:visible;}
|
||
.glitch{animation:flick .55s linear 1;}
|
||
@keyframes flick{0%,100%{opacity:1}12%{opacity:.28}22%{opacity:1}38%{opacity:.5}
|
||
50%{opacity:1}64%{opacity:.18}74%{opacity:1}88%{opacity:.55}}
|
||
|
||
/* 终端 + 进度 */
|
||
.term{min-height:76px;font-size:12.5px;line-height:1.7;letter-spacing:1px;
|
||
color:#7dffa0;text-align:left;white-space:pre;text-shadow:0 0 8px rgba(0,255,65,.5);}
|
||
.term b{color:var(--neon);font-weight:700;}
|
||
.bar{width:min(62vw,320px);height:4px;background:rgba(0,255,65,.14);border-radius:3px;overflow:hidden;}
|
||
.bar i{display:block;height:100%;width:0%;border-radius:3px;
|
||
background:linear-gradient(90deg,#00ff41,#c9ffd6);box-shadow:0 0 12px rgba(0,255,65,.85);}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div id="animLayer">
|
||
<canvas id="rain"></canvas>
|
||
<div class="grid"></div>
|
||
<div class="vig"></div>
|
||
<div class="scan"></div>
|
||
<div class="corner tl"></div><div class="corner tr"></div>
|
||
<div class="corner bl"></div><div class="corner br"></div>
|
||
<div class="hud tl">/// SECHOME-BOOT // SECURE CHANNEL</div>
|
||
<div class="hud tr">AUTH: PENDING // NODE 0x1F</div>
|
||
|
||
<div class="center">
|
||
<svg id="logoStage" viewBox="0 0 520 560" preserveAspectRatio="xMidYMid meet">
|
||
<defs>
|
||
<!-- 白底抠除 + 霓虹发光(一次成型,动画只改 clip,不重复跑滤镜) -->
|
||
<filter id="logoFx" x="-30%" y="-30%" width="160%" height="160%" color-interpolation-filters="sRGB">
|
||
<feColorMatrix type="matrix"
|
||
values="0 0 0 0 .06 0 0 0 0 1 0 0 0 0 .28 -.299 -.587 -.114 0 1"/>
|
||
<feComponentTransfer>
|
||
<feFuncA type="linear" slope="1.9" intercept="-.28"/>
|
||
</feComponentTransfer>
|
||
<feGaussianBlur stdDeviation="5" result="g"/>
|
||
<feMerge>
|
||
<feMergeNode in="g"/><feMergeNode in="g"/><feMergeNode in="SourceGraphic"/>
|
||
</feMerge>
|
||
</filter>
|
||
<clipPath id="revealClip"><rect id="revealRect" x="0" y="0" width="520" height="0"/></clipPath>
|
||
</defs>
|
||
<g clip-path="url(#revealClip)">
|
||
<g id="logoWrap">
|
||
<g id="logoG" filter="url(#logoFx)">
|
||
<image id="logoImg" x="0" y="0" width="520" height="560" href="assets/img/logo.jpg"
|
||
preserveAspectRatio="xMidYMid meet"/>
|
||
</g>
|
||
</g>
|
||
</g>
|
||
<rect id="scanEdge" x="0" y="0" width="520" height="3" fill="#7dffa0" opacity="0"/>
|
||
</svg>
|
||
|
||
<div class="term" id="term"></div>
|
||
<div class="bar"><i id="barFill"></i></div>
|
||
</div>
|
||
</div><!-- /#animLayer -->
|
||
|
||
<script>
|
||
(function(){
|
||
if(window.__hpIntroSkip) return; /* 本会话已播放过,正在跳转,无需再跑动画 */
|
||
var CFG=Object.assign(
|
||
{logo:'assets/img/logo.jpg',target:'index.php',speed:1,collapseIn:0.9,
|
||
holdBeforeCollapse:0.4,once:true,title:'',icon:''}, window.LOGO_CONFIG||{});
|
||
var K=1/(CFG.speed>0?CFG.speed:1);
|
||
var clamp01=function(v){return v<0?0:v>1?1:v;};
|
||
var $=function(id){return document.getElementById(id);};
|
||
|
||
var animLayer=$('animLayer');
|
||
var logoStage=$('logoStage'), logoImg=$('logoImg'), logoG=$('logoG');
|
||
var revealRect=$('revealRect'), scanEdge=$('scanEdge'), logoWrap=$('logoWrap');
|
||
var barFill=$('barFill'), termEl=$('term'), rainCv=$('rain');
|
||
|
||
/* 会话级标记:开始播放即写入,本次会话(含其它标签页)不再重复播放 */
|
||
if(CFG.once!==false){
|
||
try{ document.cookie='hp_intro=1; path=/; SameSite=Lax'; }catch(e){}
|
||
}
|
||
|
||
/* 标签标题 / 图标(静态页:默认取配置,留空则用 logo 作为图标) */
|
||
if(CFG.title) document.title=CFG.title;
|
||
function setFavicon(href){
|
||
var links=document.querySelectorAll("link[rel*='icon']");
|
||
if(links.length){ for(var i=0;i<links.length;i++) links[i].href=href; }
|
||
else{ var l=document.createElement('link'); l.rel='icon'; l.href=href; document.head.appendChild(l); }
|
||
}
|
||
setFavicon(CFG.icon || CFG.logo);
|
||
|
||
/* 读取图片真实尺寸,按比例布置揭示/扫光几何 */
|
||
var W=520,H=560;
|
||
function applyGeom(){
|
||
logoStage.setAttribute('viewBox','0 0 '+W+' '+H);
|
||
logoStage.style.aspectRatio=W+' / '+H;
|
||
logoImg.setAttribute('width',W); logoImg.setAttribute('height',H);
|
||
revealRect.setAttribute('width',W);
|
||
scanEdge.setAttribute('width',W);
|
||
}
|
||
var probe=new Image();
|
||
probe.onload=function(){ if(probe.naturalWidth){ W=probe.naturalWidth; H=probe.naturalHeight; } applyGeom(); };
|
||
probe.onerror=function(){ applyGeom(); };
|
||
probe.src=CFG.logo;
|
||
logoImg.setAttribute('href',CFG.logo);
|
||
applyGeom();
|
||
|
||
/* 与站点 logo 保持同步(api/site.php;失败或未设置则使用默认 logo.jpg + 霓虹)。 */
|
||
(function syncSiteLogo(){
|
||
try{
|
||
var xhr=new XMLHttpRequest();
|
||
xhr.open('GET','api/site.php',true);
|
||
xhr.timeout=2500;
|
||
xhr.onreadystatechange=function(){
|
||
if(xhr.readyState!==4) return;
|
||
try{
|
||
var d=JSON.parse(xhr.responseText||'{}');
|
||
if(d && typeof d.logo==='string' && d.logo!==''){
|
||
/* 自定义 logo:按原样展示(关闭白底抠除/霓虹,避免破坏配色) */
|
||
logoG.removeAttribute('filter');
|
||
logoImg.setAttribute('href',d.logo);
|
||
probe.onload=function(){ if(probe.naturalWidth){ W=probe.naturalWidth; H=probe.naturalHeight; } applyGeom(); };
|
||
probe.src=d.logo;
|
||
}
|
||
}catch(e){}
|
||
};
|
||
xhr.onerror=function(){};
|
||
xhr.send();
|
||
}catch(e){}
|
||
})();
|
||
|
||
/* ---------- 矩阵雨(轻量:限制列数 + 降帧) ---------- */
|
||
var cx=rainCv.getContext('2d');
|
||
var cols=[], cw=14, fs=14, rainOn=true;
|
||
function rainResize(){
|
||
rainCv.width=innerWidth; rainCv.height=innerHeight;
|
||
var n=Math.ceil(rainCv.width/cw);
|
||
cols=[]; for(var i=0;i<n;i++) cols.push(Math.random()*rainCv.height);
|
||
}
|
||
function rainStep(){
|
||
if(!rainOn) return;
|
||
cx.fillStyle='rgba(0,6,2,0.14)'; cx.fillRect(0,0,rainCv.width,rainCv.height);
|
||
cx.font=fs+'px monospace';
|
||
for(var i=0;i<cols.length;i++){
|
||
var ch=String.fromCharCode(0x30A0+((Math.random()*90)|0));
|
||
cx.fillStyle = Math.random()<0.05 ? '#c9ffd6' : 'rgba(0,255,65,0.55)';
|
||
cx.fillText(ch, i*cw, cols[i]);
|
||
cols[i] = cols[i]>rainCv.height+Math.random()*260 ? 0 : cols[i]+fs;
|
||
}
|
||
}
|
||
rainResize(); addEventListener('resize',rainResize);
|
||
var rainTimer=setInterval(rainStep,46); /* ≈22fps,开销很小 */
|
||
|
||
/* ---------- 状态 & 时间线 ---------- */
|
||
var S={rev:0,rain:0,edgeY:0,edgeO:0,flashB:1,prog:0};
|
||
var ez={
|
||
linear:function(t){return t;},
|
||
out3:function(t){return 1-Math.pow(1-t,3);},
|
||
inOut3:function(t){return t<.5?4*t*t*t:1-Math.pow(-2*t+2,3)/2;},
|
||
inOut5:function(t){return t<.5?16*t*t*t*t*t:1-Math.pow(-2*t+2,5)/2;}
|
||
};
|
||
var tweens=[];
|
||
var tw=function(s,d,apply,ease){s*=K;d*=K;tweens.push({start:s,end:s+d,dur:d,apply:apply,e:ez[ease]||ez.inOut3});};
|
||
|
||
tw(0.00,0.60,function(e){S.rain=e*0.55;},'out3'); /* 矩阵雨淡入 */
|
||
tw(0.10,1.05,function(e){ /* 自上而下扫描揭示 */
|
||
S.rev=e; S.edgeY=H*e;
|
||
S.edgeO=0.95*Math.min(1,e*6)*Math.min(1,(1-e)*8); /* 揭示边缘亮线 */
|
||
},'inOut5');
|
||
tw(1.78,0.45,function(e){S.flashB=1+Math.sin(e*Math.PI)*0.9;},'linear'); /* 通电闪光 */
|
||
tw(1.95,0.75,function(e){S.edgeY=-20+e*H; S.edgeO=Math.sin(clamp01(e)*Math.PI)*0.9;},'inOut3'); /* 扫光过顶 */
|
||
tw(2.40,1.10,function(e){S.prog=e;},'inOut3'); /* 进度条 */
|
||
|
||
var maxEnd=Math.max.apply(null,tweens.map(function(x){return x.end;}));
|
||
|
||
/* 终端打字 */
|
||
var LINES=[
|
||
{t:0.10, txt:'> INITIALIZING SECHOME CORE...', cps:34},
|
||
{t:1.30, txt:'> DECRYPTING MODULE 0x9F3A ...... [ OK ]', cps:34},
|
||
{t:2.20, txt:'> VERIFYING SIGNATURE .......... [ OK ]', cps:34},
|
||
{t:3.20, txt:'> ACCESS GRANTED', cps:26}
|
||
];
|
||
function updateTerm(t){
|
||
var html='';
|
||
for(var i=0;i<LINES.length;i++){
|
||
var L=LINES[i];
|
||
if(t<L.t) break;
|
||
var n=Math.min(L.txt.length, Math.max(0,(t-L.t)*L.cps)|0);
|
||
html+= (i?'\n':'')+L.txt.slice(0,n)+(n<L.txt.length?'_':'');
|
||
}
|
||
termEl.textContent=html;
|
||
}
|
||
|
||
function render(){
|
||
revealRect.setAttribute('height',(H*S.rev).toFixed(2));
|
||
scanEdge.setAttribute('y',(S.edgeY-1.5).toFixed(2));
|
||
scanEdge.style.opacity=S.edgeO.toFixed(3);
|
||
logoWrap.style.filter = S.flashB>1.001 ? 'brightness('+S.flashB.toFixed(3)+')' : 'none';
|
||
rainCv.style.opacity=S.rain.toFixed(3);
|
||
barFill.style.width=(S.prog*100).toFixed(1)+'%';
|
||
}
|
||
|
||
/* 稳定抖动 */
|
||
setTimeout(function(){ if(!collapsed) logoG.classList.add('glitch'); }, 1240/K);
|
||
|
||
/* ---------- 结尾坍缩 → 跳转目标页 ---------- */
|
||
var collapsed=false;
|
||
function startCollapse(){
|
||
rainOn=false; clearInterval(rainTimer);
|
||
var dur=Math.max(0.05,CFG.collapseIn*K);
|
||
animLayer.style.transitionDuration=dur+'s';
|
||
void animLayer.offsetWidth;
|
||
animLayer.classList.add('collapse');
|
||
setTimeout(function(){ location.replace(CFG.target||'index.php'); }, dur*1000+60);
|
||
}
|
||
|
||
var t0=null;
|
||
function frame(now){
|
||
if(t0===null) t0=now;
|
||
var t=(now-t0)/1000;
|
||
for(var i=0;i<tweens.length;i++){
|
||
var x=tweens[i];
|
||
if(t<x.start||t>x.end) continue;
|
||
x.apply(x.e((t-x.start)/x.dur));
|
||
}
|
||
render(); updateTerm(t);
|
||
if(t>maxEnd+CFG.holdBeforeCollapse*K){
|
||
if(!collapsed){ collapsed=true; startCollapse(); }
|
||
return;
|
||
}
|
||
requestAnimationFrame(frame);
|
||
}
|
||
requestAnimationFrame(frame);
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|