一键导入
scrollytelling
Design architecture, workflows, and code implementations for scroll-triggered 3D model manipulation and interactive "production explosion" views.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Design architecture, workflows, and code implementations for scroll-triggered 3D model manipulation and interactive "production explosion" views.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Agent-to-User Interface (A2UI) protocol implementation and client renderer scaffolding.
Infrastructure automation, configuration management, and application deployment orchestration using Ansible.
Create and manage unicode braille animations and spinners for CLIs and web apps. Use this skill when the user wants to add loading indicators, progress animations, or custom braille-based art to their terminal or browser-based application.
Agent harness for headlessly deploying Code Scaffold assets.
High-performance code intelligence MCP server. Indexes codebases into a persistent knowledge graph — average repo in milliseconds.
Comprehensive cybersecurity arsenal integrating MITRE and NIST framework methodologies, NVIDIA SkillSpector vulnerability scanning, and deep SAST secret detection.
| name | Scrollytelling |
| description | Design architecture, workflows, and code implementations for scroll-triggered 3D model manipulation and interactive "production explosion" views. |
This document provides a comprehensive overview of the design architecture, workflows, libraries, and code implementations required to build a modern, high-performance website featuring scroll-triggered 3D model manipulation and interactive "production explosion" views, similar to premium product landing pages from Microsoft Surface and Apple.
To build an impressive scrollytelling experience, you must understand the conceptual architecture that separates traditional scroll behavior from animation-driven scroll behavior.
In standard web design, scrolling changes the window.scrollY position to reveal lower portions of a page. In high-fidelity scrollytelling, scrolling is intercepted or mapped to a global timeline. The scrollbar essentially becomes the scrubbing thumb of a video player or an animation timeline.
To keep a product (like a laptop or tablet) centered on the screen while it animates, the container element must be "pinned." This is usually achieved using CSS position: sticky; top: 0; or programmatic pinning via JavaScript. The container locks in the viewport while the user scrolls through a designated track of blank vertical space (e.g., 300vh or 300% of the viewport height). The animation plays over this distance, and once complete, the container unpins, allowing the user to continue down the page.
An "exploded view" animation takes a unified 3D object and translates its constituent parts outward along specified axes (typically the Z-axis, or depth axis) relative to the object's origin.
There are two primary ways industry professionals implement production explosion views. The choice depends on performance requirements, asset availability, and asset complexity.
The model is loaded into the browser as a 3D asset. JavaScript manipulates the individual mesh nodes in real time based on scroll data.
.glb files), complex mesh tracking.The 3D explosion view is pre-rendered in software like Blender, Cinema 4D, or Maya as a high-quality 4K image sequence (e.g., 120 frames). JavaScript preloads these frames into memory and draws the specific frame to an HTML5 <canvas> based on the scroll percentage.
To ensure production-grade optimization, fluid performance across desktop and mobile browsers, and stable runtime rendering, the architecture must strictly enforce the following rules:
gltf-pipeline utilizing Draco mesh compression. High-poly surfaces must be baked down to normal maps. Total aggregate payload size for the 3D assets must target sub-5MB limits.width, height, top, margin) within an active scroll track forces continuous DOM reflows, causing catastrophic frame-rate drops (jank).transform: translate3d(), opacity) or direct low-level programmatic WebGL matrix mutations.window.addEventListener('scroll')) results in erratic behavior due to differences in scroll event dispatch frequencies between trackpads, mice, and mobile touch surfaces.requestAnimationFrame. This locks execution cycles tightly to native monitor refresh timings (60Hz / 120Hz).To minimize boilerplate and guarantee cross-browser performance (handling touch smoothing, trackpad inertia, and mobile rendering quirks), the following library stack is standard:
useScroll for native scrollytelling syncing.The following blueprint creates a pinned viewport section, initializes a Three.js environment containing a mock product (a compound group representing a screen and a chassis), and maps a scroll track to explode the components along the Y and Z axes using GSAP ScrollTrigger.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Advanced Product Explosion Scrollytelling</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background-color: #0b0b0c;
color: #ffffff;
overflow-x: hidden;
}
.scroll-section {
width: 100%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
background-color: #111112;
}
/* The container that defines the length of the animation track */
.scrolly-container {
position: relative;
width: 100%;
height: 300vh; /* 3 viewports long */
background-color: #0b0b0c;
}
/* The viewport-locked frame holding the WebGL Canvas and Text overlays */
.sticky-viewport {
position: sticky;
top: 0;
width: 100%;
height: 100vh;
overflow: hidden;
}
#webgl-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.ui-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 2;
pointer-events: none;
}
.text-step {
position: absolute;
left: 10%;
top: 50%;
transform: translateY(-50%);
max-width: 400px;
opacity: 0;
}
.text-step h2 {
font-size: 3rem;
margin-bottom: 1rem;
color: #f5f5f7;
}
.text-step p {
font-size: 1.2rem;
line-height: 1.5;
color: #86868b;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/ScrollTrigger.min.js"></script>
</head>
<body>
<section class="scroll-section">
<h1>Scroll Down to Explore Architecture</h1>
</section>
<div class="scrolly-container" id="trigger-track">
<div class="sticky-viewport">
<canvas id="webgl-canvas"></canvas>
<div class="ui-overlay">
<div class="text-step" id="step-1">
<h2>Premium Engineering</h2>
<p>Every component is meticulously organized to balance power, thermal dispersion, and architectural elegance.</p>
</div>
<div class="text-step" id="step-2">
<h2>Exploded Architecture</h2>
<p>Advanced layered components slide away along microscopic vectors to expose internal cooling modules.</p>
</div>
</div>
</div>
</div>
<section class="scroll-section">
<h1>End of Experience</h1>
</section>
<script>
// Register GSAP ScrollTrigger Plugin
gsap.registerPlugin(ScrollTrigger);
// --- THREE.JS SETUP ---
const canvas = document.querySelector('#webgl-canvas');
const scene = new THREE.Scene();
// Perspective Camera
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(0, 0, 8);
const renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
// Lighting System
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambientLight);
const dirLight1 = new THREE.DirectionalLight(0x3a86ff, 1.5);
dirLight1.position.set(5, 10, 7);
scene.add(dirLight1);
const dirLight2 = new THREE.DirectionalLight(0xff007f, 0.8);
dirLight2.position.set(-5, -5, 2);
scene.add(dirLight2);
// Geometry Generation: Creating mock layers representing product parts
const geometryChassis = new THREE.BoxGeometry(3, 2, 0.2);
const materialChassis = new THREE.MeshStandardMaterial({ color: 0x333335, roughness: 0.2, metalness: 0.8 });
const chassisMesh = new THREE.Mesh(geometryChassis, materialChassis);
const geometryScreen = new THREE.BoxGeometry(2.9, 1.9, 0.05);
const materialScreen = new THREE.MeshStandardMaterial({ color: 0x0077ff, emissive: 0x002255, roughness: 0.1 });
const screenMesh = new THREE.Mesh(geometryScreen, materialScreen);
// Position screen slightly forward along Z axis relative to chassis
screenMesh.position.z = 0.15;
const geometryInternals = new THREE.BoxGeometry(2.6, 1.6, 0.1);
const materialInternals = new THREE.MeshStandardMaterial({ color: 0x10b981, roughness: 0.5, wireframe: false });
const internalsMesh = new THREE.Mesh(geometryInternals, materialInternals);
internalsMesh.position.z = 0.0;
// Parent item group to allow shared rotation adjustments
const productGroup = new THREE.Group();
productGroup.add(chassisMesh);
productGroup.add(internalsMesh);
productGroup.add(screenMesh);
scene.add(productGroup);
// Initial default orientation slant
productGroup.rotation.x = 0.3;
productGroup.rotation.y = -0.4;
// Render loop using requestAnimationFrame for optimal FPS matching
function animate() {
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
animate();
// Handle viewport adjustments dynamically
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// --- GSAP TIMELINE & SCROLLTRIGGER CONTROL ---
// Master timeline tied directly to scroll progress
const tl = gsap.timeline({
scrollTrigger: {
trigger: "#trigger-track",
start: "top top", // Start when container top hits viewport top
end: "bottom bottom", // End when container bottom hits viewport bottom
scrub: 1, // Smoothly catch up with scroll position (takes 1 second)
}
});
// Step 1: Fade in text step 1, subtly rotate product group
tl.to("#step-1", { opacity: 1, x: 20, duration: 1 })
.to(productGroup.rotation, { y: 0.2, x: 0.5, duration: 2 }, "-=1")
// Step 2: Fade out step 1, initiate product explosion layout transformation via hardware-accelerated parameters
.to("#step-1", { opacity: 0, y: -20, duration: 1 })
.to(screenMesh.position, { z: 1.5, duration: 2 }, "-=0.5") // Push screen forward
.to(chassisMesh.position, { z: -1.5, duration: 2 }, "-=2") // Push chassis backward
.to(internalsMesh.position, { y: 1.0, duration: 2 }, "-=2") // Push motherboard upward out of alignment
.to(productGroup.rotation, { y: 1.1, x: 0.2, duration: 2 }, "-=2") // Rotate whole construction during explosion
// Step 3: Reveal final explanatory UI text overlay
.to("#step-2", { opacity: 1, x: 20, duration: 1 });
</script>
</body>
</html>