Animations: storing key frames in typed arrays

Example of replacing animation in scene, could be imcomplete
/**
 * The callback for animation iteration in scene
 */
interface IterateAnimationCallback {
    /**
     * The callback for animation iteration in scene
     * @param animation current animation
     * @param key key of context
     * @param context object holding this animation
     * @returns false to stop the iteration
     */
    (animation: Animation, key: number | string, context: any): void | boolean;
}

function iterateAnimations(scene: Scene, callBack: IterateAnimationCallback): void {
    const {
        animations,
        animatables,
        animationGroups,
        transformNodes,
        meshes,
        materials,
        textures,
        cameras,
        particleSystems,
        morphTargetManagers,
        skeletons,
        spriteManagers,
        postProcesses,
    } = scene;

    let len = animations?.length;
    if (len) {
        for (let i = 0; i < len; i++) {
            if (callBack(animations[i], i, animations) === false) {
                return;
            }
        }
    }

    len = animatables?.length;
    if (len) {
        for (let i = 0; i < len; i++) {
            const animatable = animatables[i];
            const runtimeAnimations = animatable.getAnimations();
            const length = runtimeAnimations?.length;
            if (length) {
                for (let j = 0; j < length; j++) {
                    const runtimeAnimation = runtimeAnimations[i];
                    const animation = runtimeAnimation.animation;
                    if (animation &&
                        callBack(animation, '_animation', runtimeAnimation) === false) {
                        return;
                    }
                    const target = runtimeAnimation.target;
                    if (target?.animations) {
                        const iAnimatable = target as IAnimatable;
                        const animations = iAnimatable.animations;
                        const animationsLength = animations?.length;
                        if (animations && animationsLength) {
                            for (let k = 0; k < animationsLength; k++) {
                                const animation = animations[k];
                                if (animation && callBack(animation, k, animations) === false) {
                                    return;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    len = animationGroups?.length;
    if (len) {
        for (let i = 0; i < len; i++) {
            const group = animationGroups[i];
            const targetedAnimations = group?.targetedAnimations;
            let length = targetedAnimations?.length;
            if (length) {
                for (let j = 0; j < length; j++) {
                    const targetedAnimation = targetedAnimations[j];
                    const animation = targetedAnimation?.animation;
                    if (animation && callBack(animation, 'animation', targetedAnimation)) {
                        return;
                    }
                    const target = targetedAnimation.target;
                    if (target?.animations) {
                        const iAnimatable = target as IAnimatable;
                        const animations = iAnimatable.animations;
                        const animationsLength = animations?.length;
                        if (animations && animationsLength) {
                            for (let k = 0; k < animationsLength; k++) {
                                const animation = animations[k];
                                if (animation && callBack(animation, k, animations) === false) {
                                    return;
                                }
                            }
                        }
                    }
                }
            }
            const animatables = group?.animatables;
            length = animatables?.length;
            if (length) {
                for (let j = 0; j < length; j++) {
                    const animatable = animatables[i];
                    const runtimeAnimations = animatable.getAnimations();
                    const length = runtimeAnimations?.length;
                    if (length) {
                        for (let j = 0; j < length; j++) {
                            const runtimeAnimation = runtimeAnimations[i];
                            if (runtimeAnimation.animation &&
                                callBack(
                                    runtimeAnimation.animation,
                                    '_animation',
                                    runtimeAnimation
                                ) === false) {
                                return;
                            }
                        }
                    }
                }
            }
        }
    }
    len = morphTargetManagers?.length;
    if (len) {
        for (let i = 0; i < len; i++) {
            const morphTargetManager = morphTargetManagers[i];
            const targetsLength = morphTargetManager.numTargets;
            if (!targetsLength) {
                continue;
            }
            for (let j = 0; j < targetsLength; j++) {
                const target = morphTargetManager.getTarget(j);
                const animations = target?.animations;
                const length = animations?.length;
                if (!length) {
                    continue;
                }
                for (let k = 0; k < length; k++) {
                    const animation = animations[k];
                    if (animation && callBack(animation, k, animations) === false) {
                        return;
                    }
                }
            }
        }
    }

    len = skeletons?.length;
    if (len) {
        for (let i = 0; i < len; i++) {
            const skeleton = skeletons[i];
            const bones = skeleton?.bones;
            const length = bones?.length;
            if (length) {
                for (let j = 0; j < length; j++) {
                    const target = bones[j];
                    const animations = target?.animations;
                    const animationsLength = animations?.length;
                    if (!animationsLength) {
                        continue;
                    }
                    for (let k = 0; k < animationsLength; k++) {
                        const animation = animations[k];
                        if (animation && callBack(animation, k, animations) === false) {
                            return;
                        }
                    }
                }
            }
            const animations = skeleton?.animations;
            const animationsLength = animations?.length;
            if (animationsLength) {
                for (let j = 0; j < animationsLength; j++) {
                    const animation = animations[j];
                    if (animation && callBack(animation, j, animations) === false) {
                        return;
                    }
                }
            }
        }
    }

    len = spriteManagers?.length;
    if (len) {
        for (let i = 0; i < len; i++) {
            const spriteManager = spriteManagers[i];
            const sprites = spriteManager?.sprites;
            const length = sprites?.length;
            if (length) {
                for (let j = 0; j < length; j++) {
                    const target = sprites[j];
                    const animations = target?.animations;
                    const animationsLength = animations?.length;
                    if (!animationsLength) {
                        continue;
                    }
                    for (let k = 0; k < animationsLength; k++) {
                        const animation = animations[k];
                        if (animation && callBack(animation, k, animations) === false) {
                            return;
                        }
                    }
                }
            }
            const animations = spriteManager?.texture?.animations;
            const animationsLength = animations?.length;
            if (animationsLength) {
                for (let j = 0; j < animationsLength; j++) {
                    const animation = animations[j];
                    if (animation && callBack(animation, j, animations) === false) {
                        return;
                    }
                }
            }
        }
    }

    let iAnimatables: IAnimatable[] = [];

    len = transformNodes?.length;
    if (len) {
        iAnimatables = iAnimatables.concat(transformNodes);
    }
    len = meshes?.length;
    if (len) {
        iAnimatables = iAnimatables.concat(meshes);
    }
    len = cameras?.length;
    if (len) {
        iAnimatables = iAnimatables.concat(cameras);
    }
    len = materials?.length;
    if (len) {
        iAnimatables = iAnimatables.concat(materials);
    }
    len = textures?.length;
    if (len) {
        iAnimatables = iAnimatables.concat(textures);
    }
    len = particleSystems?.length;
    if (len) {
        iAnimatables = iAnimatables.concat(particleSystems);
    }
    len = postProcesses?.length;
    if (len) {
        iAnimatables = iAnimatables.concat(postProcesses);
    }

    len = iAnimatables.length;
    if (len) {
        for (let i = 0; i < len; i++) {
            const iAnimatable = iAnimatables[i];
            const animations = iAnimatable?.animations;
            const length = animations?.length;
            if (length) {
                for (let j = 0; j < length; j++) {
                    const animation = animations[j];
                    if (animation && callBack(animation, j, animations) === false) {
                        return;
                    }
                }
            }
        }
    }
}

/**
 * Replace animation from scene
 * @param scene The scene holding animation
 * @param animation The animation to be replaced
 * @param replacement The animation to be replaced to
 */
export function replaceAnimation(scene: Scene, animation: Animation, replacement: Animation): number {
    let count = 0;
    iterateAnimations(scene, (current, key, context) => {
        if (animation === current) {
            context[key] = replacement;
            count++;
        }
    });
    return count;
}