1.1.0 • Published 8 months ago

@jgtools/ttt3d v1.1.0

Weekly downloads
-
License
MIT
Repository
github
Last release
8 months ago

TTT3D

npm npm GitHub

Tiny Transform Transitions 3D

Features

  • :heavy_check_mark: Animate 3D objects using lambda functions
  • :heavy_check_mark: Can be used with any 3D library
  • :blue_square: Written in TypeScript

Installation

Using npm

npm i @jgtools/ttt3d
import TTT3D from "@jgtools/ttt3d";
// ...

Using cdn

<script type="module">
    import TTT3D from "https://cdn.jsdelivr.net/npm/@jgtools/ttt3d@1.1.0/dist/index.min.js";
    // ...
</script>

Usage

Simple example

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]);

Advanced example

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]);
}

Docs

new TTT3D(origins: { [key: string]: number[] })

Create a new TTT3D instance.

add(name: string, fn: (c: number) => number[]): void

Add a new animation.

play(name: string, speed: number = 1, loop: boolean = false): void

Play an animation.

stop(name: string): void

Stop an animation.

update(delta: number): { [key: string]: number[] }

Update the transition system and return the result.

setWeight(name: string, weight: number): void

Set the weight of an animation.

setRate(name: string, rate: number): void

Set the rate of an animation.

setLoop(name: string, loop: boolean): void

Set whether an animation loops.

setCounter(name: string, counter: number): void

Set the counter value of an animation.

getWeight(name: string): number

Get the weight of an animation.

getRate(name: string): number

Get the rate of an animation.

getLoop(name: string): boolean

Get whether an animation loops.

getCounter(name: string): number

Get the counter value of an animation.

Build Instructions

npm i
npm run build

License

MIT

1.1.0

8 months ago

1.0.8

9 months ago

1.0.7

1 year ago

1.0.6

1 year ago

1.0.5

1 year ago

1.0.4

1 year ago

1.0.3

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago