An interactive 3D scrollytelling experience built with Svelte 5, Three.js, and WebGL. Navigate through a miniature Japanese town with smooth camera movements synchronized to your scroll position.

โจ Features
- ๐ฌ Dramatic Camera Movements: Cinematic orbital camera paths with smooth transitions
- ๐ฎ Interactive 3D Scene: High-quality GLB model at 1:1 scale without distortion
- ๐ฑ Responsive Design: Split-screen layout (40% content, 60% 3D scene) on desktop, stacked on mobile
- โก Performance Optimized: Throttled scroll events with requestAnimationFrame
- ๐จ Modern UI: Glass-morphism design with backdrop blur effects
- ๐ง Flexible Configuration: Story steps defined inline for easy customization
- ๐ Precise Scroll Mapping: Perfect synchronization between scroll position and camera
- ๐ฏ TypeScript Support: Full type safety throughout the codebase
๐ Quick Start
Prerequisites
- Node.js 20+
- npm or yarn
- Modern web browser with WebGL support
Installation
# Clone the repository
git clone https://github.com/amcaw/svelte-3d-scrollytelling.git
cd svelte-3d-scrollytelling
# Install dependencies
npm install
# Start development server
npm run dev
Open http://localhost:5173 in your browser.
๐๏ธ Project Structure
src/
โโโ lib/
โ โโโ ScrollyD.svelte # Scrollytelling component for static models
โ โโโ ScrollyDAnimated.svelte # Scrollytelling component for animated models
โโโ WorkingLib/ # Backup/development components
โ โโโ ThrelteGlobe.svelte # Original 3D globe component
โ โโโ BelgiumMap.svelte # 2D map component
โ โโโ Helper.svelte # Debug helper component
โโโ routes/
โ โโโ +page.svelte # Main page with both components
โ โโโ tokyo/
โ โโโ +page.svelte # Standalone Tokyo model page
โโโ static/
โโโ models/ # Local 3D models
โโโ arme.glb # Animated weapon model
๐ฎ How It Works
The scrollytelling experience consists of:
- 3D Model Loading: LittlestTokyo GLB model from Three.js examples
- Camera Path: Predefined camera positions and rotations for smooth navigation
- Scroll Synchronization: Real-time camera updates based on scroll progress
- Story Steps: Text content that appears alongside the 3D scene
Camera System
The camera follows a dramatic orbital path through 10 cinematic positions:
- Front View โ Dramatic Right Swing โ Full Right Side โ Swooping Behind โ Full Back View โ Left Side Approach โ Full Left Side โ High Dramatic Angle โ Close Detail Dive โ Final Cinematic Overview
Each transition is smoothly interpolated using cubic easing functions with precise scroll mapping that returns to the exact starting position when scrolling back to the top.
๐ ๏ธ Development
Available Scripts
npm run dev # Start development server
npm run build # Build for production
npm run preview # Preview production build
npm run check # Run Svelte type checking
npm run check:watch # Watch mode for type checking
Technology Stack
- Frontend: Svelte 5, TypeScript
- 3D Graphics: Three.js, WebGL
- Build Tool: Vite
- Deployment: Static site compatible
Key Components
The static model component features:
- Flexible Props: Accepts story steps as props for easy customization
- Optimized Layout: 40% left content area, 60% right 3D scene
- Fixed Model Scale: Consistent Tokyo house model at 0.04 scale
- Precise Scroll Mapping: Linear progression from 0 to 1 with perfect top/bottom alignment
- Three.js Scene: Automatic setup with proper aspect ratio handling
- Mobile Responsive: Stacked layout for smaller screens
The animated model component features:
- Animation Support: Scroll-controlled GLB animations instead of looping
- Auto-Fitting Camera: Automatically adjusts camera distance based on model size
- Local Model Support: Loads models from
/static/models/
directory
- Animation Mixer: Controls animation playback based on scroll progress
- Enhanced Lighting: Improved lighting setup for better texture visibility
- Debug Logging: Detailed animation and model structure analysis
Usage Examples
<!-- In your +page.svelte -->
<!-- Static Tokyo Model -->
<ScrollyD storySteps={[
{
title: "Front View",
content: "Starting our journey with a direct front view of the miniature town.",
cameraPosition: [0, 1, 4],
cameraRotation: [-0.2, 0, 0]
},
{
title: "Dramatic Right Swing",
content: "Sweeping dramatically to the right side with a bold camera movement.",
cameraPosition: [3.5, 1.5, 3],
cameraRotation: [-0.4, 0.8, 0]
},
// ... more steps
]} />
<!-- Animated Local Model -->
<ScrollyDAnimated
modelPath="/models/arme.glb"
enableRotation={false}
rotationSpeed={0.01}
storySteps={[
{
title: "Introduction",
content: "Welcome to our interactive 3D animation experience.",
cameraPosition: [0, 1, 4],
cameraRotation: [-0.2, 0, 0]
},
// ... more steps
]}
/>
๐ง Customization
Adding New Story Steps
Story steps are now defined inline in your page for easy customization:
<!-- In src/routes/+page.svelte -->
<ScrollyD storySteps={[
{
title: "Your Custom Title",
content: "Your story content here...",
cameraPosition: [x, y, z],
cameraRotation: [rx, ry, rz]
},
// Add more steps...
]} />
Camera Position Guidelines
- cameraPosition:
[x, y, z]
coordinates (multiplied by baseDistance=8.0)
- cameraRotation:
[rx, ry, rz]
angles in radians
- Model Scale: Fixed at 0.04 for Tokyo house consistency
- cameraPosition:
[x, y, z]
coordinates (multiplied by auto-calculated baseDistance)
- cameraRotation:
[rx, ry, rz]
angles in radians
- Model Scale: Automatic 1:1 scale with auto-fitting camera distance
- baseDistance: Automatically calculated as
maxModelDimension / 5
Camera Coordinate System
x
: Left (-) to Right (+)
y
: Down (-) to Up (+)
z
: Forward (-) to Back (+)
rx
: Pitch (look up/down)
ry
: Yaw (look left/right)
rz
: Roll (tilt)
Adding Local 3D Models
- Place your GLB file in the
static/models/
directory
- Use ScrollyDAnimated component with local path:
<ScrollyDAnimated
modelPath="/models/your-model.glb"
enableRotation={false}
rotationSpeed={0.01}
storySteps={[...]}
/>
Replace the GLB URL in ScrollyD.svelte
:
loader.load('your-model-url.glb', (gltf) => {
model = gltf.scene;
const fixedScale = 0.04; // Adjust as needed
model.scale.set(fixedScale, fixedScale, fixedScale);
model.position.y = -2;
scene.add(model);
});
Layout Customization
Modify these CSS variables in both components:
- Desktop Layout:
vis-container
left position (default: 30vw)
- Foreground Width:
.foreground
width (default: 40vw)
- ScrollyD Base Distance:
baseDistance = 8.0
(fixed for Tokyo house)
- ScrollyDAnimated Base Distance: Auto-calculated based on model size
๐ Recent Improvements
v1.2.0 - Dual Component Architecture
- ๐ฏ Component Separation: Split functionality into ScrollyD (static models) and ScrollyDAnimated (animated models)
- ๐ฌ Scroll-Controlled Animation: Animations now progress with scroll instead of looping continuously
- ๐ Local Model Support: Added support for local GLB files in
/static/models/
directory
- ๐ง Auto-Fitting Camera: ScrollyDAnimated automatically adjusts camera distance based on model size
- ๐ก Enhanced Lighting: Improved lighting setup for better texture visibility in animated models
- ๐ Debug Logging: Detailed animation and model structure analysis for development
- ๐๏ธ Main Page Integration: Both components now displayed on the main page with different stories
- ๐จ Enhanced Styling: Improved visual hierarchy with section headers and introductory text
- ๐ฏ Fixed Initial Camera Position: The camera now properly starts at the first step view on page load
- ๐ Improved Scroll Calculation: Perfect linear mapping from scroll position to camera progress (0 to 1)
- ๐ฌ Dramatic Camera Movements: More cinematic orbital paths with swooping and dramatic angles
- ๐จ Split-Screen Layout: Optimized 40% content / 60% 3D scene layout for better visual balance
- ๐ฑ Enhanced Mobile Experience: Responsive design with stacked layout for mobile devices
- ๐ง Inline Story Configuration: Story steps now defined directly in component usage for easier editing
- โก Performance Optimizations: Improved scroll handling with requestAnimationFrame
- ๐ฎ 1:1 Model Scale: Natural model proportions without distortion
- ๐งน Production Ready: Removed debug console logs for clean production code
Key Fixes
- Scroll-to-Top Behavior: Camera now correctly returns to the first step when scrolling back to the top
- Aspect Ratio Handling: Proper camera aspect ratio for the 3D scene area
- Initial Load Consistency: The default view now matches the first story step exactly
- Smooth Transitions: All camera movements use cubic easing for cinematic quality
- Animation Control: Animations are now paused and controlled by scroll progress instead of playing continuously
๐ฆ Building for Production
# Build the project
npm run build
# Preview the build
npm run preview
The built files will be in the build/
directory, ready for deployment to any static hosting service.
๐ข Deployment
This project is configured for static deployment and works with:
- Vercel: Zero-config deployment
- Netlify: Drag and drop build folder
- GitHub Pages: Enable in repository settings
- Any static hosting: Upload build folder contents
๐ค Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
)
- Commit your changes (
git commit -m 'Add some amazing feature'
)
- Push to the branch (
git push origin feature/amazing-feature
)
- Open a Pull Request
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
- Three.js for 3D graphics
- Svelte for the reactive framework
- LittlestTokyo model from Three.js examples
- Inspired by modern scrollytelling techniques