docs: function processAnimation(clip, root) {
        if (!outputJSON.animations) {
          outputJSON.animations = [];
        }
  
        var channels = [];
        var samplers = [];
  
        for (var i = 0; i < clip.tracks.length; ++i) {
          var track = clip.tracks[i];
          var trackBinding = THREE.PropertyBinding.parseTrackName(track.name);
          var trackNode = THREE.PropertyBinding.findNode(
            root,
            trackBinding.nodeName
          );
          var trackProperty = PATH_PROPERTIES[trackBinding.propertyName];
  
          if (trackBinding.objectName === 'bones') {
            if (trackNode.isSkinnedMesh === true) {
              trackNode = trackNode.skeleton.getBoneByName(
                trackBinding.objectIndex
              );
            } else {
              trackNode = undefined;
            }
          }
  
          if (!trackNode || !trackProperty) {
            console.warn(
              'THREE.GLTFExporter: Could not export animation track "%s".',
              track.name
            );
            return null;
          }
  
          var inputItemSize = 1;
          var outputItemSize = track.values.length / track.times.length;
  
          if (trackProperty === PATH_PROPERTIES.morphTargetInfluences) {
            if (
              trackNode.morphTargetInfluences.length !== 1 &&
              trackBinding.propertyIndex !== undefined
            ) {
              console.warn(
                'THREE.GLTFExporter: Skipping animation track "%s". ' +
                  'Morph target keyframe tracks must target all available morph targets ' +
                  'for the given mesh.',
                track.name
              );
              continue;
            }
  
            outputItemSize /= trackNode.morphTargetInfluences.length;
          }
  
          var interpolation;
  
          // @TODO export CubicInterpolant(InterpolateSmooth) as CUBICSPLINE
  
          // Detecting glTF cubic spline interpolant by checking factory method's special property
          // GLTFCubicSplineInterpolant is a custom interpolant and track doesn't return
          // valid value from .getInterpolation().
          if (
            track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ===
            true
          ) {
            interpolation = 'CUBICSPLINE';
  
            // itemSize of CUBICSPLINE keyframe is 9
            // (VEC3 * 3: inTangent, splineVertex, and outTangent)
            // but needs to be stored as VEC3 so dividing by 3 here.
            outputItemSize /= 3;
          } else if (track.getInterpolation() === THREE.InterpolateDiscrete) {
            interpolation = 'STEP';
          } else {
            interpolation = 'LINEAR';
          }
  
          samplers.push({
            input: processAccessor(
              new THREE.BufferAttribute(track.times, inputItemSize)
            ),
            output: processAccessor(
              new THREE.BufferAttribute(track.values, outputItemSize)
            ),
            interpolation: interpolation
          });
  
          channels.push({
            sampler: samplers.length - 1,
            target: {
              node: nodeMap.get(trackNode),
              path: trackProperty
            }
          });
        }
  
        outputJSON.animations.push({
          name: clip.name || 'clip_' + outputJSON.animations.length,
          samplers: samplers,
          channels: channels
        });
  
        return outputJSON.animations.length - 1;
      }