> 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/primeros-pasos/coding-scenes.md).

# Esenciales de programación

## Las herramientas de desarrollo

A un nivel muy alto, el Decentraland **Kit de desarrollo de software** (SDK) te permite hacer lo siguiente:

* Generar un *proyecto* predeterminado que contenga una escena de Decentraland, incluidos todos los assets necesarios para render y ejecutar tu contenido.
* Crear, probar y previsualizar el contenido de tu escena localmente en tu navegador web, completamente offline y sin tener que realizar transacciones de Ethereum ni poseer LAND.
* Escribir código TypeScript usando la API de Decentraland para añadir comportamiento interactivo y dinámico a la escena.
* Subir el contenido de tu escena al content server.
* Vincular tus tokens LAND a la URL del contenido que has subido.

Nuestro SDK incluye lo siguiente:

* **Creator Hub**: Una aplicación independiente que, entre otras cosas, te permite crear escenas con una interfaz fácil de drag-and-drop. Puedes ejecutar previews, debug, editar código y publicar. [Leer más](/creator/content-creator-es/scene-editor/comenzar/about-editor.md)
* **El ECS de Decentraland**: Un paquete de TypeScript que contiene el framework de métodos de ayuda que te permite crear experiencias interactivas. Úsalo para crear y manipular objetos en la escena y también para facilitar transacciones dentro del mundo entre players u otras aplicaciones. ( [referencia más reciente de ECS](https://github.com/decentraland/ecs-reference/blob/master/docs-latest/decentraland-ecs.md))
* **Ejemplos de escenas**: Inspírate y toma buenas prácticas de codificación de los [ejemplos de escenas](https://studios.decentraland.org/resources?sdk_version=SDK7).

Otras herramientas heredadas:

* **The Web Editor**: Una herramienta basada en la web para crear escenas simples y publicarlas.

## Requisitos

Para desarrollar una escena localmente, no necesitas poseer tokens LAND. Desarrollar y probar una escena puede hacerse completamente offline, sin necesidad de desplegar una escena en la red de Ethereum (el sistema que usa Decentraland para establecer la propiedad de LAND, de un Decentraland Name), ni en el content server.

Debes tener:

* **Creator Hub**: Una aplicación independiente que, entre otras cosas, te permite crear escenas con una interfaz fácil de drag-and-drop. Puedes ejecutar previews, debug, editar código y publicar. [Leer más](/creator/content-creator-es/scene-editor/comenzar/about-editor.md).

Si planeas editar el código de la escena, también necesitarás instalar uno de los siguientes:

* <img src="/files/1f7adb7ec831acc766f1052333cbc02eefe3db30" alt="VS Code" data-size="line"> **Visual Studio Code**: Descárgalo [aquí](https://code.visualstudio.com/). Te ayuda a escribir código mucho más rápido y con menos errores. Un editor de código fuente marca errores de sintaxis, autocompleta mientras escribes e incluso muestra sugerencias inteligentes que dependen del contexto en el que te encuentres. También puedes hacer clic en un objeto del código para ver la definición completa de su clase y qué atributos admite.
* <img src="/files/1cf55b5b976822c87bef256f3e353221cdd79d6b" alt="Cursor" data-size="line"> **Cursor AI**: Descárgalo [aquí](https://www.cursor.com/). Un potente editor de código que está integrado con IA. Te permite elegir diferentes modelos de IA para ayudarte a escribir código, todos gratis. El asistente de IA no solo autocompleta mientras escribes, también puedes pedirle que refactorice una gran base de código, escriba documentación y más.

{% hint style="info" %}
**💡 Consejo**: Puedes usar asistentes de IA como Cursor, OpenDCL o Claude Code para crear escenas completas a partir de descripciones en lenguaje natural, sin necesidad de experiencia con TypeScript. Consulta [Vibe Coding con IA](/creator/content-creator-es/scenes-sdk7/primeros-pasos/vibe-coding.md) para comenzar.
{% endhint %}

## Idiomas y sintaxis compatibles

Decentraland emplea [TypeScript (.ts)](https://www.typescriptlang.org/docs/handbook/jsx.html) como el idioma predeterminado para escribir escenas.

TypeScript es un superconjunto de JavaScript, así que si conoces JavaScript verás que es casi lo mismo, pero TypeScript incluye declaraciones de tipos. Gracias a las declaraciones de tipos, es posible tener funciones como autocomplete y mejores pistas de debug; esto acelera los tiempos de desarrollo y permite crear una base de código más sólida. Estas funciones son componentes clave para una buena experiencia de desarrollo.

Cuando se construye una escena, el código de TypeScript que escribiste se compila a JavaScript minificado, para hacerlo más ligero. El código fuente original en TypeScript nunca se sube a los servers, solo la versión compilada de JavaScript.

### Otros idiomas

Puedes usar otra herramienta o idioma en lugar de TypeScript y compilarlo a JavaScript, siempre que tus scripts compilados estén contenidos dentro de un único archivo JavaScript llamado *game.js*. Todas las declaraciones de tipos proporcionadas están hechas en TypeScript, y otros idiomas y transpilers no son compatibles oficialmente.

## Scenes

El contenido que despliegas en tu LAND se llama **scene**. Una scene es un programa interactivo que renderiza contenido 3D; esto podría ser un juego, una experiencia interactiva, una galería de arte, ¡lo que quieras!

Las scenes se despliegan en LAND virtual en Decentraland. LAND es un asset escaso y no fungible mantenido en un smart contract de Ethereum. Despliega en un solo **parcel**, un terreno de 16 metros por 16 metros de LAND, o en múltiples parcels adyacentes.

Cuando los players visitan Decentraland, descargan y renderizan el contenido de cada scene mientras recorren el mapa. Descargan las scenes cuando se alejan de ellas.

También puedes ejecutar una scene localmente en tu máquina lanzando un preview desde la CLI.

## Entities y Components

Las escenas tridimensionales en Decentraland se basan en una [Entity-Component-System](https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system) arquitectura, donde todo en una scene es una *entity*Entity *components*. Las Entities tienen Components; cada Component le da a la entity a la que pertenece propiedades específicas. Es probable que una entity de puerta tenga al menos un Component de Transform (que establece posición, rotación y escala) y otro para darle una forma. Los Components son solo un lugar para almacenar datos; no realizan ninguna acción por sí mismos.

![](/files/1670efc3f57b506ad4572b6212276c648ecf2ccd)

```ts
export function main() {
	// Crear una entity
	const door = engine.addEntity()

	// Darle a la entity una posición mediante un component Transform
	Transform.create(door, {
		position: Vector3.create(5, 1, 5),
	})

	// Darle a la entity una forma visible mediante un component GltfContainer
	GltfContainer.create(door)
}
```

Las Entities pueden anidarse dentro de otras Entities para formar una estructura de árbol. Si estás familiarizado con el desarrollo web, puede resultarte útil pensar en las Entities como elementos de un árbol DOM y en los Components como los atributos de cada uno de esos elementos.

![](/files/23a5a8556ff44aaca10d20c42984b50f36545808)

Las Entities son un concepto abstracto. Una entity es solo un id, que se usa como referencia para agrupar diferentes Components.

Consulta [Entities y components](/creator/content-creator-es/scenes-sdk7/arquitectura/entities-components.md) para un análisis en profundidad de ambos conceptos y de cómo los usan las scenes de Decentraland.

### Custom components

El conjunto predeterminado de Components (como `Transform`, `GltfContainer`, `Material`, etc.) es interpretado por el engine y tiene consecuencias directas en cómo se verá la entity, su posición, si emite sonidos, etc.

También puedes definir *custom components* para almacenar datos que puedan ser útiles para la mecánica de tu scene. El engine no sabrá cómo interpretar lo que significan los valores de estos Components, ni tendrán consecuencias directas en cómo se renderiza la scene. Sin embargo, puedes escribir lógica en el código de tu scene para supervisar estos valores y responder a ellos. Por ejemplo, puedes definir un custom "doorState" component para seguir el estado abierto/cerrado de la puerta. En este caso, el Component no es más que un lugar para almacenar un valor que mantenga un registro de este estado. Para ver la puerta abrirse y cerrarse en tu scene, luego tienes que implementar por separado la lógica que usa estos valores para afectar la rotación de la puerta, un valor del `Transform` component que el engine sí sabe cómo interpretar.

Consulta [Custom Components](/creator/content-creator-es/scenes-sdk7/arquitectura/custom-components.md) para más información.

### Obtener entities por nombre

Las entities añadidas mediante drag and drop en el Scene Editor de Creator Hub también pueden accederse mediante código para seguir editándolas y añadir comportamiento.

Usa `engine.getEntityOrNullByName()` para obtener una entity, pasando el nombre asignado a la entity en la UI del Scene Editor. Cada una debe tener un nombre único.

```ts
function main() {
	const door = engine.getEntityOrNullByName('door3')
}
```

Luego puedes hacer lo que quieras con esa entity, como añadir nuevos Components, modificar sus Components existentes, duplicarla o eliminarla.

Consulta [Get entity by name](/creator/content-creator-es/scenes-sdk7/arquitectura/entities-components.md#get-an-entity-by-name) para más información.

Si la entity es un [Smart item](/creator/content-creator-es/scene-editor/interactividad/smart-items.md), también puedes llamar a su **Actions** o suscribirte a su **Triggers** mediante código. Consulta [Reference Items](/creator/content-creator-es/scene-editor/extiende-con-codigo/reference-items.md).

## Systems

Las Entities y los Components son lugares para almacenar información sobre los objetos de una scene. *Systems* contienen funciones que cambian con el tiempo la información almacenada en los Components.

Los Systems son donde implementamos la lógica del juego; realizan las acciones que necesitan actualizarse o comprobarse periódicamente en cada tick del game loop.

Un System es una función pura y simple que se llama una vez en cada tick (hasta 30 veces por segundo), siguiendo el [*patrón de actualización*](http://gameprogrammingpatterns.com/update-method.html).

```ts
// System básico
function mySystem() {
	console.log('my system is running')
}

engine.addSystem(mySystem)

// System con dt
function mySystemDT(dt: number) {
	console.log('time since last frame:  ', dt)
}

engine.addSystem(mySystemDT)
```

Una sola scene puede tener 0 o muchos Systems ejecutándose al mismo tiempo. Los Systems pueden activarse o desactivarse en distintos momentos durante la duración de la scene. En general, es una buena práctica mantener comportamientos independientes en Systems separados.

Consulta [Systems](/creator/content-creator-es/scenes-sdk7/arquitectura/systems.md) para más detalles sobre cómo se usan los Systems en una scene.

### El game loop

El [game loop](http://gameprogrammingpatterns.com/game-loop.html) es la columna vertebral del código de una scene de Decentraland. Recorre una parte del código a intervalos regulares y hace lo siguiente:

* Escuchar la entrada del player
* Actualizar la scene
* Volver a render la scene

En la mayoría de los programas de software tradicionales, todos los eventos se activan directamente por acciones del player. Nada en el estado del programa cambiará hasta que el player haga clic en un botón, abra un menú, etc.

Pero los entornos interactivos y los juegos son diferentes. No todos los cambios en la scene son necesariamente causados por las acciones de un player. Tu scene podría tener objetos animados que se mueven por sí solos o incluso personajes no jugadores que tienen su propia IA. Algunas acciones del player también pueden requerir varios ticks para completarse; por ejemplo, si la apertura de una puerta necesita un segundo entero, la rotación de la puerta debe actualizarse incrementalmente unas 30 veces mientras se mueve.

Llamamos a cada iteración del loop un *tick*. Las scenes de Decentraland se renderizan a 30 ticks por segundo, siempre que sea posible. Si la máquina tiene dificultades para render cada tick, puede haber actualizaciones menos frecuentes.

En cada tick, la scene se actualiza; luego la scene se vuelve a renderizar, basándose en los valores actualizados.

En las scenes de Decentraland, no hay un game loop declarado explícitamente, sino que más bien los [Systems](/creator/content-creator-es/scenes-sdk7/arquitectura/systems.md) de la scene forman el game loop.

La compilación y el render de la scene se realizan en el backend; no necesitas encargarte de eso mientras desarrollas tu scene.

## Consulta de Components

Puedes [consultar components](/creator/content-creator-es/scenes-sdk7/arquitectura/querying-components.md) con el método `engine.getEntitiesWith(...components)` para hacer seguimiento de todas las entities de la scene que tengan ciertos Components.

A menudo tiene sentido consultar Components dentro de un [system](/creator/content-creator-es/scenes-sdk7/arquitectura/systems.md), y luego recorrer cada una de las entities devueltas y realizar el mismo conjunto de acciones en cada una.

Si intentas iterar sobre todas las entities de la scene en cada tick del game loop, eso podría tener un costo importante en rendimiento. Al referirte solo a las entities devueltas por una consulta, te aseguras de trabajar solo con las que son relevantes.

```ts
// Definir un System
function boxHeightSystem(dt: number) {
	// consultar entities que incluyan tanto MeshRenderer como Transform Components
	for (const [entity] of engine.getEntitiesWith(MeshRenderer, Transform)) {
		const transform = Transform.get(entity)
		console.log('a box is at height:  ', transform.position.y)
	}
}

// Añadir el System al engine
engine.addSystem(rotationSystem)
```

## Ciclo de vida de la scene

Si empiezas a escribir líneas sueltas de código directamente en `index.ts`, tu código puede carecer de contexto importante. Por ejemplo, te faltará información sobre la player entity, o sobre entities que se añadieron mediante drag and drop en Creator Hub. En el momento en que se leen tus líneas de código, esas cosas aún no se han cargado.

Para evitar ese escenario, siempre se recomienda escribir el código de carga inicial de tu scene usando la `main()` función (en el `index.ts` archivo) como punto de entrada. Esta función se ejecuta solo después de que todo el contexto inicial de la scene ya esté cargado; esto incluye cualquier cosa añadida mediante la UI del Scene Editor.

Puedes escribir tu código fuera de la `main()` función cuando:

* El código es llamado indirectamente por `main()`
* El código define un System o añade un System al engine
* El código está dentro de un [async function](/creator/content-creator-es/scenes-sdk7/patrones-de-programacion/async-functions.md)

{% hint style="warning" %}
**📔 Nota**: Cuando el código dentro de una función async o un System se ejecuta por primera vez, todo en la scene ya está correctamente inicializado.

[Custom Component](/creator/content-creator-es/scenes-sdk7/arquitectura/custom-components.md) las definiciones son una excepción; estas siempre deben escribirse fuera de la `main()` función, en un archivo separado. Necesitan interpretarse antes de que `main()` se ejecute.
{% endhint %}

## Mutabilidad

Puedes elegir trabajar con versiones mutables o inmutables (solo lectura) de un Component. La `.get()` función en un Component devuelve una versión inmutable del Component. Solo puedes leer sus valores, pero no puedes cambiar ninguna de sus propiedades.

El `.getMutable()` función devuelve una representación del Component que te permite cambiar sus valores. Usa versiones mutables solo cuando planees hacer cambios en un Component. Trabajar con versiones inmutables de Components resulta en una gran mejora de rendimiento.

```ts
// obtener una versión inmutable (solo lectura)
const immutableTransform = Transform.get(myEntity)

// lo siguiente NO funciona:
// 	immutableTransform.position.y = 2

const mutableTransform = Transform.getMutable(myEntity)

// lo siguiente SÍ cambia la posición de la entity
mutableTransform.position.y = 2
```

Consulta [mutable data](/creator/content-creator-es/scenes-sdk7/patrones-de-programacion/mutable-data.md) para más detalles.

## Poniéndolo todo junto

El *engine* es lo que se encuentra entre *entities*, y *components* por un lado y *systems* por el otro.

![](/files/2d53d91bbcb09a914c9129e7842b19e99a15e11b)

Todos los valores almacenados en los Components de la scene representan el estado de la scene en ese momento. Con cada tick del game loop, el engine ejecuta las funciones de cada uno de los Systems para actualizar los valores almacenados en los Components.

Después de que todos los Systems se ejecutan, los Components de cada entity tendrán nuevos valores. Cuando el engine renderiza la scene, usará estos nuevos valores actualizados y los players verán que las entities cambian para reflejar sus nuevos estados.

```ts
export function main() {
	// Crear una entity
	const cube = engine.addEntity()

	// Darle a la entity una posición mediante un component Transform
	Transform.create(cube, {
		position: Vector3.create(5, 1, 5),
	})

	// Darle a la entity una forma visible mediante un Component MeshRenderer
	MeshRenderer.setBox(cube)
}

// Definir un System
function rotationSystem(dt: number) {
	// consultar entities que incluyan tanto MeshRenderer como Transform Components
	for (const [entity] of engine.getEntitiesWith(MeshRenderer, Transform)) {
		const transform = Transform.getMutable(entity)
		transform.rotation = Quaternion.multiply(
			transform.rotation,
			Quaternion.fromAngleAxis(dt * 10, Vector3.Up())
		)
	}
}

// Añadir el System al engine
engine.addSystem(rotationSystem)
```

En el ejemplo anterior, una `cube` entity y un `rotationSystem` system se añaden al engine. La `cube` entity tiene un `Transform`y un `MeshRenderer` component. En cada tick del game loop, se llama al `rotationSystem` system, y cambia los valores de rotación en el `Transform` component de la `cube` entity.

Ten en cuenta que la mayor parte del código anterior se ejecuta solo una vez, al cargar la scene. La excepción es el `rotationSystem` system, que se llama en cada tick del game loop.

## Desacoplamiento de la scene

Tus scenes no se ejecutan en el mismo contexto que el engine (es decir, el hilo principal). Creamos el SDK de una manera completamente desacoplada del rendering engine. Lo diseñamos así por razones tanto de seguridad como de rendimiento.

Debido a este desacoplamiento, el código de tu scene no tiene acceso al DOM ni al objeto `window` , así que no puedes acceder a datos como el navegador o la ubicación geográfica del player.

El desacoplamiento funciona mediante el protocolo RPC; este protocolo asigna una pequeña parte del client para renderizar solo la scene y controlar eventos.

También hemos abstraído el protocolo de comunicación. Esto nos permite ejecutar las scenes localmente en un WebWorker.

No queremos que los developers intervengan con el interior del engine ni siquiera que necesiten saber qué hay dentro del engine. Necesitamos garantizar una experiencia coherente para los players en todo el mapa de Decentraland, y es más probable que ocurran errores en ese nivel "bajo".

Este desacoplamiento también es importante para evitar que las scenes vecinas interfieran con la experiencia de los players mientras están en la scene de otra persona. Un player podría tener varias scenes cercanas cargadas al mismo tiempo, cada una ejecutando su propio código. Algunas acciones (como abrir links externos o mover al player) solo están permitidas cuando el player está parado sobre esa scene en particular, no si la scene está cargada pero el player está fuera.

## Tree Shaking

Al convertir el código fuente en TypeScript al código compilado en JavaScript minificado, el proceso realiza [tree shaking](https://en.wikipedia.org/wiki/Tree_shaking) para asegurarse de que solo se conviertan las partes del código que realmente se están usando. Esto ayuda a mantener el código final de la scene lo más ligero posible. Es especialmente útil al usar librerías externas, ya que a menudo estas librerías incluyen mucha funcionalidad que no se usa y que, de otro modo, engordaría la scene.

Como consecuencia del tree shaking, cualquier código que quieras que tu scene ejecute necesita estar referenciado de una forma u otra por los puntos de entrada de tu código: la `main()` función en `index.ts`. Los Systems también pueden añadirse al engine en el `index.ts` archivo, sin hacer referencia a `main()`. Cualquier código que no esté referenciado explícita o indirectamente por estos archivos no se incluirá en la scene.

Por ejemplo, supongamos que tienes un archivo llamado `extraContent.ts` con el siguiente contenido; la entity no se renderizará y el System no empezará a ejecutarse:

```ts
// extraContent.ts

const myEntity = engine.addEntity()
Transform.create(myEntity, {
	position: { x: 8, y: 0, z: 8 },
})
MeshRenderer.setBox(myEntity)

function mySystem(dt: number) {
	console.log('system running')
}

engine.addSystem(mySystem)
```

Para hacerlo ejecutarse como parte de tu scene, puedes referenciarlo desde `index.ts` de la siguiente manera:

```ts
// en extraContent.ts

export function addEntities() {
	const myEntity = engine.addEntity()
	Transform.create(myEntity, {
		position: { x: 8, y: 0, z: 8 },
	})
	MeshRenderer.setBox(myEntity)
}

export function mySystem(dt: number) {
	console.log('system running')
}

/////////////////////////////

// en index.ts

import { addEntities, mySystem } from '/extraContent'

export function main() {
	addEntities()
}

engine.addSystem(mySystem)
```

La excepción a esta regla son las definiciones de custom components. Estas no deben accederse mediante el punto de entrada de la `main()` función, ya que necesitan interpretarse antes que todo lo demás.

## Imports

Todas las funciones, objetos, Components y otros elementos usados por la scene deben importarse en cada archivo para poder usarlos. Esto es una consecuencia de [tree-shaking](#tree-shaking), ya que evita empaquetar todo el SDK y en su lugar solo incluye las partes que usa la scene.

Los fragmentos a lo largo de la documentación omiten las líneas de importación al inicio de cada archivo para mantenerlos limpios, pero para que funcionen debes añadirlas a la scene.

Cuando usas VS Studio Code para escribir tus scenes, las opciones inteligentes de autocompletado deberían encargarse de gestionar las importaciones por ti mientras escribes, sin que tengas que ser consciente de ello.

Sin embargo, cuando pegas un fragmento en tu scene, es probable que veas algunos elementos marcados en rojo, que no están importados en ese archivo. Para corregirlo:

* Haz clic en cada palabra subrayada
* Haz clic en el icono de la bombilla a la izquierda de la línea
* Selecciona **Add Import From**
* Aparece una línea de importación al inicio del archivo.

![](/files/22cc151fac4baa95b96eeaab5db5c9d0cb72a3dd)

Si hay muchas cosas diferentes que importar, también puedes seleccionar **Add all missing imports** en el mismo menú desplegable.

Ten en cuenta que las importaciones deben hacerse en cada archivo donde se use un elemento.

VS Studio Code debería poder resolver por sí solo las rutas correctas para tus imports. Si por cualquier motivo tiene problemas para hacerlo, un truco es pegar las siguientes instrucciones de importación vacías al inicio de tu archivo. VS Studio debería encargarse a partir de ahí.

```ts
import {} from '@dcl/sdk/ecs'
import {} from '@dcl/sdk/math'
```

## Versiones del SDK

Cuando desarrollas una nueva scene, usas por defecto la versión estable `@latest` del SDK.

Puedes instalar la versión `@next` del SDK si quieres aprovechar o previsualizar funciones próximas que aún no han llegado a la versión estable más reciente.

Para hacerlo, abre el `package.json` archivo de tu scene y cambia las siguientes líneas:

```json
  "devDependencies": {
    "@dcl/js-runtime": "next",
    "@dcl/sdk": "next"
  },
```

Luego ejecuta el siguiente comando en la carpeta del proyecto de tu scene:

```
npm i
```

Consulta [gestionar dependencias](/creator/content-creator-es/scenes-sdk7/libraries/manage-dependencies.md) para más detalles.

{% hint style="warning" %}
**📔 Nota**: Ten en cuenta que la versión @next puede sufrir problemas de vez en cuando. La sintaxis y el nombre de las nuevas funciones pueden cambiar antes de que se publique una versión estable.
{% 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.decentraland.org/creator/content-creator-es/scenes-sdk7/primeros-pasos/coding-scenes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
