Skip to content

Instantly share code, notes, and snippets.

@e1blue
Created March 21, 2018 13:52
Show Gist options
  • Save e1blue/5ff46636e2766801215110fc5702e0a6 to your computer and use it in GitHub Desktop.
Save e1blue/5ff46636e2766801215110fc5702e0a6 to your computer and use it in GitHub Desktop.
Jack in a Box Factory

Jack in a Box Factory

These Jack in a boxes are all made, tested and then discarded straight away. Not sure how this factory makes any money.

Made with GSAP and Three.js. Everything except the face texture was created in code.

A Pen by Steve Gardner on CodePen.

License.

console.clear();
declare var THREE:any;
declare var TweenMax:any;
declare var TimelineMax:any;
declare var Bounce:any;
declare var Power2:any;
declare var Power3:any;
declare var Elastic:any;
TweenMax.lagSmoothing(0);
THREE.ImageUtils.crossOrigin = '';
interface JackInABox {
jack: Jack;
box: Box;
group: any;
}
let colors =
{
blue: '#4281A4',
green: '#48A9A6',
background: '#D0CBC7',
ground: '#E4DFDA',
yellow: '#D4B483',
red: '#C1666B',
lid: '#B05D62',
skin: '#F5D6BA'
}
let settings =
{
openSpeed: 0.8
}
let Utils =
{
degToRad: function(degrees)
{
return degrees * Math.PI / 180;
}
}
class Stage
{
floor: any;
private container: any;
private camera: any;
private scene: any;
private renderer: any;
private light: any;
private softLight: any;
private group: any;
constructor()
{
// container
this.container = document.createElement( 'div' );
document.body.appendChild( this.container );
// renderer
this.renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: false
});
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.setClearColor(colors.background, 1);
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.container.appendChild( this.renderer.domElement );
// scene
this.scene = new THREE.Scene();
//this.scene.fog = new THREE.Fog( colors.ground, 0, 10);
// camera
let aspect = window.innerWidth / window.innerHeight;
let d = 20;
this.camera = new THREE.OrthographicCamera( - d * aspect, d * aspect, d, - d, -100, 1000);
this.camera.position.x = 30;
this.camera.position.y = 10;
this.camera.position.z = -10;
this.camera.lookAt(new THREE.Vector3(0, 5, 0));
//light
this.light = new THREE.DirectionalLight(0xffffff, 0.5);
this.light.castShadow = true;
this.light.position.set(8, 15, -5);
this.scene.add(this.light);
this.softLight = new THREE.AmbientLight( 0xffffff, 0.5 );
this.scene.add(this.softLight)
// floor
var width = 500;
var depth = 1000;
var geometry = new THREE.PlaneGeometry(depth, width);
var material = new THREE.MeshBasicMaterial({
color: colors.ground,
shading: THREE.FlatShading
});
var plane = new THREE.Mesh(geometry, material);
plane.rotation.x = -Utils.degToRad(90); //1.57079633;
plane.position.y = 0;
plane.position.z = - width / 2;
this.floor = new THREE.Group();
this.floor.add(plane);
this.scene.add(this.floor);
// group
this.group = new THREE.Group();
this.scene.add(this.group);
}
render = function()
{
this.renderer.render(this.scene, this.camera);
}
add = function(elem)
{
this.scene.add(elem);
}
remove = function(elem)
{
this.scene.remove(elem);
}
}
class Box
{
group: any;
private lid: any;
private crank: any;
private openAnimation = new TimelineMax();
private closeAnimation = new TimelineMax();
private dropAnimation = new TimelineMax();
private fallAnimation = new TimelineMax();
closed: boolean;
private crankSpeed: number;
private crankAnimation: any;
constructor()
{
this.closed = true;
this.group = new THREE.Group();
var material = new THREE.MeshToonMaterial({
color: colors.red
});
var geometry = new THREE.BoxGeometry(4, 1, 4);
var boxBottom = new THREE.Mesh(geometry, material);
boxBottom.position.y = 0.5;
//boxBottom.castShadow = true;
//boxBottom.receiveShadow = true;
var geometry = new THREE.BoxGeometry(6, 1, 6);
var boxBack = new THREE.Mesh(geometry, material);
boxBack.position.y = 2.5;
boxBack.position.x = -2.5;
boxBack.rotation.z = Utils.degToRad(90);
//boxBack.castShadow = true;
//boxBack.receiveShadow = true;
var geometry = new THREE.BoxGeometry(6, 1, 6);
var boxFront = new THREE.Mesh(geometry, material);
boxFront.position.y = 2.5;
boxFront.position.x = 2.5;
boxFront.rotation.z = Utils.degToRad(90);
//boxFront.castShadow = true;
//boxFront.receiveShadow = true;
var geometry = new THREE.BoxGeometry(4, 1, 6);
var boxLeft = new THREE.Mesh(geometry, material);
boxLeft.position.y = 2.5;
boxLeft.position.z = 2.5;
boxLeft.rotation.x = Utils.degToRad(90);
//boxLeft.castShadow = true;
//boxLeft.receiveShadow = true;
var geometry = new THREE.BoxGeometry(4, 1, 6);
var boxRight = new THREE.Mesh(geometry, material);
boxRight.position.y = 2.5;
boxRight.position.z = -2.5;
boxRight.rotation.x = Utils.degToRad(90);
//boxRight.castShadow = true;
//boxRight.receiveShadow = true;
var geometry = new THREE.BoxGeometry(6, 1.75, 6);
geometry.applyMatrix(new THREE.Matrix4().makeTranslation(3, 1, 0));
var material = new THREE.MeshToonMaterial({
color: colors.lid
});
this.lid = new THREE.Mesh(geometry, material);
this.lid.position.y = 5.4;
this.lid.position.x = -3;
//this.lid.castShadow = true;
//this.lid.receiveShadow = true;
this.group.add(this.lid);
this.group.add(boxBottom);
this.group.add(boxBack);
this.group.add(boxLeft);
this.group.add(boxRight);
this.group.add(boxFront);
this.crank = new THREE.Group();
var geometry = new THREE.CylinderGeometry(0.3, 0.3, 0.6, 8);
var material = new THREE.MeshToonMaterial({
color: colors.yellow
});
var axel = new THREE.Mesh(geometry, material);
axel.rotation.x = Utils.degToRad(90);
//axel.castShadow = true;
//axel.receiveShadow = true;
var geometry = new THREE.BoxGeometry(1, 0.3, 3, 8);
var material = new THREE.MeshToonMaterial({
color: colors.yellow
});
var shaft = new THREE.Mesh(geometry, material);
shaft.position.y = 1;
shaft.rotation.x = Utils.degToRad(90);
//shaft.castShadow = true;
//shaft.receiveShadow = true;
var geometry = new THREE.CylinderGeometry(0.5, 0.5, 1, 8);
var material = new THREE.MeshToonMaterial({
color: colors.yellow
});
var handle = new THREE.Mesh(geometry, material);
handle.position.z = -0.6;
handle.position.y = 2;
handle.rotation.x = Utils.degToRad(90);
//handle.castShadow = true;
//handle.receiveShadow = true;
this.crank.add(axel);
this.crank.add(shaft);
this.crank.add(handle);
this.crank.position.z = -3.5;
this.crank.position.y = 3.5;
this.crank.rotation.z = Utils.degToRad(Math.random() * 360);
this.group.add(this.crank);
this.group.position.y = 20;
this.setAnimation();
}
setAnimation = function()
{
var speed = 1;
var boxBounceSpeed = speed / 3;
this.openAnimation.clear();
this.openAnimation.stop();
this.openAnimation.to(this.group.position, boxBounceSpeed, {
y: 4,
delay: 0,
ease: Power2.easeInOut
});
this.openAnimation.to(this.group.position, boxBounceSpeed * 2, {
y: 0,
x: 0,
z: 0,
ease: Bounce.easeOut
});
this.openAnimation.to(this.lid.rotation, speed, {
z: 2,
ease: Bounce.easeOut
}, 0);
this.openAnimation.to(this.crank.rotation, speed * 3, {
z: Utils.degToRad(180),
ease: Elastic.easeOut
}, 0);
// -----
this.crankSpeed = 0;
this.crankAnimation = setInterval(() => {this.moveCrank()}, 20);
// -----
this.dropAnimation.clear();
this.dropAnimation.stop();
this.dropAnimation.to(this.group.position, 1, {y: 0, delay: 0.5, ease: Bounce.easeOut});
// -----
this.fallAnimation.clear();
this.fallAnimation.stop();
this.fallAnimation.to(this.group.position, 1, {y: -20, delay: 0.2, ease: Power3.easeIn});
this.fallAnimation.to(this.group.rotation, 1, {x: Utils.degToRad(120), delay: 0.2, ease: Power3.easeIn}, 0);
}
moveCrank = function()
{
if (this.closed)
{
this.crank.rotation.z = this.crank.rotation.z > Utils.degToRad(360) ? 0 : this.crank.rotation.z + this.crankSpeed;
if (this.crankSpeed < 0.1) this.crankSpeed += 0.005;
}
}
add = function(elem)
{
this.group.add(elem);
}
stopAnimations = function()
{
this.openAnimation.stop();
this.closeAnimation.stop();
}
open = function(skipAnimation:boolean = false)
{
this.closed = false;
//this.stopAnimations();
this.openAnimation.duration(skipAnimation ? 0.1 : 3);
this.openAnimation.restart();
}
close = function()
{
this.closed = true;
//this.stopAnimations();
this.closeAnimation.duration(3);
this.closeAnimation.restart();
}
drop = function(skipAnimation:boolean = false)
{
this.dropAnimation.duration(skipAnimation ? 0.1 : 1);
this.dropAnimation.restart();
}
fall = function(skipAnimation:boolean = false)
{
this.fallAnimation.duration(skipAnimation ? 0.1 : 1);
this.fallAnimation.restart();
}
}
class Jack
{
group: any;
private body: any;
private head: any;
private leftHand: any;
private rightHand: any;
private openAnimation = new TimelineMax();
private closeAnimation = new TimelineMax();
private moveAnimation = new TimelineMax();
constructor(color: string, face: string)
{
this.group = new THREE.Group();
var geometry = new THREE.CylinderGeometry(1.1, 1.3, 2.5, 15);
var material = new THREE.MeshToonMaterial({
color: color
});
this.body = new THREE.Mesh(geometry, material);
this.body.position.y = 2.5;
//this.body.castShadow = true;
//this.body.receiveShadow = true;
var material = new THREE.MeshToonMaterial({
color: colors.skin,
map: face
});
var geometry = new THREE.SphereGeometry(1.7, 32, 32);
this.head = new THREE.Mesh(geometry, material);
this.head.position.y = 4;
//this.head.castShadow = true;
//this.head.receiveShadow = true;
var material = new THREE.MeshToonMaterial({
color: colors.skin
});
var geometry = new THREE.SphereGeometry(0.5, 32, 32);
this.leftHand = new THREE.Mesh(geometry, material);
this.leftHand.position.z = -1.5;
this.leftHand.position.y = 2;
//this.leftHand.castShadow = true;
//this.leftHand.receiveShadow = true;
var geometry = new THREE.SphereGeometry(0.5, 32, 32);
this.rightHand = new THREE.Mesh(geometry, material);
this.rightHand.position.z = 1.5;
this.rightHand.position.y = 2;
//this.rightHand.castShadow = true;
//this.rightHand.receiveShadow = true;
this.group.add(this.body);
this.group.add(this.head);
this.group.add(this.leftHand);
this.group.add(this.rightHand);
this.setAnimation();
}
setAnimation = function()
{
var speed = 1;
// open animation
this.openAnimation.clear();
this.openAnimation.stop();
var jackDelay = 0.2;
this.openAnimation.to(this.group.position, speed * 2, {
y: 5,
ease: Elastic.easeOut
}, jackDelay);
this.openAnimation.to(this.leftHand.position, speed * 2, {
z: -2.1,
y: 3.8,
ease: Elastic.easeOut
}, jackDelay)
this.openAnimation.to(this.rightHand.position, speed * 2, {
z: 2.1,
y: 3.8,
ease: Elastic.easeOut
}, jackDelay)
this.openAnimation.to(this.group.rotation, speed / 3, {
x: Math.random() - 0.5,
z: Math.random() - 0.5,
ease: Power3.easeInOut
}, jackDelay);
this.openAnimation.to(this.group.rotation, speed * 4, {
x: 0,
z: (Math.random() / 10) - 0.1,
ease: Elastic.easeOut
}, speed / 3);
this.openAnimation.to(this.head.position, speed * 3, {
y: 6,
ease: Elastic.easeOut
}, jackDelay)
// move animation
this.moveAnimation.clear();
this.moveAnimation.stop();
this.moveAnimation.to(this.group.rotation, 0.6, {
x: -0.5,
ease: Power3.easeIn
}, 0);
this.moveAnimation.to(this.group.rotation, speed * 2, {
x: 0,
ease: Elastic.easeOut
});
}
stopAnimations = function()
{
this.openAnimation.pause();
this.closeAnimation.pause();
this.moveAnimation.pause();
}
open = function(skipAnimation:boolean = false)
{
this.openAnimation.duration(skipAnimation ? 0.1 : 3);
this.openAnimation.restart();
}
close = function()
{
//this.stopAnimations();
//this.closeAnimation.duration(6);
this.closeAnimation.restart();
}
move = function(speed: number)
{
this.moveAnimation.restart();
}
}
class Dispenser
{
group: any;
private tube: any;
private lidLeft: any;
private lidRight: any;
private openAnimation = new TimelineMax();
constructor()
{
this.group = new THREE.Group();
var geometry = new THREE.BoxGeometry(10, 30, 10);
geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0, 15, 0));
var material = new THREE.MeshToonMaterial({
color: '#eeeeee'
});
this.tube = new THREE.Mesh(geometry, material);
this.group.add(this.tube);
var geometry = new THREE.BoxGeometry(10, 1, 5);
geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0, -0.5, 2.5));
var material = new THREE.MeshToonMaterial({
color: '#dddddd'
});
this.lidLeft = new THREE.Mesh(geometry, material);
this.group.add(this.lidLeft);
var geometry = new THREE.BoxGeometry(10, 1, 5);
geometry.applyMatrix(new THREE.Matrix4().makeTranslation(0, -0.5, -2.5));
var material = new THREE.MeshToonMaterial({
color: '#dddddd'
});
this.lidRight = new THREE.Mesh(geometry, material);
this.group.add(this.lidRight);
this.lidLeft.position.z = -5
this.lidLeft.rotation.x = Utils.degToRad(90)
this.lidRight.position.z = 5
this.lidRight.rotation.x = Utils.degToRad(-90)
this.setAnimation();
}
setAnimation = function()
{
this.openAnimation.clear();
this.openAnimation.stop();
this.openAnimation.fromTo(this.lidRight.rotation, 1, {x: Utils.degToRad(0)}, {x: Utils.degToRad(-90), ease: Elastic.easeOut}, 0);
this.openAnimation.fromTo(this.lidLeft.rotation, 1, {x: Utils.degToRad(0)}, {x: Utils.degToRad(90), ease: Elastic.easeOut}, 0);
this.openAnimation.fromTo(this.lidRight.rotation, 0.5,{x: Utils.degToRad(-90)}, {x: Utils.degToRad(0), ease: Power3.easeInOut}, 1.5);
this.openAnimation.fromTo(this.lidLeft.rotation, 0.5, {x: Utils.degToRad(90)}, {x: Utils.degToRad(0), ease: Power3.easeInOut}, 1.5);
}
open = function()
{
this.openAnimation.restart();
}
}
class App
{
private colorChoices: string[];
private face: any;
private stage: Stage;
private dispenser: Dispenser;
private jacks: JackInABox[];
private time: number = 4;
private count: number = 0;
private belt: any;
private beltTexture: any;
constructor(count:number = 5)
{
this.count = count;
this.jacks = [];
this.face = THREE.ImageUtils.loadTexture('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAtAAAAEACAYAAACagUEuAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABV0RVh0Q3JlYXRpb24gVGltZQAxMy80LzE2VqbobgAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAA9LSURBVHic7d1diJV1HsDx33Ne5oyjzoyao07DZI0ppr3Q5q7NhLAv7GIUXRRtS0Et3iQFJd0s1LJEsUXUxlbQTSzsRQlLu8su7G53UoZ2ERFmEBm0ma69aNOWk6bjnL0ol7AX5+885zznnPl8QATl/P4/Fc58fXjmOVm9Xq8HAAAwLaWiFwAAgHYioAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIIGABgCABAIaAAASCGgAAEggoAEAIEGl6AUAWt3k5GTs3LkzduzYEbt27Yp9+/bFxMRERET09PTE0NBQrF27NsbGxmJ0dDSq1WrBG3/h6NGj8cILL8SOHTvijTfeiH379sXRo0cjIqK3tzeGh4fjwgsvjA0bNsT3vve9KJVcUwGYjqxer9eLXgKgFR07diy2bt0azzzzTBw6dGhar+nv74+bbropbrjhhuju7m7wht/sk08+iT/+8Y/x7LPP/j/0T2fZsmXxy1/+Mq655pool8sN3hCgvQlogG/w6quvxm9+85vYv3//Gb1+2bJlce+998all16a82bfbdu2bfHb3/42xsfHz+j1K1eujPvuuy9GRkZy3gygcwhogFP89a9/jQceeCCmpqZmNKdUKsVdd90VP//5z3Pa7NvV6/V48skn4w9/+MOMZ9Vqtbj//vvjhz/8YQ6bAXQeAQ3wFX/605/ioYceynXmli1b4sYbb8x15ql+97vfxTPPPJPbvFKpFA8++GD86Ec/ym0mQKfwHSMAX3rppZfi4Ycfzn3uo48+Gi+88ELuc0/685//nGs8R0RMTU3FPffcE2+++WaucwE6gSvQAPHFN95dd9118dFHHzVkfm9vb/zlL3+J/v7+XOfu3bs3brjhhjh27Fiuc09avnx5bN26tWWeLALQClyBBoiIp556qmHxHPFFoD/55JO5z3300UcbFs8REf/+979j69atDZsP0I4ENDDrjY+Px7PPPtvwc/72t7/Fhx9+mNu8N998M7Zv357bvG/z9NNPNzTSAdqNgAZmveeee64pgTg5ORn/+te/cpv397//PbdZ3+XQoUPx4osvNuUsgHYgoIFZrxlXcU96/vnnW3LW6TTymyAB2o2ABma1er0er732WtPOe/311+PEiRMznnPw4ME4cOBADhtNz65du5p2FkCrE9DArHbw4ME4cuRI086bnJw84083/Kp33nknh22mb9++fTE5OdnUMwFalYAGZrUz/cjrmfj0009nPOOTTz7JYZPpm5qais8++6ypZwK0KgEN0GR53MIx048ZPxN57A3QCQQ0MKvNnTu36WfOmzdvxjN6enpy2KT1zwRoRQIamNWWLFkS5XK5aedlWRZnn332jOcMDw/nsM30DQwMRK1Wa+qZAK1KQAOzWqVSiZUrVzbtvJGRkVxCdNmyZdHX15fDRtOzevXqpp0F0OoENDDrXXHFFU07a3R0NJc5pVIp1q9fn8us6RgbG2vaWQCtTkADs97GjRsjy7KmnHXVVVe15Kzv0tXVFT/5yU+achZAOxDQwKw3PDwcGzZsaPg5o6Ojcd555+U2b/369U25/eTaa6+N3t7ehp8D0C4ENEBE3HHHHdHV1dWw+eVyOe68885cZ2ZZFlu2bMl15ql6e3tj06ZNDT0DoN0IaID44ir07bff3rD5mzdvzvXq80nr1q2L66+/Pve5J919993R39/fsPkA7UhAA3zpF7/4RVx99dW5z/3pT38aN998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');
//this.beltTexture = THREE.ImageUtils.loadTexture('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAo0lEQVQ4T92SOw7EIAxEbYlAGhoUag7CJbhDLsCpU6RKRxE+K7wbqqzcQ2MhzYzFY9A51+B31nUFa+1z/TtzznAcByAiIACMANb5IpghQGs9GCilYNs2FsV933CeJ+kwxkgBrTUQQrDmR1BrJc8MEL33xKC/qTfRGMNyKKUQRGpiCGFAlFKC1poN6Muu6/r+wgRV3vd9NLEXaVkWlkEXpJRI9wF2LD6fpIaHQwAAAABJRU5ErkJggg==');
this.colorChoices = [colors.blue];//, colors.green, colors.yellow];
this.stage = new Stage();
this.stage.floor.position.z = (Math.floor(this.count / 2) * 15) - 8;
this.stage.floor.position.y = -1.5;
this.dispenser = new Dispenser();
this.dispenser.group.position.y = 16;
this.dispenser.group.position.z = Math.floor(this.count / 2) * -15;
this.stage.add(this.dispenser.group);
var width = this.count * 20;
var depth = 30;
var geometry = new THREE.PlaneGeometry(depth, width);
var material = new THREE.MeshBasicMaterial({
color: '#777777',
shading: THREE.FlatShading,
//map: this.beltTexture
});
//this.beltTexture.repeat.y = 100;
//this.beltTexture.wrapS = this.beltTexture.wrapT = THREE.RepeatWrapping;
//this.beltTexture.repeat.set( depth / 8, width / 8 );
var plane = new THREE.Mesh(geometry, material);
plane.rotation.x = -Utils.degToRad(90); //1.57079633;
plane.position.y = -1;
plane.position.z = - width / 2;
this.belt = new THREE.Group();
this.belt.add(plane);
this.stage.add(this.belt)
this.belt.position.z = - Math.floor(this.count / 2) * -11;
this.tick();
while(this.jacks.length < this.count)
{
this.addJack(true);
}
this.move(true);
}
tick = function()
{
this.stage.render();
requestAnimationFrame(() => {this.tick()});
}
addJack = function(skipAnimation:boolean = false)
{
let jack = new Jack(this.colorChoices[Math.floor(Math.random() * this.colorChoices.length)], this.face);
let box = new Box();
let group = new THREE.Group();
group.position.z = Math.floor(this.count / 2) * -15;
box.add(jack.group);
group.add(box.group);
this.jacks.push({box: box, jack: jack, group: group});
this.stage.add(group);
box.drop(skipAnimation);
this.dispenser.open();
}
move = function(skipAnimation:boolean = false)
{
while(this.jacks.length >= this.count)
{
let removed = this.jacks.shift();
if(removed) this.stage.remove(removed.group)
}
for(let i = this.jacks.length - 1; i >= 0; i--)
{
if(this.jacks[i])
{
var box: Box = this.jacks[i].box;
var jack: Jack = this.jacks[i].jack;
var group: any = this.jacks[i].group;
if(!box.closed) this.jacks[i].jack.move(2.2);
if(i <= Math.floor(this.count / 2) && box.closed)
{
if(i != Math.floor(this.count / 2))
{
this.jacks[i].box.open(true);
this.jacks[i].jack.open(true);
}
else setTimeout(() =>
{
this.jacks[i].box.open();
this.jacks[i].jack.open();
}, 1000);
}
if(i == 0)
{
this.jacks[i].box.fall(skipAnimation);
}
TweenMax.to(group.position, skipAnimation ? 0 : 1, {z: (Math.floor(this.count/2) - i) * 15, ease:Power3.easeInOut});
//TweenMax.to(this.beltTexture.offset, skipAnimation ? 0 : 1, {y: '+=0.5', ease:Power3.easeInOut});
}
}
this.addJack();
setTimeout(() => {this.move()}, this.time * 1000);
}
}
let app = new App(5);
<script src="//codepen.io/steveg3003/pen/zBVakw"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenMax.min.js"></script>
html, body
{
margin: 0;
overflow: hidden;
height: 100%;
width: 100%;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment