Custom Animations
You can use TWEEN directly to create completely custom animation effects.
How to Use
After obtaining the player instance through ref or onReady, use getElementsByName or click events to get elements, then apply TWEEN animations directly to element properties (position, rotation, scale, color, etc.).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>ICraft Player TWEEN Custom Animation Demo</title>
<style>
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
}
#container {
width: 100%;
height: 100vh;
position: relative;
}
#controls {
position: absolute;
bottom: 10px;
right: 10px;
padding: 10px;
font-size: 14px;
}
</style>
<script src="https://unpkg.com/@icraft/player@latest/dist/umd/icraft-player.min.js"></script>
<script src="https://unpkg.com/@tweenjs/tween.js@23.1.3/dist/tween.umd.js"></script>
</head>
<body>
<div id="container"></div>
<div id="controls">
<div>
<button id="pauseBtn">pause</button>
</div>
</div>
</body>
<script>
let player = null;
let isPaused = false;
let allAnimations = [];
let currentTween = null;
const playerInstance = new ICraftPlayer({
src: "/templates/tween.iplayer",
container: document.getElementById("container"),
onReady: (playerRef) => {
player = playerRef;
const car = player.getElementsByName("car")?.[0];
if (car) {
startSquarePathAnimation(car);
}
},
});
function startSquarePathAnimation(car) {
const startPos = {
x: car.position.x,
y: car.position.y,
z: car.position.z,
};
const startRot = car.rotation.y;
const pathSegments = [
{
to: { x: startPos.x, y: startPos.y, z: startPos.z + 20 },
rotation: startRot,
},
{
to: { x: startPos.x + 20, y: startPos.y, z: startPos.z + 20 },
rotation: startRot - Math.PI / 2,
},
{
to: { x: startPos.x + 20, y: startPos.y, z: startPos.z },
rotation: startRot - Math.PI,
},
{
to: { x: startPos.x, y: startPos.y, z: startPos.z },
rotation: startRot - (Math.PI * 3) / 2,
},
];
const animations = [];
pathSegments.forEach((segment, index) => {
const moveTween = new TWEEN.Tween(car.position)
.to(segment.to, 2000)
.easing(TWEEN.Easing.Quadratic.InOut);
const rotateTween = new TWEEN.Tween(car.rotation)
.to({ y: segment.rotation }, 300)
.easing(TWEEN.Easing.Quadratic.InOut);
moveTween.onStart(() => {
rotateTween.start();
});
animations.push(moveTween);
});
for (let i = 0; i < animations.length; i++) {
const nextIndex = (i + 1) % animations.length;
animations[i].chain(animations[nextIndex]);
}
allAnimations = animations;
animations[0].start();
currentTween = animations[0];
startTweenUpdateLoop();
}
function startTweenUpdateLoop() {
function animate() {
TWEEN.update();
requestAnimationFrame(animate);
}
animate();
}
function togglePause() {
const pauseBtn = document.getElementById("pauseBtn");
if (isPaused) {
allAnimations.forEach((animation) => {
if (animation.isPaused && animation.isPaused()) {
animation.resume();
}
});
isPaused = false;
pauseBtn.textContent = "pause";
pauseBtn.className = "";
} else {
allAnimations.forEach((animation) => {
if (animation.pause) {
animation.pause();
}
});
isPaused = true;
pauseBtn.textContent = "play";
pauseBtn.className = "pause";
}
}
document.getElementById("pauseBtn").addEventListener("click", togglePause);
window.addEventListener("beforeunload", () => {
if (currentTween) {
currentTween.stop();
}
TWEEN.removeAll();
});
</script>
</html>
Common Animation Examples
Position Animation
// Move to target position
const moveTween = new TWEEN.Tween(element.position)
.to({ x: 10, y: 5, z: 0 }, 1000)
.easing(TWEEN.Easing.Quadratic.InOut)
.start();Rotation Animation
// Rotate 360 degrees around Y axis
const rotateTween = new TWEEN.Tween(element.rotation)
.to({ y: element.rotation.y + Math.PI * 2 }, 2000)
.easing(TWEEN.Easing.Cubic.InOut)
.start();Scale Animation
// Scale to 1.5x
const scaleTween = new TWEEN.Tween(element.scale)
.to({ x: 1.5, y: 1.5, z: 1.5 }, 1000)
.easing(TWEEN.Easing.Back.Out)
.start();Combined Animation
// Execute multiple animations simultaneously
const moveTween = new TWEEN.Tween(element.position).to({ x: 5, y: 3, z: 2 }, 2000);
const rotateTween = new TWEEN.Tween(element.rotation).to({ y: Math.PI }, 2000);
const scaleTween = new TWEEN.Tween(element.scale).to({ x: 1.2, y: 1.2, z: 1.2 }, 2000);
// Start simultaneously
moveTween.start();
rotateTween.start();
scaleTween.start();Chained Animation
// Execute animations sequentially
const firstTween = new TWEEN.Tween(element.position).to({ x: 5 }, 1000);
const secondTween = new TWEEN.Tween(element.position).to({ y: 5 }, 1000);
const thirdTween = new TWEEN.Tween(element.position).to({ z: 5 }, 1000);
// Chain animations
firstTween.chain(secondTween);
secondTween.chain(thirdTween);
firstTween.start();API
TWEEN
TWEEN library provides powerful animation capabilities:
| Method | Description | Parameters |
|---|---|---|
| constructor | Create new tween instance | (object: Object) |
| to | Set animation target | (properties: Object, duration: number) |
| easing | Set easing function | (easing: Function) |
| start | Start animation | () => Tween |
| stop | Stop animation | () => Tween |
| chain | Chain next animation | (...tweens: Tween[]) |
| yoyo | Enable yoyo animation | (yoyo: boolean) |
| repeat | Set repeat count | (times: number) |
| onUpdate | Animation update callback | (callback: Function) |
| onComplete | Animation complete callback | (callback: Function) |
Easing Functions
TWEEN provides rich easing functions:
TWEEN.Easing.Linear.None- LinearTWEEN.Easing.Quadratic.In/Out/InOut- QuadraticTWEEN.Easing.Cubic.In/Out/InOut- CubicTWEEN.Easing.Quartic.In/Out/InOut- QuarticTWEEN.Easing.Quintic.In/Out/InOut- QuinticTWEEN.Easing.Sinusoidal.In/Out/InOut- SinusoidalTWEEN.Easing.Exponential.In/Out/InOut- ExponentialTWEEN.Easing.Circular.In/Out/InOut- CircularTWEEN.Easing.Elastic.In/Out/InOut- ElasticTWEEN.Easing.Back.In/Out/InOut- BackTWEEN.Easing.Bounce.In/Out/InOut- Bounce
Element Properties
Common element properties that can be animated:
| Property | Description | Type |
|---|---|---|
| position | Position (x, y, z) | Vector3 |
| rotation | Rotation (x, y, z) | Euler |
| scale | Scale (x, y, z) | Vector3 |
Best Practices
- Performance Considerations: Avoid running too many animations simultaneously, properly use
stop()method to clean up animations - Memory Management: Use ref to save animation instances for better management and cleanup
- User Experience: Provide ways to stop animations, such as clicking empty area to stop
- Animation Composition: Properly use chained and parallel animations to create complex effects
- Easing Functions: Choose appropriate easing functions to make animations more natural
TWEEN Documentation
https://tweenjs.github.io/tween.js (opens in a new tab)
注意
⚠️
javascript version needs to import the TWEEN library separately to use TWEEN animations. And it is very important to start the rendering loop.
function startTweenUpdateLoop() {
function animate() {
TWEEN.update();
requestAnimationFrame(animate);
}
animate();
}