code: def look_at_quat(
      position: ArrayLike,
      target: ArrayLike,
      up: Union[str, ArrayLike] = "Y",
      front: Union[str, ArrayLike] = "-Z",
  ) -> Tuple[float, float, float, float]:
      # convert directions to vectors if needed
      world_up = convert_str_direction_to_vector("Z")
      world_right = convert_str_direction_to_vector("X")
      if isinstance(up, str):
          up = convert_str_direction_to_vector(up)
      if isinstance(front, str):
          front = convert_str_direction_to_vector(front)
  
      up = normalize(ensure_3d_vector(up))
      front = normalize(ensure_3d_vector(front))
      right = np.cross(up, front)
  
      target = ensure_3d_vector(target)
      position = ensure_3d_vector(position)
  
      # construct the desired coordinate basis front, right, up
      look_at_front = normalize(target - position)
      look_at_right = normalize(
          np.cross(world_up, look_at_front), fallback=world_right
      )
      look_at_up = normalize(np.cross(look_at_front, look_at_right))
  
      rotation_matrix1 = np.stack(
          [look_at_right, look_at_up, look_at_front]
      )
      rotation_matrix2 = np.stack([right, up, front])
      return tuple(
          pyquat.Quaternion(
              matrix=(rotation_matrix1.T @ rotation_matrix2)
          )
      )
  
imports: import itertools
  import numpy
  import pyquaternion
  import traitlets
  from typing import Optional, Union, Tuple
  from kubric.core import traits
  from kubric.core import assets
  from kubric.core import materials
  from kubric.kubric_typing import ArrayLike
label_desc: Use image node_id 5 for calling a global function with example usage: look_at_quat(position, target, up, front) and returns: tuple