lightweight-3d-effects
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLightweight 3D Effects Skill
轻量级3D效果技能
Overview
概述
This skill combines three powerful libraries for decorative 3D elements and micro-interactions:
- Zdog: Pseudo-3D engine for designer-friendly vector illustrations
- Vanta.js: Animated 3D backgrounds powered by Three.js/p5.js
- Vanilla-Tilt.js: Smooth parallax tilt effects responding to mouse/gyroscope
本技能结合了三个功能强大的库,用于实现装饰性3D元素和微交互:
- Zdog:面向设计师的伪3D引擎,用于创建矢量插图
- Vanta.js:基于Three.js/p5.js的动画3D背景库
- Vanilla-Tilt.js:响应鼠标/陀螺仪的流畅视差倾斜效果库
When to Use This Skill
适用场景
- Add decorative 3D illustrations without heavy frameworks
- Create animated backgrounds for hero sections
- Implement subtle parallax tilt effects on cards/images
- Build lightweight landing pages with visual depth
- Add micro-interactions that enhance UX without performance impact
- 无需重型框架即可添加装饰性3D插图
- 为首屏区域创建动画背景
- 在卡片/图片上实现细微的视差倾斜效果
- 构建具有视觉深度的轻量级落地页
- 添加不影响性能的微交互以提升用户体验
Zdog - Pseudo-3D Illustrations
Zdog - 伪3D插图
Core Concepts
核心概念
Zdog is a pseudo-3D engine that renders flat, round designs in 3D space using Canvas or SVG.
Key Features:
- Designer-friendly declarative API
- Small file size (~28kb minified)
- Canvas or SVG rendering
- Drag rotation built-in
- Smooth animations
Zdog是一款伪3D引擎,可使用Canvas或SVG在3D空间中渲染扁平化、圆润风格的设计。
核心特性:
- 设计师友好的声明式API
- 小巧的文件体积(压缩后约28kb)
- 支持Canvas或SVG渲染
- 内置拖拽旋转功能
- 流畅的动画效果
Basic Setup
基础配置
html
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/zdog@1/dist/zdog.dist.min.js"></script>
<style>
.zdog-canvas {
display: block;
margin: 0 auto;
background: #FDB;
cursor: move;
}
</style>
</head>
<body>
<canvas class="zdog-canvas" width="240" height="240"></canvas>
<script>
let isSpinning = true;
let illo = new Zdog.Illustration({
element: '.zdog-canvas',
zoom: 4,
dragRotate: true,
onDragStart: function() {
isSpinning = false;
},
});
// Add shapes
new Zdog.Ellipse({
addTo: illo,
diameter: 20,
translate: { z: 10 },
stroke: 5,
color: '#636',
});
new Zdog.Rect({
addTo: illo,
width: 20,
height: 20,
translate: { z: -10 },
stroke: 3,
color: '#E62',
fill: true,
});
function animate() {
illo.rotate.y += isSpinning ? 0.03 : 0;
illo.updateRenderGraph();
requestAnimationFrame(animate);
}
animate();
</script>
</body>
</html>html
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/zdog@1/dist/zdog.dist.min.js"></script>
<style>
.zdog-canvas {
display: block;
margin: 0 auto;
background: #FDB;
cursor: move;
}
</style>
</head>
<body>
<canvas class="zdog-canvas" width="240" height="240"></canvas>
<script>
let isSpinning = true;
let illo = new Zdog.Illustration({
element: '.zdog-canvas',
zoom: 4,
dragRotate: true,
onDragStart: function() {
isSpinning = false;
},
});
// 添加图形
new Zdog.Ellipse({
addTo: illo,
diameter: 20,
translate: { z: 10 },
stroke: 5,
color: '#636',
});
new Zdog.Rect({
addTo: illo,
width: 20,
height: 20,
translate: { z: -10 },
stroke: 3,
color: '#E62',
fill: true,
});
function animate() {
illo.rotate.y += isSpinning ? 0.03 : 0;
illo.updateRenderGraph();
requestAnimationFrame(animate);
}
animate();
</script>
</body>
</html>Zdog Shapes
Zdog图形
Basic Shapes:
javascript
// Circle
new Zdog.Ellipse({
addTo: illo,
diameter: 80,
stroke: 20,
color: '#636',
});
// Rectangle
new Zdog.Rect({
addTo: illo,
width: 80,
height: 60,
stroke: 10,
color: '#E62',
fill: true,
});
// Rounded Rectangle
new Zdog.RoundedRect({
addTo: illo,
width: 60,
height: 40,
cornerRadius: 10,
stroke: 4,
color: '#C25',
fill: true,
});
// Polygon
new Zdog.Polygon({
addTo: illo,
radius: 40,
sides: 5,
stroke: 8,
color: '#EA0',
fill: true,
});
// Line
new Zdog.Shape({
addTo: illo,
path: [
{ x: -40, y: 0 },
{ x: 40, y: 0 },
],
stroke: 6,
color: '#636',
});
// Bezier Curve
new Zdog.Shape({
addTo: illo,
path: [
{ x: -40, y: -20 },
{
bezier: [
{ x: -40, y: 20 },
{ x: 40, y: 20 },
{ x: 40, y: -20 },
],
},
],
stroke: 4,
color: '#C25',
closed: false,
});基础图形:
javascript
// 圆形
new Zdog.Ellipse({
addTo: illo,
diameter: 80,
stroke: 20,
color: '#636',
});
// 矩形
new Zdog.Rect({
addTo: illo,
width: 80,
height: 60,
stroke: 10,
color: '#E62',
fill: true,
});
// 圆角矩形
new Zdog.RoundedRect({
addTo: illo,
width: 60,
height: 40,
cornerRadius: 10,
stroke: 4,
color: '#C25',
fill: true,
});
// 多边形
new Zdog.Polygon({
addTo: illo,
radius: 40,
sides: 5,
stroke: 8,
color: '#EA0',
fill: true,
});
// 直线
new Zdog.Shape({
addTo: illo,
path: [
{ x: -40, y: 0 },
{ x: 40, y: 0 },
],
stroke: 6,
color: '#636',
});
// 贝塞尔曲线
new Zdog.Shape({
addTo: illo,
path: [
{ x: -40, y: -20 },
{
bezier: [
{ x: -40, y: 20 },
{ x: 40, y: 20 },
{ x: 40, y: -20 },
],
},
],
stroke: 4,
color: '#C25',
closed: false,
});Zdog Groups
Zdog组
Organize shapes into groups for complex models:
javascript
// Create a group
let head = new Zdog.Group({
addTo: illo,
translate: { y: -40 },
});
// Add shapes to group
new Zdog.Ellipse({
addTo: head,
diameter: 60,
stroke: 30,
color: '#FED',
});
// Eyes
new Zdog.Ellipse({
addTo: head,
diameter: 8,
stroke: 4,
color: '#333',
translate: { x: -10, z: 15 },
});
new Zdog.Ellipse({
addTo: head,
diameter: 8,
stroke: 4,
color: '#333',
translate: { x: 10, z: 15 },
});
// Mouth
new Zdog.Shape({
addTo: head,
path: [
{ x: -10, y: 0 },
{
bezier: [
{ x: -5, y: 5 },
{ x: 5, y: 5 },
{ x: 10, y: 0 },
],
},
],
stroke: 2,
color: '#333',
translate: { y: 5, z: 15 },
closed: false,
});
// Rotate entire group
head.rotate.y = Math.PI / 4;将图形分组以构建复杂模型:
javascript
// 创建组
let head = new Zdog.Group({
addTo: illo,
translate: { y: -40 },
});
// 向组中添加图形
new Zdog.Ellipse({
addTo: head,
diameter: 60,
stroke: 30,
color: '#FED',
});
// 眼睛
new Zdog.Ellipse({
addTo: head,
diameter: 8,
stroke: 4,
color: '#333',
translate: { x: -10, z: 15 },
});
new Zdog.Ellipse({
addTo: head,
diameter: 8,
stroke: 4,
color: '#333',
translate: { x: 10, z: 15 },
});
// 嘴巴
new Zdog.Shape({
addTo: head,
path: [
{ x: -10, y: 0 },
{
bezier: [
{ x: -5, y: 5 },
{ x: 5, y: 5 },
{ x: 10, y: 0 },
],
},
],
stroke: 2,
color: '#333',
translate: { y: 5, z: 15 },
closed: false,
});
// 旋转整个组
head.rotate.y = Math.PI / 4;Zdog Animation
Zdog动画
javascript
// Continuous rotation
function animate() {
illo.rotate.y += 0.03;
illo.updateRenderGraph();
requestAnimationFrame(animate);
}
animate();
// Bounce animation
let t = 0;
function bounceAnimate() {
t += 0.05;
illo.translate.y = Math.sin(t) * 20;
illo.updateRenderGraph();
requestAnimationFrame(bounceAnimate);
}
bounceAnimate();
// Interactive rotation with easing
let targetRotateY = 0;
let currentRotateY = 0;
document.addEventListener('mousemove', (event) => {
targetRotateY = (event.clientX / window.innerWidth - 0.5) * Math.PI;
});
function smoothAnimate() {
// Ease towards target
currentRotateY += (targetRotateY - currentRotateY) * 0.1;
illo.rotate.y = currentRotateY;
illo.updateRenderGraph();
requestAnimationFrame(smoothAnimate);
}
smoothAnimate();javascript
// 持续旋转
function animate() {
illo.rotate.y += 0.03;
illo.updateRenderGraph();
requestAnimationFrame(animate);
}
animate();
// 弹跳动画
let t = 0;
function bounceAnimate() {
t += 0.05;
illo.translate.y = Math.sin(t) * 20;
illo.updateRenderGraph();
requestAnimationFrame(bounceAnimate);
}
bounceAnimate();
// 带缓动的交互式旋转
let targetRotateY = 0;
let currentRotateY = 0;
document.addEventListener('mousemove', (event) => {
targetRotateY = (event.clientX / window.innerWidth - 0.5) * Math.PI;
});
function smoothAnimate() {
// 向目标值缓动
currentRotateY += (targetRotateY - currentRotateY) * 0.1;
illo.rotate.y = currentRotateY;
illo.updateRenderGraph();
requestAnimationFrame(smoothAnimate);
}
smoothAnimate();Vanta.js - Animated 3D Backgrounds
Vanta.js - 动画3D背景
Core Concepts
核心概念
Vanta.js provides animated WebGL backgrounds with minimal setup, powered by Three.js or p5.js.
Key Features:
- 14+ animated effects (Waves, Birds, Net, Clouds, etc.)
- Mouse/touch interaction
- Customizable colors and settings
- ~120KB total (including Three.js)
- 60fps on most devices
Vanta.js提供可快速配置的WebGL动画背景,基于Three.js或p5.js实现。
核心特性:
- 14种以上的动画效果(波浪、飞鸟、网格、云朵等)
- 支持鼠标/触摸交互
- 可自定义颜色和设置
- 总文件体积约120KB(包含Three.js)
- 在大多数设备上可实现60fps帧率
Basic Setup
基础配置
html
<!DOCTYPE html>
<html>
<head>
<style>
#vanta-bg {
width: 100%;
height: 100vh;
}
.content {
position: relative;
z-index: 1;
color: white;
text-align: center;
padding: 100px 20px;
}
</style>
</head>
<body>
<div id="vanta-bg">
<div class="content">
<h1>My Animated Background</h1>
<p>Content goes here</p>
</div>
</div>
<!-- Three.js (required) -->
<script src="https://cdn.jsdelivr.net/npm/three@0.134.0/build/three.min.js"></script>
<!-- Vanta.js effect -->
<script src="https://cdn.jsdelivr.net/npm/vanta@0.5.24/dist/vanta.waves.min.js"></script>
<script>
VANTA.WAVES({
el: "#vanta-bg",
mouseControls: true,
touchControls: true,
gyroControls: false,
minHeight: 200.00,
minWidth: 200.00,
scale: 1.00,
scaleMobile: 1.00,
color: 0x23153c,
shininess: 30.00,
waveHeight: 15.00,
waveSpeed: 0.75,
zoom: 0.65
});
</script>
</body>
</html>html
<!DOCTYPE html>
<html>
<head>
<style>
#vanta-bg {
width: 100%;
height: 100vh;
}
.content {
position: relative;
z-index: 1;
color: white;
text-align: center;
padding: 100px 20px;
}
</style>
</head>
<body>
<div id="vanta-bg">
<div class="content">
<h1>我的动画背景</h1>
<p>内容区域</p>
</div>
</div>
<!-- 依赖Three.js -->
<script src="https://cdn.jsdelivr.net/npm/three@0.134.0/build/three.min.js"></script>
<!-- Vanta.js效果 -->
<script src="https://cdn.jsdelivr.net/npm/vanta@0.5.24/dist/vanta.waves.min.js"></script>
<script>
VANTA.WAVES({
el: "#vanta-bg",
mouseControls: true,
touchControls: true,
gyroControls: false,
minHeight: 200.00,
minWidth: 200.00,
scale: 1.00,
scaleMobile: 1.00,
color: 0x23153c,
shininess: 30.00,
waveHeight: 15.00,
waveSpeed: 0.75,
zoom: 0.65
});
</script>
</body>
</html>Available Effects
可用效果
1. WAVES (Three.js)
javascript
VANTA.WAVES({
el: "#vanta-bg",
color: 0x23153c,
shininess: 30,
waveHeight: 15,
waveSpeed: 0.75,
zoom: 0.65
});2. CLOUDS (Three.js)
javascript
VANTA.CLOUDS({
el: "#vanta-bg",
skyColor: 0x68b8d7,
cloudColor: 0xadc1de,
cloudShadowColor: 0x183550,
sunColor: 0xff9919,
sunGlareColor: 0xff6633,
sunlightColor: 0xff9933,
speed: 1.0
});3. BIRDS (p5.js required)
html
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vanta@0.5.24/dist/vanta.birds.min.js"></script>
<script>
VANTA.BIRDS({
el: "#vanta-bg",
backgroundColor: 0x23153c,
color1: 0xff0000,
color2: 0x0000ff,
birdSize: 1.5,
wingSpan: 20,
speedLimit: 5,
separation: 40,
alignment: 40,
cohesion: 40,
quantity: 3
});
</script>4. NET (Three.js)
javascript
VANTA.NET({
el: "#vanta-bg",
color: 0x3fff00,
backgroundColor: 0x23153c,
points: 10,
maxDistance: 20,
spacing: 15,
showDots: true
});5. CELLS (p5.js required)
javascript
VANTA.CELLS({
el: "#vanta-bg",
color1: 0x00ff00,
color2: 0xff0000,
size: 1.5,
speed: 1.0,
scale: 1.0
});6. FOG (Three.js)
javascript
VANTA.FOG({
el: "#vanta-bg",
highlightColor: 0xff3f81,
midtoneColor: 0x1d004d,
lowlightColor: 0x2b1a5e,
baseColor: 0x000000,
blurFactor: 0.6,
speed: 1.0,
zoom: 1.0
});Other effects: GLOBE, TRUNK, TOPOLOGY, DOTS, HALO, RINGS
1. WAVES(基于Three.js)
javascript
VANTA.WAVES({
el: "#vanta-bg",
color: 0x23153c,
shininess: 30,
waveHeight: 15,
waveSpeed: 0.75,
zoom: 0.65
});2. CLOUDS(基于Three.js)
javascript
VANTA.CLOUDS({
el: "#vanta-bg",
skyColor: 0x68b8d7,
cloudColor: 0xadc1de,
cloudShadowColor: 0x183550,
sunColor: 0xff9919,
sunGlareColor: 0xff6633,
sunlightColor: 0xff9933,
speed: 1.0
});3. BIRDS(需要依赖p5.js)
html
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vanta@0.5.24/dist/vanta.birds.min.js"></script>
<script>
VANTA.BIRDS({
el: "#vanta-bg",
backgroundColor: 0x23153c,
color1: 0xff0000,
color2: 0x0000ff,
birdSize: 1.5,
wingSpan: 20,
speedLimit: 5,
separation: 40,
alignment: 40,
cohesion: 40,
quantity: 3
});
</script>4. NET(基于Three.js)
javascript
VANTA.NET({
el: "#vanta-bg",
color: 0x3fff00,
backgroundColor: 0x23153c,
points: 10,
maxDistance: 20,
spacing: 15,
showDots: true
});5. CELLS(需要依赖p5.js)
javascript
VANTA.CELLS({
el: "#vanta-bg",
color1: 0x00ff00,
color2: 0xff0000,
size: 1.5,
speed: 1.0,
scale: 1.0
});6. FOG(基于Three.js)
javascript
VANTA.FOG({
el: "#vanta-bg",
highlightColor: 0xff3f81,
midtoneColor: 0x1d004d,
lowlightColor: 0x2b1a5e,
baseColor: 0x000000,
blurFactor: 0.6,
speed: 1.0,
zoom: 1.0
});其他效果: GLOBE、TRUNK、TOPOLOGY、DOTS、HALO、RINGS
Configuration Options
配置选项
javascript
// Common options for all effects
{
el: "#element-id", // Required: target element
mouseControls: true, // Enable mouse interaction
touchControls: true, // Enable touch interaction
gyroControls: false, // Device orientation
minHeight: 200.00, // Minimum height
minWidth: 200.00, // Minimum width
scale: 1.00, // Size scale
scaleMobile: 1.00, // Mobile scale
// Colors (hex numbers, not strings)
color: 0x23153c,
backgroundColor: 0x000000,
// Performance
forceAnimate: false, // Force animation even when hidden
// Effect-specific options vary by effect
}javascript
// 所有效果的通用配置
{
el: "#element-id", // 必填:目标元素
mouseControls: true, // 启用鼠标交互
touchControls: true, // 启用触摸交互
gyroControls: false, // 设备方向控制
minHeight: 200.00, // 最小高度
minWidth: 200.00, // 最小宽度
scale: 1.00, // 尺寸缩放
scaleMobile: 1.00, // 移动端缩放
// 颜色(十六进制数值,而非字符串)
color: 0x23153c,
backgroundColor: 0x000000,
// 性能相关
forceAnimate: false, // 即使元素隐藏也强制动画
// 各效果的专属配置有所不同
}Vanta.js Methods
Vanta.js方法
javascript
// Initialize and store reference
const vantaEffect = VANTA.WAVES({
el: "#vanta-bg",
// ... options
});
// Destroy when done (important for SPAs)
vantaEffect.destroy();
// Update options dynamically
vantaEffect.setOptions({
color: 0xff0000,
waveHeight: 20
});
// Resize (usually automatic)
vantaEffect.resize();javascript
// 初始化并保存引用
const vantaEffect = VANTA.WAVES({
el: "#vanta-bg",
// ... 配置项
});
// 不再使用时销毁(单页应用中至关重要)
vantaEffect.destroy();
// 动态更新配置
vantaEffect.setOptions({
color: 0xff0000,
waveHeight: 20
});
// 调整尺寸(通常自动触发)
vantaEffect.resize();React Integration
React集成
jsx
import { useEffect, useRef, useState } from 'react';
import VANTA from 'vanta/dist/vanta.waves.min';
import * as THREE from 'three';
function VantaBackground() {
const vantaRef = useRef(null);
const [vantaEffect, setVantaEffect] = useState(null);
useEffect(() => {
if (!vantaEffect) {
setVantaEffect(VANTA.WAVES({
el: vantaRef.current,
THREE: THREE,
mouseControls: true,
touchControls: true,
color: 0x23153c,
shininess: 30,
waveHeight: 15,
waveSpeed: 0.75
}));
}
return () => {
if (vantaEffect) vantaEffect.destroy();
};
}, [vantaEffect]);
return (
<div ref={vantaRef} style={{ width: '100%', height: '100vh' }}>
<div className="content">
<h1>React + Vanta.js</h1>
</div>
</div>
);
}jsx
import { useEffect, useRef, useState } from 'react';
import VANTA from 'vanta/dist/vanta.waves.min';
import * as THREE from 'three';
function VantaBackground() {
const vantaRef = useRef(null);
const [vantaEffect, setVantaEffect] = useState(null);
useEffect(() => {
if (!vantaEffect) {
setVantaEffect(VANTA.WAVES({
el: vantaRef.current,
THREE: THREE,
mouseControls: true,
touchControls: true,
color: 0x23153c,
shininess: 30,
waveHeight: 15,
waveSpeed: 0.75
}));
}
return () => {
if (vantaEffect) vantaEffect.destroy();
};
}, [vantaEffect]);
return (
<div ref={vantaRef} style={{ width: '100%', height: '100vh' }}>
<div className="content">
<h1>React + Vanta.js</h1>
</div>
</div>
);
}Vanilla-Tilt.js - Parallax Tilt Effects
Vanilla-Tilt.js - 视差倾斜效果
Core Concepts
核心概念
Vanilla-Tilt.js adds smooth 3D tilt effects responding to mouse movement and device orientation.
Key Features:
- Lightweight (~8.5kb minified)
- No dependencies
- Gyroscope support
- Optional glare effect
- Smooth transitions
Vanilla-Tilt.js可为元素添加响应鼠标移动和设备方向的流畅3D倾斜效果。
核心特性:
- 轻量级(压缩后约8.5kb)
- 无依赖
- 支持陀螺仪控制
- 可选眩光效果
- 平滑过渡动画
Basic Setup
基础配置
html
<!DOCTYPE html>
<html>
<head>
<style>
.tilt-card {
width: 300px;
height: 400px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 15px;
margin: 50px auto;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 24px;
transform-style: preserve-3d;
}
.tilt-inner {
transform: translateZ(60px);
}
</style>
</head>
<body>
<div class="tilt-card" data-tilt>
<div class="tilt-inner">Hover Me!</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vanilla-tilt@1.8.1/dist/vanilla-tilt.min.js"></script>
</body>
</html>html
<!DOCTYPE html>
<html>
<head>
<style>
.tilt-card {
width: 300px;
height: 400px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 15px;
margin: 50px auto;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 24px;
transform-style: preserve-3d;
}
.tilt-inner {
transform: translateZ(60px);
}
</style>
</head>
<body>
<div class="tilt-card" data-tilt>
<div class="tilt-inner">悬停试试!</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vanilla-tilt@1.8.1/dist/vanilla-tilt.min.js"></script>
</body>
</html>Configuration Options
配置选项
javascript
VanillaTilt.init(document.querySelector(".tilt-card"), {
// Rotation
max: 25, // Max tilt angle (degrees)
reverse: false, // Reverse tilt direction
startX: 0, // Initial tilt X (degrees)
startY: 0, // Initial tilt Y (degrees)
// Appearance
perspective: 1000, // Transform perspective (lower = more intense)
scale: 1.1, // Scale on hover (1 = no scale)
// Animation
speed: 400, // Transition speed (ms)
transition: true, // Enable smooth transitions
easing: "cubic-bezier(.03,.98,.52,.99)",
// Behavior
axis: null, // Restrict to "x" or "y" axis
reset: true, // Reset on mouse leave
"reset-to-start": true, // Reset to start position vs [0,0]
// Glare effect
glare: true, // Enable glare
"max-glare": 0.5, // Glare opacity (0-1)
"glare-prerender": false, // Pre-render glare elements
// Advanced
full-page-listening: false, // Listen to entire page
gyroscope: true, // Enable device orientation
gyroscopeMinAngleX: -45, // Min X angle
gyroscopeMaxAngleX: 45, // Max X angle
gyroscopeMinAngleY: -45, // Min Y angle
gyroscopeMaxAngleY: 45, // Max Y angle
gyroscopeSamples: 10 // Calibration samples
});javascript
VanillaTilt.init(document.querySelector(".tilt-card"), {
// 旋转设置
max: 25, // 最大倾斜角度(度)
reverse: false, // 反转倾斜方向
startX: 0, // 初始X轴倾斜角度(度)
startY: 0, // 初始Y轴倾斜角度(度)
// 外观设置
perspective: 1000, // 变换透视值(值越小效果越强)
scale: 1.1, // 悬停时的缩放比例(1表示不缩放)
// 动画设置
speed: 400, // 过渡速度(毫秒)
transition: true, // 启用平滑过渡
easing: "cubic-bezier(.03,.98,.52,.99)",
// 行为设置
axis: null, // 限制仅在"x"或"y"轴倾斜
reset: true, // 鼠标离开时重置
"reset-to-start": true, // 重置到初始位置还是[0,0]
// 眩光效果
glare: true, // 启用眩光
"max-glare": 0.5, // 眩光透明度(0-1)
"glare-prerender": false, // 预渲染眩光元素
// 高级设置
full-page-listening: false, // 监听整个页面的鼠标移动
gyroscope: true, // 启用设备方向控制
gyroscopeMinAngleX: -45, // X轴最小角度
gyroscopeMaxAngleX: 45, // X轴最大角度
gyroscopeMinAngleY: -45, // Y轴最小角度
gyroscopeMaxAngleY: 45, // Y轴最大角度
gyroscopeSamples: 10 // 校准采样次数
});Advanced Examples
高级示例
Card with Glare Effect:
html
<div class="tilt-card" data-tilt
data-tilt-glare
data-tilt-max-glare="0.5"
data-tilt-scale="1.1">
<div class="tilt-inner">
<h3>Premium Card</h3>
<p>With glare effect</p>
</div>
</div>Layered 3D Effect:
html
<style>
.tilt-card {
transform-style: preserve-3d;
}
.layer-1 {
transform: translateZ(20px);
}
.layer-2 {
transform: translateZ(40px);
}
.layer-3 {
transform: translateZ(60px);
}
</style>
<div class="tilt-card" data-tilt data-tilt-max="15">
<div class="layer-1">Background</div>
<div class="layer-2">Middle</div>
<div class="layer-3">Front</div>
</div>Programmatic Control:
javascript
const element = document.querySelector(".tilt-card");
VanillaTilt.init(element, {
max: 25,
speed: 400,
glare: true,
"max-glare": 0.5
});
// Get tilt values
element.addEventListener("tiltChange", (e) => {
console.log("Tilt:", e.detail);
});
// Reset programmatically
element.vanillaTilt.reset();
// Destroy instance
element.vanillaTilt.destroy();
// Get current values
const values = element.vanillaTilt.getValues();
console.log(values); // { tiltX, tiltY, percentageX, percentageY, angle }带眩光效果的卡片:
html
<div class="tilt-card" data-tilt
data-tilt-glare
data-tilt-max-glare="0.5"
data-tilt-scale="1.1">
<div class="tilt-inner">
<h3>高级卡片</h3>
<p>带有眩光效果</p>
</div>
</div>分层3D效果:
html
<style>
.tilt-card {
transform-style: preserve-3d;
}
.layer-1 {
transform: translateZ(20px);
}
.layer-2 {
transform: translateZ(40px);
}
.layer-3 {
transform: translateZ(60px);
}
</style>
<div class="tilt-card" data-tilt data-tilt-max="15">
<div class="layer-1">背景层</div>
<div class="layer-2">中间层</div>
<div class="layer-3">前景层</div>
</div>程序化控制:
javascript
const element = document.querySelector(".tilt-card");
VanillaTilt.init(element, {
max: 25,
speed: 400,
glare: true,
"max-glare": 0.5
});
// 获取倾斜值
element.addEventListener("tiltChange", (e) => {
console.log("倾斜值:", e.detail);
});
// 程序化重置
element.vanillaTilt.reset();
// 销毁实例
element.vanillaTilt.destroy();
// 获取当前值
const values = element.vanillaTilt.getValues();
console.log(values); // { tiltX, tiltY, percentageX, percentageY, angle }React Integration
React集成
jsx
import { useEffect, useRef } from 'react';
import VanillaTilt from 'vanilla-tilt';
function TiltCard({ children, options }) {
const tiltRef = useRef(null);
useEffect(() => {
const element = tiltRef.current;
VanillaTilt.init(element, {
max: 25,
speed: 400,
glare: true,
"max-glare": 0.5,
...options
});
return () => {
element.vanillaTilt.destroy();
};
}, [options]);
return (
<div ref={tiltRef} className="tilt-card">
{children}
</div>
);
}
// Usage
<TiltCard options={{ max: 30, scale: 1.1 }}>
<h3>My Card</h3>
</TiltCard>jsx
import { useEffect, useRef } from 'react';
import VanillaTilt from 'vanilla-tilt';
function TiltCard({ children, options }) {
const tiltRef = useRef(null);
useEffect(() => {
const element = tiltRef.current;
VanillaTilt.init(element, {
max: 25,
speed: 400,
glare: true,
"max-glare": 0.5,
...options
});
return () => {
element.vanillaTilt.destroy();
};
}, [options]);
return (
<div ref={tiltRef} className="tilt-card">
{children}
</div>
);
}
// 使用示例
<TiltCard options={{ max: 30, scale: 1.1 }}>
<h3>我的卡片</h3>
</TiltCard>Common Patterns
常见模式
Pattern 1: Hero Section with Vanta + Content
模式1:Vanta背景+内容首屏
html
<section id="hero">
<div class="hero-content">
<h1>Welcome</h1>
<p>Animated background with content overlay</p>
<button>Get Started</button>
</div>
</section>
<style>
#hero {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
}
.hero-content {
position: relative;
z-index: 1;
color: white;
text-align: center;
padding-top: 20vh;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/three@0.134.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vanta@0.5.24/dist/vanta.waves.min.js"></script>
<script>
VANTA.WAVES({
el: "#hero",
mouseControls: true,
touchControls: true,
color: 0x23153c,
waveHeight: 20,
waveSpeed: 1.0
});
</script>html
<section id="hero">
<div class="hero-content">
<h1>欢迎访问</h1>
<p>带有动画背景的内容叠加效果</p>
<button>开始使用</button>
</div>
</section>
<style>
#hero {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
}
.hero-content {
position: relative;
z-index: 1;
color: white;
text-align: center;
padding-top: 20vh;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/three@0.134.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vanta@0.5.24/dist/vanta.waves.min.js"></script>
<script>
VANTA.WAVES({
el: "#hero",
mouseControls: true,
touchControls: true,
color: 0x23153c,
waveHeight: 20,
waveSpeed: 1.0
});
</script>Pattern 2: Zdog Icon Grid
模式2:Zdog图标网格
html
<div class="icon-grid">
<canvas class="icon" width="120" height="120"></canvas>
<canvas class="icon" width="120" height="120"></canvas>
<canvas class="icon" width="120" height="120"></canvas>
</div>
<script src="https://unpkg.com/zdog@1/dist/zdog.dist.min.js"></script>
<script>
document.querySelectorAll('.icon').forEach((canvas, index) => {
let illo = new Zdog.Illustration({
element: canvas,
zoom: 3,
dragRotate: true
});
// Create different icon for each canvas
const icons = [
createHeartIcon,
createStarIcon,
createCheckIcon
];
icons[index](illo);
function animate() {
illo.rotate.y += 0.02;
illo.updateRenderGraph();
requestAnimationFrame(animate);
}
animate();
});
function createHeartIcon(illo) {
new Zdog.Shape({
addTo: illo,
path: [
{ x: 0, y: -10 },
{
bezier: [
{ x: -20, y: -20 },
{ x: -20, y: 0 },
{ x: 0, y: 10 }
]
},
{
bezier: [
{ x: 20, y: 0 },
{ x: 20, y: -20 },
{ x: 0, y: -10 }
]
}
],
stroke: 6,
color: '#E62',
fill: true,
closed: false
});
}
</script>html
<div class="icon-grid">
<canvas class="icon" width="120" height="120"></canvas>
<canvas class="icon" width="120" height="120"></canvas>
<canvas class="icon" width="120" height="120"></canvas>
</div>
<script src="https://unpkg.com/zdog@1/dist/zdog.dist.min.js"></script>
<script>
document.querySelectorAll('.icon').forEach((canvas, index) => {
let illo = new Zdog.Illustration({
element: canvas,
zoom: 3,
dragRotate: true
});
// 为每个canvas创建不同的图标
const icons = [
createHeartIcon,
createStarIcon,
createCheckIcon
];
icons[index](illo);
function animate() {
illo.rotate.y += 0.02;
illo.updateRenderGraph();
requestAnimationFrame(animate);
}
animate();
});
function createHeartIcon(illo) {
new Zdog.Shape({
addTo: illo,
path: [
{ x: 0, y: -10 },
{
bezier: [
{ x: -20, y: -20 },
{ x: -20, y: 0 },
{ x: 0, y: 10 }
]
},
{
bezier: [
{ x: 20, y: 0 },
{ x: 20, y: -20 },
{ x: 0, y: -10 }
]
}
],
stroke: 6,
color: '#E62',
fill: true,
closed: false
});
}
</script>Pattern 3: Tilt Card Gallery
模式3:倾斜卡片画廊
html
<div class="card-gallery">
<div class="card" data-tilt data-tilt-glare data-tilt-max-glare="0.3">
<img src="product1.jpg" alt="Product 1">
<h3>Product 1</h3>
</div>
<div class="card" data-tilt data-tilt-glare data-tilt-max-glare="0.3">
<img src="product2.jpg" alt="Product 2">
<h3>Product 2</h3>
</div>
<div class="card" data-tilt data-tilt-glare data-tilt-max-glare="0.3">
<img src="product3.jpg" alt="Product 3">
<h3>Product 3</h3>
</div>
</div>
<style>
.card-gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
padding: 50px;
}
.card {
background: white;
border-radius: 15px;
padding: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
transform-style: preserve-3d;
}
.card img {
width: 100%;
border-radius: 10px;
transform: translateZ(40px);
}
.card h3 {
margin-top: 15px;
transform: translateZ(60px);
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vanilla-tilt@1.8.1/dist/vanilla-tilt.min.js"></script>html
<div class="card-gallery">
<div class="card" data-tilt data-tilt-glare data-tilt-max-glare="0.3">
<img src="product1.jpg" alt="产品1">
<h3>产品1</h3>
</div>
<div class="card" data-tilt data-tilt-glare data-tilt-max-glare="0.3">
<img src="product2.jpg" alt="产品2">
<h3>产品2</h3>
</div>
<div class="card" data-tilt data-tilt-glare data-tilt-max-glare="0.3">
<img src="product3.jpg" alt="产品3">
<h3>产品3</h3>
</div>
</div>
<style>
.card-gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
padding: 50px;
}
.card {
background: white;
border-radius: 15px;
padding: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
transform-style: preserve-3d;
}
.card img {
width: 100%;
border-radius: 10px;
transform: translateZ(40px);
}
.card h3 {
margin-top: 15px;
transform: translateZ(60px);
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vanilla-tilt@1.8.1/dist/vanilla-tilt.min.js"></script>Pattern 4: Combined Effect - Vanta Background + Tilt Cards
模式4:组合效果 - Vanta背景+倾斜卡片
html
<div id="vanta-section">
<div class="container">
<h1>Our Services</h1>
<div class="services-grid">
<div class="service-card" data-tilt data-tilt-scale="1.05">
<div class="icon">🚀</div>
<h3>Fast</h3>
<p>Lightning quick performance</p>
</div>
<div class="service-card" data-tilt data-tilt-scale="1.05">
<div class="icon">🎨</div>
<h3>Beautiful</h3>
<p>Stunning visual design</p>
</div>
<div class="service-card" data-tilt data-tilt-scale="1.05">
<div class="icon">💪</div>
<h3>Powerful</h3>
<p>Feature-rich platform</p>
</div>
</div>
</div>
</div>
<script>
// Vanta background
VANTA.NET({
el: "#vanta-section",
color: 0x3fff00,
backgroundColor: 0x23153c,
points: 10,
maxDistance: 20
});
// Tilt cards
VanillaTilt.init(document.querySelectorAll(".service-card"), {
max: 15,
speed: 400,
glare: true,
"max-glare": 0.3
});
</script>html
<div id="vanta-section">
<div class="container">
<h1>我们的服务</h1>
<div class="services-grid">
<div class="service-card" data-tilt data-tilt-scale="1.05">
<div class="icon">🚀</div>
<h3>极速性能</h3>
<p>闪电般的响应速度</p>
</div>
<div class="service-card" data-tilt data-tilt-scale="1.05">
<div class="icon">🎨</div>
<h3>精美设计</h3>
<p>令人惊艳的视觉效果</p>
</div>
<div class="service-card" data-tilt data-tilt-scale="1.05">
<div class="icon">💪</div>
<h3>功能强大</h3>
<p>特性丰富的平台</p>
</div>
</div>
</div>
</div>
<script>
// Vanta背景
VANTA.NET({
el: "#vanta-section",
color: 0x3fff00,
backgroundColor: 0x23153c,
points: 10,
maxDistance: 20
});
// 倾斜卡片
VanillaTilt.init(document.querySelectorAll(".service-card"), {
max: 15,
speed: 400,
glare: true,
"max-glare": 0.3
});
</script>Performance Best Practices
性能优化最佳实践
Zdog Optimization
Zdog优化
- Limit Shape Count: Keep total shapes under 100 for smooth 60fps
- Use Groups: Organize related shapes for easier management
- Optimize Animation Loop: Only call when needed
updateRenderGraph() - Canvas vs SVG: Canvas is faster for animations, SVG for static illustrations
- 限制图形数量:总图形数控制在100个以内,以保证60fps流畅运行
- 使用组管理:将相关图形分组,便于管理和操作
- 优化动画循环:仅在必要时调用
updateRenderGraph() - 选择合适的渲染方式:Canvas更适合动画场景,SVG适合静态插图
Vanta.js Optimization
Vanta.js优化
- Single Instance: Use only 1-2 Vanta effects per page
- Mobile Fallback: Disable on mobile or use static background
- Destroy on Unmount: Always call in SPAs
.destroy() - Reduce Particle Count: Lower ,
pointsfor better performancequantity
javascript
// Mobile detection and fallback
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
if (!isMobile) {
VANTA.WAVES({
el: "#hero",
// ... options
});
} else {
document.getElementById('hero').style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
}- 单实例使用:每页仅使用1-2个Vanta效果
- 移动端降级:在移动端禁用效果或使用静态背景
- 组件卸载时销毁:在单页应用中务必调用
.destroy() - 减少粒子数量:降低、
points等参数以提升性能quantity
javascript
// 移动端检测与降级处理
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
if (!isMobile) {
VANTA.WAVES({
el: "#hero",
// ... 配置项
});
} else {
document.getElementById('hero').style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
}Vanilla-Tilt Optimization
Vanilla-Tilt.js优化
- Limit Instances: Apply to visible elements only
- Reduce : Lower for better mobile performance
gyroscopeSamples - Disable on Low-End Devices: Check device capabilities
- Use CSS : Hint browser for transforms
will-change
css
.tilt-card {
will-change: transform;
}- 限制实例数量:仅对可见元素应用效果
- 减少陀螺仪采样次数:降低值以提升移动端性能
gyroscopeSamples - 低端设备禁用:检测设备性能并决定是否启用效果
- 使用CSS will-change:提示浏览器提前准备变换
css
.tilt-card {
will-change: transform;
}Common Pitfalls
常见陷阱
Pitfall 1: Multiple Vanta Instances
陷阱1:多个Vanta实例
Problem: Multiple Vanta effects cause performance issues
Solution: Use only one effect, or lazy-load effects per section
javascript
// Intersection Observer to load Vanta only when visible
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && !entry.target.vantaEffect) {
entry.target.vantaEffect = VANTA.WAVES({
el: entry.target,
// ... options
});
}
});
});
observer.observe(document.getElementById('hero'));问题:多个Vanta效果导致性能下降
解决方案:仅使用一个效果,或按区域懒加载效果
javascript
// 使用Intersection Observer仅在元素可见时加载Vanta效果
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && !entry.target.vantaEffect) {
entry.target.vantaEffect = VANTA.WAVES({
el: entry.target,
// ... 配置项
});
}
});
});
observer.observe(document.getElementById('hero'));Pitfall 2: Memory Leaks in SPAs
陷阱2:单页应用中的内存泄漏
Problem: Vanta/Tilt not destroyed on component unmount
Solution: Always clean up
javascript
// React useEffect cleanup
useEffect(() => {
const effect = VANTA.WAVES({ el: vantaRef.current });
return () => {
effect.destroy(); // Important!
};
}, []);问题:组件卸载时未销毁Vanta/Tilt实例
解决方案:务必进行清理操作
javascript
// React useEffect清理示例
useEffect(() => {
const effect = VANTA.WAVES({ el: vantaRef.current });
return () => {
effect.destroy(); // 至关重要!
};
}, []);Pitfall 3: Zdog Not Rendering
陷阱3:Zdog无法渲染
Problem: Canvas appears blank
Causes:
- Forgot to call
updateRenderGraph() - Canvas size is 0
- Shapes are outside view
Solution:
javascript
// Always call updateRenderGraph after shape changes
illo.updateRenderGraph();
// Ensure canvas has dimensions
<canvas width="240" height="240"></canvas>
// Check shape positions are visible
new Zdog.Ellipse({
addTo: illo,
diameter: 20,
translate: { z: 0 }, // Keep close to origin
});问题:Canvas显示空白
可能原因:
- 忘记调用
updateRenderGraph() - Canvas尺寸为0
- 图形位于可视区域外
解决方案:
javascript
// 图形变更后务必调用updateRenderGraph
illo.updateRenderGraph();
// 确保Canvas有明确的尺寸
<canvas width="240" height="240"></canvas>
// 检查图形位置是否在可视范围内
new Zdog.Ellipse({
addTo: illo,
diameter: 20,
translate: { z: 0 }, // 保持在原点附近
});Pitfall 4: Tilt Not Working on Mobile
陷阱4:移动端倾斜效果无效
Problem: Tilt doesn't respond on mobile devices
Solution: Enable gyroscope controls
javascript
VanillaTilt.init(element, {
gyroscope: true,
gyroscopeMinAngleX: -45,
gyroscopeMaxAngleX: 45
});问题:在移动设备上倾斜效果无响应
解决方案:启用陀螺仪控制
javascript
VanillaTilt.init(element, {
gyroscope: true,
gyroscopeMinAngleX: -45,
gyroscopeMaxAngleX: 45
});Pitfall 5: Color Format Confusion (Vanta.js)
陷阱5:Vanta.js颜色格式错误
Problem: Colors don't work
Cause: Vanta.js uses hex numbers, not strings
javascript
// ❌ Wrong
color: "#23153c"
// ✅ Correct
color: 0x23153c问题:颜色设置不生效
原因:Vanta.js使用十六进制数值,而非字符串
javascript
// ❌ 错误写法
color: "#23153c"
// ✅ 正确写法
color: 0x23153cResources
资源链接
Zdog:
Vanta.js:
Vanilla-Tilt.js:
Zdog相关:
Vanta.js相关:
Vanilla-Tilt.js相关:
Related Skills
相关技能
- threejs-webgl: For more complex 3D graphics beyond decorative effects
- gsap-scrolltrigger: For animating these effects on scroll
- motion-framer: For React component animations alongside these effects
- react-three-fiber: Advanced 3D when lightweight effects aren't enough
- threejs-webgl:用于实现超出装饰性效果的复杂3D图形
- gsap-scrolltrigger:用于在滚动时触发这些效果的动画
- motion-framer:用于在React组件动画中搭配这些效果
- react-three-fiber:当轻量级效果无法满足需求时的高级3D方案