moeru-ai/airi · warning

Camera is not perspective camera, type error!

Error message

Camera is not perspective camera, type error!

What it means

After awaiting the camera and renderer DOM element, the component requires cameraTres.value instanceof PerspectiveCamera. With any other camera type (e.g. an OrthographicCamera scene) it warns and returns, so controls.value is never created and the component silently does nothing. Pan/zoom/rotate are configured disabled anyway, but no OrbitControls instance exists at all after this early return.

Source

Thrown at packages/stage-ui-three/src/components/Controls/OrbitControls.vue:184

      },
    )
  }

  disposeControlsChange?.()
  controls.value?.addEventListener('change', onChange)
  disposeControlsChange = () => controls.value?.removeEventListener('change', onChange)
}

onMounted(async () => {
  // wait until camera is not undefined
  await until(() => cameraTres.value && renderer.domElement).toBeTruthy()
  if (!cameraTres.value || !renderer.domElement) {
    console.warn('Camera or Renderer initialisation failure!')
    return
  }
  // Narrow down the camera's type
  if (!(cameraTres.value instanceof PerspectiveCamera)) {
    console.warn('Camera is not perspective camera, type error!')
    return
  }
  camera.value = cameraTres.value as PerspectiveCamera
  // Obtain orbitControl instance
  controls.value = new OrbitControls(camera.value, renderer.domElement)
  controls.value.enablePan = false
  controls.value.enableZoom = false
  controls.value.enableRotate = false
  // Align to tresjs conventions
  controls.value.mouseButtons = {
    LEFT: MOUSE.ROTATE,
    MIDDLE: MOUSE.DOLLY,
    RIGHT: MOUSE.PAN,
  }
  controls.value.touches = {
    ONE: TOUCH.ROTATE,
    TWO: TOUCH.DOLLY_PAN,
  }

View on GitHub (pinned to 677329427f)

Solutions

  1. Ensure the scene renders with a PerspectiveCamera before this component mounts
  2. Extend the guard to support OrthographicCamera if your scene needs it
  3. Verify cameraTres resolves to the camera object, not a wrapper or group
  4. Null-check controls.value downstream — it stays undefined after the early return

Example fix

// before
if (!(cameraTres.value instanceof PerspectiveCamera)) {
  console.warn('Camera is not perspective camera, type error!')
  return
}
camera.value = cameraTres.value as PerspectiveCamera

// after: reuse the narrowed guard
if (!isPerspectiveCamera(cameraTres.value)) {
  console.warn('Camera is not perspective camera, type error!')
  return
}
camera.value = cameraTres.value // already narrowed, no cast needed
Defensive patterns

Strategy: type-guard

Type guard

import { PerspectiveCamera } from 'three'

function isPerspectiveCamera(camera: unknown): camera is PerspectiveCamera {
  return camera instanceof PerspectiveCamera
}

Prevention

When it happens

Trigger: Scene camera is an OrthographicCamera (2D-style scene); the camera ref resolving to a non-camera object; dropping this component into a scene not built for perspective cameras.

Common situations: Reusing the OrbitControls component in an orthographic/2D scene; a TresJS scene where the camera slot is filled by a custom camera.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/3240c7e77da28c57. Report an issue: GitHub.