Switch back and forth between xrController and FaceController

Is is possible to switch back and forth between xrController and FaceController using the same camera and threejs instances without XR8.stop() and XR8.run(), and instead use XR8.pause and XR8.resume? This is a threejs project.

The below call to swap() runs without errors and seems to switch out the controllers, though when switching back to XrController no image target recognition/tracking seems to be happening. The events reality.imageloading and reality.imagescanning are dispatched and I can see the image targets being loaded. Though no tracking…

const onxrloaded = () => {
  XR8.XrController.configure({disableWorldTracking: true})

  XR8.FaceController.configure({
    meshGeometry: [
      XR8.FaceController.MeshGeometry.FACE,
      XR8.FaceController.MeshGeometry.EYES,
      XR8.FaceController.MeshGeometry.MOUTH,
    ],
    coordinates: {mirroredDisplay: true},
    maxDetections: 3,
  })

  window.xrController = XR8.XrController.pipelineModule();
  window.faceController = XR8.FaceController.pipelineModule();

  XR8.addCameraPipelineModules([
    XR8.GlTextureRenderer.pipelineModule(),
    XR8.Threejs.pipelineModule(),
    window.xrController,
    window.LandingPage.pipelineModule(),
    XRExtras.FullWindowCanvas.pipelineModule(),
    XRExtras.Loading.pipelineModule(),
    XRExtras.RuntimeError.pipelineModule(),

    appModule(),
  ])

  document.body.insertAdjacentHTML('beforeend', camerafeedHtml)

  XR8.run({
    canvas: document.getElementById('camerafeed'),
    allowedDevices: XR8.XrConfig.device().ANY,
  })
}

const appModule = () =>
{
  let isFaceTrackingMode = false
  let imageTargets = []

  const imageTargetLoading = ({detail}) =>
  {
    imageTargets = []

    for (let i = 0; i < detail.imageTargets.length; i++) {
      imageTargets.push(detail.imageTargets[i].name);
    }
  }

  swap()
  {
      XR8.pause();

      isFaceTrackingMode = !isFaceTrackingMode;
      if (isFaceTrackingMode) {
        XR8.removeCameraPipelineModule(window.xrController.name);
        XR8.addCameraPipelineModule(window.faceController);
      } else {
        XR8.removeCameraPipelineModule(window.faceController.name);
        XR8.XrController.configure({disableWorldTracking: true, imageTargets: imageTargets})
        XR8.addCameraPipelineModule(window.xrController);
      }

      XR8.resume()
    }

  return {
    listeners: [
      { event: 'reality.imageloading', process: imageTargetLoading},
      { event: 'reality.imagescanning', process: imageTargetScanning},
      { event: 'reality.imagefound', process: showTarget},
      { event: 'reality.imageupdated', process: updateTarget},
      { event: 'reality.imagelost', process: hideTarget},
    ],
  }
}

fwiw, replacing XR8.pause() and XR8.resume() with XR8.stop() and XR8.run() is not as seamless and causes a momentary wait, but it works. We still would love to know if there is way to make the transition as fast and seamless as possible, ideally without having to wait a few seconds for the swap to happen.

To enhance its aesthetic appeal, consider adding CSS and a gradient fade.

Check out this example project using A-frame instead of three.js, which still serves as a valuable reference.