Sometimes it’s more useful to implement animations via AnimationMixer.

const animations = {
  idle: "Idle" // Name of animation clip
};
const events = {
  render: "render"
};

//EXAMPLE OF USAGE
this.activeSceneModel.$parent.emitter.addListener("geenee-model-placed", () => {
  initializeMixer();

  setTimeout(() => playAnim(animations.idle, mixer, clips), 500);

  this.activeSceneModel.userCallbacks.onRender = render;
});

// Update the mixer on each frame
const render = () => {
    const renderEvent = new Event(events.render);
    document.dispatchEvent(renderEvent);
  };

//ANIMATIONS
let mixer = undefined;
let clips = undefined;
const clock = new THREE.Clock();
const initializeMixer = () => {
  const mesh = this.object3D.children[0];

  // Create an AnimationMixer, and get the list of AnimationClip instances
  mixer = new THREE.AnimationMixer(mesh);
  clips = mesh.animations;

	// Update mixer each frame
  document.addEventListener("render", () => {
    mixer.update(clock.getDelta());
  });
};

const stopAnim = (name, mixer) => {
  mixer.clipAction(name).stop();
};
const playAnim = (name, mixer, clips) => {
  stopAllAnimations(clips, mixer);
  mixer.clipAction(name).play();
};
const animAction = (name, mixer) => {
  return mixer.clipAction(name);
};

const crossFade = (out, to, mixer, clips, time) => {
  stopAllAnimations(clips, mixer);
  animAction(out, mixer).play();
  animAction(out, mixer).crossFadeTo(animAction(to, mixer), time);
  animAction(to, mixer).play();
};

const playAllAnimations = (clips, mixer) => {
  // Play all animations
  clips.forEach(function (clip) {
    mixer.clipAction(clip).play();
  });
};

const stopAllAnimations = (clips, mixer) => {
  // Play all animations
  clips.forEach(function (clip) {
    mixer.clipAction(clip).stop();
  });
};