Help with animation bug

https://jsfiddle.net/uvfpwzb9/

I setup a simple scene to demo the problem. Click the button to start the animation and notice that it doesn’t animate down as far as it animates up.

The keyframes are pretty straightforward:

await asyncAnimate([new THREE.NumberKeyframeTrack(machineRead.uuid + '.position[y]', [0, SPEED], [machineRead.position.y, machineRead.position.y - 150])])

    await asyncAnimate([new THREE.NumberKeyframeTrack(machineRead.uuid + '.position[y]', [0, SPEED], [machineRead.position.y, machineRead.position.y + 150])])

Looks like I needed to add

mixer.stopAllAction() in there. Now it’s working:

  function asyncAnimate(tracks) {
    return new Promise((resolve, reject) => {
      let clip =  new THREE.AnimationClip(null, SPEED, [...tracks])
      console.log(clip)
      let clipAction = mixer.clipAction(clip)
      clipAction.setLoop(THREE.LoopOnce)
      clipAction.clampWhenFinished = true
      clipAction.play()

      function res() {
        console.log("finished")


        mixer.removeEventListener('finished', res)
        mixer.stopAllAction()
        resolve()
      }
      mixer.addEventListener('finished', res)


    })
  }

Is there a special reason for using two keyframe tracks? Why not using a single one which contains the entire animation data?

Example: https://jsfiddle.net/uvfpwzb9/4/

The animation clips are dynamically created based on some state. You can see an example in another question I opened: As animations go faster there is increasing error in accuracy

Here’s one section where i’m creating the animations:

  for (let child of [...readGroups.children].reverse()) {

    console.log(child.name, child.position.z, readGroups.position.z)

    cb('testing ' + child.name)
    await asyncAnimate([
      new THREE.NumberKeyframeTrack(readGroups.uuid + '.position[z]', [0, SPEED], [readGroups.position.z, - child.position.z + 150])
    ])

    if (child.name == state.read) {
      cb('match! moving down')
      await asyncAnimate([
        new THREE.NumberKeyframeTrack(child.uuid + '.position[y]', [0, SPEED], [child.position.y, child.position.y - 150])
      ])
      readChild = child
      scene.remove(readClone)
      break
    } else {
      await asyncAnimate([
        new THREE.NumberKeyframeTrack(child.uuid + '.position[y]', [0, SPEED], [child.position.y, child.position.y - 30])
      ])
      await asyncAnimate([
        new THREE.NumberKeyframeTrack(child.uuid + '.position[y]', [0, SPEED], [child.position.y, child.position.y + 30])
      ])
      cb('no match moving...')
    }
  }

will probably be helpful to throw in the asyncAnimate function too:

function asyncAnimate(tracks) {
    return new Promise((resolve, reject) => {
      let clip =  new THREE.AnimationClip(null, SPEED, [...tracks])
      let clipAction = mixer.clipAction(clip)
      clipAction.setLoop(THREE.LoopOnce)
      clipAction.clampWhenFinished = true
      clipAction.play()

      function res() {
        mixer.removeEventListener('finished', res)
        mixer.stopAllAction()
        resolve()
      }
      mixer.addEventListener('finished', res)
    })
  }