46 lines
7.5 KiB
HTML
46 lines
7.5 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>Rhine Lab · 前段 2D 动效对照</title>
|
||
<style>
|
||
*{box-sizing:border-box}body{margin:0;background:#eae5e1;color:#262824;font:14px Arial,"Microsoft YaHei",sans-serif}main{max-width:1800px;margin:auto;padding:28px}h1{font-size:22px;margin:0 0 10px;font-weight:600}p{line-height:1.7;color:#64645c;margin:0 0 22px}.views{display:grid;grid-template-columns:1fr 1fr;gap:12px}figure{margin:0}figcaption{margin:10px 0;font-size:12px}video,iframe{display:block;width:100%;aspect-ratio:16/9;border:0;background:#eae5e1}nav{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:22px 0 16px}button,a{font:inherit;color:inherit;border:1px solid #bcb9af;background:transparent;padding:9px 14px;cursor:pointer;text-decoration:none}button:hover,a:hover{background:#dcd6cc}button:focus-visible,input:focus-visible,a:focus-visible{outline:2px solid #94714b;outline-offset:3px}input{width:100%;accent-color:#786047}output{font:14px monospace;margin-left:auto}.marks{display:flex;gap:8px;flex-wrap:wrap;margin-top:14px}small{display:block;margin-top:20px;color:#64645c;line-height:1.8}@media(max-width:850px){main{padding:16px}}
|
||
.reference-frame{position:relative}.reference-frame img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;z-index:1;pointer-events:none}.reference-frame.playing img{display:none}
|
||
.crop{overflow:hidden;aspect-ratio:16/9}.crop>*{transform:scale(var(--zoom,1));transform-origin:var(--origin,50% 50%)}body[data-focus="ring"]{--zoom:1.7;--origin:50% 50%}body[data-focus="brand"]{--zoom:2.6;--origin:0% 0%}body[data-focus="company"]{--zoom:2.7;--origin:50% 46%}body[data-focus="orbit"]{--zoom:3.8;--origin:50% 50%}body[data-focus="logo"]{--zoom:3.8;--origin:50% 50%}body[data-focus="gap"]{--zoom:3.8;--origin:29% 50%}</style>
|
||
<main>
|
||
<h1>前段 2D 动效对照</h1>
|
||
<p>左侧为原片,右侧为实时界面。拖动时间轴或逐帧前后移动,两侧会同步;原片每秒 25 帧。</p>
|
||
<div class="views">
|
||
<figure><figcaption>原视频 · 6.76–27.00 秒</figcaption><div class="crop"><div class="reference-frame"><img id="reference-still" alt="原视频当前帧" src="boot-frames/0169.jpg"><video id="reference" muted playsinline preload="auto" src="../《明日方舟》特别映像%20[莱茵生命:访问]%20[BV1rr4y1b7sz].mp4"></video></div></div></figure>
|
||
<figure><figcaption>实时界面 · 逐帧重建</figcaption><div class="crop"><iframe id="replica" title="实时场景对照" src="/?time=1.76&freeze=1&review=1"></iframe></div></figure>
|
||
</div>
|
||
<nav><button id="play">播放对照</button><button id="prev">← 前一帧</button><button id="next">后一帧 →</button><a href="/" target="_blank">播放完整尺寸动画 ↗</a><a href="/?scene=archive" target="_blank">进入交互 ↗</a><output id="stamp">6.76 s · FRAME 169</output></nav>
|
||
<input id="timeline" aria-label="原视频帧位置" type="range" min="169" max="675" step="1" value="169">
|
||
<nav aria-label="局部放大"><label>放大位置 <select id="focus"><option value="full">完整画面</option><option value="logo">Logo 绘制与符号 · 3.8×</option><option value="gap">Logo 移动缺口 · 3.8×</option><option value="brand">左上三行文字 · 2.6×</option><option value="ring">权限圆环 · 1.7×</option><option value="orbit">小圆与环绕点 · 3.8×</option><option value="company">名称黑底扫过 · 2.7×</option></select></label><button data-frame="237">9.48 · 连续笔画</button><button data-frame="248">9.92 · 符号展开</button><button data-frame="258">10.32 · 加号旋转</button><button data-frame="460">18.40 · 缺口移动</button><button data-frame="278">11.12 · 第一行</button><button data-frame="280">11.20 · 第二行</button><button data-frame="282">11.28 · 第三行</button><button data-frame="305">12.20 · 三行落定</button><button data-frame="551">22.04 · 环绕点出现</button><button data-frame="568">22.72 · 小圆收束</button><button data-frame="592">23.68 · 黑底快速段</button><button data-frame="610">24.40 · 黑底落定</button></nav>
|
||
<div class="marks"><button data-frame="187">7.48 · 英文输入</button><button data-frame="240">9.60 · 标志绘制</button><button data-frame="286">11.44 · 身份输入</button><button data-frame="337">13.48 · 姓名</button><button data-frame="500">20.00 · 圆环收拢</button><button data-frame="540">21.60 · 圆环落定</button><button data-frame="550">22.00 · 中心图形</button><button data-frame="569">22.76 · 黑白闪切</button><button data-frame="594">23.76 · 黑底扫过</button><button data-frame="635">25.40 · 欢迎页</button><button data-frame="669">26.76 · 白场转场</button><label>速度 <select id="speed"><option value="1">正常</option><option value="0.5">半速</option><option value="0.25">四分之一</option></select></label></div>
|
||
<small>仅用于本地复核。产品从原片画面变白后开始,不包含黑底鹰角片头;原视频不进入产品页面。← / → 逐帧前后移动。</small>
|
||
</main>
|
||
<script type="module">
|
||
const video=document.querySelector('#reference'),frame=document.querySelector('#replica'),slider=document.querySelector('#timeline'),stamp=document.querySelector('#stamp'),play=document.querySelector('#play');
|
||
const still=document.querySelector('#reference-still'),params=new URLSearchParams(location.search);let desired=Math.max(169,Math.min(675,Number(params.get('frame'))||169))/25;
|
||
if(['full','logo','gap','brand','ring','orbit','company'].includes(params.get('focus'))){document.body.dataset.focus=params.get('focus');document.querySelector('#focus').value=params.get('focus')}
|
||
function sync(t){desired=t;still.src=`boot-frames/${String(Math.round(t*25)).padStart(4,'0')}.jpg`;slider.value=String(Math.round(t*25));stamp.textContent=`${t.toFixed(2)} s · FRAME ${Math.round(t*25)}`;frame.contentWindow.postMessage({type:'rhine-review-frame',time:t-5},location.origin)}
|
||
function pause(){video.pause();video.parentElement.classList.remove('playing');play.textContent='播放对照'}
|
||
function seek(n){pause();const t=Math.max(169,Math.min(675,n))/25;desired=t;sync(t);video.currentTime=t}
|
||
video.addEventListener('loadedmetadata',()=>seek(Math.round(desired*25)));
|
||
frame.addEventListener('load',()=>sync(desired));
|
||
slider.addEventListener('input',()=>seek(Number(slider.value)));
|
||
document.querySelector('#prev').onclick=()=>seek(Number(slider.value)-1);
|
||
document.querySelector('#next').onclick=()=>seek(Number(slider.value)+1);
|
||
document.querySelectorAll('[data-frame]').forEach(b=>b.onclick=()=>seek(Number(b.dataset.frame)));
|
||
play.onclick=async()=>{if(!video.paused){pause();return}if(video.currentTime>=27.0)seek(169);await video.play();video.parentElement.classList.add('playing');play.textContent='暂停'};
|
||
video.addEventListener('seeked',()=>sync(video.currentTime));
|
||
function tick(_,metadata){if(!video.paused){if(metadata.mediaTime>=27.04){seek(169)}else sync(metadata.mediaTime)}video.requestVideoFrameCallback(tick)}
|
||
video.requestVideoFrameCallback(tick);
|
||
document.querySelector('#speed').onchange=e=>video.playbackRate=Number(e.target.value);
|
||
document.querySelector('#focus').onchange=e=>{document.body.dataset.focus=e.target.value;seek({logo:229,gap:425,brand:278,ring:532,orbit:544,company:592,full:Number(slider.value)}[e.target.value])};
|
||
document.addEventListener('keydown',e=>{if(e.target===slider)return;if(e.code==='ArrowLeft'){e.preventDefault();seek(Number(slider.value)-1)}if(e.code==='ArrowRight'){e.preventDefault();seek(Number(slider.value)+1)}});
|
||
</script>
|
||
</html>
|
||
|