H5源码复现 | 快手十三周年 – 你身体里住着怎样的少年
先看效果
已关注
关注
重播 分享 赞
文件目录一览

代码部分
server.js
const Koa = require('koa');const serve = require('koa-static');const fetch = require('node-fetch');const path = require('path');const app = new Koa();const CDN_BASE = 'https://cdn.timaworks.com/kuaishou13/images';// 代理中间件:/proxy/xxx → CDNapp.use(async (ctx, next) => {if (!ctx.path.startsWith('/proxy/')) return next();const filename = ctx.path.slice('/proxy/'.length);const cdnUrl = `${CDN_BASE}/${filename}`;console.log(`[proxy] ${filename}`);const headers = {};if (ctx.headers.range) headers['Range'] = ctx.headers.range;try {const res = await fetch(cdnUrl, { headers });ctx.status = res.status;['content-type','content-length','content-range','accept-ranges','last-modified','etag','cache-control'].forEach(h => {const v = res.headers.get(h);if (v) ctx.set(h, v);});ctx.set('Access-Control-Allow-Origin', '*');ctx.body = res.body;} catch (err) {console.error(`[proxy error]`, err.message);ctx.status = 502;ctx.body = 'proxy error';}});// 静态文件(index.html 等)app.use(serve(path.join(__dirname)));const PORT = 3300;app.listen(PORT, () => {console.log(`服务已启动: http://localhost:3300`);});
index.html
<!DOCTYPE html><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0, user-scalable=no"><title>你身体里住着怎样的少年</title><linkrel="stylesheet"href="style.css"></head><body><divid="stage"><!-- ① 加载页 --><divid="loading"class="slider active fade-in"><imgclass="full-img"src="/proxy/loading-bg.jpg"alt=""><imgid="loading-text-img"class="full-img"src="/proxy/loading-text.png"alt=""><imgid="loading-bird"src="/proxy/loading-bird.gif"alt=""><imgid="loading-bar-img"src="/proxy/loading-percentBar.png"alt=""><divid="loading-percent">0%</div></div><!-- ② Intro 介绍页 --><divid="intro"class="slider"><divclass="video-layer"id="intro-mv-layer"><videoclass="full-video"id="intro-mv"playsinlinemutedpreload="auto"><sourcesrc="/proxy/intro-mv.mp4"type="video/mp4"></video></div><divclass="video-layer"id="intro-loop-layer"><videoclass="full-video"id="intro-loop"playsinlinemutedlooppreload="auto"><sourcesrc="/proxy/intro-loop.mp4"type="video/mp4"></video></div></div><!-- ③ Q1 --><divid="q1"class="slider"><divclass="video-layer"id="q1-mv-layer"><videoclass="full-video"id="q1-mv"playsinlinemutedpreload="auto"><sourcesrc="/proxy/q1-mv.mp4"type="video/mp4"></video></div><divclass="video-layer"id="q1-loop-layer"><videoclass="full-video"id="q1-loop"playsinlinemutedlooppreload="auto"><sourcesrc="/proxy/q1-loop.mp4"type="video/mp4"></video></div><!-- shadownBt:[w,h,x,y] / 750x1624 --><divclass="options-area"id="q1-options"><buttonclass="option-btn"data-index="0"style="left:18.67%;top:35.59%;width:45.33%;height:5.30%"></button><buttonclass="option-btn"data-index="1"style="left:28.00%;top:45.14%;width:57.87%;height:5.85%"></button><buttonclass="option-btn"data-index="2"style="left:17.33%;top:54.43%;width:66.00%;height:6.47%"></button><buttonclass="option-btn"data-index="3"style="left:18.67%;top:66.38%;width:63.33%;height:6.65%"></button></div></div><!-- ④ Q2 --><divid="q2"class="slider"><divclass="video-layer"id="q2-mv-layer"><videoclass="full-video"id="q2-mv"playsinlinemutedpreload="auto"><sourcesrc="/proxy/q2-mv.mp4"type="video/mp4"></video></div><divclass="video-layer"id="q2-loop-layer"><videoclass="full-video"id="q2-loop"playsinlinemutedlooppreload="auto"><sourcesrc="/proxy/q2-loop.mp4"type="video/mp4"></video></div><divclass="options-area"id="q2-options"><buttonclass="option-btn"data-index="0"style="left:18.27%;top:23.21%;width:40.00%;height:12.62%"></button><buttonclass="option-btn"data-index="1"style="left:46.80%;top:37.59%;width:44.27%;height:12.87%"></button><buttonclass="option-btn"data-index="2"style="left:4.93%;top:53.26%;width:46.80%;height:14.59%"></button><buttonclass="option-btn"data-index="3"style="left:44.27%;top:71.43%;width:49.73%;height:14.17%"></button></div></div><!-- ⑤ Q3 --><divid="q3"class="slider"><divclass="video-layer"id="q3-mv-layer"><videoclass="full-video"id="q3-mv"playsinlinemutedpreload="auto"><sourcesrc="/proxy/q3-mv.mp4"type="video/mp4"></video></div><divclass="video-layer"id="q3-loop-layer"><videoclass="full-video"id="q3-loop"playsinlinemutedlooppreload="auto"><sourcesrc="/proxy/q3-loop.mp4"type="video/mp4"></video></div><divclass="options-area"id="q3-options"><buttonclass="option-btn"data-index="0"style="left:17.33%;top:24.14%;width:25.07%;height:19.46%"></button><buttonclass="option-btn"data-index="1"style="left:56.93%;top:30.48%;width:29.60%;height:16.01%"></button><buttonclass="option-btn"data-index="2"style="left:4.80%;top:50.74%;width:44.80%;height:16.20%"></button><buttonclass="option-btn"data-index="3"style="left:64.00%;top:51.60%;width:32.67%;height:18.54%"></button></div></div><!-- ⑥ Q4(音频选项,有重放按钮) --><divid="q4"class="slider"><divclass="video-layer"id="q4-mv-layer"><videoclass="full-video"id="q4-mv"playsinlinemutedpreload="auto"><sourcesrc="/proxy/q4-mv.mp4"type="video/mp4"></video></div><divclass="video-layer"id="q4-loop-layer"><videoclass="full-video"id="q4-loop"playsinlinemutedlooppreload="auto"><sourcesrc="/proxy/q4-loop.mp4"type="video/mp4"></video></div><!-- Q4 选项 + 重放按钮交替:奇数行=选项,偶数行=重放 --><divclass="options-area"id="q4-options"><buttonclass="option-btn"data-index="0"style="left:4.93%;top:24.57%;width:49.33%;height:4.31%"></button><buttonclass="option-btn"data-index="1"style="left:50.13%;top:31.04%;width:35.60%;height:3.88%"></button><buttonclass="option-btn"data-index="2"style="left:4.27%;top:35.90%;width:50.40%;height:6.04%"></button><buttonclass="option-btn"data-index="3"style="left:50.00%;top:43.41%;width:46.00%;height:4.80%"></button></div><!-- 重放按钮 --><buttonclass="replay-btn"data-audio="q4a"style="display:none;left:57.87%;top:24.45%;width:10.00%;height:5.05%"></button><buttonclass="replay-btn"data-audio="q4b"style="display:none;left:33.73%;top:30.00%;width:14.80%;height:4.93%"></button><buttonclass="replay-btn"data-audio="q4c"style="display:none;left:56.93%;top:35.59%;width:13.60%;height:6.59%"></button><buttonclass="replay-btn"data-audio="q4d"style="display:none;left:34.67%;top:42.80%;width:12.00%;height:5.54%"></button></div><!-- ⑦ Info 页(填昵称、选性别) --><divid="info"class="slider"><divclass="video-layer"id="info-mv-layer"><videoclass="full-video"id="info-mv"playsinlinemutedpreload="auto"><sourcesrc="/proxy/info-mv.mp4"type="video/mp4"></video></div><divid="info-form"><inputid="nickname-input"type="text"maxlength="6"placeholder=""><!-- 对勾图片,选中后显示 --><imgid="checked-male"class="checked-img"src="/proxy/info-selected.png"alt=""><imgid="checked-female"class="checked-img"src="/proxy/info-selected.png"alt=""><imgid="checked-all"class="checked-img visible"src="/proxy/info-selected.png"alt=""><!-- 透明点击热区 --><buttonclass="gender-tap"id="tap-male"data-sex="male"></button><buttonclass="gender-tap"id="tap-female"data-sex="female"></button><buttonclass="gender-tap"id="tap-all"data-sex="all"></button><buttonid="submit-btn"></button></div></div><!-- ⑧ Poster 结果页 --><divid="poster"class="slider"><divclass="video-layer"id="ending-mv-layer"><videoclass="full-video"id="ending-mv"playsinlinemutedpreload="auto"><sourcesrc="/proxy/ending-mv.mp4"type="video/mp4"></video></div><divclass="video-layer"id="ending-loop-layer"><videoclass="full-video"id="ending-loop"playsinlinemutedlooppreload="auto"><sourcesrc="/proxy/ending-loop.mp4"type="video/mp4"></video></div><imgid="poster-img"alt="海报"><imgid="tag-img"alt="标签"><divid="ctag-text"></div><divid="poster-nickname"></div><divid="save-tip">长按图片保存</div></div><!-- 页面切换遮罩 --><divid="transition-mask"></div><!-- 音乐按钮(始终在 stage 左上角) --><buttonid="music-btn"></button></div><scriptsrc="app.js"></script></body></html>
app.js
// ============================================================// 答案映射表(原始 app.js 中的 posterMap)// key: "Q1答案 Q2答案 Q3答案 Q4答案",value: 海报数组// ============================================================const POSTER_MAP = {"Ti Se Fi Ne": [{id:1,sex:"male",x:691,y:790,cTag:"举起生活的热血铁男"},{id:2,sex:"female",x:691,y:85,cTag:"体能MAX的热汗少女"},{id:19,sex:"female",x:691,y:790,cTag:"人见人爱的诺贝尓可爱奖得主"}],"Ti Si Fi Ne": [{id:3,sex:"male",x:691,y:85,cTag:"满脑袋英雄梦的国风少年郎"},{id:4,sex:"female",x:58,y:169,cTag:"铁打的花仙子"}],"Ti Se Fi Ni": [{id:5,sex:"female",x:59,y:789,cTag:"在森林找宝藏的波妞"},{id:6,sex:"female",x:59,y:789,cTag:"都市里的田园禾伙人"},{id:7,sex:"male",x:691,y:85,cTag:"永远在启程的荒野骑士"}],"Ti Si Fi Ni": [{id:8,sex:"female",x:58,y:169,cTag:"人间淡淡主理人"},{id:9,sex:"male",x:691,y:85,cTag:"随地起舞的野生梦想家"},{id:7,sex:"male",x:691,y:85,cTag:"永远在启程的荒野骑士"}],"Ti Se Fe Ne": [{id:10,sex:"male",x:58,y:169,cTag:"邪魅娟狂的语录小伙"},{id:11,sex:"female",x:691,y:85,cTag:"体会人生百态的全能掌镜人"},{id:6,sex:"female",x:59,y:789,cTag:"都市里的田园禾伙人"}],"Ti Si Fe Ne": [{id:12,sex:"female",x:58,y:169,cTag:"自带BGM的美少女壮士"},{id:13,sex:"female",x:58,y:169,cTag:"如夏花般绚烂的C位少女"},{id:14,sex:"male",x:691,y:85,cTag:"没有背景靠自己的努力小伙"},{id:5,sex:"female",x:59,y:789,cTag:"在森林找宝藏的波妞"}],"Ti Se Fe Ni": [{id:15,sex:"female",x:58,y:169,cTag:"语速180迈的互联网嘴替"},{id:16,sex:"male",x:58,y:169,cTag:"精神状态遥遥领先的显眼包"},{id:16,sex:"female",x:58,y:169,cTag:"精神状态遥遥领先的显眼包"},{id:17,sex:"male",x:691,y:85,cTag:"全是鬼点子的搞怪戏精"},{id:25,sex:"male",x:691,y:85,cTag:"爱说实话的小话唠"}],"Ti Si Fe Ni": [{id:18,sex:"male",x:58,y:169,cTag:"专治各种不舒服的顶牛妙手"},{id:19,sex:"female",x:691,y:790,cTag:"人见人爱的诺贝尓可爱奖得主"}],"Te Se Fi Ne": [{id:20,sex:"male",x:691,y:790,cTag:"迎着朝阳全力奔跑的孤勇者"},{id:21,sex:"female",x:691,y:790,cTag:"掌勺走天涯的少女宅急便"},{id:22,sex:"male",x:691,y:85,cTag:"大锅杂烩世间好味的游侠"},{id:22,sex:"female",x:691,y:85,cTag:"大锅杂烩世间好味的游侠"},{id:34,sex:"male",x:691,y:85,cTag:"走花路的民间超模"}],"Te Si Fi Ne": [{id:23,sex:"female",x:691,y:85,cTag:"洞察先机的生意捕手"},{id:24,sex:"male",x:59,y:789,cTag:"游乐人间的不受控NPC"},{id:28,sex:"male",x:691,y:790,cTag:"天马行空的民间爱迪生"},{id:21,sex:"female",x:691,y:790,cTag:"掌勺走天涯的少女宅急便"}],"Te Se Fi Ni": [{id:25,sex:"male",x:691,y:85,cTag:"爱说实话的小话唠"},{id:26,sex:"female",x:691,y:85,cTag:"24K的纯神金小妹"}],"Te Si Fi Ni": [{id:27,sex:"male",x:58,y:169,cTag:"玩的就是真实的挑战玩家"},{id:28,sex:"male",x:691,y:790,cTag:"天马行空的民间爱迪生"},{id:31,sex:"female",x:691,y:85,cTag:"一路打怪升级的爽文女主"},{id:13,sex:"female",x:58,y:169,cTag:"如夏花般绚烂的C位少女"}],"Te Se Fe Ne": [{id:29,sex:"male",x:691,y:85,cTag:"随地大小聊的社交悍匪"},{id:29,sex:"female",x:691,y:85,cTag:"随地大小聊的社交悍匪"},{id:30,sex:"male",x:691,y:790,cTag:"行走人间的行为E术家"},{id:31,sex:"female",x:691,y:85,cTag:"一路打怪升级的爽文女主"},{id:26,sex:"female",x:691,y:85,cTag:"24K的纯神金小妹"}],"Te Si Fe Ne": [{id:32,sex:"male",x:691,y:85,cTag:"一秒换头的时尚ICON"},{id:33,sex:"female",x:691,y:790,cTag:"麻袋当披风也能是人间高定"},{id:34,sex:"male",x:691,y:85,cTag:"走花路的民间超模"}],"Te Se Fe Ni": [{id:35,sex:"female",x:58,y:169,cTag:"每一步都算数的摘星女主"},{id:36,sex:"female",x:58,y:169,cTag:"真诚而热烈的毛孩子"},{id:36,sex:"male",x:58,y:169,cTag:"真诚而热烈的毛孩子"},{id:37,sex:"male",x:691,y:790,cTag:"东北话十级表演艺术家"},{id:4,sex:"female",x:58,y:169,cTag:"铁打的花仙子"},{id:20,sex:"male",x:691,y:790,cTag:"迎着朝阳全力奔跑的孤勇者"}],"Te Si Fe Ni": [{id:38,sex:"male",x:691,y:85,cTag:"民间采风的野生音乐人"},{id:39,sex:"female",x:58,y:169,cTag:"实力开麦的嘴强王者"},{id:30,sex:"male",x:691,y:790,cTag:"行走人间的行为E术家"}],};// 每题答案编码(index → 字符串)const ANSWER_KEYS = [["Te","Ti","Ti","Te"], // Q1["Si","Se","Si","Se"], // Q2["Fi","Fi","Fe","Fe"], // Q3["Ne","Ne","Ni","Ni"], // Q4];// 原始设计稿尺寸const DESIGN_W = 750, DESIGN_H = 1624;// ============================================================// 状态// ============================================================let answers = []; // 收集的答案字符串let userSex = null; // "male" | "female" | nulllet bgm = null; // Audio 对象// ============================================================// 工具// ============================================================// 切换 sliderfunction showSlider(id) {document.querySelectorAll('.slider').forEach(el => el.classList.remove('active'));document.getElementById(id).classList.add('active');}// iOS:intro-mv 开始播放后,对其余视频 play() 后 100ms 暂停以触发缓冲function preloadOtherVideos() {document.querySelectorAll('video:not(#intro-mv)').forEach(v => {v.play().then(() => setTimeout(() => v.pause(), 300)).catch(() => {});});}// 播放 mv,结束后回调;onPlaying 在视频真正有画面时调用function playMV(videoId, onEnded, onPlaying) {const video = document.getElementById(videoId);const layer = document.getElementById(videoId + '-layer');video.onplaying = () => { layer.classList.add('visible'); if (onPlaying) onPlaying(); };video.onended = onEnded || null;setTimeout(() => video.play().catch(err => {console.warn('autoplay blocked, waiting for interaction:', err.message);const retry = () => { document.removeEventListener('click', retry); video.play().catch(() => {}); };document.addEventListener('click', retry, { once: true });}), 50);}// 显示并播放 loop 视频function playLoop(videoId) {const video = document.getElementById(videoId);document.getElementById(videoId + '-layer').classList.add('visible');video.play().catch(() => {});}// 暂停视频function pauseVideo(videoId) {const v = document.getElementById(videoId);if (v) v.pause();}// 显示选项热区function showOptions(id) {document.getElementById(id).classList.add('visible');}// 设计稿坐标 → 当前舞台比例(用于海报昵称定位)function scaleX(x) { return (x / DESIGN_W) * 100 + '%'; }function scaleY(y) { return (y / DESIGN_H) * 100 + '%'; }// ============================================================// 背景音乐// ============================================================function initBGM() {bgm = new Audio('/proxy/music.mp3');bgm.loop = true;bgm.volume = 0.6;const btn = document.getElementById('music-btn');btn.addEventListener('click', () => {if (bgm.paused) { bgm.play(); btn.classList.remove('paused'); }else { bgm.pause(); btn.classList.add('paused'); }});}function playBGM() {if (bgm && bgm.paused) bgm.play().catch(() => {});}// ============================================================// 页面流程// ============================================================function goIntro() {transitionToSlider('intro', (onReady) => {playBGM();playMV('intro-mv', () => {playLoop('intro-loop');setTimeout(() => goQ(1), 2000);}, () => {onReady();preloadOtherVideos();});});}// 新 slider 叠在旧 slider 上,等 onReady() 调用后再淡入,淡入完成后隐藏旧的function transitionToSlider(targetSliderId, callback) {const prev = document.querySelector('.slider.active');const next = document.getElementById(targetSliderId);next.classList.add('active');const onReady = () => {requestAnimationFrame(() => requestAnimationFrame(() => {next.classList.add('fade-in');setTimeout(() => {if (prev && prev !== next) prev.classList.remove('active', 'fade-in');}, 400);}));};if (callback) callback(onReady);}function goQ(n) {const prevLoops = ['intro-loop', 'q1-loop', 'q2-loop', 'q3-loop'];pauseVideo(prevLoops[n - 1]);// 背景图 id 对应关系transitionToSlider('q' + n, (hideMask) => {playMV('q' + n + '-mv', () => {playLoop('q' + n + '-loop');showOptions('q' + n + '-options');if (n === 4) showQ4Replays();}, hideMask);});}// ============================================================// Q4 音频重放// ============================================================const q4Audios = {};function initQ4Audios() {['q4a','q4b','q4c','q4d'].forEach(k => {q4Audios[k] = new Audio('/proxy/' + k + '.mp3');});}function stopAllQ4() {Object.values(q4Audios).forEach(a => { a.pause(); a.currentTime = 0; });}function showQ4Replays() {document.querySelectorAll('.replay-btn').forEach(btn => {btn.style.display = 'block';});// 自动播放第一个stopAllQ4();q4Audios['q4a'].play().catch(() => {});}// ============================================================// Info 页// ============================================================function goInfo() {pauseVideo('q4-loop');transitionToSlider('info', (hideMask) => {playMV('info-mv', () => {document.getElementById('info-form').classList.add('visible');}, hideMask);});}// 性别选择document.querySelectorAll('.gender-tap').forEach(btn => {btn.addEventListener('click', () => {document.querySelectorAll('.checked-img').forEach(img => img.classList.remove('visible'));document.getElementById('checked-' + btn.dataset.sex).classList.add('visible');userSex = btn.dataset.sex === 'all' ? null : btn.dataset.sex;});});// 提交document.getElementById('submit-btn').addEventListener('click', () => {const nickname = document.getElementById('nickname-input').value.trim();if (!nickname) { document.getElementById('nickname-input').focus(); return; }goPoster(nickname);});// ============================================================// Poster 页// ============================================================function goPoster(nickname) {// 根据答案 + 性别选海报const key = answers.join(' ');let pool = POSTER_MAP[key] || POSTER_MAP[Object.keys(POSTER_MAP)[0]];if (userSex === 'male') pool = pool.filter(p => p.sex === 'male');else if (userSex === 'female') pool = pool.filter(p => p.sex === 'female');if (!pool.length) pool = POSTER_MAP[key] || [];const pick = pool[Math.floor(Math.random() * pool.length)];// 设置海报图const posterImg = document.getElementById('poster-img');posterImg.src = '/proxy/posters/poster-' + pick.id + '.jpg';posterImg.onload = () => posterImg.classList.add('visible');// 设置标签图const tagImg = document.getElementById('tag-img');tagImg.src = '/proxy/tags/tag-' + pick.id + '.png';// 设置文字标签document.getElementById('ctag-text').textContent = pick.cTag;// 设置昵称位置(设计稿坐标换算)const nn = document.getElementById('poster-nickname');nn.textContent = '@' + nickname;nn.style.left = scaleX(pick.x);nn.style.top = scaleY(pick.y + 140);transitionToSlider('poster', (hideMask) => {// 播放 ending-mv → ending-loop,然后依次显示元素playMV('ending-mv', () => {playLoop('ending-loop');setTimeout(() => {tagImg.classList.add('visible');nn.classList.add('visible');}, 500);setTimeout(() => {document.getElementById('ctag-text').classList.add('visible');}, 1500);setTimeout(() => {document.getElementById('save-tip').classList.add('visible');}, 2500);}, hideMask);});}// ============================================================// 事件绑定// ============================================================// Q1~Q3 选项[1,2,3].forEach(n => {document.getElementById('q' + n + '-options').addEventListener('click', e => {const btn = e.target.closest('.option-btn');if (!btn) return;const idx = parseInt(btn.dataset.index);answers.push(ANSWER_KEYS[n-1][idx]);document.getElementById('q' + n + '-options').classList.remove('visible');goQ(n + 1);});});// Q4 选项document.getElementById('q4-options').addEventListener('click', e => {const btn = e.target.closest('.option-btn');if (!btn) return;const idx = parseInt(btn.dataset.index);answers.push(ANSWER_KEYS[3][idx]);stopAllQ4();document.getElementById('q4-options').classList.remove('visible');document.querySelectorAll('.replay-btn').forEach(b => b.style.display = 'none');goInfo();});// Q4 重放按钮document.querySelectorAll('.replay-btn').forEach(btn => {btn.addEventListener('click', e => {e.stopPropagation();stopAllQ4();q4Audios[btn.dataset.audio].play().catch(() => {});});});// ============================================================// 加载 + 启动// ============================================================function startLoading() {const bar = document.getElementById('loading-bar-img');const text = document.getElementById('loading-percent');let pct = 0;let done = false;const update = (v) => {pct = v;bar.style.width = (18.4 * v / 100) + '%';text.textContent = v + '%';};const assets = ['loading-bg.jpg','intro-bg.jpg','q1-bg.jpg','q2-bg.jpg','q3-bg.jpg'];let loaded = 0;assets.forEach(name => {const img = new Image();img.onload = img.onerror = () => update(Math.round(++loaded / assets.length * 70));img.src = '/proxy/' + name;});setTimeout(() => {const t = setInterval(() => {if (pct >= 100) {clearInterval(t);done = true;// 进度跑完,等待点击小鸟document.getElementById('loading-bird').style.cursor = 'pointer';return;}update(pct + 1);}, 25);}, 600);document.getElementById('loading-bird').addEventListener('click', () => {if (!done) return;goIntro();});}initBGM();initQ4Audios();startLoading();
style.css
* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }body {background: #000;margin: 0;display: flex;justify-content: center;align-items: center;height: 100vh;overflow: hidden;}#stage {position: relative;/* 电脑:按高度撑满,保持比例,两侧留黑 */height: 100vh;width: calc(100vh * 750 / 1334);overflow: hidden;background: #000;flex-shrink: 0;}/* 手机:完全撑满视口,不保持比例(原版行为) */@media (max-aspect-ratio: 750/1334) {body { height: 100dvh; }#stage {width: 100vw;height: 100dvh;}}.slider {position: absolute;inset: 0;display: none;opacity: 0;transition: opacity 0.4s;}.slider.active { display: block; }.slider.fade-in { opacity: 1; }/* 全屏视频/图片 */.full-video, .full-img {position: absolute;inset: 0;width: 100%;height: 100%;object-fit: cover;}/* 视频层(mv/loop 叠加,fade 切换) */.video-layer {position: absolute;inset: 0;opacity: 0;transition: opacity 0.3s;}.video-layer.visible { opacity: 1; }/* 加载页 */#loading-bird {position: absolute;left: 37.07%;top: 35.47%;width: 10%;}#loading-bar-img {position: absolute;left: 40.8%; /* x=306/750 */top: 47.66%; /* y=774/1624 */height: 1%; /* 图片本身高度自适应 */width: 0%;max-width: 18.4%; /* 138/750 */overflow: hidden;transition: width 0.3s;object-fit: cover;object-position: left;}#loading-percent {position: absolute;width: 100%;text-align: center;top: 61.6%;color: #fff;font-size: 14px;}/* 透明选项热区 */.options-area {position: absolute;inset: 0;display: none;z-index: 10;}.options-area.visible { display: block; }.option-btn {position: absolute;cursor: pointer;background: transparent;border: none;/* 调试坐标时取消注释:*//* outline: 2px solid rgba(255,0,0,0.5); */}.replay-btn {position: absolute;cursor: pointer;background: transparent;border: none;z-index: 11;/* outline: 2px solid rgba(0,255,0,0.5); */}/* ---- Info 页 ---- */#info-form {position: absolute;inset: 0;z-index: 10;display: none;pointer-events: none;}#info-form.visible {display: block;pointer-events: auto;}/* 输入框:可见,覆盖在视频对应位置 *//* 原始坐标 x:240,y:760 / 750x1624 */#nickname-input {position: absolute;left: 32%; /* 240/750 */top: 46.8%; /* 760/1624 */width: 33.3%; /* 250/750 */height: 2.46%; /* 40/1624 */font-size: 20px;text-align: center;color: #4f708c;background: transparent;border: none;outline: none;caret-color: #4f708c;}/* 性别对勾图片:默认隐藏,选中后显示 *//* x:200,y:900 / x:340,y:900 / x:500,y:900 */.checked-img {position: absolute;width: 6%;top: 55.4%; /* 900/1624 */opacity: 0;pointer-events: none;transition: opacity 0.15s;}.checked-img.visible { opacity: 1; }#checked-male { left: 26.67%; } /* 200/750 */#checked-female{ left: 45.33%; } /* 340/750 */#checked-all { left: 66.67%; } /* 500/750 *//* 성별 클릭 투명 열역 */.gender-tap {position: absolute;top: 53%;width: 12%;height: 8%;cursor: pointer;background: transparent;border: none;}#tap-male { left: 24%; }#tap-female { left: 43%; }#tap-all { left: 64%; }/* 提交透明热区 shadownBt:[160,60,300,1006] */#submit-btn {position: absolute;left: 40%; /* 300/750 */top: 61.9%; /* 1006/1624 */width: 21.3%; /* 160/750 */height: 3.7%; /* 60/1624 */background: transparent;border: none;cursor: pointer;}/* ---- Poster 页 ---- */#poster-img {position: absolute;inset: 0;width: 100%;height: 100%;object-fit: cover;opacity: 0;transition: opacity 0.5s;}#poster-img.visible { opacity: 1; }#poster-nickname {position: absolute;color: #fff;font-size: 13px;text-align: center;text-shadow: 0 0 8px rgba(0,0,0,0.3);line-height: 1.2;word-break: break-all;pointer-events: none;opacity: 0;transition: opacity 0.3s;}#poster-nickname.visible { opacity: 1; }#tag-img {position: absolute;top: 0; left: 0;width: 100%;opacity: 0;transition: opacity 0.5s;}#tag-img.visible { opacity: 1; }#ctag-text {position: absolute;width: 100%;text-align: center;font-size: 17px;color: #434c5f;letter-spacing: 0.1em;opacity: 0;transition: opacity 0.5s;}#ctag-text.visible { opacity: 1; }#save-tip {position: absolute;bottom: 20px;left: 50%;transform: translateX(-50%);color: rgba(255,255,255,0.8);font-size: 12px;white-space: nowrap;opacity: 0;transition: opacity 0.3s;}#save-tip.visible { opacity: 1; }/* 页面切换遮罩 */#transition-mask {position: absolute;inset: 0;background: #000;opacity: 0;pointer-events: none;transition: opacity 0.4s;z-index: 100;}/* 音乐按钮:雪碧图上帧=播放,下帧=暂停,无旋转 */#music-btn {position: absolute;top: 20px;left: 20px;width: 30px;height: 30px;border: none;padding: 0;cursor: pointer;z-index: 9999;background: url('/proxy/musicBt.png') no-repeat center 0px;background-size: 100% auto;}#music-btn.paused {background-position: center -50px;}
夜雨聆风