remove = (targets, renderable, propertyName) => {
  const targetsArray = parseTargets(targets);
  const parent = renderable ? renderable : engine;
  let removeMatches;
  if (parent._hasChildren) {
    forEachChildren(parent, (/** @type {Renderable} */child) => {
      if (!child._hasChildren) {
        removeMatches = removeTargetsFromAnimation(targetsArray, /** @type {Animation} */(child), propertyName);
        // Remove the child from its parent if no tweens and no children left after the removal
        if (removeMatches && !child._head) {
          // TODO: Call child.onInterupt() here when implemented
          child.cancel();
          removeChild(parent, child);
        }
      }
      // Make sure to also remove engine's children targets
      // NOTE: Avoid recursion?
      if (child._head) {
        remove(targets, child);
      } else {
        child._hasChildren = false;
      }
    }, true);
  } else {
    removeMatches = removeTargetsFromAnimation(
      targetsArray,
      /** @type {Animation} */(parent),
      propertyName
    );
  }

  if (removeMatches && !parent._head) {
    parent._hasChildren = false;
    // TODO: Call child.onInterupt() here when implemented
    // Cancel the parent if there are no tweens and no children left after the removal
    // We have to check if the .cancel() method exist to handle cases where the parent is the engine itself
    if (/** @type {Renderable} */(parent).cancel) /** @type {Renderable} */(parent).cancel();
  }

  return targetsArray;
}
@param  {TargetsParam} targets
@param  {Renderable}   [renderable]
@param  {String}       [propertyName]
@return {TargetsArray}