feat: phase2 immersive journey (semantic scene transitions + camera feel)
All checks were successful
Deploy / deploy (push) Successful in 1s

This commit is contained in:
Chen Gu
2026-04-24 09:38:36 +08:00
parent 82a2d231c3
commit df1732c54c
3 changed files with 102 additions and 1 deletions

View File

@@ -134,15 +134,42 @@
});
}
// ═══ 场景滚动进度 + 旅程节点高亮 ═══
// ═══ 场景滚动进度 + 旅程节点高亮 + 语义场景切换 ═══
function setupStoryJourney() {
const body = document.getElementById('storyBody');
const progress = document.getElementById('storyProgress');
const article = document.querySelector('.story-journey');
if (!body || !progress) return;
const scenes = Array.from(body.querySelectorAll(':scope > p'));
if (!scenes.length) return;
const sceneProfiles = [
{ key: 'starsea', keywords: ['星海', '星辰', '光河', '漂浮', '夜晚'] },
{ key: 'crystal', keywords: ['水晶', '冰晶', '棱镜', '森林'] },
{ key: 'calling', keywords: ['使命', '记录', '召唤', '欢迎'] },
{ key: 'void', keywords: ['深渊', '平静', '对话'] }
];
const detectScene = (text) => {
let matched = 'void';
let best = 0;
for (const profile of sceneProfiles) {
let score = 0;
for (const kw of profile.keywords) {
if (text.includes(kw)) score++;
}
if (score > best) {
best = score;
matched = profile.key;
}
}
return matched;
};
let currentScene = '';
let shiftTimer;
const onScroll = () => {
const rect = body.getBoundingClientRect();
const total = Math.max(body.scrollHeight - window.innerHeight, 1);
@@ -161,6 +188,21 @@
}
});
scenes.forEach((p, idx) => p.classList.toggle('active-scene', idx === activeIndex));
const activeText = scenes[activeIndex]?.innerText || '';
const scene = detectScene(activeText);
if (scene !== currentScene) {
currentScene = scene;
document.body.dataset.scene = scene;
document.body.classList.add('scene-shift');
clearTimeout(shiftTimer);
shiftTimer = setTimeout(() => document.body.classList.remove('scene-shift'), 420);
}
if (article) {
const camY = scrolled * 0.018;
article.style.transform = `translate3d(0, ${camY}px, 0)`;
}
};
window.addEventListener('scroll', onScroll, { passive: true });