Forráskód Böngészése

Merge branch 'animations-disconnect'

David Catuhe 6 éve
szülő
commit
d51e37b723

+ 1 - 1
dist/preview release/packagesSizeBaseLine.json

@@ -1 +1 @@
-{"engineOnly":303950,"sceneOnly":567058,"minGridMaterial":695590,"minStandardMaterial":791420}
+{"engineOnly":303948,"sceneOnly":512262,"minGridMaterial":640875,"minStandardMaterial":761667}

+ 1 - 1
loaders/src/glTF/2.0/Extensions/MSFT_audio_emitter.ts

@@ -2,7 +2,7 @@ import { Nullable } from "babylonjs/types";
 import { Vector3 } from "babylonjs/Maths/math";
 import { Tools } from "babylonjs/Misc/tools";
 import { AnimationGroup } from "babylonjs/Animations/animationGroup";
-import { AnimationEvent } from "babylonjs/Animations/animation";
+import { AnimationEvent } from "babylonjs/Animations/animationEvent";
 import { TransformNode } from "babylonjs/Meshes/transformNode";
 import { Sound } from "babylonjs/Audio/sound";
 import { WeightedSound } from "babylonjs/Audio/weightedsound";

+ 2 - 2
loaders/src/glTF/2.0/glTFLoader.ts

@@ -5,7 +5,7 @@ import { LoadFileError, IFileRequest, Tools } from "babylonjs/Misc/tools";
 import { Camera } from "babylonjs/Cameras/camera";
 import { FreeCamera } from "babylonjs/Cameras/freeCamera";
 import { AnimationGroup } from "babylonjs/Animations/animationGroup";
-import { Animation, IAnimationKey, AnimationKeyInterpolation } from "babylonjs/Animations/animation";
+import { Animation } from "babylonjs/Animations/animation";
 import { Bone } from "babylonjs/Bones/bone";
 import { Skeleton } from "babylonjs/Bones/skeleton";
 import { IParticleSystem } from "babylonjs/Particles/IParticleSystem";
@@ -22,11 +22,11 @@ import { MorphTarget } from "babylonjs/Morph/morphTarget";
 import { MorphTargetManager } from "babylonjs/Morph/morphTargetManager";
 import { SceneLoaderProgressEvent } from "babylonjs/Loading/sceneLoader";
 import { Scene } from "babylonjs/scene";
-
 import { IProperty, AccessorType, CameraType, AnimationChannelTargetPath, AnimationSamplerInterpolation, AccessorComponentType, MaterialAlphaMode, TextureMinFilter, TextureWrapMode, TextureMagFilter, MeshPrimitiveMode } from "babylonjs-gltf2interface";
 import { _IAnimationSamplerData, IGLTF, ISampler, INode, IScene, IMesh, IAccessor, ISkin, ICamera, IAnimation, IAnimationChannel, IAnimationSampler, IBuffer, IBufferView, IMaterialPbrMetallicRoughness, IMaterial, ITextureInfo, ITexture, IImage, IMeshPrimitive, IArrayItem as IArrItem, _ISamplerData } from "./glTFLoaderInterfaces";
 import { IGLTFLoaderExtension } from "./glTFLoaderExtension";
 import { IGLTFLoader, GLTFFileLoader, GLTFLoaderState, IGLTFLoaderData, GLTFLoaderCoordinateSystemMode, GLTFLoaderAnimationStartMode } from "../glTFFileLoader";
+import { IAnimationKey, AnimationKeyInterpolation } from 'babylonjs/Animations/animationKey';
 
 interface IFileRequestInfo extends IFileRequest {
     _lengthComputable?: boolean;

+ 2 - 1
serializers/src/glTF/2.0/glTFAnimation.ts

@@ -3,13 +3,14 @@ import { AnimationSamplerInterpolation, AnimationChannelTargetPath, AccessorType
 import { Nullable } from "babylonjs/types";
 import { Vector3, Quaternion } from "babylonjs/Maths/math";
 import { Tools } from "babylonjs/Misc/tools";
-import { Animation, IAnimationKey, AnimationKeyInterpolation } from "babylonjs/Animations/animation";
+import { Animation } from "babylonjs/Animations/animation";
 import { TransformNode } from "babylonjs/Meshes/transformNode";
 import { Mesh } from "babylonjs/Meshes/mesh";
 import { Scene } from "babylonjs/scene";
 
 import { _BinaryWriter } from "./glTFExporter";
 import { _GLTFUtilities } from "./glTFUtilities";
+import { IAnimationKey, AnimationKeyInterpolation } from 'babylonjs/Animations/animationKey';
 
 /**
  * @hidden

+ 574 - 0
src/Animations/animatable.ts

@@ -4,6 +4,10 @@ import { RuntimeAnimation } from "./runtimeAnimation";
 import { Nullable } from "../types";
 import { Observable } from "../Misc/observable";
 import { Scene } from "../scene";
+import { Matrix, Quaternion, Tmp, Vector3 } from '../Maths/math';
+import { PrecisionDate } from '../Misc/precisionDate';
+import { Bone } from '../Bones/bone';
+import { Node } from "../node";
 
 /**
  * Class used to store an actual running animation
@@ -421,3 +425,573 @@ export class Animatable {
         return running;
     }
 }
+
+declare module "../scene" {
+    export interface Scene {
+        /** @hidden */
+        _registerTargetForLateAnimationBinding(runtimeAnimation: RuntimeAnimation, originalValue: any): void;
+
+        /** @hidden */
+        _processLateAnimationBindingsForMatrices(holder: {
+            totalWeight: number,
+            animations: RuntimeAnimation[],
+            originalValue: Matrix
+        }): any;
+
+        /** @hidden */
+        _processLateAnimationBindingsForQuaternions(holder: {
+            totalWeight: number,
+            animations: RuntimeAnimation[],
+            originalValue: Quaternion
+        }, refQuaternion: Quaternion): Quaternion;
+
+        /** @hidden */
+        _processLateAnimationBindings(): void;
+
+        /** @hidden */
+        _animate(): void;
+
+        /**
+         * Will start the animation sequence of a given target
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param weight defines the weight to apply to the animation (1.0 by default)
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @param targetMask defines if the target should be animated if animations are present (this is called recursively on descendant animatables regardless of return value)
+         * @param onAnimationLoop defines the callback to call when an animation loops
+         * @returns the animatable object created for this animation
+         */
+        beginWeightedAnimation(target: any, from: number, to: number, weight: number, loop?: boolean, speedRatio?: number,
+            onAnimationEnd?: () => void, animatable?: Animatable, targetMask?: (target: any) => boolean, onAnimationLoop?: () => void): Animatable;
+
+        /**
+         * Will start the animation sequence of a given target
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @param stopCurrent defines if the current animations must be stopped first (true by default)
+         * @param targetMask defines if the target should be animate if animations are present (this is called recursively on descendant animatables regardless of return value)
+         * @param onAnimationLoop defines the callback to call when an animation loops
+         * @returns the animatable object created for this animation
+         */
+        beginAnimation(target: any, from: number, to: number, loop?: boolean, speedRatio?: number,
+            onAnimationEnd?: () => void, animatable?: Animatable, stopCurrent?: boolean,
+            targetMask?: (target: any) => boolean, onAnimationLoop?: () => void): Animatable;
+
+        /**
+         * Will start the animation sequence of a given target and its hierarchy
+         * @param target defines the target
+         * @param directDescendantsOnly if true only direct descendants will be used, if false direct and also indirect (children of children, an so on in a recursive manner) descendants will be used.
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @param stopCurrent defines if the current animations must be stopped first (true by default)
+         * @param targetMask defines if the target should be animated if animations are present (this is called recursively on descendant animatables regardless of return value)
+         * @param onAnimationLoop defines the callback to call when an animation loops
+         * @returns the list of created animatables
+         */
+        beginHierarchyAnimation(target: any, directDescendantsOnly: boolean, from: number, to: number, loop?: boolean, speedRatio?: number,
+            onAnimationEnd?: () => void, animatable?: Animatable, stopCurrent?: boolean,
+            targetMask?: (target: any) => boolean, onAnimationLoop?: () => void): Animatable[];
+
+        /**
+         * Begin a new animation on a given node
+         * @param target defines the target where the animation will take place
+         * @param animations defines the list of animations to start
+         * @param from defines the initial value
+         * @param to defines the final value
+         * @param loop defines if you want animation to loop (off by default)
+         * @param speedRatio defines the speed ratio to apply to all animations
+         * @param onAnimationEnd defines the callback to call when an animation ends (will be called once per node)
+         * @param onAnimationLoop defines the callback to call when an animation loops
+         * @returns the list of created animatables
+         */
+        beginDirectAnimation(target: any, animations: Animation[], from: number, to: number, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void, onAnimationLoop?: () => void): Animatable;
+
+        /**
+         * Begin a new animation on a given node and its hierarchy
+         * @param target defines the root node where the animation will take place
+         * @param directDescendantsOnly if true only direct descendants will be used, if false direct and also indirect (children of children, an so on in a recursive manner) descendants will be used.
+         * @param animations defines the list of animations to start
+         * @param from defines the initial value
+         * @param to defines the final value
+         * @param loop defines if you want animation to loop (off by default)
+         * @param speedRatio defines the speed ratio to apply to all animations
+         * @param onAnimationEnd defines the callback to call when an animation ends (will be called once per node)
+         * @param onAnimationLoop defines the callback to call when an animation loops
+         * @returns the list of animatables created for all nodes
+         */
+        beginDirectHierarchyAnimation(target: Node, directDescendantsOnly: boolean, animations: Animation[], from: number, to: number, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void, onAnimationLoop?: () => void): Animatable[];
+
+        /**
+         * Gets the animatable associated with a specific target
+         * @param target defines the target of the animatable
+         * @returns the required animatable if found
+         */
+        getAnimatableByTarget(target: any): Nullable<Animatable>;
+
+        /**
+         * Gets all animatables associated with a given target
+         * @param target defines the target to look animatables for
+         * @returns an array of Animatables
+         */
+        getAllAnimatablesByTarget(target: any): Array<Animatable>;
+
+        /**
+         * Will stop the animation of the given target
+         * @param target - the target
+         * @param animationName - the name of the animation to stop (all animations will be stopped if both this and targetMask are empty)
+         * @param targetMask - a function that determines if the animation should be stopped based on its target (all animations will be stopped if both this and animationName are empty)
+         */
+        stopAnimation(target: any, animationName?: string, targetMask?: (target: any) => boolean): void;
+
+        /**
+        * Stops and removes all animations that have been applied to the scene
+        */
+        stopAllAnimations(): void;
+    }
+}
+
+Scene.prototype._animate = function(): void {
+    if (!this.animationsEnabled || this._activeAnimatables.length === 0) {
+        return;
+    }
+
+    // Getting time
+    var now = PrecisionDate.Now;
+    if (!this._animationTimeLast) {
+        if (this._pendingData.length > 0) {
+            return;
+        }
+        this._animationTimeLast = now;
+    }
+    var deltaTime = this.useConstantAnimationDeltaTime ? 16.0 : (now - this._animationTimeLast) * this.animationTimeScale;
+    this._animationTime += deltaTime;
+    this._animationTimeLast = now;
+    for (var index = 0; index < this._activeAnimatables.length; index++) {
+        this._activeAnimatables[index]._animate(this._animationTime);
+    }
+
+    // Late animation bindings
+    this._processLateAnimationBindings();
+};
+
+Scene.prototype.beginWeightedAnimation = function(target: any, from: number, to: number, weight = 1.0, loop?: boolean, speedRatio: number = 1.0,
+    onAnimationEnd?: () => void, animatable?: Animatable, targetMask?: (target: any) => boolean, onAnimationLoop?: () => void): Animatable {
+
+    let returnedAnimatable = this.beginAnimation(target, from, to, loop, speedRatio, onAnimationEnd, animatable, false, targetMask, onAnimationLoop);
+    returnedAnimatable.weight = weight;
+
+    return returnedAnimatable;
+};
+
+Scene.prototype.beginAnimation = function(target: any, from: number, to: number, loop?: boolean, speedRatio: number = 1.0,
+    onAnimationEnd?: () => void, animatable?: Animatable, stopCurrent = true,
+    targetMask?: (target: any) => boolean, onAnimationLoop?: () => void): Animatable {
+
+    if (from > to && speedRatio > 0) {
+        speedRatio *= -1;
+    }
+
+    if (stopCurrent) {
+        this.stopAnimation(target, undefined, targetMask);
+    }
+
+    if (!animatable) {
+        animatable = new Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd, undefined, onAnimationLoop);
+    }
+
+    const shouldRunTargetAnimations = targetMask ? targetMask(target) : true;
+    // Local animations
+    if (target.animations && shouldRunTargetAnimations) {
+        animatable.appendAnimations(target, target.animations);
+    }
+
+    // Children animations
+    if (target.getAnimatables) {
+        var animatables = target.getAnimatables();
+        for (var index = 0; index < animatables.length; index++) {
+            this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent, targetMask, onAnimationLoop);
+        }
+    }
+
+    animatable.reset();
+
+    return animatable;
+};
+
+Scene.prototype.beginHierarchyAnimation = function(target: any, directDescendantsOnly: boolean, from: number, to: number, loop?: boolean, speedRatio: number = 1.0,
+    onAnimationEnd?: () => void, animatable?: Animatable, stopCurrent = true,
+    targetMask?: (target: any) => boolean, onAnimationLoop?: () => void): Animatable[] {
+
+    let children = target.getDescendants(directDescendantsOnly);
+
+    let result = [];
+    result.push(this.beginAnimation(target, from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent, targetMask));
+    for (var child of children) {
+        result.push(this.beginAnimation(child, from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent, targetMask));
+    }
+
+    return result;
+};
+
+Scene.prototype.beginDirectAnimation = function(target: any, animations: Animation[], from: number, to: number, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void, onAnimationLoop?: () => void): Animatable {
+    if (speedRatio === undefined) {
+        speedRatio = 1.0;
+    }
+
+    var animatable = new Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd, animations, onAnimationLoop);
+
+    return animatable;
+};
+
+Scene.prototype.beginDirectHierarchyAnimation = function(target: Node, directDescendantsOnly: boolean, animations: Animation[], from: number, to: number, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void, onAnimationLoop?: () => void): Animatable[] {
+    let children = target.getDescendants(directDescendantsOnly);
+
+    let result = [];
+    result.push(this.beginDirectAnimation(target, animations, from, to, loop, speedRatio, onAnimationEnd, onAnimationLoop));
+    for (var child of children) {
+        result.push(this.beginDirectAnimation(child, animations, from, to, loop, speedRatio, onAnimationEnd, onAnimationLoop));
+    }
+
+    return result;
+};
+
+Scene.prototype.getAnimatableByTarget = function(target: any): Nullable<Animatable> {
+    for (var index = 0; index < this._activeAnimatables.length; index++) {
+        if (this._activeAnimatables[index].target === target) {
+            return this._activeAnimatables[index];
+        }
+    }
+
+    return null;
+};
+
+Scene.prototype.getAllAnimatablesByTarget = function(target: any): Array<Animatable> {
+    let result = [];
+    for (var index = 0; index < this._activeAnimatables.length; index++) {
+        if (this._activeAnimatables[index].target === target) {
+            result.push(this._activeAnimatables[index]);
+        }
+    }
+
+    return result;
+};
+
+/**
+ * Will stop the animation of the given target
+ * @param target - the target
+ * @param animationName - the name of the animation to stop (all animations will be stopped if both this and targetMask are empty)
+ * @param targetMask - a function that determines if the animation should be stopped based on its target (all animations will be stopped if both this and animationName are empty)
+ */
+Scene.prototype.stopAnimation = function(target: any, animationName?: string, targetMask?: (target: any) => boolean): void {
+    var animatables = this.getAllAnimatablesByTarget(target);
+
+    for (var animatable of animatables) {
+        animatable.stop(animationName, targetMask);
+    }
+};
+
+/**
+ * Stops and removes all animations that have been applied to the scene
+ */
+Scene.prototype.stopAllAnimations = function(): void {
+    if (this._activeAnimatables) {
+        for (let i = 0; i < this._activeAnimatables.length; i++) {
+            this._activeAnimatables[i].stop();
+        }
+        this._activeAnimatables = [];
+    }
+
+    for (var group of this.animationGroups) {
+        group.stop();
+    }
+};
+
+Scene.prototype._registerTargetForLateAnimationBinding = function(runtimeAnimation: RuntimeAnimation, originalValue: any): void {
+    let target = runtimeAnimation.target;
+    this._registeredForLateAnimationBindings.pushNoDuplicate(target);
+
+    if (!target._lateAnimationHolders) {
+        target._lateAnimationHolders = {};
+    }
+
+    if (!target._lateAnimationHolders[runtimeAnimation.targetPath]) {
+        target._lateAnimationHolders[runtimeAnimation.targetPath] = {
+            totalWeight: 0,
+            animations: [],
+            originalValue: originalValue
+        };
+    }
+
+    target._lateAnimationHolders[runtimeAnimation.targetPath].animations.push(runtimeAnimation);
+    target._lateAnimationHolders[runtimeAnimation.targetPath].totalWeight += runtimeAnimation.weight;
+};
+
+Scene.prototype._processLateAnimationBindingsForMatrices = function(holder: {
+    totalWeight: number,
+    animations: RuntimeAnimation[],
+    originalValue: Matrix
+}): any {
+    let normalizer = 1.0;
+    let finalPosition = Tmp.Vector3[0];
+    let finalScaling = Tmp.Vector3[1];
+    let finalQuaternion = Tmp.Quaternion[0];
+    let startIndex = 0;
+    let originalAnimation = holder.animations[0];
+    let originalValue = holder.originalValue;
+
+    var scale = 1;
+    if (holder.totalWeight < 1.0) {
+        // We need to mix the original value in
+        originalValue.decompose(finalScaling, finalQuaternion, finalPosition);
+        scale = 1.0 - holder.totalWeight;
+    } else {
+        startIndex = 1;
+        // We need to normalize the weights
+        normalizer = holder.totalWeight;
+        originalAnimation.currentValue.decompose(finalScaling, finalQuaternion, finalPosition);
+        scale = originalAnimation.weight / normalizer;
+        if (scale == 1) {
+            return originalAnimation.currentValue;
+        }
+    }
+
+    finalScaling.scaleInPlace(scale);
+    finalPosition.scaleInPlace(scale);
+    finalQuaternion.scaleInPlace(scale);
+
+    for (var animIndex = startIndex; animIndex < holder.animations.length; animIndex++) {
+        var runtimeAnimation = holder.animations[animIndex];
+        var scale = runtimeAnimation.weight / normalizer;
+        let currentPosition = Tmp.Vector3[2];
+        let currentScaling = Tmp.Vector3[3];
+        let currentQuaternion = Tmp.Quaternion[1];
+
+        runtimeAnimation.currentValue.decompose(currentScaling, currentQuaternion, currentPosition);
+        currentScaling.scaleAndAddToRef(scale, finalScaling);
+        currentQuaternion.scaleAndAddToRef(scale, finalQuaternion);
+        currentPosition.scaleAndAddToRef(scale, finalPosition);
+    }
+
+    Matrix.ComposeToRef(finalScaling, finalQuaternion, finalPosition, originalAnimation._workValue);
+    return originalAnimation._workValue;
+};
+
+Scene.prototype._processLateAnimationBindingsForQuaternions = function(holder: {
+    totalWeight: number,
+    animations: RuntimeAnimation[],
+    originalValue: Quaternion
+}, refQuaternion: Quaternion): Quaternion {
+    let originalAnimation = holder.animations[0];
+    let originalValue = holder.originalValue;
+
+    if (holder.animations.length === 1) {
+        Quaternion.SlerpToRef(originalValue, originalAnimation.currentValue, Math.min(1.0, holder.totalWeight), refQuaternion);
+        return refQuaternion;
+    }
+
+    let normalizer = 1.0;
+    let quaternions: Array<Quaternion>;
+    let weights: Array<number>;
+
+    if (holder.totalWeight < 1.0) {
+        let scale = 1.0 - holder.totalWeight;
+
+        quaternions = [];
+        weights = [];
+
+        quaternions.push(originalValue);
+        weights.push(scale);
+    } else {
+        if (holder.animations.length === 2) { // Slerp as soon as we can
+            Quaternion.SlerpToRef(holder.animations[0].currentValue, holder.animations[1].currentValue, holder.animations[1].weight / holder.totalWeight, refQuaternion);
+            return refQuaternion;
+        }
+        quaternions = [];
+        weights = [];
+
+        normalizer = holder.totalWeight;
+    }
+    for (var animIndex = 0; animIndex < holder.animations.length; animIndex++) {
+        let runtimeAnimation = holder.animations[animIndex];
+        quaternions.push(runtimeAnimation.currentValue);
+        weights.push(runtimeAnimation.weight / normalizer);
+    }
+
+    // https://gamedev.stackexchange.com/questions/62354/method-for-interpolation-between-3-quaternions
+
+    let cumulativeAmount = 0;
+    let cumulativeQuaternion: Nullable<Quaternion> = null;
+    for (var index = 0; index < quaternions.length;) {
+        if (!cumulativeQuaternion) {
+            Quaternion.SlerpToRef(quaternions[index], quaternions[index + 1], weights[index + 1] / (weights[index] + weights[index + 1]), refQuaternion);
+            cumulativeQuaternion = refQuaternion;
+            cumulativeAmount = weights[index] + weights[index + 1];
+            index += 2;
+            continue;
+        }
+        cumulativeAmount += weights[index];
+        Quaternion.SlerpToRef(cumulativeQuaternion, quaternions[index], weights[index] / cumulativeAmount, cumulativeQuaternion);
+        index++;
+    }
+
+    return cumulativeQuaternion!;
+};
+
+Scene.prototype._processLateAnimationBindings = function(): void {
+    if (!this._registeredForLateAnimationBindings.length) {
+        return;
+    }
+    for (var index = 0; index < this._registeredForLateAnimationBindings.length; index++) {
+        var target = this._registeredForLateAnimationBindings.data[index];
+
+        for (var path in target._lateAnimationHolders) {
+            var holder = target._lateAnimationHolders[path];
+            let originalAnimation: RuntimeAnimation = holder.animations[0];
+            let originalValue = holder.originalValue;
+
+            let matrixDecomposeMode = Animation.AllowMatrixDecomposeForInterpolation && originalValue.m; // ie. data is matrix
+
+            let finalValue: any = target[path];
+            if (matrixDecomposeMode) {
+                finalValue = this._processLateAnimationBindingsForMatrices(holder);
+            } else {
+                let quaternionMode = originalValue.w !== undefined;
+                if (quaternionMode) {
+                    finalValue = this._processLateAnimationBindingsForQuaternions(holder, finalValue || Quaternion.Identity());
+                } else {
+
+                    let startIndex = 0;
+                    let normalizer = 1.0;
+
+                    if (holder.totalWeight < 1.0) {
+                        // We need to mix the original value in
+                        if (originalValue.scale) {
+                            finalValue = originalValue.scale(1.0 - holder.totalWeight);
+                        } else {
+                            finalValue = originalValue * (1.0 - holder.totalWeight);
+                        }
+                    } else {
+                        // We need to normalize the weights
+                        normalizer = holder.totalWeight;
+                        let scale = originalAnimation.weight / normalizer;
+                        if (scale !== 1) {
+                            if (originalAnimation.currentValue.scale) {
+                                finalValue = originalAnimation.currentValue.scale(scale);
+                            } else {
+                                finalValue = originalAnimation.currentValue * scale;
+                            }
+                        } else {
+                            finalValue = originalAnimation.currentValue;
+                        }
+
+                        startIndex = 1;
+                    }
+
+                    for (var animIndex = startIndex; animIndex < holder.animations.length; animIndex++) {
+                        var runtimeAnimation = holder.animations[animIndex];
+                        var scale = runtimeAnimation.weight / normalizer;
+                        if (runtimeAnimation.currentValue.scaleAndAddToRef) {
+                            runtimeAnimation.currentValue.scaleAndAddToRef(scale, finalValue);
+                        } else {
+                            finalValue += runtimeAnimation.currentValue * scale;
+                        }
+                    }
+                }
+            }
+            target[path] = finalValue;
+        }
+
+        target._lateAnimationHolders = {};
+    }
+    this._registeredForLateAnimationBindings.reset();
+};
+
+declare module "../Bones/bone" {
+    export interface Bone {
+        /**
+         * Copy an animation range from another bone
+         * @param source defines the source bone
+         * @param rangeName defines the range name to copy
+         * @param frameOffset defines the frame offset
+         * @param rescaleAsRequired defines if rescaling must be applied if required
+         * @param skelDimensionsRatio defines the scaling ratio
+         * @returns true if operation was successful
+         */
+        copyAnimationRange(source: Bone, rangeName: string, frameOffset: number, rescaleAsRequired: boolean, skelDimensionsRatio: Nullable<Vector3>): boolean;
+    }
+}
+
+Bone.prototype.copyAnimationRange = function(source: Bone, rangeName: string, frameOffset: number, rescaleAsRequired = false, skelDimensionsRatio: Nullable<Vector3> = null): boolean {
+    // all animation may be coming from a library skeleton, so may need to create animation
+    if (this.animations.length === 0) {
+        this.animations.push(new Animation(this.name, "_matrix", source.animations[0].framePerSecond, Animation.ANIMATIONTYPE_MATRIX, 0));
+        this.animations[0].setKeys([]);
+    }
+
+    // get animation info / verify there is such a range from the source bone
+    var sourceRange = source.animations[0].getRange(rangeName);
+    if (!sourceRange) {
+        return false;
+    }
+    var from = sourceRange.from;
+    var to = sourceRange.to;
+    var sourceKeys = source.animations[0].getKeys();
+
+    // rescaling prep
+    var sourceBoneLength = source.length;
+    var sourceParent = source.getParent();
+    var parent = this.getParent();
+    var parentScalingReqd = rescaleAsRequired && sourceParent && sourceBoneLength && this.length && sourceBoneLength !== this.length;
+    var parentRatio = parentScalingReqd && parent && sourceParent ? parent.length / sourceParent.length : 1;
+
+    var dimensionsScalingReqd = rescaleAsRequired && !parent && skelDimensionsRatio && (skelDimensionsRatio.x !== 1 || skelDimensionsRatio.y !== 1 || skelDimensionsRatio.z !== 1);
+
+    var destKeys = this.animations[0].getKeys();
+
+    // loop vars declaration
+    var orig: { frame: number, value: Matrix };
+    var origTranslation: Vector3;
+    var mat: Matrix;
+
+    for (var key = 0, nKeys = sourceKeys.length; key < nKeys; key++) {
+        orig = sourceKeys[key];
+        if (orig.frame >= from && orig.frame <= to) {
+            if (rescaleAsRequired) {
+                mat = orig.value.clone();
+
+                // scale based on parent ratio, when bone has parent
+                if (parentScalingReqd) {
+                    origTranslation = mat.getTranslation();
+                    mat.setTranslation(origTranslation.scaleInPlace(parentRatio));
+
+                    // scale based on skeleton dimension ratio when root bone, and value is passed
+                } else if (dimensionsScalingReqd && skelDimensionsRatio) {
+                    origTranslation = mat.getTranslation();
+                    mat.setTranslation(origTranslation.multiplyInPlace(skelDimensionsRatio));
+
+                    // use original when root bone, and no data for skelDimensionsRatio
+                } else {
+                    mat = orig.value;
+                }
+            } else {
+                mat = orig.value;
+            }
+            destKeys.push({ frame: orig.frame + frameOffset, value: mat });
+        }
+    }
+    this.animations[0].createRange(rangeName, from + frameOffset, to + frameOffset);
+    return true;
+};

+ 7 - 211
src/Animations/animation.ts

@@ -1,225 +1,21 @@
 import { IEasingFunction, EasingFunction } from "./easing";
-import { Path2, Vector3, Quaternion, Vector2, Color3, Size, Matrix } from "../Maths/math";
+import { Vector3, Quaternion, Vector2, Color3, Size, Matrix } from "../Maths/math";
 import { Scalar } from "../Maths/math.scalar";
 
 import { Nullable } from "../types";
 import { Scene } from "../scene";
 import { IAnimatable } from "../Misc/tools";
-import { Node } from "../node";
-import { Texture } from "../Materials/Textures/texture";
 import { SerializationHelper } from "../Misc/decorators";
+import { _TypeStore } from '../Misc/typeStore';
+import { IAnimationKey, AnimationKeyInterpolation } from './animationKey';
+import { AnimationRange } from './animationRange';
+import { AnimationEvent } from './animationEvent';
+import { Node } from "../node";
 
 declare type Animatable = import("./animatable").Animatable;
 declare type RuntimeAnimation = import("./runtimeAnimation").RuntimeAnimation;
 
 /**
- * Represents the range of an animation
- */
-export class AnimationRange {
-    /**
-     * Initializes the range of an animation
-     * @param name The name of the animation range
-     * @param from The starting frame of the animation
-     * @param to The ending frame of the animation
-     */
-    constructor(
-        /**The name of the animation range**/
-        public name: string,
-        /**The starting frame of the animation */
-        public from: number,
-        /**The ending frame of the animation*/
-        public to: number) {
-    }
-
-    /**
-     * Makes a copy of the animation range
-     * @returns A copy of the animation range
-     */
-    public clone(): AnimationRange {
-        return new AnimationRange(this.name, this.from, this.to);
-    }
-}
-
-/**
- * Composed of a frame, and an action function
- */
-export class AnimationEvent {
-    /**
-     * Specifies if the animation event is done
-     */
-    public isDone: boolean = false;
-
-    /**
-     * Initializes the animation event
-     * @param frame The frame for which the event is triggered
-     * @param action The event to perform when triggered
-     * @param onlyOnce Specifies if the event should be triggered only once
-     */
-    constructor(
-        /** The frame for which the event is triggered **/
-        public frame: number,
-        /** The event to perform when triggered **/
-        public action: (currentFrame: number) => void,
-        /** Specifies if the event should be triggered only once**/
-        public onlyOnce?: boolean) {
-    }
-
-    /** @hidden */
-    public _clone(): AnimationEvent {
-        return new AnimationEvent(this.frame, this.action, this.onlyOnce);
-    }
-}
-
-/**
- * A cursor which tracks a point on a path
- */
-export class PathCursor {
-    /**
-     * Stores path cursor callbacks for when an onchange event is triggered
-     */
-    private _onchange = new Array<(cursor: PathCursor) => void>();
-
-    /**
-     * The value of the path cursor
-     */
-    value: number = 0;
-
-    /**
-     * The animation array of the path cursor
-     */
-    animations = new Array<Animation>();
-
-    /**
-     * Initializes the path cursor
-     * @param path The path to track
-     */
-    constructor(private path: Path2) {
-    }
-
-    /**
-     * Gets the cursor point on the path
-     * @returns A point on the path cursor at the cursor location
-     */
-    public getPoint(): Vector3 {
-        var point = this.path.getPointAtLengthPosition(this.value);
-        return new Vector3(point.x, 0, point.y);
-    }
-
-    /**
-     * Moves the cursor ahead by the step amount
-     * @param step The amount to move the cursor forward
-     * @returns This path cursor
-     */
-    public moveAhead(step: number = 0.002): PathCursor {
-        this.move(step);
-
-        return this;
-    }
-
-    /**
-     * Moves the cursor behind by the step amount
-     * @param step The amount to move the cursor back
-     * @returns This path cursor
-     */
-    public moveBack(step: number = 0.002): PathCursor {
-        this.move(-step);
-
-        return this;
-    }
-
-    /**
-     * Moves the cursor by the step amount
-     * If the step amount is greater than one, an exception is thrown
-     * @param step The amount to move the cursor
-     * @returns This path cursor
-     */
-    public move(step: number): PathCursor {
-
-        if (Math.abs(step) > 1) {
-            throw "step size should be less than 1.";
-        }
-
-        this.value += step;
-        this.ensureLimits();
-        this.raiseOnChange();
-
-        return this;
-    }
-
-    /**
-     * Ensures that the value is limited between zero and one
-     * @returns This path cursor
-     */
-    private ensureLimits(): PathCursor {
-        while (this.value > 1) {
-            this.value -= 1;
-        }
-        while (this.value < 0) {
-            this.value += 1;
-        }
-
-        return this;
-    }
-
-    /**
-     * Runs onchange callbacks on change (used by the animation engine)
-     * @returns This path cursor
-     */
-    private raiseOnChange(): PathCursor {
-        this._onchange.forEach((f) => f(this));
-
-        return this;
-    }
-
-    /**
-     * Executes a function on change
-     * @param f A path cursor onchange callback
-     * @returns This path cursor
-     */
-    public onchange(f: (cursor: PathCursor) => void): PathCursor {
-        this._onchange.push(f);
-
-        return this;
-    }
-}
-
-/**
- * Defines an interface which represents an animation key frame
- */
-export interface IAnimationKey {
-    /**
-     * Frame of the key frame
-     */
-    frame: number;
-    /**
-     * Value at the specifies key frame
-     */
-    value: any;
-    /**
-     * The input tangent for the cubic hermite spline
-     */
-    inTangent?: any;
-    /**
-     * The output tangent for the cubic hermite spline
-     */
-    outTangent?: any;
-    /**
-     * The animation interpolation type
-     */
-    interpolation?: AnimationKeyInterpolation;
-}
-
-/**
- * Enum for the animation key frame interpolation type
- */
-export enum AnimationKeyInterpolation {
-    /**
-     * Do not interpolate between keys and use the start key value only. Tangents are ignored
-     */
-    STEP = 1
-}
-
-/**
  * Class used to store any kind of animation
  */
 export class Animation {
@@ -1238,5 +1034,5 @@ export class Animation {
     }
 }
 
-Texture._AnimationParser = Animation.Parse;
+_TypeStore.RegisteredTypes["BABYLON.Animation"] = Animation;
 Node._AnimationRangeFactory = (name: string, from: number, to: number) => new AnimationRange(name, from, to);

+ 29 - 0
src/Animations/animationEvent.ts

@@ -0,0 +1,29 @@
+/**
+ * Composed of a frame, and an action function
+ */
+export class AnimationEvent {
+    /**
+     * Specifies if the animation event is done
+     */
+    public isDone: boolean = false;
+
+    /**
+     * Initializes the animation event
+     * @param frame The frame for which the event is triggered
+     * @param action The event to perform when triggered
+     * @param onlyOnce Specifies if the event should be triggered only once
+     */
+    constructor(
+        /** The frame for which the event is triggered **/
+        public frame: number,
+        /** The event to perform when triggered **/
+        public action: (currentFrame: number) => void,
+        /** Specifies if the event should be triggered only once**/
+        public onlyOnce?: boolean) {
+    }
+
+    /** @hidden */
+    public _clone(): AnimationEvent {
+        return new AnimationEvent(this.frame, this.action, this.onlyOnce);
+    }
+}

+ 2 - 1
src/Animations/animationGroup.ts

@@ -1,5 +1,6 @@
 import { Animatable } from "./animatable";
-import { IAnimationKey, Animation } from "./animation";
+import { Animation } from "./animation";
+import { IAnimationKey } from "./animationKey";
 
 import { Scene, IDisposable } from "../scene";
 import { Observable } from "../Misc/observable";

+ 35 - 0
src/Animations/animationKey.ts

@@ -0,0 +1,35 @@
+/**
+ * Defines an interface which represents an animation key frame
+ */
+export interface IAnimationKey {
+    /**
+     * Frame of the key frame
+     */
+    frame: number;
+    /**
+     * Value at the specifies key frame
+     */
+    value: any;
+    /**
+     * The input tangent for the cubic hermite spline
+     */
+    inTangent?: any;
+    /**
+     * The output tangent for the cubic hermite spline
+     */
+    outTangent?: any;
+    /**
+     * The animation interpolation type
+     */
+    interpolation?: AnimationKeyInterpolation;
+}
+
+/**
+ * Enum for the animation key frame interpolation type
+ */
+export enum AnimationKeyInterpolation {
+    /**
+     * Do not interpolate between keys and use the start key value only. Tangents are ignored
+     */
+    STEP = 1
+}

+ 27 - 0
src/Animations/animationRange.ts

@@ -0,0 +1,27 @@
+/**
+ * Represents the range of an animation
+ */
+export class AnimationRange {
+    /**
+     * Initializes the range of an animation
+     * @param name The name of the animation range
+     * @param from The starting frame of the animation
+     * @param to The ending frame of the animation
+     */
+    constructor(
+        /**The name of the animation range**/
+        public name: string,
+        /**The starting frame of the animation */
+        public from: number,
+        /**The ending frame of the animation*/
+        public to: number) {
+    }
+
+    /**
+     * Makes a copy of the animation range
+     * @returns A copy of the animation range
+     */
+    public clone(): AnimationRange {
+        return new AnimationRange(this.name, this.from, this.to);
+    }
+}

+ 5 - 1
src/Animations/index.ts

@@ -3,4 +3,8 @@ export * from "./animation";
 export * from "./animationGroup";
 export * from "./animationPropertiesOverride";
 export * from "./easing";
-export * from "./runtimeAnimation";
+export * from "./runtimeAnimation";
+export * from "./animationEvent";
+export * from "./animationGroup";
+export * from "./animationKey";
+export * from "./animationRange";

+ 114 - 0
src/Animations/pathCursor.ts

@@ -0,0 +1,114 @@
+import { Path2, Vector3 } from '../Maths/math';
+
+/**
+ * A cursor which tracks a point on a path
+ */
+export class PathCursor {
+    /**
+     * Stores path cursor callbacks for when an onchange event is triggered
+     */
+    private _onchange = new Array<(cursor: PathCursor) => void>();
+
+    /**
+     * The value of the path cursor
+     */
+    value: number = 0;
+
+    /**
+     * The animation array of the path cursor
+     */
+    animations = new Array<Animation>();
+
+    /**
+     * Initializes the path cursor
+     * @param path The path to track
+     */
+    constructor(private path: Path2) {
+    }
+
+    /**
+     * Gets the cursor point on the path
+     * @returns A point on the path cursor at the cursor location
+     */
+    public getPoint(): Vector3 {
+        var point = this.path.getPointAtLengthPosition(this.value);
+        return new Vector3(point.x, 0, point.y);
+    }
+
+    /**
+     * Moves the cursor ahead by the step amount
+     * @param step The amount to move the cursor forward
+     * @returns This path cursor
+     */
+    public moveAhead(step: number = 0.002): PathCursor {
+        this.move(step);
+
+        return this;
+    }
+
+    /**
+     * Moves the cursor behind by the step amount
+     * @param step The amount to move the cursor back
+     * @returns This path cursor
+     */
+    public moveBack(step: number = 0.002): PathCursor {
+        this.move(-step);
+
+        return this;
+    }
+
+    /**
+     * Moves the cursor by the step amount
+     * If the step amount is greater than one, an exception is thrown
+     * @param step The amount to move the cursor
+     * @returns This path cursor
+     */
+    public move(step: number): PathCursor {
+
+        if (Math.abs(step) > 1) {
+            throw "step size should be less than 1.";
+        }
+
+        this.value += step;
+        this.ensureLimits();
+        this.raiseOnChange();
+
+        return this;
+    }
+
+    /**
+     * Ensures that the value is limited between zero and one
+     * @returns This path cursor
+     */
+    private ensureLimits(): PathCursor {
+        while (this.value > 1) {
+            this.value -= 1;
+        }
+        while (this.value < 0) {
+            this.value += 1;
+        }
+
+        return this;
+    }
+
+    /**
+     * Runs onchange callbacks on change (used by the animation engine)
+     * @returns This path cursor
+     */
+    private raiseOnChange(): PathCursor {
+        this._onchange.forEach((f) => f(this));
+
+        return this;
+    }
+
+    /**
+     * Executes a function on change
+     * @param f A path cursor onchange callback
+     * @returns This path cursor
+     */
+    public onchange(f: (cursor: PathCursor) => void): PathCursor {
+        this._onchange.push(f);
+
+        return this;
+    }
+}

+ 2 - 1
src/Animations/runtimeAnimation.ts

@@ -1,6 +1,7 @@
 import { DeepImmutable } from "../types";
 import { Quaternion, Vector3, Vector2, Size, Color3, Matrix } from "../Maths/math";
-import { Animation, AnimationEvent } from "./animation";
+import { Animation } from "./animation";
+import { AnimationEvent } from "./animationEvent";
 
 declare type Animatable = import("./animatable").Animatable;
 

+ 3 - 73
src/Bones/bone.ts

@@ -3,12 +3,13 @@ import { Skeleton } from "./skeleton";
 import { Vector3, Quaternion, Matrix, Space } from "../Maths/math";
 import { ArrayTools } from "../Misc/arrayTools";
 import { Nullable } from "../types";
-import { Animation } from "../Animations/animation";
-import { AnimationPropertiesOverride } from "../Animations/animationPropertiesOverride";
 import { AbstractMesh } from "../Meshes/abstractMesh";
 import { TransformNode } from "../Meshes/transformNode";
 import { Node } from "../node";
 
+declare type Animation = import("../Animations/animation").Animation;
+declare type AnimationPropertiesOverride = import("../Animations/animationPropertiesOverride").AnimationPropertiesOverride;
+
 /**
  * Class used to store bone information
  * @see http://doc.babylonjs.com/how_to/how_to_use_bones_and_skeletons
@@ -363,77 +364,6 @@ export class Bone extends Node {
     }
 
     /**
-     * Copy an animation range from another bone
-     * @param source defines the source bone
-     * @param rangeName defines the range name to copy
-     * @param frameOffset defines the frame offset
-     * @param rescaleAsRequired defines if rescaling must be applied if required
-     * @param skelDimensionsRatio defines the scaling ratio
-     * @returns true if operation was successful
-     */
-    public copyAnimationRange(source: Bone, rangeName: string, frameOffset: number, rescaleAsRequired = false, skelDimensionsRatio: Nullable<Vector3> = null): boolean {
-        // all animation may be coming from a library skeleton, so may need to create animation
-        if (this.animations.length === 0) {
-            this.animations.push(new Animation(this.name, "_matrix", source.animations[0].framePerSecond, Animation.ANIMATIONTYPE_MATRIX, 0));
-            this.animations[0].setKeys([]);
-        }
-
-        // get animation info / verify there is such a range from the source bone
-        var sourceRange = source.animations[0].getRange(rangeName);
-        if (!sourceRange) {
-            return false;
-        }
-        var from = sourceRange.from;
-        var to = sourceRange.to;
-        var sourceKeys = source.animations[0].getKeys();
-
-        // rescaling prep
-        var sourceBoneLength = source.length;
-        var sourceParent = source.getParent();
-        var parent = this.getParent();
-        var parentScalingReqd = rescaleAsRequired && sourceParent && sourceBoneLength && this.length && sourceBoneLength !== this.length;
-        var parentRatio = parentScalingReqd && parent && sourceParent ? parent.length / sourceParent.length : 1;
-
-        var dimensionsScalingReqd = rescaleAsRequired && !parent && skelDimensionsRatio && (skelDimensionsRatio.x !== 1 || skelDimensionsRatio.y !== 1 || skelDimensionsRatio.z !== 1);
-
-        var destKeys = this.animations[0].getKeys();
-
-        // loop vars declaration
-        var orig: { frame: number, value: Matrix };
-        var origTranslation: Vector3;
-        var mat: Matrix;
-
-        for (var key = 0, nKeys = sourceKeys.length; key < nKeys; key++) {
-            orig = sourceKeys[key];
-            if (orig.frame >= from && orig.frame <= to) {
-                if (rescaleAsRequired) {
-                    mat = orig.value.clone();
-
-                    // scale based on parent ratio, when bone has parent
-                    if (parentScalingReqd) {
-                        origTranslation = mat.getTranslation();
-                        mat.setTranslation(origTranslation.scaleInPlace(parentRatio));
-
-                        // scale based on skeleton dimension ratio when root bone, and value is passed
-                    } else if (dimensionsScalingReqd && skelDimensionsRatio) {
-                        origTranslation = mat.getTranslation();
-                        mat.setTranslation(origTranslation.multiplyInPlace(skelDimensionsRatio));
-
-                        // use original when root bone, and no data for skelDimensionsRatio
-                    } else {
-                        mat = orig.value;
-                    }
-                } else {
-                    mat = orig.value;
-                }
-                destKeys.push({ frame: orig.frame + frameOffset, value: mat });
-            }
-        }
-        this.animations[0].createRange(rangeName, from + frameOffset, to + frameOffset);
-        return true;
-    }
-
-    /**
      * Translate the bone in local or world space
      * @param vec The amount to translate the bone
      * @param space The space that the translation is in

+ 2 - 1
src/Bones/skeleton.ts

@@ -9,7 +9,8 @@ import { AbstractMesh } from "../Meshes/abstractMesh";
 import { RawTexture } from "../Materials/Textures/rawTexture";
 import { Animatable } from "../Animations/animatable";
 import { AnimationPropertiesOverride } from "../Animations/animationPropertiesOverride";
-import { AnimationRange, Animation } from "../Animations/animation";
+import { Animation } from "../Animations/animation";
+import { AnimationRange } from "../Animations/animationRange";
 import { EngineStore } from "../Engines/engineStore";
 import { Constants } from "../Engines/constants";
 import { Logger } from "../Misc/logger";

+ 5 - 4
src/Cameras/camera.ts

@@ -12,8 +12,7 @@ import { AbstractMesh } from "../Meshes/abstractMesh";
 import { Ray } from "../Culling/ray";
 import { ICullable } from "../Culling/boundingInfo";
 import { Logger } from "../Misc/logger";
-
-import { Animation } from "../Animations/animation";
+import { _TypeStore } from '../Misc/typeStore';
 
 declare type PostProcess = import("../PostProcesses/postProcess").PostProcess;
 declare type RenderTargetTexture = import("../Materials/Textures/renderTargetTexture").RenderTargetTexture;
@@ -1211,8 +1210,10 @@ export class Camera extends Node {
         if (parsedCamera.animations) {
             for (var animationIndex = 0; animationIndex < parsedCamera.animations.length; animationIndex++) {
                 var parsedAnimation = parsedCamera.animations[animationIndex];
-
-                camera.animations.push(Animation.Parse(parsedAnimation));
+                const internalClass = _TypeStore.GetClass("BABYLON.Animation");
+                if (internalClass) {
+                    camera.animations.push(internalClass.Parse(parsedAnimation));
+                }
             }
             Node.ParseAnimationRanges(camera, parsedCamera, scene);
         }

+ 6 - 3
src/Lights/light.ts

@@ -6,8 +6,9 @@ import { Node } from "../node";
 import { AbstractMesh } from "../Meshes/abstractMesh";
 import { Effect } from "../Materials/effect";
 import { UniformBuffer } from "../Materials/uniformBuffer";
-import { Animation } from "../Animations/animation";
 import { IShadowGenerator } from "./Shadows/shadowGenerator";
+import { _TypeStore } from '../Misc/typeStore';
+
 /**
  * Base class of all the lights in Babylon. It groups all the generic information about lights.
  * Lights are used, as you would expect, to affect how meshes are seen, in terms of both illumination and colour.
@@ -610,8 +611,10 @@ export abstract class Light extends Node {
         if (parsedLight.animations) {
             for (var animationIndex = 0; animationIndex < parsedLight.animations.length; animationIndex++) {
                 var parsedAnimation = parsedLight.animations[animationIndex];
-
-                light.animations.push(Animation.Parse(parsedAnimation));
+                const internalClass = _TypeStore.GetClass("BABYLON.Animation");
+                if (internalClass) {
+                    light.animations.push(internalClass.Parse(parsedAnimation));
+                }
             }
             Node.ParseAnimationRanges(light, parsedLight, scene);
         }

+ 10 - 7
src/Loading/Plugins/babylonFileLoader.ts

@@ -11,7 +11,6 @@ import { Material } from "../../Materials/material";
 import { MultiMaterial } from "../../Materials/multiMaterial";
 import { CubeTexture } from "../../Materials/Textures/cubeTexture";
 import { HDRCubeTexture } from "../../Materials/Textures/hdrCubeTexture";
-import { Animation } from "../../Animations/animation";
 import { AnimationGroup } from "../../Animations/animationGroup";
 import { Light } from "../../Lights/light";
 import { SceneComponentConstants } from "../../sceneComponent";
@@ -27,6 +26,7 @@ import { MorphTargetManager } from "../../Morph/morphTargetManager";
 import { CannonJSPlugin } from "../../Physics/Plugins/cannonJSPlugin";
 import { OimoJSPlugin } from "../../Physics/Plugins/oimoJSPlugin";
 import { ReflectionProbe } from "../../Probes/reflectionProbe";
+import { _TypeStore } from '../../Misc/typeStore';
 
 /** @hidden */
 export var _BabylonLoaderRegistered = true;
@@ -104,11 +104,14 @@ var loadAssetContainer = (scene: Scene, data: string, rootUrl: string, onError?:
         if (parsedData.animations !== undefined && parsedData.animations !== null) {
             for (index = 0, cache = parsedData.animations.length; index < cache; index++) {
                 var parsedAnimation = parsedData.animations[index];
-                var animation = Animation.Parse(parsedAnimation);
-                scene.animations.push(animation);
-                container.animations.push(animation);
-                log += (index === 0 ? "\n\tAnimations:" : "");
-                log += "\n\t\t" + animation.toString(fullDetails);
+                const internalClass = _TypeStore.GetClass("BABYLON.Animation");
+                if (internalClass) {
+                    let animation = internalClass.Parse(parsedAnimation);
+                    scene.animations.push(animation);
+                    container.animations.push(animation);
+                    log += (index === 0 ? "\n\tAnimations:" : "");
+                    log += "\n\t\t" + animation.toString(fullDetails);
+                }
             }
         }
 
@@ -376,7 +379,7 @@ SceneLoader.RegisterPlugin({
                                         parsedData.geometries[geometryType].forEach((parsedGeometryData: any) => {
                                             if (parsedGeometryData.id === parsedMesh.geometryId) {
                                                 switch (geometryType) {
-                                                       case "vertexData":
+                                                    case "vertexData":
                                                         Geometry.Parse(parsedGeometryData, scene, rootUrl);
                                                         break;
                                                 }

+ 6 - 3
src/Materials/Textures/cubeTexture.ts

@@ -5,10 +5,11 @@ import { Scene } from "../../scene";
 import { Matrix, Vector3 } from "../../Maths/math";
 import { BaseTexture } from "../../Materials/Textures/baseTexture";
 import { Texture } from "../../Materials/Textures/texture";
-import { Animation } from "../../Animations/animation";
 import { _TimeToken } from "../../Instrumentation/timeToken";
 import { _DepthCullingState, _StencilState, _AlphaState } from "../../States/index";
 import { Constants } from "../../Engines/constants";
+import { _TypeStore } from '../../Misc/typeStore';
+
 /**
  * Class for creating a cube texture
  */
@@ -318,8 +319,10 @@ export class CubeTexture extends BaseTexture {
         if (parsedTexture.animations) {
             for (var animationIndex = 0; animationIndex < parsedTexture.animations.length; animationIndex++) {
                 var parsedAnimation = parsedTexture.animations[animationIndex];
-
-                texture.animations.push(Animation.Parse(parsedAnimation));
+                const internalClass = _TypeStore.GetClass("BABYLON.Animation");
+                if (internalClass) {
+                    texture.animations.push(internalClass.Parse(parsedAnimation));
+                }
             }
         }
 

+ 5 - 7
src/Materials/Textures/texture.ts

@@ -7,8 +7,8 @@ import { Matrix, Vector3, Plane } from "../../Maths/math";
 import { BaseTexture } from "../../Materials/Textures/baseTexture";
 import { Constants } from "../../Engines/constants";
 import { _AlphaState } from "../../States/index";
+import { _TypeStore } from '../../Misc/typeStore';
 
-declare type Animation = import("../../Animations/animation").Animation;
 declare type CubeTexture = import("../../Materials/Textures/cubeTexture").CubeTexture;
 declare type MirrorTexture = import("../../Materials/Textures/mirrorTexture").MirrorTexture;
 declare type RenderTargetTexture = import("../../Materials/Textures/renderTargetTexture").RenderTargetTexture;
@@ -19,10 +19,6 @@ declare type RenderTargetTexture = import("../../Materials/Textures/renderTarget
  */
 export class Texture extends BaseTexture {
     /** @hidden */
-    public static _AnimationParser = (jsonAnimation: any): Animation => {
-        throw "Animation needs to be imported before being deserialized.";
-    }
-    /** @hidden */
     public static _CubeTextureParser = (jsonTexture: any, scene: Scene, rootUrl: string): CubeTexture => {
         throw "CubeTexture needs to be imported before being deserialized.";
     }
@@ -672,8 +668,10 @@ export class Texture extends BaseTexture {
         if (texture && parsedTexture.animations) {
             for (var animationIndex = 0; animationIndex < parsedTexture.animations.length; animationIndex++) {
                 var parsedAnimation = parsedTexture.animations[animationIndex];
-
-                texture.animations.push(Texture._AnimationParser(parsedAnimation));
+                const internalClass = _TypeStore.GetClass("BABYLON.Animation");
+                if (internalClass) {
+                    texture.animations.push(internalClass.Parse(parsedAnimation));
+                }
             }
         }
 

+ 2 - 1
src/Materials/material.ts

@@ -14,11 +14,12 @@ import { UniformBuffer } from "./uniformBuffer";
 import { Effect } from "./effect";
 import { BaseTexture } from "../Materials/Textures/baseTexture";
 import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture";
-import { Animation } from "../Animations/animation";
 import { MaterialDefines } from "./materialDefines";
 import { Constants } from "../Engines/constants";
 import { Logger } from "../Misc/logger";
 
+declare type Animation = import("../Animations/animation").Animation;
+
 declare var BABYLON: any;
 
 /**

+ 9 - 5
src/Meshes/mesh.ts

@@ -18,7 +18,6 @@ import { BoundingInfo } from "../Culling/boundingInfo";
 import { BoundingSphere } from "../Culling/boundingSphere";
 import { Effect } from "../Materials/effect";
 import { Material } from "../Materials/material";
-import { Animation } from "../Animations/animation";
 import { SceneLoaderFlags } from "../Loading/sceneLoaderFlags";
 import { Skeleton } from "../Bones/skeleton";
 import { MorphTargetManager } from "../Morph/morphTargetManager";
@@ -26,6 +25,7 @@ import { PhysicsImpostor } from "../Physics/physicsImpostor";
 import { Constants } from "../Engines/constants";
 import { SerializationHelper } from "../Misc/decorators";
 import { Logger } from "../Misc/logger";
+import { _TypeStore } from '../Misc/typeStore';
 
 declare type LinesMesh = import("./linesMesh").LinesMesh;
 declare type InstancedMesh = import("./instancedMesh").InstancedMesh;
@@ -2884,8 +2884,10 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
         if (parsedMesh.animations) {
             for (var animationIndex = 0; animationIndex < parsedMesh.animations.length; animationIndex++) {
                 var parsedAnimation = parsedMesh.animations[animationIndex];
-
-                mesh.animations.push(Animation.Parse(parsedAnimation));
+                const internalClass = _TypeStore.GetClass("BABYLON.Animation");
+                if (internalClass) {
+                    mesh.animations.push(internalClass.Parse(parsedAnimation));
+                }
             }
             Node.ParseAnimationRanges(mesh, parsedMesh, scene);
         }
@@ -2971,8 +2973,10 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
                 if (parsedInstance.animations) {
                     for (animationIndex = 0; animationIndex < parsedInstance.animations.length; animationIndex++) {
                         parsedAnimation = parsedInstance.animations[animationIndex];
-
-                        instance.animations.push(Animation.Parse(parsedAnimation));
+                        const internalClass = _TypeStore.GetClass("BABYLON.Animation");
+                        if (internalClass) {
+                            instance.animations.push(internalClass.Parse(parsedAnimation));
+                        }
                     }
                     Node.ParseAnimationRanges(instance, parsedInstance, scene);
 

+ 7 - 3
src/Morph/morphTarget.ts

@@ -5,9 +5,11 @@ import { Scene } from "../scene";
 import { EngineStore } from "../Engines/engineStore";
 import { AbstractMesh } from "../Meshes/abstractMesh";
 import { VertexBuffer } from "../Meshes/buffer";
-import { Animation } from "../Animations/animation";
 import { AnimationPropertiesOverride } from "../Animations/animationPropertiesOverride";
 import { serialize, SerializationHelper } from "../Misc/decorators";
+import { _TypeStore } from '../Misc/typeStore';
+
+declare type Animation = import("../Animations/animation").Animation;
 
 /**
  * Defines a target to use with MorphTargetManager
@@ -236,8 +238,10 @@ export class MorphTarget implements IAnimatable {
         if (serializationObject.animations) {
             for (var animationIndex = 0; animationIndex < serializationObject.animations.length; animationIndex++) {
                 var parsedAnimation = serializationObject.animations[animationIndex];
-
-                result.animations.push(Animation.Parse(parsedAnimation));
+                const internalClass = _TypeStore.GetClass("BABYLON.Animation");
+                if (internalClass) {
+                    result.animations.push(internalClass.Parse(parsedAnimation));
+                }
             }
         }
 

+ 2 - 1
src/Particles/IParticleSystem.ts

@@ -6,7 +6,8 @@ import { Texture } from "../Materials/Textures/texture";
 import { BoxParticleEmitter, IParticleEmitterType, PointParticleEmitter, HemisphericParticleEmitter, SphereParticleEmitter, SphereDirectedParticleEmitter, CylinderParticleEmitter, ConeParticleEmitter } from "../Particles/EmitterTypes/index";
 import { Scene } from "../scene";
 import { ColorGradient, FactorGradient, Color3Gradient } from "../Misc/tools";
-import { Animation } from "../Animations/animation";
+
+declare type Animation = import("../Animations/animation").Animation;
 
 /**
  * Interface representing a particle system in Babylon.js.

+ 3 - 2
src/Particles/baseParticleSystem.ts

@@ -2,14 +2,15 @@ import { Nullable } from "../types";
 import { Color4, Vector2, Vector3 } from "../Maths/math";
 import { AbstractMesh } from "../Meshes/abstractMesh";
 import { ImageProcessingConfiguration, ImageProcessingConfigurationDefines } from "../Materials/imageProcessingConfiguration";
-import { Texture } from "../Materials/Textures/texture";
 import { ProceduralTexture } from "../Materials/Textures/Procedurals/proceduralTexture";
 import { RawTexture } from "../Materials/Textures/rawTexture";
 import { Scene } from "../scene";
 import { ColorGradient, FactorGradient, Color3Gradient, IValueGradient } from "../Misc/tools";
-import { Animation } from "../Animations/animation";
 import { BoxParticleEmitter, IParticleEmitterType, PointParticleEmitter, HemisphericParticleEmitter, SphereParticleEmitter, SphereDirectedParticleEmitter, CylinderParticleEmitter, CylinderDirectedParticleEmitter, ConeParticleEmitter } from "../Particles/EmitterTypes/index";
 import { Constants } from "../Engines/constants";
+import { Texture } from '../Materials/Textures/texture';
+
+declare type Animation = import("../Animations/animation").Animation;
 
 /**
  * This represents the base class for particle system in Babylon.

+ 5 - 2
src/Particles/particleSystem.ts

@@ -15,7 +15,6 @@ import { RawTexture } from "../Materials/Textures/rawTexture";
 import { ProceduralTexture } from "../Materials/Textures/Procedurals/proceduralTexture";
 import { EngineStore } from "../Engines/engineStore";
 import { Scene, IDisposable } from "../scene";
-import { Animation } from "../Animations/animation";
 import { BoxParticleEmitter, IParticleEmitterType, HemisphericParticleEmitter, SphereParticleEmitter, SphereDirectedParticleEmitter, CylinderParticleEmitter, ConeParticleEmitter } from "../Particles/EmitterTypes/index";
 import { IParticleSystem } from "./IParticleSystem";
 import { BaseParticleSystem } from "./baseParticleSystem";
@@ -24,6 +23,7 @@ import { SubEmitter, SubEmitterType } from "./subEmitter";
 import { Constants } from "../Engines/constants";
 import { SerializationHelper } from "../Misc/decorators";
 import { DeepCopier } from "../Misc/deepCopier";
+import { _TypeStore } from '../Misc/typeStore';
 
 import "../Shaders/particles.fragment";
 import "../Shaders/particles.vertex";
@@ -2349,7 +2349,10 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
         if (parsedParticleSystem.animations) {
             for (var animationIndex = 0; animationIndex < parsedParticleSystem.animations.length; animationIndex++) {
                 var parsedAnimation = parsedParticleSystem.animations[animationIndex];
-                particleSystem.animations.push(Animation.Parse(parsedAnimation));
+                const internalClass = _TypeStore.GetClass("BABYLON.Animation");
+                if (internalClass) {
+                    particleSystem.animations.push(internalClass.Parse(parsedAnimation));
+                }
             }
             particleSystem.beginAnimationOnStart = parsedParticleSystem.beginAnimationOnStart;
             particleSystem.beginAnimationFrom = parsedParticleSystem.beginAnimationFrom;

+ 2 - 1
src/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline.ts

@@ -11,7 +11,6 @@ import { Constants } from "../../../Engines/constants";
 import { IDisposable } from "../../../scene";
 import { GlowLayer } from "../../../Layers/glowLayer";
 import { Scene } from "../../../scene";
-import { Animation } from "../../../Animations/animation";
 import { PostProcess } from "../../../PostProcesses/postProcess";
 import { SharpenPostProcess } from "../../../PostProcesses/sharpenPostProcess";
 import { ImageProcessingPostProcess } from "../../../PostProcesses/imageProcessingPostProcess";
@@ -25,6 +24,8 @@ import { BloomEffect } from "../../../PostProcesses/bloomEffect";
 import { _TypeStore } from '../../../Misc/typeStore';
 import { EngineStore } from "../../../Engines/engineStore";
 
+declare type Animation = import("../../../Animations/animation").Animation;
+
 /**
  * The default rendering pipeline can be added to a scene to apply common post processing effects such as anti-aliasing or depth of field.
  * See https://doc.babylonjs.com/how_to/using_default_rendering_pipeline

+ 2 - 1
src/PostProcesses/RenderPipeline/Pipelines/standardRenderingPipeline.ts

@@ -17,10 +17,11 @@ import { SpotLight } from "../../../Lights/spotLight";
 import { DirectionalLight } from "../../../Lights/directionalLight";
 import { GeometryBufferRenderer } from "../../../Rendering/geometryBufferRenderer";
 import { Scene } from "../../../scene";
-import { Animation } from "../../../Animations/animation";
 import { Constants } from "../../../Engines/constants";
 import { _TypeStore } from '../../../Misc/typeStore';
 
+declare type Animation = import("../../../Animations/animation").Animation;
+
 import "../../../Shaders/standard.fragment";
 /**
  * Standard rendering pipeline

+ 1 - 1
src/PostProcesses/postProcess.ts

@@ -6,7 +6,6 @@ import { Color4, Vector2 } from "../Maths/math";
 import { Camera } from "../Cameras/camera";
 import { Effect } from "../Materials/effect";
 import { Scene } from "../scene";
-import { Animation } from "../Animations/animation";
 import { Constants } from "../Engines/constants";
 
 import "../Shaders/postprocess.vertex";
@@ -14,6 +13,7 @@ import "../Shaders/postprocess.vertex";
 declare type InternalTexture = import("../Materials/Textures/internalTexture").InternalTexture;
 declare type WebVRFreeCamera = import("../Cameras/VR/webVRCamera").WebVRFreeCamera;
 declare type Engine = import("../Engines/engine").Engine;
+declare type Animation = import("../Animations/animation").Animation;
 
 /**
  * Size options for a post process

+ 2 - 1
src/abstractScene.ts

@@ -7,7 +7,6 @@ import { Skeleton } from "./Bones/skeleton";
 import { MorphTargetManager } from "./Morph/morphTargetManager";
 import { AssetContainer } from "./assetContainer";
 import { IParticleSystem } from "./Particles/IParticleSystem";
-import { Animation } from "./Animations/animation";
 import { AnimationGroup } from "./Animations/animationGroup";
 import { BaseTexture } from "./Materials/Textures/baseTexture";
 import { Material } from "./Materials/material";
@@ -17,6 +16,8 @@ import { Camera } from "./Cameras/camera";
 import { Light } from "./Lights/light";
 import { Node } from "./node";
 
+declare type Animation = import("./Animations/animation").Animation;
+
 /**
  * Defines how the parser contract is defined.
  * These parsers are used to parse a list of specific assets (like particle systems, etc..)

+ 1 - 2
src/node.ts

@@ -10,8 +10,7 @@ import { EngineStore } from "./Engines/engineStore";
 declare type Animatable = import("./Animations/animatable").Animatable;
 declare type AnimationPropertiesOverride = import("./Animations/animationPropertiesOverride").AnimationPropertiesOverride;
 declare type Animation = import("./Animations/animation").Animation;
-declare type AnimationRange = import("./Animations/animation").AnimationRange;
-
+declare type AnimationRange = import("./Animations/animationRange").AnimationRange;
 declare type AbstractMesh = import("./Meshes/abstractMesh").AbstractMesh;
 
 /**

+ 17 - 447
src/scene.ts

@@ -5,7 +5,7 @@ import { Observable, Observer } from "./Misc/observable";
 import { SmartArrayNoDuplicate, SmartArray, ISmartArrayLike } from "./Misc/smartArray";
 import { StringDictionary } from "./Misc/stringDictionary";
 import { Tags } from "./Misc/tags";
-import { Color4, Color3, Plane, Vector2, Vector3, Matrix, Tmp, Quaternion, Frustum } from "./Maths/math";
+import { Color4, Color3, Plane, Vector2, Vector3, Matrix, Tmp, Frustum } from "./Maths/math";
 import { Geometry } from "./Meshes/geometry";
 import { TransformNode } from "./Meshes/transformNode";
 import { SubMesh } from "./Meshes/subMesh";
@@ -25,11 +25,6 @@ import { ImageProcessingConfiguration } from "./Materials/imageProcessingConfigu
 import { Effect } from "./Materials/effect";
 import { UniformBuffer } from "./Materials/uniformBuffer";
 import { MultiMaterial } from "./Materials/multiMaterial";
-import { Animation } from "./Animations/animation";
-import { RuntimeAnimation } from "./Animations/runtimeAnimation";
-import { AnimationGroup } from "./Animations/animationGroup";
-import { Animatable } from "./Animations/animatable";
-import { AnimationPropertiesOverride } from "./Animations/animationPropertiesOverride";
 import { Light } from "./Lights/light";
 import { PickingInfo } from "./Collisions/pickingInfo";
 import { ICollisionCoordinator } from "./Collisions/collisionCoordinator";
@@ -51,6 +46,10 @@ import { Logger } from "./Misc/logger";
 import { EngineStore } from "./Engines/engineStore";
 import { AbstractActionManager } from './Actions/abstractActionManager';
 
+declare type Animation = import("./Animations/animation").Animation;
+declare type Animatable = import("./Animations/animatable").Animatable;
+declare type AnimationGroup = import("./Animations/animationGroup").AnimationGroup;
+declare type AnimationPropertiesOverride = import("./Animations/animationPropertiesOverride").AnimationPropertiesOverride;
 declare type Collider = import("./Collisions/collider").Collider;
 
 /**
@@ -592,7 +591,9 @@ export class Scene extends AbstractScene implements IAnimatable {
     public onMeshImportedObservable = new Observable<AbstractMesh>();
 
     // Animations
-    private _registeredForLateAnimationBindings = new SmartArrayNoDuplicate<any>(256);
+
+    /** @hidden */
+    public _registeredForLateAnimationBindings = new SmartArrayNoDuplicate<any>(256);
 
     // Pointers
     /**
@@ -1032,8 +1033,12 @@ export class Scene extends AbstractScene implements IAnimatable {
 
     private _animationRatio: number;
 
-    private _animationTimeLast: number;
-    private _animationTime: number = 0;
+    /** @hidden */
+    public _animationTimeLast: number;
+
+    /** @hidden */
+    public _animationTime: number = 0;
+
     /**
      * Gets or sets a general scale for animation speed
      * @see https://www.babylonjs-playground.com/#IBU2W7#3
@@ -1060,7 +1065,9 @@ export class Scene extends AbstractScene implements IAnimatable {
     /** @hidden */
     public _toBeDisposed = new Array<Nullable<IDisposable>>(256);
     private _activeRequests = new Array<IFileRequest>();
-    private _pendingData = new Array();
+
+    /** @hidden */
+    public _pendingData = new Array();
     private _isDisposed = false;
 
     /**
@@ -2480,188 +2487,6 @@ export class Scene extends AbstractScene implements IAnimatable {
         }, 150);
     }
 
-    // Animations
-
-    /**
-     * Will start the animation sequence of a given target
-     * @param target defines the target
-     * @param from defines from which frame should animation start
-     * @param to defines until which frame should animation run.
-     * @param weight defines the weight to apply to the animation (1.0 by default)
-     * @param loop defines if the animation loops
-     * @param speedRatio defines the speed in which to run the animation (1.0 by default)
-     * @param onAnimationEnd defines the function to be executed when the animation ends
-     * @param animatable defines an animatable object. If not provided a new one will be created from the given params
-     * @param targetMask defines if the target should be animated if animations are present (this is called recursively on descendant animatables regardless of return value)
-     * @param onAnimationLoop defines the callback to call when an animation loops
-     * @returns the animatable object created for this animation
-     */
-    public beginWeightedAnimation(target: any, from: number, to: number, weight = 1.0, loop?: boolean, speedRatio: number = 1.0,
-        onAnimationEnd?: () => void, animatable?: Animatable, targetMask?: (target: any) => boolean, onAnimationLoop?: () => void): Animatable {
-
-        let returnedAnimatable = this.beginAnimation(target, from, to, loop, speedRatio, onAnimationEnd, animatable, false, targetMask, onAnimationLoop);
-        returnedAnimatable.weight = weight;
-
-        return returnedAnimatable;
-    }
-
-    /**
-     * Will start the animation sequence of a given target
-     * @param target defines the target
-     * @param from defines from which frame should animation start
-     * @param to defines until which frame should animation run.
-     * @param loop defines if the animation loops
-     * @param speedRatio defines the speed in which to run the animation (1.0 by default)
-     * @param onAnimationEnd defines the function to be executed when the animation ends
-     * @param animatable defines an animatable object. If not provided a new one will be created from the given params
-     * @param stopCurrent defines if the current animations must be stopped first (true by default)
-     * @param targetMask defines if the target should be animate if animations are present (this is called recursively on descendant animatables regardless of return value)
-     * @param onAnimationLoop defines the callback to call when an animation loops
-     * @returns the animatable object created for this animation
-     */
-    public beginAnimation(target: any, from: number, to: number, loop?: boolean, speedRatio: number = 1.0,
-        onAnimationEnd?: () => void, animatable?: Animatable, stopCurrent = true,
-        targetMask?: (target: any) => boolean, onAnimationLoop?: () => void): Animatable {
-
-        if (from > to && speedRatio > 0) {
-            speedRatio *= -1;
-        }
-
-        if (stopCurrent) {
-            this.stopAnimation(target, undefined, targetMask);
-        }
-
-        if (!animatable) {
-            animatable = new Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd, undefined, onAnimationLoop);
-        }
-
-        const shouldRunTargetAnimations = targetMask ? targetMask(target) : true;
-        // Local animations
-        if (target.animations && shouldRunTargetAnimations) {
-            animatable.appendAnimations(target, target.animations);
-        }
-
-        // Children animations
-        if (target.getAnimatables) {
-            var animatables = target.getAnimatables();
-            for (var index = 0; index < animatables.length; index++) {
-                this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent, targetMask, onAnimationLoop);
-            }
-        }
-
-        animatable.reset();
-
-        return animatable;
-    }
-
-    /**
-     * Will start the animation sequence of a given target and its hierarchy
-     * @param target defines the target
-     * @param directDescendantsOnly if true only direct descendants will be used, if false direct and also indirect (children of children, an so on in a recursive manner) descendants will be used.
-     * @param from defines from which frame should animation start
-     * @param to defines until which frame should animation run.
-     * @param loop defines if the animation loops
-     * @param speedRatio defines the speed in which to run the animation (1.0 by default)
-     * @param onAnimationEnd defines the function to be executed when the animation ends
-     * @param animatable defines an animatable object. If not provided a new one will be created from the given params
-     * @param stopCurrent defines if the current animations must be stopped first (true by default)
-     * @param targetMask defines if the target should be animated if animations are present (this is called recursively on descendant animatables regardless of return value)
-     * @param onAnimationLoop defines the callback to call when an animation loops
-     * @returns the list of created animatables
-     */
-    public beginHierarchyAnimation(target: any, directDescendantsOnly: boolean, from: number, to: number, loop?: boolean, speedRatio: number = 1.0,
-        onAnimationEnd?: () => void, animatable?: Animatable, stopCurrent = true,
-        targetMask?: (target: any) => boolean, onAnimationLoop?: () => void): Animatable[] {
-
-        let children = target.getDescendants(directDescendantsOnly);
-
-        let result = [];
-        result.push(this.beginAnimation(target, from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent, targetMask));
-        for (var child of children) {
-            result.push(this.beginAnimation(child, from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent, targetMask));
-        }
-
-        return result;
-    }
-
-    /**
-     * Begin a new animation on a given node
-     * @param target defines the target where the animation will take place
-     * @param animations defines the list of animations to start
-     * @param from defines the initial value
-     * @param to defines the final value
-     * @param loop defines if you want animation to loop (off by default)
-     * @param speedRatio defines the speed ratio to apply to all animations
-     * @param onAnimationEnd defines the callback to call when an animation ends (will be called once per node)
-     * @param onAnimationLoop defines the callback to call when an animation loops
-     * @returns the list of created animatables
-     */
-    public beginDirectAnimation(target: any, animations: Animation[], from: number, to: number, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void, onAnimationLoop?: () => void): Animatable {
-        if (speedRatio === undefined) {
-            speedRatio = 1.0;
-        }
-
-        var animatable = new Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd, animations, onAnimationLoop);
-
-        return animatable;
-    }
-
-    /**
-     * Begin a new animation on a given node and its hierarchy
-     * @param target defines the root node where the animation will take place
-     * @param directDescendantsOnly if true only direct descendants will be used, if false direct and also indirect (children of children, an so on in a recursive manner) descendants will be used.
-     * @param animations defines the list of animations to start
-     * @param from defines the initial value
-     * @param to defines the final value
-     * @param loop defines if you want animation to loop (off by default)
-     * @param speedRatio defines the speed ratio to apply to all animations
-     * @param onAnimationEnd defines the callback to call when an animation ends (will be called once per node)
-     * @param onAnimationLoop defines the callback to call when an animation loops
-     * @returns the list of animatables created for all nodes
-     */
-    public beginDirectHierarchyAnimation(target: Node, directDescendantsOnly: boolean, animations: Animation[], from: number, to: number, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void, onAnimationLoop?: () => void): Animatable[] {
-        let children = target.getDescendants(directDescendantsOnly);
-
-        let result = [];
-        result.push(this.beginDirectAnimation(target, animations, from, to, loop, speedRatio, onAnimationEnd, onAnimationLoop));
-        for (var child of children) {
-            result.push(this.beginDirectAnimation(child, animations, from, to, loop, speedRatio, onAnimationEnd, onAnimationLoop));
-        }
-
-        return result;
-    }
-
-    /**
-     * Gets the animatable associated with a specific target
-     * @param target defines the target of the animatable
-     * @returns the required animatable if found
-     */
-    public getAnimatableByTarget(target: any): Nullable<Animatable> {
-        for (var index = 0; index < this._activeAnimatables.length; index++) {
-            if (this._activeAnimatables[index].target === target) {
-                return this._activeAnimatables[index];
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * Gets all animatables associated with a given target
-     * @param target defines the target to look animatables for
-     * @returns an array of Animatables
-     */
-    public getAllAnimatablesByTarget(target: any): Array<Animatable> {
-        let result = [];
-        for (var index = 0; index < this._activeAnimatables.length; index++) {
-            if (this._activeAnimatables[index].target === target) {
-                result.push(this._activeAnimatables[index]);
-            }
-        }
-
-        return result;
-    }
-
     /**
      * Gets all animatable attached to the scene
      */
@@ -2670,36 +2495,6 @@ export class Scene extends AbstractScene implements IAnimatable {
     }
 
     /**
-     * Will stop the animation of the given target
-     * @param target - the target
-     * @param animationName - the name of the animation to stop (all animations will be stopped if both this and targetMask are empty)
-     * @param targetMask - a function that determines if the animation should be stopped based on its target (all animations will be stopped if both this and animationName are empty)
-     */
-    public stopAnimation(target: any, animationName?: string, targetMask?: (target: any) => boolean): void {
-        var animatables = this.getAllAnimatablesByTarget(target);
-
-        for (var animatable of animatables) {
-            animatable.stop(animationName, targetMask);
-        }
-    }
-
-    /**
-     * Stops and removes all animations that have been applied to the scene
-     */
-    public stopAllAnimations(): void {
-        if (this._activeAnimatables) {
-            for (let i = 0; i < this._activeAnimatables.length; i++) {
-                this._activeAnimatables[i].stop();
-            }
-            this._activeAnimatables = [];
-        }
-
-        for (var group of this.animationGroups) {
-            group.stop();
-        }
-    }
-
-    /**
      * Resets the last animation time frame.
      * Useful to override when animations start running when loading a scene for the first time.
      */
@@ -2707,231 +2502,6 @@ export class Scene extends AbstractScene implements IAnimatable {
         this._animationTimeLast = PrecisionDate.Now;
     }
 
-    private _animate(): void {
-        if (!this.animationsEnabled || this._activeAnimatables.length === 0) {
-            return;
-        }
-
-        // Getting time
-        var now = PrecisionDate.Now;
-        if (!this._animationTimeLast) {
-            if (this._pendingData.length > 0) {
-                return;
-            }
-            this._animationTimeLast = now;
-        }
-        var deltaTime = this.useConstantAnimationDeltaTime ? 16.0 : (now - this._animationTimeLast) * this.animationTimeScale;
-        this._animationTime += deltaTime;
-        this._animationTimeLast = now;
-        for (var index = 0; index < this._activeAnimatables.length; index++) {
-            this._activeAnimatables[index]._animate(this._animationTime);
-        }
-
-        // Late animation bindings
-        this._processLateAnimationBindings();
-    }
-
-    /** @hidden */
-    public _registerTargetForLateAnimationBinding(runtimeAnimation: RuntimeAnimation, originalValue: any): void {
-        let target = runtimeAnimation.target;
-        this._registeredForLateAnimationBindings.pushNoDuplicate(target);
-
-        if (!target._lateAnimationHolders) {
-            target._lateAnimationHolders = {};
-        }
-
-        if (!target._lateAnimationHolders[runtimeAnimation.targetPath]) {
-            target._lateAnimationHolders[runtimeAnimation.targetPath] = {
-                totalWeight: 0,
-                animations: [],
-                originalValue: originalValue
-            };
-        }
-
-        target._lateAnimationHolders[runtimeAnimation.targetPath].animations.push(runtimeAnimation);
-        target._lateAnimationHolders[runtimeAnimation.targetPath].totalWeight += runtimeAnimation.weight;
-    }
-
-    private _processLateAnimationBindingsForMatrices(holder: {
-        totalWeight: number,
-        animations: RuntimeAnimation[],
-        originalValue: Matrix
-    }): any {
-        let normalizer = 1.0;
-        let finalPosition = Tmp.Vector3[0];
-        let finalScaling = Tmp.Vector3[1];
-        let finalQuaternion = Tmp.Quaternion[0];
-        let startIndex = 0;
-        let originalAnimation = holder.animations[0];
-        let originalValue = holder.originalValue;
-
-        var scale = 1;
-        if (holder.totalWeight < 1.0) {
-            // We need to mix the original value in
-            originalValue.decompose(finalScaling, finalQuaternion, finalPosition);
-            scale = 1.0 - holder.totalWeight;
-        } else {
-            startIndex = 1;
-            // We need to normalize the weights
-            normalizer = holder.totalWeight;
-            originalAnimation.currentValue.decompose(finalScaling, finalQuaternion, finalPosition);
-            scale = originalAnimation.weight / normalizer;
-            if (scale == 1) {
-                return originalAnimation.currentValue;
-            }
-        }
-
-        finalScaling.scaleInPlace(scale);
-        finalPosition.scaleInPlace(scale);
-        finalQuaternion.scaleInPlace(scale);
-
-        for (var animIndex = startIndex; animIndex < holder.animations.length; animIndex++) {
-            var runtimeAnimation = holder.animations[animIndex];
-            var scale = runtimeAnimation.weight / normalizer;
-            let currentPosition = Tmp.Vector3[2];
-            let currentScaling = Tmp.Vector3[3];
-            let currentQuaternion = Tmp.Quaternion[1];
-
-            runtimeAnimation.currentValue.decompose(currentScaling, currentQuaternion, currentPosition);
-            currentScaling.scaleAndAddToRef(scale, finalScaling);
-            currentQuaternion.scaleAndAddToRef(scale, finalQuaternion);
-            currentPosition.scaleAndAddToRef(scale, finalPosition);
-        }
-
-        Matrix.ComposeToRef(finalScaling, finalQuaternion, finalPosition, originalAnimation._workValue);
-        return originalAnimation._workValue;
-    }
-
-    private _processLateAnimationBindingsForQuaternions(holder: {
-        totalWeight: number,
-        animations: RuntimeAnimation[],
-        originalValue: Quaternion
-    }, refQuaternion: Quaternion): Quaternion {
-        let originalAnimation = holder.animations[0];
-        let originalValue = holder.originalValue;
-
-        if (holder.animations.length === 1) {
-            Quaternion.SlerpToRef(originalValue, originalAnimation.currentValue, Math.min(1.0, holder.totalWeight), refQuaternion);
-            return refQuaternion;
-        }
-
-        let normalizer = 1.0;
-        let quaternions: Array<Quaternion>;
-        let weights: Array<number>;
-
-        if (holder.totalWeight < 1.0) {
-            let scale = 1.0 - holder.totalWeight;
-
-            quaternions = [];
-            weights = [];
-
-            quaternions.push(originalValue);
-            weights.push(scale);
-        } else {
-            if (holder.animations.length === 2) { // Slerp as soon as we can
-                Quaternion.SlerpToRef(holder.animations[0].currentValue, holder.animations[1].currentValue, holder.animations[1].weight / holder.totalWeight, refQuaternion);
-                return refQuaternion;
-            }
-            quaternions = [];
-            weights = [];
-
-            normalizer = holder.totalWeight;
-        }
-        for (var animIndex = 0; animIndex < holder.animations.length; animIndex++) {
-            let runtimeAnimation = holder.animations[animIndex];
-            quaternions.push(runtimeAnimation.currentValue);
-            weights.push(runtimeAnimation.weight / normalizer);
-        }
-
-        // https://gamedev.stackexchange.com/questions/62354/method-for-interpolation-between-3-quaternions
-
-        let cumulativeAmount = 0;
-        let cumulativeQuaternion: Nullable<Quaternion> = null;
-        for (var index = 0; index < quaternions.length;) {
-            if (!cumulativeQuaternion) {
-                Quaternion.SlerpToRef(quaternions[index], quaternions[index + 1], weights[index + 1] / (weights[index] + weights[index + 1]), refQuaternion);
-                cumulativeQuaternion = refQuaternion;
-                cumulativeAmount = weights[index] + weights[index + 1];
-                index += 2;
-                continue;
-            }
-            cumulativeAmount += weights[index];
-            Quaternion.SlerpToRef(cumulativeQuaternion, quaternions[index], weights[index] / cumulativeAmount, cumulativeQuaternion);
-            index++;
-        }
-
-        return cumulativeQuaternion!;
-    }
-
-    private _processLateAnimationBindings(): void {
-        if (!this._registeredForLateAnimationBindings.length) {
-            return;
-        }
-        for (var index = 0; index < this._registeredForLateAnimationBindings.length; index++) {
-            var target = this._registeredForLateAnimationBindings.data[index];
-
-            for (var path in target._lateAnimationHolders) {
-                var holder = target._lateAnimationHolders[path];
-                let originalAnimation: RuntimeAnimation = holder.animations[0];
-                let originalValue = holder.originalValue;
-
-                let matrixDecomposeMode = Animation.AllowMatrixDecomposeForInterpolation && originalValue.m; // ie. data is matrix
-
-                let finalValue: any = target[path];
-                if (matrixDecomposeMode) {
-                    finalValue = this._processLateAnimationBindingsForMatrices(holder);
-                } else {
-                    let quaternionMode = originalValue.w !== undefined;
-                    if (quaternionMode) {
-                        finalValue = this._processLateAnimationBindingsForQuaternions(holder, finalValue || Quaternion.Identity());
-                    } else {
-
-                        let startIndex = 0;
-                        let normalizer = 1.0;
-
-                        if (holder.totalWeight < 1.0) {
-                            // We need to mix the original value in
-                            if (originalValue.scale) {
-                                finalValue = originalValue.scale(1.0 - holder.totalWeight);
-                            } else {
-                                finalValue = originalValue * (1.0 - holder.totalWeight);
-                            }
-                        } else {
-                            // We need to normalize the weights
-                            normalizer = holder.totalWeight;
-                            let scale = originalAnimation.weight / normalizer;
-                            if (scale !== 1) {
-                                if (originalAnimation.currentValue.scale) {
-                                    finalValue = originalAnimation.currentValue.scale(scale);
-                                } else {
-                                    finalValue = originalAnimation.currentValue * scale;
-                                }
-                            } else {
-                                finalValue = originalAnimation.currentValue;
-                            }
-
-                            startIndex = 1;
-                        }
-
-                        for (var animIndex = startIndex; animIndex < holder.animations.length; animIndex++) {
-                            var runtimeAnimation = holder.animations[animIndex];
-                            var scale = runtimeAnimation.weight / normalizer;
-                            if (runtimeAnimation.currentValue.scaleAndAddToRef) {
-                                runtimeAnimation.currentValue.scaleAndAddToRef(scale, finalValue);
-                            } else {
-                                finalValue += runtimeAnimation.currentValue * scale;
-                            }
-                        }
-                    }
-                }
-                target[path] = finalValue;
-            }
-
-            target._lateAnimationHolders = {};
-        }
-        this._registeredForLateAnimationBindings.reset();
-    }
-
     // Matrix
     /** @hidden */
     public _switchToAlternateCameraConfiguration(active: boolean): void {