Tiny Transform Transitions 3D
- ✔️ Animate 3D objects using lambda functions
- ✔️ Can be used with any 3D library
- 🟦 Written in TypeScript
npm i @jgtools/ttt3d
import TTT3D from "@jgtools/ttt3d";
// ...
<script type="module">
import TTT3D from "https://cdn.jsdelivr.net/npm/@jgtools/[email protected]/dist/index.min.js";
// ...
</script>
Animating a jumping cube.
Create cube and define animations:
const geo = new THREE.BoxGeometry(1, 1, 1);
const mat = new THREE.MeshLambertMaterial({ color: 0x00ffff });
const cube = new THREE.Mesh(geo, mat);
scene.add(cube);
// create ttt3d instance
// [pos.x, pos.y, pos.z, rot.x, rot.y, rot.z, scale.x, scale.y, scale.z]
const origins = {
cube: [0, 0, 0, 0, 0, 0, 1, 1, 1],
};
const ttt = new TTT3D(origins);
// setup jump transition
ttt.add("jump", (c) => {
const t = Math.sin(c * Math.PI);
return {
cube: [0, t * 2, 0, 0, t * 4, 0, 0, t, 0],
};
});
// play jump transition every 3 seconds
setInterval(() => ttt.play("jump"), 3000);
Update each frame and apply result to mesh:
// update transition system
const res = ttt.update(delta);
// update mesh transform
const part = res["cube"];
cube.position.set(part[0], part[1], part[2]);
cube.rotation.set(part[3], part[4], part[5]);
cube.scale.set(part[6], part[7], part[8]);
Animating an idling, walking and jumping cube with legs.
Create player parts and define animations:
const player = new THREE.Group();
scene.add(player);
const matHead = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
const matFoot = new THREE.MeshLambertMaterial({ color: 0xff0000 });
const geo = new THREE.BoxGeometry();
const head = new THREE.Mesh(geo, matHead);
const rightFoot = new THREE.Mesh(geo, matFoot);
const leftFoot = new THREE.Mesh(geo, matFoot);
player.add(head);
player.add(rightFoot);
player.add(leftFoot);
const playerParts = new Map();
playerParts.set("head", head);
playerParts.set("rightFoot", rightFoot);
playerParts.set("leftFoot", leftFoot);
// setup ttt3d with default transforms
const origins = {
head: [0, 0.8, 0, 0, 0, 0, 1, 1, 1],
rightFoot: [-0.3, -0.5, 0, 0, 0, 0, 0.4, 0.3, 0.6],
leftFoot: [0.3, -0.5, 0, 0, 0, 0, 0.4, 0.3, 0.6],
};
const ttt = new TTT3D(origins);
// create animations
ttt.add("idle", (c) => {
const t = Math.sin(c * Math.PI);
return {
head: [0, t * 0.1],
};
});
ttt.add("walk", (c) => {
const t = Math.sin(c * Math.PI * 2);
return {
head: [0, 0, 0.2 * t],
rightFoot: [0, 0, t * 0.3, -0.2 * t],
leftFoot: [0, 0, -t * 0.3, 0.2 * t],
};
});
ttt.add("jump", (c) => {
const t = Math.sin(c * Math.PI);
const hs = outElastic(t);
return {
head: [0, t, 0, -t * 0.4, 0, 0, -hs * 0.4, hs * 0.5, -hs * 0.4],
rightFoot: [0, t, 0, t],
leftFoot: [0, t * 1.3, 0, t * 1.5],
};
});
ttt.play("idle", 1, true);
ttt.play("walk", 0.6, true);
setInterval(() => ttt.play("jump", 0.6), 3000);
let isWalking = true;
setInterval(() => isWalking = !isWalking, 5000);
Update each frame and apply result to meshes:
// blend smoothly between the walk and idle
const BLEND_SPEED = 3;
let w = ttt.getWeight("idle") || 0;
w += delta * (isWalking ? -BLEND_SPEED : BLEND_SPEED);
w = Math.min(Math.max(0, w), 1);
ttt.setWeight("idle", w);
ttt.setWeight("walk", 1 - w);
// update ttt and apply transforms to meshes
const res = ttt.update(delta);
for (const [k, e] of playerParts) {
e.position.set(res[k][0], res[k][1], res[k][2]);
e.rotation.set(res[k][3], res[k][4], res[k][5]);
e.scale.set(res[k][6], res[k][7], res[k][8]);
}
Create a new TTT3D instance.
Add a new animation.
Play an animation.
Stop an animation.
Update the transition system and return the result.
Set the weight of an animation.
Set the rate of an animation.
Set whether an animation loops.
Set the counter value of an animation.
Get the weight of an animation.
Get the rate of an animation.
Get whether an animation loops.
Get the counter value of an animation.
npm i
npm run build
MIT