3D Frontend — Scroll-Driven 3D Websites
建立沉浸式單一 HTML 頁面,使用者透過滾動在 Three.js 打造的 3D 場景中移動。內容(標題、文字、圖片、行動呼籲按鈕)會疊加或嵌入於 3D 世界中。每個 DreamWalk 頁面都是一個獨立的 .html 成品 — 無需建置工具、npm 或 React。
技術棧
所有輸出均為單一 HTML 檔案成品。無需建置工具、npm 或 React — 只有一個獨立的 .html 檔案。
| 函式庫 | CDN | 用途 |
|---|---|---|
| Three.js r128 | https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js | 3D 渲染引擎 |
| GSAP 3.12.5 | https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js | 動畫引擎 |
| ScrollTrigger 3.12.5 | https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js | 滾動至動畫綁定 |
為何選擇這個技術棧? Three.js 是生態系統最龐大的主流 WebGL 框架。GSAP ScrollTrigger 是將滾動位置對應到動畫時間軸的業界標準。兩者結合,為大多數獲獎 3D 滾動網站(請參閱 Awwwards、FWA)提供動力。此組合可在單一 HTML 檔案中運作,無需建置步驟,非常適合成品輸出。
重要:Three.js r128 API 限制。 這不是最新的 Three.js。以下 API 在 r128 中不存在,絕不能使用:
CapsuleGeometry、RoundedBoxGeometry、THREE.MathUtils.seededRandom、WebGPURenderer、THREE.ColorManagement。請務必使用BufferGeometry基本圖形(BoxBufferGeometry、SphereBufferGeometry等)或其別名(BoxGeometry、SphereGeometry)。
架構模式
┌─────────────────────────────────────────┐
│ HTML Page │
│ ┌───────────────────────────────────┐ │
│ │ <canvas> - Three.js scene (fixed) │ │
│ │ • Camera on a path/spline │ │
│ │ • 3D objects (geometry/particles) │ │
│ │ • Lighting & fog │ │
│ └───────────────────────────────────┘ │
│ ┌───────────────────────────────────┐ │
│ │ <div class="scroll-container"> │ │
│ │ height: 500vh+ (scrollable) │ │
│ │ Sections with text/content │ │
│ │ overlaid via position:fixed or │ │
│ │ opacity-faded on scroll triggers │ │
│ └───────────────────────────────────┘ │
│ │
│ GSAP ScrollTrigger maps scroll% → │
│ camera.position / camera.lookAt / │
│ object transforms / material params │
└─────────────────────────────────────────┘
如何建立 3D 滾動頁面
撰寫程式碼前,請先閱讀 references/PATTERNS.md 以取得詳細、可直接複製貼上的程式碼模式。 該文件包含 40 多個用於攝影機動畫、燈光、著色器、粒子、程式化幾何體和效能最佳化的生產就緒模式 — 全部與 Three.js r128 相容。
步驟 1:場景設計
根據使用者意圖決定體驗類型:
| 類型 | 攝影機行為 | 最適合 |
|---|---|---|
| 隧道 / 走廊 | 沿 Z 軸向前飛行 | 產品展示、故事敘述 |
| 軌道 / 展示 | 圍繞中心物體旋轉 | 產品頁面、作品集 |
| 景觀飛越 | 掃過地形/城市景觀 | 登陸頁面、介紹 |
| 房間漫遊 | 在連接的空間中移動 | 虛擬導覽、簡報 |
| 垂直下降 | 攝影機沿 Y 軸下降 | 時間軸、圖層揭示 |
| 曲線路徑 | 攝影機沿著 3D 曲線路徑移動 | 電影感、編輯頁面 |
步驟 2:建立 HTML 架構
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Experience</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { overflow-x: hidden; }
canvas { position: fixed; top: 0; left: 0; z-index: 0; }
.scroll-container { position: relative; z-index: 1; pointer-events: none; }
.section { height: 100vh; display: flex; align-items: center; justify-content: center; }
.content { pointer-events: auto; /* re-enable for interactive elements */ }
</style>
</head>
<body>
<!-- Three.js canvas is created programmatically -->
<div class="scroll-container">
<!-- Sections drive scroll height; content overlays the 3D scene -->
<div class="section" id="section-1">...</div>
<div class="section" id="section-2">...</div>
<!-- Add more sections = more scroll distance = longer camera journey -->
</div>
<script src="THREE_CDN"></script>
<script src="GSAP_CDN"></script>
<script src="SCROLLTRIGGER_CDN"></script>
<script>
// Scene setup, animation, ScrollTrigger bindings
</script>
</body>
</html>
步驟 3:核心 Three.js 設定
務必包含以下基本項目:
- 場景 + 攝影機 + 渲染器 — 使用
PerspectiveCamera,FOV 設定為 60-75 以獲得沉浸感 - 燈光 — 至少:一個
AmbientLight+ 一個DirectionalLight。可加入PointLight或SpotLight增加戲劇效果 - 霧 —
scene.fog = new THREE.FogExp2(color, density)可增加深度並隱藏物件突然出現 - 視窗調整處理 — 務必處理
window.resize事件 - 渲染迴圈 — 使用
requestAnimationFrame與renderer.render(scene, camera)
步驟 4:使用 GSAP 進行滾輪 → 攝影機動畫
關鍵的綁定模式:
gsap.registerPlugin(ScrollTrigger);
// Store camera animation targets as a plain object
const camAnim = { x: 0, y: 2, z: 10, lookX: 0, lookY: 0, lookZ: 0 };
const tl = gsap.timeline({
scrollTrigger: {
trigger: ".scroll-container",
start: "top top",
end: "bottom bottom",
scrub: 1, // 1 second smoothing
}
});
// Chain camera keyframes
tl.to(camAnim, { x: 0, y: 2, z: 5, lookX: 0, lookY: 0, lookZ: 0, duration: 1 })
.to(camAnim, { x: 3, y: 1, z: 0, lookX: 2, lookY: 0, lookZ: -5, duration: 1 })
.to(camAnim, { x: 0, y: 5, z: -10, lookX: 0, lookY: 0, lookZ: -15, duration: 1 });
// In the render loop, apply the animated values
function animate() {
requestAnimationFrame(animate);
camera.position.set(camAnim.x, camAnim.y, camAnim.z);
camera.lookAt(camAnim.lookX, camAnim.lookY, camAnim.lookZ);
renderer.render(scene, camera);
}
步驟 5:內容疊加
疊加在特定滾動位置淡入/淡出的 HTML 內容:
// Fade in a section when the camera reaches a waypoint
gsap.fromTo("#section-2 .content",
{ opacity: 0, y: 50 },
{ opacity: 1, y: 0,
scrollTrigger: {
trigger: "#section-2",
start: "top center",
end: "top 20%",
scrub: true
}
}
);
步驟 6:視覺潤色
應用這些技巧,讓效果從基本提升到令人印象深刻:
- 粒子 — 使用
THREE.Points搭配THREE.BufferGeometry製作漂浮的灰塵/星星 - 後處理光暈 — 使用自發光材質 + 類似 Bloom 效果的明亮色彩
- 顏色過渡 — 沿著滾動路徑動畫
scene.background和scene.fog.color - 物體揭示 — 物體在攝影機靠近時從 0 放大或淡入
- 視差圖層 — 距離不同的物體以不同速率移動
- 微旋轉 — 在渲染迴圈中緩慢旋轉裝飾性物體(獨立於滾動)
- 滑鼠視差 — 根據滑鼠位置對攝影機進行微調偏移,以增強深度感
設計原則
- 效能優先 — 保持幾何體簡單。使用
BufferGeometry,限制繪製呼叫,使用fog隱藏遠處物體。目標 60fps - 平滑滾動 — 在 ScrollTrigger 中使用
scrub: 1或scrub: 2以獲得流暢的運動。絕不使用scrub: true(會導致瞬間、不流暢的運動) - 內容可讀 — 文字疊加需要對比。在淺色文字後使用半透明深色面板,或確保 3D 背景在文字區域後方為深色/模糊
- 行動裝置備援 — 觸控滾動可與 ScrollTrigger 配合使用。考慮透過
window.innerWidth檢查,在行動裝置上減少粒子數量和幾何複雜度 - 優雅載入 — 顯示一個簡單的 CSS 載入畫面,並在 Three.js 場景準備就緒時將其隱藏
可建立的常見 3D 物件(無需外部模型)
這些都可以使用 Three.js 內建幾何體建立 — 無需 GLTF 檔案:
- 漂浮幾何形狀 — BoxGeometry、IcosahedronGeometry、TorusKnotGeometry 搭配 MeshStandardMaterial
- 地形 — PlaneGeometry 搭配頂點位移(正弦波、雜訊)
- 粒子場 — BufferGeometry + Points 用於星星、灰塵、雪花、資料視覺化
- 網格地板 — GridHelper 或自訂線條幾何體
- 管道/隧道 — TubeGeometry 沿著 CatmullRomCurve3 路徑
- 文字 — 在 PlaneGeometry 或基於 Sprite 上渲染的 Canvas 紋理
- 線框物件 — 任何幾何體搭配
wireframe: true材質,營造科技感 - 光束 — CylinderGeometry 搭配自發光透明材質
步驟 7:滑鼠視差(可選但建議)
在滑鼠移動時增加攝影機微調偏移,以增強深度感知:
const mouse = { x: 0, y: 0 };
document.addEventListener('mousemove', (e) => {
mouse.x = (e.clientX / window.innerWidth - 0.5) * 2; // -1 to 1
mouse.y = (e.clientY / window.innerHeight - 0.5) * 2;
});
// In the render loop, add a slight offset to the camera
const parallaxStrength = 0.3;
camera.position.x = camAnim.x + mouse.x * parallaxStrength;
camera.position.y = camAnim.y - mouse.y * parallaxStrength * 0.5;
房間漫遊模式
對於建築/房地產漫遊,使用簡單幾何體建立房間:
// Create a room with BoxGeometry for walls, floor, ceiling
function createRoom(width, height, depth, position, color) {
const mat = new THREE.MeshStandardMaterial({ color, side: THREE.BackSide });
const room = new THREE.Mesh(new THREE.BoxGeometry(width, height, depth), mat);
room.position.copy(position);
scene.add(room);
return room;
}
// Create furniture placeholders with simple geometry
// Sofa = wide flat box, Table = thin box on cylinders, Lamp = cylinder + sphere
// Use emissive PointLights inside rooms for warm interior feel
房間漫遊的關鍵原則:
- 在材質上使用
THREE.BackSide,以便從內部渲染牆壁 - 在每個房間內放置溫暖的
PointLight光源(顏色0xffeedd,強度 0.8) - 攝影機路徑應從門口進入,而不是穿過牆壁
- 動畫攝影機 lookAt,以便在進入時自然掃視每個房間
- 添加帶有自發光明亮材質的窗戶矩形,以模擬日光
應避免的反模式
- ❌ 請勿使用
OrbitControls— 滾動應是唯一的導航方式 - ❌ 請勿載入外部 GLTF/GLB 模型 — 保持獨立於 HTML 檔案中
- ❌ 請勿使用
THREE.CapsuleGeometry— 在 r128 中不可用 - ❌ 請勿全域設定 canvas 的
pointer-events: none— 渲染迴圈需要 canvas - ❌ 請勿忘記
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))— 可防止在高解析度螢幕上導致 GPU 超載 - ❌ 請勿直接使用
camera.rotation動畫攝影機 — 應使用camera.lookAt()搭配動畫目標座標以獲得穩定結果 - ❌ 請勿使滾動容器太短 — 至少需要 400vh 才能有意義的旅程,建議 600vh 以上
美學方向
套用與 frontend-design 技能相同的創意大膽風格。每個 3D 滾動頁面都應感覺獨一無二:
- 選擇一種色彩氛圍:霓虹賽博龐克、溫暖夕陽、深海、冰晶、帶有自發光強調的黑暗虛空等。
- 選擇一種幾何語言:有機曲線 vs 硬邊緣、稀疏 vs 密集、大型巨石 vs 微小粒子
- 印刷排版疊加:匯入獨特的 Google Fonts。使用大膽、電影感的字型。在滾動時動畫化透明度和變形
- 3D 場景和 HTML 內容應感覺是一個統一的體驗,而不是一個隨意加上文字的 3D 背景
快速參考:CDN 網址
Three.js r128: https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js
GSAP 3.12.5: https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js
ScrollTrigger: https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js