![]()
🎭 角色简介
– 你将扮演提刑司内的主要四人组,分别为陆长闲、楼以观、严墨心、徐攸淼,你需要注意平衡这四位的出场戏份。
– 需要平衡这四人组工作与休息的时间,需要松弛有度。
– 在扮演这四位的基础上,你需要格外扮演赵玥以及多位随机NPC来增加世界的丰富度。
– 大魏是女子地位颇高的王朝,禁止女性刻板印象,因…
💬 开场白
“`html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>云台书卷</title><style>
/* — 全局与字体设定 — */
:root {
–bg-color-1: #c6d5c2; /* 主背景色 – 淡绿 */
–bg-color-2: #a9bca4; /* 渐变背景色 – 稍深绿 */
–accent-color: #f0f5f9; /* 高亮色 – 月白 */
–font-color: #4b6048; /* 字体色 – 墨绿 */
–shadow-color: rgba(75, 96, 72, 0.2);
–border-color: #e0e6e2;
}@import url('https://fonts.font.im/css?family=Noto+Serif+SC:wght@400;700&display=swap');
body {
background: linear-gradient(145deg, var(–bg-color-2), var(–bg-color-1));
margin: 0;
padding: 20px;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
font-family: 'Noto Serif SC', 'Source Han Serif SC', 'Songti SC', serif;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}*, *::before, *::after { box-sizing: border-box; }
/* — “进入大魏”初始界面 — */
#entry-gate { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(25, 30, 25, 0.7); display: flex; align-items: center; justify-content: center; z-index: 100; backdrop-filter: blur(5px); transition: opacity 0.5s ease; }
#entry-button { background: none; border: 1px solid var(–accent-color); color: var(–accent-color); padding: 15px 30px; font-size: 1.2em; font-family: 'Noto Serif SC', serif; cursor: pointer; border-radius: 5px; transition: background 0.3s, color 0.3s; }
#entry-button:hover { background: var(–accent-color); color: var(–font-color); }/* — 整体书卷容器 — */
.character-sheet-container { width: 100%; max-width: 800px; margin: 20px auto; background: #fdfdfd; border-radius: 10px; box-shadow: 0 10px 30px var(–shadow-color); border: 1px solid rgba(255,255,255,0.5); display: none; }/* — 顶部播放器区域 — */
#player-section { padding: 20px 25px; display: flex; align-items: center; gap: 20px; background: linear-gradient(to bottom, #ffffff, #f7faf6); border-radius: 10px 10px 0 0; }
.album-art-wrapper { flex-shrink: 0; }
.album-art { width: 90px; height: 90px; border-radius: 50%; object-fit: cover; border: 3px solid var(–bg-color-1); animation: spin 20s linear infinite paused; transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out; }
.album-art.playing { animation-play-state: running; }
.album-art.fade-out, .track-title.fade-out, .track-artist.fade-out { opacity: 0; }
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
.player-core { width: 100%; color: var(–font-color); position: relative; }
.track-info { margin-bottom: 8px; position: relative; height: 45px; }
.track-title, .track-artist { transition: opacity 0.3s ease-in-out; }
.track-title { font-size: 1.2em; font-weight: 700; margin: 0; }
.track-artist { font-size: 0.9em; opacity: 0.8; margin-top: 2px; }
.progress-container { width: 100%; margin-bottom: 5px; }
.timeline { width: 100%; height: 8px; background: var(–bg-color-1); border-radius: 4px; cursor: pointer; padding: 2px 0;}
.progress-bar { width: 0%; height: 100%; background: var(–font-color); border-radius: 4px; pointer-events: none; }
.time-display { display: flex; justify-content: space-between; font-size: 0.8em; color: var(–bg-color-2); }
.controls { display: flex; align-items: center; justify-content: center; gap: 15px; margin-top: 5px; }
.control-btn { background: none; border: none; cursor: pointer; padding: 5px; }
.control-btn svg { width: 22px; height: 22px; fill: var(–bg-color-2); transition: fill 0.2s; }
.control-btn:hover svg { fill: var(–font-color); }
.play-pause-btn svg { width: 36px; height: 36px; }/* 加载期间禁用控件 */
.player-core.is-loading .controls,
.player-core.is-loading .timeline {
pointer-events: none;
opacity: 0.5;
transition: opacity 0.2s;
}/* 巧思:水墨风格分隔线 */
.section-divider { height: 30px; background-image: url('data:image/svg+xml;utf8,<svg width="100" height="5" xmlns="http://www.w3.org/2000/svg"><path d="M0 2.5 Q 25 0, 50 2.5 T 100 2.5" stroke="%23a9bca4" fill="none" stroke-width="1" stroke-opacity="0.6"/></svg>'); background-repeat: repeat-x; background-position: center; margin: 10px 0; }/* — 角色介绍区 — */
#character-section { padding: 20px 25px; }
.section-title { font-size: 1.1em; font-weight: 700; color: var(–font-color); margin: 0 0 15px 0; text-align: center; }
.character-selector { display: flex; flex-wrap: wrap; gap: 15px; justify-content: center; }
.char-select-btn { background-color: #f7faf6; border: 1px solid var(–border-color); padding: 8px 16px; border-radius: 20px; cursor: pointer; font-family: inherit; font-size: 0.9em; color: var(–bg-color-2); transition: all 0.2s ease-out; }
.char-select-btn:hover { background-color: var(–bg-color-1); color: white; transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.05); }/* — 角色详情弹窗(Modal) — */
#character-modal { display: none; position: fixed; z-index: 101; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.6); align-items: center; justify-content: center; backdrop-filter: blur(4px); }
.modal-content-wrapper { animation: modal-fade-in 0.4s cubic-bezier(0.165, 0.84, 0.44, 1); }
.modal-content { position: relative; background: white; padding: 30px; border-radius: 8px; max-width: 600px; width: 90vw; max-height: 80vh; overflow-y: auto; }
.close-modal-btn { position: absolute; top: 10px; right: 15px; font-size: 28px; font-weight: bold; color: #aaa; cursor: pointer; transition: color 0.2s; }
.close-modal-btn:hover { color: #333; }
#modal-character-name { margin-top: 0; color: var(–font-color); }
#modal-character-description p { line-height: 1.8; color: #555; }
@keyframes modal-fade-in { from { transform: scale(0.9); opacity: 0; } to { transform: scale(1); opacity: 1; } }/* — 游玩提醒区 — */
#reminder-section { padding: 20px 25px 40px; }
#reminder-section .section-title { font-size: 1.6em; letter-spacing: 2px; margin-bottom: 20px; }
.reminder-content { background-color: #fdfdfd; border: 1px solid var(–border-color); padding: 20px 25px; border-radius: 8px; font-size: 0.95em; color: var(–font-color); box-shadow: 0 5px 15px rgba(75, 96, 72, 0.1); }
.reminder-content p { margin: 0; line-height: 1.8; }/* 响应式设计 */
@media (max-width: 768px) {
body { padding: 0; }
.character-sheet-container { margin: 0; border-radius: 0; min-height: 100vh; }
#player-section, #character-section, #reminder-section { padding: 15px; }
.album-art { width: 70px; height: 70px; }
.controls { gap: 10px; }
.control-btn svg { width: 20px; height: 20px; }
.play-pause-btn svg { width: 32px; height: 32px; }
}
</style>
</head>
<body><!– HTML 结构部分保持不变 –>
<div id="entry-gate"><button id="entry-button">进入大魏</button></div>
<div class="character-sheet-container" id="main-content">
<section id="player-section">
<div class="album-art-wrapper"><img id="album-art-img" class="album-art" src="" alt="专辑封面"></div>
<div class="player-core">
<audio id="main-audio"></audio>
<div class="track-info">
<p id="track-title" class="track-title"></p>
<p id="track-artist" class="track-artist"></p>
</div>
<div class="progress-container">
<div id="timeline" class="timeline"><div id="progress-bar" class="progress-bar"></div></div>
<div class="time-display"><span id="current-time">00:00</span><span id="total-time">00:00</span></div>
</div>
<div class="controls">
<button id="prev-btn" class="control-btn" title="上一首"><svg viewBox="0 0 24 24"><path d="M6,18V6H8V18H6M9.5,12L18,6V18L9.5,12Z" /></svg></button>
<button id="rewind-btn" class="control-btn" title="后退10秒"><svg viewBox="0 0 24 24"><path d="M11.5,12A2.5,2.5 0 0,0 9,14.5A2.5,2.5 0 0,0 11.5,17A2.5,2.5 0 0,0 14,14.5A2.5,2.5 0 0,0 11.5,12M11.5,6.5V9.17C12.42,9.64 13,10.5 13,11.5C13,12.5 12.42,13.36 11.5,13.83V16.5A5,5 0 0,0 16.5,11.5A5,5 0 0,0 11.5,6.5M6.5,6.5V16.5A5,5 0 0,0 11.5,21.5A5,5 0 0,0 16.5,16.5V13.83C17.58,13.36 18.5,12.5 18.5,11.5C18.5,10.5 17.58,9.64 16.5,9.17V6.5A5,5 0 0,0 11.5,1.5A5,5 0 0,0 6.5,6.5Z"></path></svg></button>
<button id="play-pause-btn" class="control-btn play-pause-btn" title="播放/暂停"><svg id="play-icon" viewBox="0 0 24 24"><path d="M8,5.14V19.14L19,12.14L8,5.14Z" /></svg><svg id="pause-icon" viewBox="0 0 24 24" style="display: none;"><path d="M14,19H18V5H14M6,19H10V5H6V19Z" /></svg></button>
<button id="forward-btn" class="control-btn" title="前进10秒"><svg viewBox="0 0 24 24"><path d="M12.5,12A2.5,2.5 0 0,1 15,14.5A2.5,2.5 0 0,1 12.5,17A2.5,2.5 0 0,1 10,14.5A2.5,2.5 0 0,1 12.5,12M12.5,6.5V9.17C11.58,9.64 11,10.5 11,11.5C11,12.5 11.58,13.36 12.5,13.83V16.5A5,5 0 0,1 7.5,11.5A5,5 0 0,1 12.5,6.5M17.5,6.5V16.5A5,5 0 0,1 12.5,21.5A5,5 0 0,1 7.5,16.5V13.83C6.42,13.36 5.5,12.5 5.5,11.5C5.5,10.5 6.42,9.64 7.5,9.17V6.5A5,5 0 0,1 12.5,1.5A5,5 0 0,1 17.5,6.5Z"></path></svg></button>
<button id="next-btn" class="control-btn" title="下一首"><svg viewBox="0 0 24 24"><path d="M16,18H18V6H16V18M6,6V18L14.5,12L6,6Z" /></svg></button>
</div>
</div>
</section>
<div class="section-divider"></div>
<section id="character-section"> <h3 class="section-title">人物介绍</h3><div class="character-selector" id="character-selector"></div> </section>
<div id="character-modal"> <div class="modal-content-wrapper"> <div class="modal-content"> <span class="close-modal-btn">×</span><h2 id="modal-character-name"></h2><div id="modal-character-description"></div></div></div></div>
<div class="section-divider"></div>
<section id="reminder-section"> <h3 class="section-title">大魏游玩介绍</h3><div class="reminder-content"><p>本角色卡为提刑司多人卡,角色4+1,因为是由四位单人卡扩建而来,因此角色人设写的较为多,本卡世界书较重,请采用轻量预设进行游玩。没有玩过单人卡也不影响游玩此卡,同时我对于世界观进行了微调,所以与陆楼严徐的单人卡世界观会有细微差异点,同时因为图床问题加载歌曲图片会较为慢,三首歌的图片分别为陆楼赵。那么祝大家玩的开心!点击第二页为正式开场白。</p></div> </section>
</div><script>
document.addEventListener('DOMContentLoaded', () => {const playlist = [
{ title: "余生付雪夜", artist: "赤羽", src: "https://sharkpan.xyz/f/NzKMfv/%E4%BD%99%E7%94%9F%E4%BB%98%E9%9B%AA%E5%A4%9C-%E8%B5%A4%E7%BE%BD.mp3", albumArt: "https://sharkpan.xyz/f/xZm3sX/IMG_20250729_034246.jpg" },
{ title: "跨越千山,仍未见你的模样", artist: "变奏的梦想/喵步小雨中", src: "https://sharkpan.xyz/f/VELVtY/%E8%B7%A8%E8%B6%8A%E5%8D%83%E5%B1%B1%EF%BC%8C%E4%BB%8D%E6%9C%AA%E8%A7%81%E4%BD%A0%E7%9A%84%E6%A8%A1%E6%A0%B7.mp3", albumArt: "https://sharkpan.xyz/f/dox3C8/IMG_20250729_033950.jpg" },
{ title: "火灵", artist: "喵步小雨中", src: "https://sharkpan.xyz/f/Eyr2TD/%E7%81%AB%E7%81%B5.mp3", albumArt: "https://sharkpan.xyz/f/YL26H1/mmexport1755334873127.jpg" }
];
const characterData = {
'char1': { name: '陆长闲', description: `<p>提刑司掌刑院巡案使陆长闲。传闻陆大人经常加班不眠,她于公务时如鹰隼般锐利,私下却像个混迹市井的江湖人,慵懒而风趣。她追逐证据,也相信直觉,为了杜绝冤案重演,不惜游走在规则的刀锋之上。</p>` },'char2': { name: '楼以观', description: `<p>提刑司司宪院掌案判官,一位看似温和病弱的文官。无人知晓,她便是十四年前“清和公主案”中唯一的幸存者——赵津。往事如烟,流年似水,她如今享受着这来之不易充满人间烟火的本身。</p>` },'char3': { name: '严墨心', description: `<p>提刑司司宪院监察使,外表古板严肃,宛如行走的标尺,内心却在面对计划外的善意与人情世故时手足无措。她能背下整部律典,却会在坊市中迷路;她会因同僚报告中的一个错字而驳回,也会笨拙地递上关心对方的字条。</p>` },'char4': { name: '徐攸淼', description: `<p>提刑司典狱院司刑使,来自西北边军世家,如同照进阴森诏狱的一缕烈阳。她为人爽朗仗义,武艺高强,精通审讯之术,令罪犯闻风丧胆。但这位看似粗中有细的悍将,私下里却是个怕鬼的数学白痴,会偷偷喂养流浪的狸奴,也会在闲暇时用一双布满厚茧的手,雕刻出最精巧的木制小物。</p>` },'char5': { name: '赵玥', description: `<p>大魏荣和长公主,当朝天子之胞妹,提刑司与镇北军的实际掌控者。她龙威天成,野心勃勃,十五年来步步为营,只为夺回本属于自己的皇位。在她眼中,万物皆为棋子,唯有江山值得她倾注所有。这位未来的女帝,在冷酷的帝王心术之下,亦有对北境的怀念与孤高不胜寒。</p>` }
};// — 元素获取 —
const playerCore = document.querySelector('.player-core');
const audio = document.getElementById('main-audio');
const albumArt = document.getElementById('album-art-img');
const trackTitleEl = document.getElementById('track-title');
const trackArtistEl = document.getElementById('track-artist');
const playPauseBtn = document.getElementById('play-pause-btn');
const playIcon = document.getElementById('play-icon');
const pauseIcon = document.getElementById('pause-icon');
const prevBtn = document.getElementById('prev-btn');
const nextBtn = document.getElementById('next-btn');
const rewindBtn = document.getElementById('rewind-btn');
const forwardBtn = document.getElementById('forward-btn');
const timeline = document.getElementById('timeline');
const progressBar = document.getElementById('progress-bar');
const currentTimeEl = document.getElementById('current-time');
const totalTimeEl = document.getElementById('total-time');
const entryGate = document.getElementById('entry-gate');
const entryButton = document.getElementById('entry-button');
const mainContent = document.getElementById('main-content');
const characterSelector = document.getElementById('character-selector');
const modalName = document.getElementById('modal-character-name');
const modalDescription = document.getElementById('modal-character-description');
const closeModalBtn = document.querySelector('.close-modal-btn');
const characterModal = document.getElementById('character-modal');let currentTrackIndex = 0;
let isDragging = false;
let hasInteracted = false; // 用户是否已交互的标志// — 【最终重构】核心切歌函数 —
function loadTrack(index, shouldAutoplay) {
if (playerCore.classList.contains('is-loading')) return;
playerCore.classList.add('is-loading');currentTrackIndex = index;
const track = playlist[index];albumArt.classList.add('fade-out');
trackTitleEl.classList.add('fade-out');
trackArtistEl.classList.add('fade-out');setTimeout(() => {
trackTitleEl.textContent = track.title;
trackArtistEl.textContent = track.artist;
trackTitleEl.classList.remove('fade-out');
trackArtistEl.classList.remove('fade-out');const newAlbumArt = new Image();
newAlbumArt.onload = () => {
albumArt.src = newAlbumArt.src;
albumArt.classList.remove('fade-out');
};
newAlbumArt.onerror = () => {
console.error("封面加载失败:", track.albumArt);
albumArt.src = '';
albumArt.classList.remove('fade-out');
}
newAlbumArt.src = track.albumArt + '?t=' + new Date().getTime();audio.src = track.src;
}, 300); // 必须匹配CSS中的 transition-durationconst onCanPlay = () => {
if (shouldAutoplay && hasInteracted) {
audio.play().catch(e => console.error("自动播放失败:", e));
}
playerCore.classList.remove('is-loading');
audio.removeEventListener('canplay', onCanPlay, false);
};const onError = () => {
console.error("音频加载失败");
playerCore.classList.remove('is-loading');
audio.removeEventListener('error', onError, false);
}// 清理旧监听器,防止重复绑定
audio.removeEventListener('canplay', onCanPlay, false);
audio.removeEventListener('error', onError, false);audio.addEventListener('canplay', onCanPlay);
audio.addEventListener('error', onError);
}// — 辅助函数 —
function togglePlayPause() { if (audio.paused) { audio.play(); } else { audio.pause(); } }
function updateUIOnPlayState() {
if (audio.paused || audio.ended) {
playIcon.style.display = 'block'; pauseIcon.style.display = 'none'; albumArt.classList.remove('playing');
} else {
playIcon.style.display = 'none'; pauseIcon.style.display = 'block'; albumArt.classList.add('playing');
}
}
function formatTime(seconds) {
if (isNaN(seconds)) return '00:00';
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
}
function updateProgress() {
if (audio.duration && !isDragging) {
progressBar.style.width = `${(audio.currentTime / audio.duration) * 100}%`;
currentTimeEl.textContent = formatTime(audio.currentTime);
}
}
function setProgressFromEvent(e) {
const timelineRect = timeline.getBoundingClientRect();
const clientX = e.type.startsWith('touch') ? e.touches[0].clientX : e.clientX;
const percent = Math.max(0, Math.min(1, (clientX – timelineRect.left) / timelineRect.width));
if(isFinite(audio.duration)) audio.currentTime = percent * audio.duration;
}// — 事件监听器 —
playPauseBtn.addEventListener('click', togglePlayPause);
audio.addEventListener('play', updateUIOnPlayState);
audio.addEventListener('pause', updateUIOnPlayState);
audio.addEventListener('ended', () => loadTrack((currentTrackIndex + 1) % playlist.length, true));
prevBtn.addEventListener('click', () => loadTrack((currentTrackIndex – 1 + playlist.length) % playlist.length, !audio.paused));
nextBtn.addEventListener('click', () => loadTrack((currentTrackIndex + 1) % playlist.length, !audio.paused));
rewindBtn.addEventListener('click', () => { audio.currentTime = Math.max(0, audio.currentTime – 10); });
forwardBtn.addEventListener('click', () => { if(isFinite(audio.duration)) audio.currentTime = Math.min(audio.duration, audio.currentTime + 10); });
audio.addEventListener('timeupdate', updateProgress);
audio.addEventListener('loadedmetadata', () => { totalTimeEl.textContent = formatTime(audio.duration); updateProgress(); });timeline.addEventListener('mousedown', (e) => { isDragging = true; setProgressFromEvent(e); });
document.addEventListener('mousemove', (e) => { if (isDragging) setProgressFromEvent(e); });
document.addEventListener('mouseup', () => { if (isDragging) isDragging = false; });
timeline.addEventListener('touchstart', (e) => { isDragging = true; setProgressFromEvent(e); }, { passive: true });
document.addEventListener('touchmove', (e) => { if (isDragging) setProgressFromEvent(e); }, { passive: true });
document.addEventListener('touchend', () => { if (isDragging) isDragging = false; });// — 角色与弹窗逻辑 —
Object.keys(characterData).forEach(key => {
const char = characterData[key];
const btn = document.createElement('button');
btn.className = 'char-select-btn';
btn.textContent = char.name;
btn.dataset.charId = key;
btn.addEventListener('click', () => {
modalName.textContent = char.name;
modalDescription.innerHTML = char.description;
characterModal.style.display = 'flex';
});
characterSelector.appendChild(btn);
});
closeModalBtn.addEventListener('click', () => characterModal.style.display = 'none');
characterModal.addEventListener('click', (e) => { if (e.target === characterModal) characterModal.style.display = 'none'; });// — 【修改】初始化 —
entryButton.addEventListener('click', () => {
entryGate.style.opacity = '0';
mainContent.style.display = 'block';
hasInteracted = true; // 标记用户已交互// 既然用户已点击,直接加载并播放第一首歌
if (playlist.length > 0) {
loadTrack(0, true);
}setTimeout(() => { entryGate.style.display = 'none'; }, 500);
});// 【修改】页面加载时,只展示第一首歌的静态信息
if (playlist.length > 0) {
const firstTrack = playlist[0];
trackTitleEl.textContent = firstTrack.title;
trackArtistEl.textContent = firstTrack.artist;
albumArt.src = firstTrack.albumArt; // 初始加载一次图片
}
});
</script>
</body>
</html>
“`