一个把品牌变成”可滚动世界”的开源脚手架
scroll-world 是 oso95 开源的一个”技能包(skill)“,核心理念只有一句话:把任意品牌的视觉资产——logo、产品图、色卡——拆成图层,再用 Three.js + ScrollTrigger 拼成一个可滚动推进的 3D 叙事。用户下滑推进场景,上滑回退,无需 Unity / Unreal,仅靠浏览器就能跑出电影感官网。它在 2026-07-12 凭借 ⭐830 冲上 GitHub Trending,背后是两条推力:WebGPU 在 Chrome / Safari 正式稳定、Three.js r166 把 PBR 与 glTF 流水线打磨到接近无坑;加上 Apple Vision Pro 把”空间浏览”概念重新带回桌面端,独立开发者都急着把品牌官网升级成”3D 体验”,scroll-world 正好是门槛最低的入场券。
1. 滚动到底,3D 相机却停在原地?
现象:用户滚到页面底部,3D 镜头还没推进到终点;或者镜头动了,DOM 滚动条却卡死。
根因:直接监听 wheel 并 preventDefault() 会把浏览器原生滚动完全接管,但 requestAnimationFrame 里用 lerp 平滑相机时,scrollY 已经不再更新,两条时间轴就此脱钩。
解法:让 ScrollTrigger 接管滚动驱动,把 progress 直接映射到相机参数:
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
ScrollTrigger.create({
trigger: "#scroll-world",
start: "top top",
end: "+4000",
scrub: 1,
pin: true,
onUpdate(self) {
camera.position.z = 10 - self.progress * 8;
world.rotation.y = self.progress * Math.PI * 2;
camera.lookAt(0, 0, 0);
},
});
scrub: 1 会把动画绑到滚动条上,pin 住画布避免布局抖动,相机再也不会”掉队”。
2. 移动端 iPhone 跌到 15fps,触控镜头抽搐?
现象:桌面端 60fps 一到 Safari 移动端就崩到 15-20fps,双指捏合缩放时镜头还会”跳一下”。
根因:每帧都重传纹理、setPixelRatio(window.devicePixelRatio) 在 iPhone 14 上等于把像素量放大 9 倍,OrbitControls 的 enableZoom 又把 touch 事件抢走,与 ScrollTrigger 的 pinch 判定打架。
解法:限制 dpr、复用纹理、按需渲染、关掉冲突控件:
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(width, height, false);
const dirty = { flag: true };
renderer.domElement.addEventListener("pointerdown", () => (dirty.flag = true));
function tick() {
if (dirty.flag) {
renderer.render(scene, camera);
dirty.flag = false;
}
requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
controls.enableZoom = false; // 让滚动驱动距离,不要触控打架
按需渲染能把空帧从 60 次/秒降到 0 次,电量与温度都明显改善。
3. Google 只能索引到一个空 canvas,SEO 暴跌?
现象:上线后 Search Console 显示”网页无可索引内容”,首屏 LCP 文本几乎为零,关键词排名一周内掉 30 位。
根因:所有品牌故事都渲染进 WebGL,HTML 里只剩一个 <canvas id="scroll-world"></canvas>,Googlebot(特别是 2026 还在用 Chromium 二代渲染的版本)抓不到任何语义内容。
解法:3D 是增强层,语义才是主层——SSR/预渲染一份完整 HTML 副本,3D 作为渐进增强:
<main>
<!-- 给爬虫看的完整内容 -->
<h1>ACME 2026 春夏系列</h1>
<p>从街头到山野,ACME 用可回收尼龙与生物基橡胶重塑了 7 双经典鞋型……</p>
<!-- 给浏览器看的 3D 层 -->
<canvas id="scroll-world" aria-hidden="true"></canvas>
<noscript><img src="/hero-poster.jpg" alt="ACME 春夏主视觉" /></noscript>
</main>
再用 IntersectionObserver 把 canvas 升级到 lazy mount,首屏 HTML 体积保持 14KB 以内,LCP 立刻回到 1.8s。
小结
scroll-world 不是银弹,它真正解决的问题是把”3D 品牌叙事”从电影公司手里抢回到普通前端团队。但要让它上线不掉链子,记住三条:滚动交给 ScrollTrigger、渲染改成按需、内容做双层 SSR。先跑通这三点,再去追求 Apple Vision Pro 的空间体验,否则你只是在给品牌官网加一个会卡的彩蛋。
Sources
- GitHub Trending 2026-07-12, oso95/scroll-world
- r/webdev: “Anyone shipping 3D scroll sites in production?” thread, July 2026
- Three.js Discussion #28641: “ScrollTrigger + WebGLRenderTarget performance on iOS”
- gsap forums: Scrub & pin best practices for full-page WebGL
- Google Search Central: JavaScript-rendered content indexing, 2026 update