> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/creator/content-creator-es/scenes-sdk7/fundamentos-del-contenido-3d/camera.md).

# Cámara

Aprende a controlar la cámara del jugador

Como creador, puedes tener control total sobre la cámara del jugador. De forma predeterminada, los jugadores son libres de elegir entre un modo de cámara en 1ª o 3ª persona mientras exploran tu escena, pero puedes imponer una modalidad de cámara diferente.

Las cámaras virtuales pueden ser estáticas, pueden rotar para mirar siempre al jugador o a alguna otra entidad, o pueden estar adjuntas al jugador o a alguna otra entidad para acompañarlo siempre.

{% hint style="warning" %}
**📔 Nota**: Para cambiar entre las cámaras predeterminadas en 1ª y 3ª persona, consulta [Áreas modificadoras de cámara](#1st-and-3rd-person-camera-modes).
{% endhint %}

## Modos de cámara en 1ª y 3ª persona

Los jugadores normalmente pueden cambiar entre cámara en primera y tercera persona presionando V en el teclado. Usa una `CameraModeArea` para forzar el modo de cámara a 1ª o 3ª persona para todos los jugadores que permanezcan dentro de un área específica de tu escena.

```ts
const entity = engine.addEntity()

CameraModeArea.create(entity, {
	area: Vector3.create(4, 3, 4),
	mode: CameraType.CT_FIRST_PERSON,
})
```

Si el modo de cámara actual de un jugador no coincide con el de la `CameraModeArea`, se cambiarán a ese modo de cámara. Aparece una notificación en pantalla para aclarar que este cambio se debe a la escena. Mientras estén dentro, los jugadores no pueden cambiar su modo de cámara. Cuando un jugador abandona la `CameraModeArea`, su modo de cámara se restaura al que tenía antes de entrar.

Usa `CameraModeArea` en regiones donde los jugadores tendrían una experiencia significativamente mejor usando un modo de cámara específico. Por ejemplo, la primera persona es ideal si el jugador necesita hacer clic en un objeto pequeño, o la tercera persona puede ser útil para que los jugadores noten alguna entidad que tu escena haya adjuntado sobre su cabeza. No asumas que los jugadores saben cómo cambiar de modo de cámara; muchos jugadores primerizos podrían no saber que tienen esa opción, o no recordar la tecla para hacerlo.

{% hint style="warning" %}
**📔 Nota**: Las áreas modificadoras de cámara se ven afectadas por la *posición* y *rotación* del componente Transform de su entidad anfitriona, pero no se ven afectadas por la *escala*.
{% endhint %}

{% hint style="warning" %}
**📔 Nota**: Si superpones varias áreas modificadoras de cámara, la última que sea instanciada por el código de tu escena tendrá prioridad sobre las demás.
{% endhint %}

Al crear un `CameraModeArea` componente, debes proporcionar lo siguiente:

* `area`: Tamaño del área modificadora
* `modo`: Qué modo de cámara forzar en esta área, de entre los `CameraType` enum.

Los modos de cámara admitidos son:

* `CameraType.CT_FIRST_PERSON`
* `CameraType.CT_THIRD_PERSON`

### Consultar el modo de cámara

Puedes consultar el modo de cámara del jugador usando el `CameraMode` componente en el `engine.CameraEntity`.

```ts
const cameraMode = CameraMode.get(engine.CameraEntity)
if (cameraMode.mode === CameraType.CT_FIRST_PERSON) {
	console.log('El jugador está usando la cámara en 1ª persona')
} else {
	console.log('El jugador está usando la cámara en 3ª persona')
}
```

También puedes suscribirte a los cambios en el modo de cámara usando el `onChange` función en el `CameraMode` componente.

```ts
CameraMode.onChange(engine.CameraEntity, (cameraMode) => {
	if (!cameraMode) return
	console.log('El modo de cámara del jugador cambió a', cameraMode.mode)
})
```

## Uso de cámaras virtuales

Para usar un comportamiento de cámara personalizado en tu escena, necesitas dos cosas:

* Crear una cámara virtual: crea una entidad en tu escena y asígnale un `VirtualCamera`.
* Asignar esa cámara virtual: agrega una `MainCamera` componente al [reserved entity](/creator/content-creator-es/scenes-sdk7/arquitectura/entities-components.md#reserved-entities) `engine.CameraEntity`, con una referencia a la entidad con el `VirtualCamera` componente.

A continuación, la cámara se adjuntará a la entidad con el `VirtualCamera` componente. Si la entidad se mueve o rota, la cámara se mueve con ella.

```ts
function main() {
	const myCustomCamera = engine.addEntity()
	Transform.create(myCustomCamera, {
		position: Vector3.create(1, 2, 1),
	})
	VirtualCamera.create(myCustomCamera, {})

	const mainCamera = MainCamera.createOrReplace(engine.CameraEntity, {
		virtualCameraEntity: myCustomCamera,
	})
}
```

En este ejemplo, la cámara estará siempre en una posición fija en la escena, mientras el jugador permanezca dentro de los límites de la escena. En cuanto el jugador salga de los límites de la escena, se restaurará el comportamiento predeterminado de la cámara.

### Campo de visión

Puedes sobrescribir el campo de visión (FOV) predeterminado del Explorer para una cámara virtual estableciendo la `fov` propiedad, en grados. La sobrescritura se aplica solo mientras esta cámara virtual esté activa. Si omites `fov` se usa el valor predeterminado del Explorer (normalmente 60 grados).

```ts
const cinematicCamera = engine.addEntity()
Transform.create(cinematicCamera, {
	position: Vector3.create(8, 3, 2),
})
VirtualCamera.create(cinematicCamera, {
	fov: 45,
})
```

Un FOV más estrecho (valor menor) hace zoom, útil para cinemáticas o apuntar. Un FOV más amplio (valor mayor) muestra más de la escena, útil para vistas panorámicas.

Tu escena puede incluir tantas entidades con un `VirtualCamera`componente como quieras, y cambiar dinámicamente entre varias cámaras virtuales a medida que el jugador se mueve, o cuando realiza ciertas acciones. Solo una cámara virtual está activa en cada momento, y esto lo asigna el `MainCamera` componente en `engine.CameraEntity`.

Para volver al comportamiento predeterminado de la cámara, establece el valor en `undefined` en `MainCamera.virtualCameraEntity`. Entonces el jugador puede cambiar libremente entre cámaras en 1ª y 3ª persona. Si quieres que el jugador use solo uno de estos dos modos, puedes usar una [Áreas modificadoras de cámara](#1st-and-3rd-person-camera-modes) para forzar uno de los dos.

{% hint style="warning" %}
**📔 Nota**: Las áreas modificadoras de cámara solo tienen efecto en el jugador si no hay cámaras virtuales activas. Si la escena está usando actualmente una cámara virtual y el jugador entra en un área modificadora de cámara, no pasa nada.

Si un modelo 3D incluye un `cámara` como nodo como parte de su contenido, el SDK no puede usarlo. Debes crear todas las cámaras como entidades con el SDK.
{% endhint %}

```ts
function main() {
	// cámara virtual personalizada
	const myCustomCamera = engine.addEntity()
	Transform.create(myCustomCamera, {
		position: Vector3.create(1, 2, 1),
	})
	VirtualCamera.create(myCustomCamera, {})

	const mainCamera = MainCamera.createOrReplace(engine.CameraEntity, {
		virtualCameraEntity: myCustomCamera,
	})

	// cubo clicable
	const clickCube = engine.addEntity()
	Transform.create(clickCube, { position: Vector3.create(8, 0, 8) })
	MeshRenderer.setBox(clickCube)
	MeshCollider.setBox(clickCube)
	pointerEventsSystem.onPointerDown(
		{
			entity: clickCube,
			opts: { button: InputAction.IA_POINTER, hoverText: 'Restablecer cámara' },
		},
		() => {
			// restablecer la cámara al comportamiento predeterminado
			const mainCamera = MainCamera.getMutable(engine.CameraEntity)
			mainCamera.virtualCameraEntity = undefined
		}
	)
}
```

{% hint style="info" %}
**💡 Consejo**: Cuando la cámara se aleja del avatar, a menudo es una buena práctica congelar también los movimientos del avatar. Así el jugador no avanza a ciegas hacia obstáculos. Consulta [Modificadores de entrada](/creator/content-creator-es/scenes-sdk7/interactividad/avatares/locomotion.md#freeze-the-player)
{% endhint %}

Para permitir que el jugador controle una cámara virtual con el ratón, lee la `screenDelta` propiedad del `PrimaryPointerInfo` componente para ver cuánto se movió el cursor en cada fotograma, y luego aplica ese movimiento a la rotación de la cámara. Esto funciona incluso mientras el cursor está bloqueado. Consulta [Movimiento del ratón](/creator/content-creator-es/scenes-sdk7/interactividad/mouse-movement.md) para ver un ejemplo completo de control de cámara con el ratón.

## Vista cenital

Puedes usar una cámara virtual para ver la escena desde una vista cenital; esto puede ser una variación divertida de la perspectiva normal de tu avatar y habilitar distintas mecánicas de juego.

Deberías evitar colocar una cámara mirando exactamente hacia abajo. En su lugar, inclina siempre la cámara ligeramente; incluso 1 grado es suficiente. Esto se debe a que los controles de dirección del jugador se basan en la perspectiva de la cámara, no en la orientación del avatar. Si la cámara mira desde una vista cenital perfecta, no hay una definición clara de qué dirección es cuál. Una inclinación imperceptible de 1 grado es suficiente para establecer una dirección hacia delante.

```ts
function main() {
	// cámara de vista cenital
	const myCustomCamera = engine.addEntity()
	Transform.create(myCustomCamera, {
		position: Vector3.create(8, 5, 8),
		rotation: Quaternion.fromEulerDegrees(91, 0, 0),
		// Nota que la rotación es 91º, no 90º
	})
	VirtualCamera.create(myCustomCamera, {})

	const mainCamera = MainCamera.createOrReplace(engine.CameraEntity, {
		virtualCameraEntity: myCustomCamera,
	})
}
```

## Campo de visión

Puedes establecer un campo de visión (FOV) personalizado en una cámara virtual con la `fov` propiedad. El valor está en grados. Si se omite, el valor predeterminado es 60.

```ts
VirtualCamera.create(myCustomCamera, {
	fov: 90,
})
```

Un FOV más amplio (valor mayor) muestra más de la escena a la vez y crea una sensación de velocidad, lo que puede ser útil para juegos de carreras. Un FOV más estrecho (valor menor) hace zoom y es útil para apuntar o para tomas cinematográficas.

## Transiciones de cámara

Siempre que la escena cambia entre cámaras virtuales, o entre el comportamiento de cámara predeterminado y las cámaras virtuales, los jugadores ven una transición. La posición, la rotación y cualquier otro parámetro de la cámara virtual cambian suavemente a lo largo de un período de tiempo.

La configuración de transición de una cámara virtual determina cómo transicionas *hacia* esa cámara, desde cualquier otra cámara de la escena, incluida la predeterminada. No afectan cómo transicionas *out* a partir de esa cámara.

```ts
VirtualCamera.create(myCustomCamera1, {
	defaultTransition: { transitionMode: VirtualCamera.Transition.Time(6) },
})
```

{% hint style="info" %}
**💡 Consejo**: Para evitar tener una transición y cambiar instantáneamente a una cámara, establece el tiempo o la velocidad de transición en 0.
{% endhint %}

Según tu caso de uso, quizá prefieras establecer la velocidad de la transición en lugar de la duración:

* **Tiempo fijo**: Estableces la duración de la transición; la cámara se moverá tan rápido como sea necesario para completar el recorrido en ese período de tiempo.
* **Velocidad fija**: Estableces qué tan rápido quieres que se mueva la cámara virtual durante la transición; la duración dependerá de la distancia. El valor usado para la velocidad se interpreta como **metros por segundo**.

A continuación se muestran ejemplos de ambos modos de transición:

```ts
// duración fija
VirtualCamera.create(myCustomCamera1, {
	defaultTransition: { transitionMode: VirtualCamera.Transition.Time(6) },
})

// velocidad fija
VirtualCamera.create(myCustomCamera1, {
	defaultTransition: { transitionMode: VirtualCamera.Transition.Speed(3) },
})
```

A continuación hay un ejemplo completo con dos cámaras virtuales y transiciones entre ellas:

```ts
function main() {
	// cámara virtual personalizada 1
	const myCustomCamera1 = engine.addEntity()
	Transform.create(myCustomCamera1, {
		position: Vector3.create(1, 2, 1),
	})
	VirtualCamera.create(myCustomCamera1, {
		defaultTransition: { transitionMode: VirtualCamera.Transition.Time(1) },
	})

	// cámara virtual personalizada 2
	const myCustomCamera2 = engine.addEntity()
	Transform.create(myCustomCamera2, {
		position: Vector3.create(1, 2, 1),
	})
	VirtualCamera.create(myCustomCamera2, {
		defaultTransition: { transitionMode: VirtualCamera.Transition.Time(3) },
	})

	const mainCamera = MainCamera.createOrReplace(engine.CameraEntity, {
		virtualCameraEntity: myCustomCamera1,
	})

	// cubo clicable
	const clickCube = engine.addEntity()
	Transform.create(clickCube, { position: Vector3.create(8, 0, 8) })
	MeshRenderer.setBox(clickCube)
	MeshCollider.setBox(clickCube)
	pointerEventsSystem.onPointerDown(
		{
			entity: clickCube,
			opts: { button: InputAction.IA_POINTER, hoverText: 'Restablecer cámara' },
		},
		() => {
			// restablecer la cámara al comportamiento predeterminado
			const mainCamera = MainCamera.getMutable(engine.CameraEntity)
			mainCamera.virtualCameraEntity =
				mainCamera.virtualCameraEntity == myCustomCamera1
					? myCustomCamera2
					: myCustomCamera1
		}
	)
}
```

Las transiciones siempre se mueven en línea recta, sin tener en cuenta ningún obstáculo en el camino. En su lugar, podrías crear una transición manualmente usando otra cámara virtual como intermediaria; de ese modo tendrías control total sobre sus movimientos. Esta cámara virtual intermediaria podría realizar un [Tween](/creator/content-creator-es/scenes-sdk7/fundamentos-del-contenido-3d/move-entities.md#move-between-two-points) desde la posición de la primera cámara hasta la posición de la segunda cámara, o seguir una ruta más personalizada que evite obstáculos o haga un desvío cinematográfico.

## Seguimiento de cámara

Puedes configurar una cámara virtual para que siempre mire hacia la dirección del jugador, o de alguna entidad específica de la escena. La posición de la cámara permanecerá estática, pero su rotación cambiará para mantener siempre centrada esta entidad.

Esto se puede lograr con el `lookAtEntity` property en el `VirtualCamera` componente. Para seguir al jugador, usa el [reserved entity](/creator/content-creator-es/scenes-sdk7/arquitectura/entities-components.md#reserved-entities) `engine.PlayerEntity`.

```ts
const myCustomCamera1 = engine.addEntity()
Transform.create(myCustomCamera1, {
	position: Vector3.create(1, 2, 1),
})
VirtualCamera.create(myCustomCamera1, {
	lookAtEntity: engine.PlayerEntity,
})
```

Si una entidad está siendo seguida por la cámara, esto solo cambiará la rotación, no la posición de la cámara.

A medida que la cámara rota, el Transform de la entidad con el `VirtualCamera` componente no cambia. Sin embargo, puedes leer la rotación de la cámara desde el Transform en `engine.CameraEntity`CameraEntity `VirtualCamera` La rotación y la posición de esta entidad serán absolutas; no estarán condicionadas por las de la entidad con el `lookAtEntity` componente. La rotación de este transform se ve afectada igual que por el comportamiento

{% hint style="warning" %}
**📔 Nota**: Si configuras la cámara virtual con un `lookAtEntity` que haga referencia a la misma entidad que contiene la cámara virtual, o a la `engine.CameraEntity` entidad, el comportamiento resultante será el mismo que no asignar ninguna entidad en absoluto.
{% endhint %}

## Adjuntar al jugador

Otro uso de la cámara virtual es seguir al jugador desde una distancia o ángulo personalizados, adjuntando una cámara virtual a la entidad del jugador. Ten en cuenta que el jugador no puede cambiar libremente la rotación de la cámara, así que en este caso la rotación de la cámara quedará fijada a la de la cámara virtual. Esto podría ser útil, por ejemplo, para juegos de carreras, donde se espera que el jugador siempre mire hacia delante.

```ts
function main() {
	const myCustomCamera = engine.addEntity()
	Transform.create(myCustomCamera, {
		position: Vector3.create(0, 1, 5),
		parent: engine.PlayerEntity,
	})
	VirtualCamera.create(myCustomCamera, {
		defaultTransition: { transitionMode: VirtualCamera.Transition.Time(2) },
	})

	const mainCamera = MainCamera.createOrReplace(engine.CameraEntity, {
		virtualCameraEntity: myCustomCamera,
	})
}
```

## Cámaras y colliders

Cuando la cámara de un jugador se mueve en modo de tercera persona, la cámara puede quedar bloqueada por colliders o no, dependiendo de las capas de colisión asignadas a las entidades. Ten esto en cuenta al diseñar tu escena; quizá quieras evitar que la cámara atraviese paredes u otras entidades.

Consulta [Colliders](/creator/content-creator-es/scenes-sdk7/fundamentos-del-contenido-3d/colliders.md#cameras-and-colliders) para más detalles sobre cómo configurar colliders para tu escena.

## Modo espectador (cámara de observador)

Puedes construir un modo espectador que cambie al jugador de un movimiento normal de avatar a una cámara de libre recorrido o que siga al jugador. Esto es útil para roles de observador en juegos competitivos, cámaras de director para eventos en vivo o sistemas de repetición.

El patrón combina varias funcionalidades del SDK:

| Funcionalidad                       | API del SDK                               | Propósito                                 |
| ----------------------------------- | ----------------------------------------- | ----------------------------------------- |
| Vista de cámara personalizada       | `VirtualCamera` + `MainCamera`            | Reemplaza la cámara del jugador           |
| Congelar el movimiento del avatar   | `InputModifier` (`disableAll: true`)      | Libera WASD para controlar la cámara      |
| Seguir a los jugadores en la escena | `onEnterScene` / `onLeaveScene`           | Construye una lista de objetivos a seguir |
| Controles de cámara                 | `inputSystem.isPressed(InputAction.IA_*)` | WASD para pitch/yaw, E/F para zoom        |
| Control de cámara con el ratón      | `PrimaryPointerInfo.screenDelta`          | Gira la cámara con el ratón               |

### Arquitectura del rig de cámara

Usa una **rig de dos entidades** para que yaw y pitch permanezcan independientes:

```
rigRoot (entidad)           -- posición mundial + rotación de yaw
└── rigCamera (hija)      -- rotación de pitch + desplazamiento orbital
    └── VirtualCamera
```

`rigRoot` contiene el yaw (giro izquierda/derecha) y se interpola hacia el objetivo a seguir o un pivote de cámara libre. `rigCamera` maneja el pitch (inclinación arriba/abajo) y la distancia orbital desde la raíz. Dividir yaw y pitch entre dos Transforms mantiene la matemática de Euler sencilla.

### Activar y desactivar

```ts
// Activar el modo espectador
const rigRoot = engine.addEntity()
Transform.create(rigRoot, {
  position: Vector3.create(8, 8, 8),
  rotation: Quaternion.fromEulerDegrees(0, 0, 0),
})

const rigCamera = engine.addEntity()
Transform.create(rigCamera, { parent: rigRoot })
VirtualCamera.create(rigCamera, {})

MainCamera.createOrReplace(engine.CameraEntity, { virtualCameraEntity: rigCamera })
InputModifier.createOrReplace(engine.PlayerEntity, {
  mode: InputModifier.Mode.Standard({ disableAll: true }),
})
```

```ts
// Desactivar el modo espectador
// IMPORTANTE: limpia MainCamera ANTES de eliminar la entidad VirtualCamera.
// Si eliminas la entidad primero, el engine sigue enlazado a una entidad muerta
// y la vista cae a los pies del jugador.
const mainCamera = MainCamera.getMutableOrNull(engine.CameraEntity)
if (mainCamera) mainCamera.virtualCameraEntity = undefined

engine.removeEntity(rigCamera)
engine.removeEntity(rigRoot)

InputModifier.createOrReplace(engine.PlayerEntity, {
  mode: InputModifier.Mode.Standard({ disableAll: false }),
})
```

{% hint style="danger" %}
**Advertencia:** Limpia siempre `MainCamera.virtualCameraEntity` antes de eliminar la entidad de la cámara. Eliminar la entidad primero deja al engine apuntando a una referencia muerta, lo que hace que la vista se rompa.
{% endhint %}

### Límites de la cámara

El engine desactiva `VirtualCamera` las entidades que se mueven fuera de los límites de parcela de tu escena. Si la cámara sale del área de la escena, deja de funcionar silenciosamente. Ajusta la posición de la cámara para que permanezca dentro de la caja delimitada alineada a los ejes (AABB) de la escena en cada fotograma, con un pequeño margen.

```ts
// Ejemplo de límites para una escena de una parcela 1x1 (16m x 16m)
const BOUNDS_MIN = Vector3.create(0, 0, 0)
const BOUNDS_MAX = Vector3.create(16, 20, 16)
const BOUNDS_MARGIN = 0.5
```

Para escenas más grandes, ajusta los límites para que coincidan con tus `scene.json` parcels. El límite de altura de la escena es de 330 metros independientemente del número de parcels. Una escena de 4x4 parcels podría usar `Vector3.create(64, 330, 64)`.

### Seguimiento de jugadores

Usa `onEnterScene` y `onLeaveScene` para construir una lista en vivo de jugadores en tu escena. Luego, los jugadores pueden ciclar entre objetivos de seguimiento con teclas (por ejemplo, `IA_ACTION_3` y `IA_ACTION_4`). Cuando sigues a un jugador, la raíz del rig interpola hacia la posición del Transform del jugador seguido, y la cámara hija orbita a una distancia configurable.

```ts
import { onEnterScene, onLeaveScene } from '@dcl/sdk/src/players'

const playerEntities = new Map<string, Entity>()
let playerIds: string[] = []

onEnterScene((player) => {
  if (!player) return
  playerIds.push(player.userId)
  playerEntities.set(player.userId, player.entity)
})

onLeaveScene((userId) => {
  if (!userId) return
  playerIds = playerIds.filter((id) => id !== userId)
  playerEntities.delete(userId)
})
```

Para seguir a un jugador en cada fotograma, interpola la raíz del rig hacia su posición:

```ts
const followEntity = playerEntities.get(followTargetId)
if (followEntity) {
  const targetPos = Transform.get(followEntity).position
  const rootTransform = Transform.getMutable(rigRoot)
  rootTransform.position = Vector3.lerp(
    rootTransform.position,
    Vector3.add(targetPos, Vector3.create(0, 1, 0)),
    0.1
  )
}
```

Consulta [El jugador entra o sale de la escena](/creator/content-creator-es/scenes-sdk7/interactividad/event-listeners.md#player-enters-or-leaves-scene) para más sobre `onEnterScene` y `onLeaveScene`.

### Control de cámara con el ratón mientras se observa

Lee `PrimaryPointerInfo.screenDelta` cada fotograma para girar la cámara con el ratón. Esto funciona mientras el puntero está bloqueado. Consulta [Movimiento del ratón](/creator/content-creator-es/scenes-sdk7/interactividad/mouse-movement.md) para ver un ejemplo completo de control de cámara con el ratón.

```ts
const MOUSE_SENSITIVITY = 0.15 // degrees per pixel
let yaw = 0
let pitch = 45

function spectateMouseLook() {
  const isLocked = PointerLock.getOrNull(engine.CameraEntity)?.isPointerLocked ?? false
  if (!isLocked) return

  const delta = PrimaryPointerInfo.getOrNull(engine.RootEntity)?.screenDelta
  if (!delta) return

  yaw = (yaw + delta.x * MOUSE_SENSITIVITY) % 360
  // delta.y crece hacia abajo, así que mover el ratón hacia arriba da un valor negativo: añadirlo inclina la cámara hacia arriba; aplica un límite para evitar que se dé la vuelta
  pitch = Math.max(-25, Math.min(80, pitch + delta.y * MOUSE_SENSITIVITY))
}
```

{% hint style="warning" %}
**Nota:** `screenDelta` es solo para escritorio. En móvil siempre informa `0`. Si tu escena está orientada a móviles, diseña un plan de respaldo basado en toques.
{% endhint %}

### Implementación completa de referencia

El [`33,20-spectate-mode`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/33,20-spectate-mode) la escena de prueba contiene un módulo de espectador autónomo en `src/spectate.ts`. Admite modos de free-cam y follow-cam, controles WASD + control de cámara con el ratón, ciclado de jugadores, zoom de distancia orbital, ajuste de límites y un HUD en pantalla que muestra los controles y el objetivo actual de seguimiento.

Para usarlo en tu propio proyecto:

1. Copiar `src/spectate.ts` en tu escena.
2. Actualizar `PIVOT`, `BOUNDS_MIN`, y `BOUNDS_MAX` en la parte superior del archivo para que coincida con los parcels de tu escena. Este es el error de integración más común.
3. Conecta `toggleSpectate()` a cualquier trigger: una entidad clicable, un botón de UI o una pulsación de tecla.

{% hint style="info" %}
**💡 Consejo**: Para ver ejemplos funcionales del control de cámara, consulta la [`2,22-virtual-cameras`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/2,22-virtual-cameras) escena de prueba, que recorre varias `VirtualCamera` entidades a través de `MainCamera` incluyendo `lookAtEntity` una cámara apuntada al jugador y una cámara interpolada; [`32,20-virtual-camera-mouse-look`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/32,20-virtual-camera-mouse-look), que controla una cámara de control con el ratón mientras el puntero está bloqueado; [`33,20-spectate-mode`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/33,20-spectate-mode), que implementa una cámara completa de espectador/observador con modos follow-cam y free-cam; y [`9,99-modifier-areas`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/9,99-modifier-areas), que fuerza un modo de cámara dentro de un volumen con `CameraModeArea`.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.decentraland.org/creator/content-creator-es/scenes-sdk7/fundamentos-del-contenido-3d/camera.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
