> 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/scenes-sdk7/getting-started/sdk-101.md).

# SDK Quick Start

The Decentraland SDK is a powerful tool that lets you create or enhance your scenes by writing code in Typescript (Javascript + Types).

This tutorial walks you through creating your first scene, mixing the different tools you have available: the visual Scene Editor of the Creator Hub, hand-written code, and AI-assisted **vibe coding**. You'll use all three together, and learn when each one shines.

## Install the Creator Hub

The Creator Hub allows you to build, preview and deploy Decentraland scenes. Download the Creator Hub [here](https://decentraland.org/download/creator-hub).

To edit your scene's code, you also need a code editor. [Visual Studio Code](https://code.visualstudio.com/) and [Cursor](https://www.cursor.com/) are both great options, but any code editor works.

Read the [Installation guide](/creator/scene-editor/get-started/editor-installation.md) for more details.

## Create your first scene

1. Open the Creator Hub.
2. Select the **Scenes** tab, and click **New Scene**.

   ![](/files/Sp7N7I2AtgQjMQPXoJz0)
3. Pick a starting template. For this exercise, pick the **Empty Scene**.

This step may take a couple of minutes. It populates your folder with the default set of files for a basic scene. Once that's done, you'll see the empty grid of your scene.

## Add items from the asset packs

Explore the **Asset packs** on the bottom section of the Scene Editor, and drag a couple of items into your scene. Any items will do for now.

![](/files/1zhrDPWV481ohN7N8wFG)

Already placed items can be clicked and dragged to reposition them. See [Scene editor essentials](/creator/scene-editor/get-started/scene-editor-essentials.md#position-items) for more details.

{% hint style="info" %}
**💡 Tip**: Cover the entire scene with a ground item. Items of type **Ground** have a paint bucket icon on them. If you drag one of these into your scene, it covers all of your scene's ground with copies of this item.

<img src="/files/Jnt8UTD2pKU4SS7BOzjc" alt="Ground" data-size="original">
{% endhint %}

## Run a preview

Click the **Preview** button on the top menu to load your scene inside Decentraland. You can now explore the scene as a Decentraland avatar.

![](/files/vHDAf6kGdDlFiqRPK59T)

You can keep the preview window open while you work: it updates every time you make a change. Read more in [preview a scene](/creator/scenes-sdk7/getting-started/preview-scene.md).

## Custom 3D assets

Download this 3D model of an avocado in *glb* format from the following [link](https://github.com/decentraland-scenes/avocado/raw/main/avocado-glb.zip) and unzip it.

![](/files/sco02lfFbQSvxPrEHTyc)

Drag the **avocado.glb** file from your file explorer onto the bottom panel of the Scene Editor (the same panel that holds the **Asset Packs** and **Local Assets** tabs) and click **Import**.

![](/files/GRxOiqgIuiefVNWmiDO7)

You can now find the **avocado.glb** model in the **Local Assets** tab, inside the **Scene** folder. Drag the file onto your scene, like any item from the Asset Packs.

![](/files/S4khhyrNLnAt5nfyQ6nw)

## Edit the scene code

Click the **<> Code** button on the top menu to open your scene project in your code editor.

![](/files/jjBKzspRh4t2aDMEwv7d)

{% hint style="warning" %}
**📔 Note**: If nothing opens, make sure you have a code editor like [Visual Studio Code](https://code.visualstudio.com/) or [Cursor](https://www.cursor.com/) installed.
{% endhint %}

On the left margin of your code editor you can navigate the files and folder structure of your project. Open the `index.ts` file inside the `src` folder. Its content should look like this:

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

export function main() {}
```

This file defines a function called `main()`. This function is the entry point to the scene: any code you put there runs when the scene first loads. As a rule of thumb, write your code inside `main()`. See [Scene lifecycle](/creator/scenes-sdk7/getting-started/coding-scenes.md#scene-lifecycle) for more details.

You already dragged one avocado into the scene visually. Now let's add a second one, this time by writing code. Replace the full contents of your `index.ts` file with the following:

```ts
import { Vector3 } from '@dcl/sdk/math'
import { engine, Transform, GltfContainer } from '@dcl/sdk/ecs'

export function main() {
	// create a fresh new Entity
	let avocado2 = engine.addEntity()

	// give it a Transform
	Transform.create(avocado2, {
		position: Vector3.create(8, 0, 8),
	})

	// give it a GLTF
	GltfContainer.create(avocado2, {
		src: 'assets/scene/avocado.glb',
	})
}
```

These lines create a new [entity](/creator/scenes-sdk7/architecture/entities-components.md), give it a [shape](/creator/scenes-sdk7/3d-content-essentials/shape-components.md) based on the 3D model you downloaded, and [set its position](/creator/scenes-sdk7/3d-content-essentials/entity-positioning.md) via the **Transform** component.

Run the scene preview: you should now see two avocados, the one you added in the Scene Editor and the one you added via code.

![](/files/6Shp1mB2B8VikHDzNkrH)

{% hint style="warning" %}
**📔 Note**: The second avocado exists **only in your code**. It shows up when you run the scene, but the Scene Editor canvas and entity tree can't display entities created in `index.ts`. Don't be alarmed if you don't see it in the editor. This is a key thing to keep in mind when you mix visual editing with code.
{% endhint %}

Both avocados are built from the same pieces. Select the **first** avocado in the Scene Editor: the properties panel shows a **Transform** and a **GltfContainer** component with the same kinds of fields you just wrote in code. They're two views of the same thing.

![](/files/IXfnWBmy7F1wdtrx7lWR)

## Add interactivity with a Script

Let's make an avocado respond to the player. Instead of writing this in `index.ts`, we'll use the **Script component**: a way to attach code directly to an item in the Scene Editor. It keeps each item's behavior self-contained, and you can even reuse the same script on several items.

1. In the Scene Editor, select the first avocado (the one you dragged in; remember, the code-only avocado isn't visible here).
2. Click the **+** button at the top of the properties panel and add the **Script** component.
3. Click **+ Create New Script** and name it `AvocadoScript`.

![](/files/Sfcn0bjkn0yjn0O8Ldps)

4. Click the **<> Code** button on the Script component to open the new file in your code editor.

The script is a class with three main parts (comments trimmed for brevity):

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

export class AvocadoScript {
	constructor(
		public src: string, // DO NOT REMOVE
		public entity: Entity, // DO NOT REMOVE
		// Add your custom inputs below
	) {}

	start() {
		// Called once, when the scene loads
	}

	update(dt: number) {
		// Called on every frame
	}
}
```

* The **constructor** defines parameters that show up as editable fields on the Script component in the Creator Hub. Don't remove `src` or `entity`.
* **`start()`** runs **once**, when the scene loads. Use it for setup: creating components, registering click handlers, etc.
* **`update(dt)`** runs on **every frame** of the game, roughly 30 times per second. Use it for continuous behavior, like movement. `dt` tells you how many seconds passed since the last frame.

Inside the class, `this.entity` always refers to the entity that holds the Script component: in this case, your avocado. This is what makes scripts reusable: attach the same script to ten items, and each one acts on itself.

### Vibe code your first interaction

You can write the following code by hand, but this is a great moment to try **vibe coding**: describing what you want to an AI assistant, and letting it write the code. Most code editors have one built in, like Cursor's chat, GitHub Copilot in VS Code, or [Claude Code](https://claude.com/product/claude-code). Before your first prompt, install the Decentraland SDK skills, so the AI knows the SDK's patterns and makes far fewer mistakes:

```bash
npx skills add decentraland/sdk-skills
```

See [Vibe Coding with AI](/creator/scenes-sdk7/getting-started/vibe-coding.md) for setup options and prompting tips.

Now try a prompt like this:

> In @AvocadoScript.ts, make the avocado log a message to the console when the player clicks on it.

You should end up with something like this (or paste it in yourself):

```ts
import { engine, Entity, pointerEventsSystem, InputAction } from '@dcl/sdk/ecs'
import {} from '@dcl/sdk/math'

export class AvocadoScript {
	constructor(
		public src: string,
		public entity: Entity,
	) {}

	start() {
		pointerEventsSystem.onPointerDown(
			{
				entity: this.entity,
				opts: { button: InputAction.IA_POINTER },
			},
			() => {
				console.log('CLICKED AVOCADO')
			}
		)
	}

	update(dt: number) {}
}
```

The `pointerEventsSystem.onPointerDown()` statement defines three things:

* What `entity` the pointer events work on: here `this.entity`, the avocado holding the script.
* An `opts` object: what button to use, and other optional arguments we're not using now.
* A function that runs every time the entity is clicked.

To see the logged message, run the preview and open the console by clicking the ![](/files/U3NUJd1Ri2m0ihUjwtiJ) icon on the top-right corner. You can also toggle it by pressing the **\`** key. Each time you click the avocado, you'll see:

![](/files/xr1HOMVIBkTZionm4vkc)

{% hint style="warning" %}
**📔 Note**: For an entity to be clickable, it must have a collider geometry. The model used here already includes one. See [Colliders](https://github.com/decentraland/docs/tree/main/creator/sdk7/3d-modeling/colliders.md) for workarounds for models that don't.
{% endhint %}

### Make the avocado vanish

Logging text is nice, but let's make the click do something visible. Ask your AI assistant:

> When the avocado is clicked, make it shrink to nothing with a bouncy tween, instead of just logging. Also set the hover text to "Collect".

You should end up with something like:

```ts
import { engine, Entity, pointerEventsSystem, InputAction, Tween, EasingFunction } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

export class AvocadoScript {
	constructor(
		public src: string,
		public entity: Entity,
	) {}

	start() {
		pointerEventsSystem.onPointerDown(
			{
				entity: this.entity,
				opts: { button: InputAction.IA_POINTER, hoverText: 'Collect' },
			},
			() => {
				this.collect()
			}
		)
	}

	collect() {
		Tween.setScale(
			this.entity,
			Vector3.One(),
			Vector3.Zero(),
			500,
			EasingFunction.EF_EASEINBOUNCE
		)
	}

	update(dt: number) {}
}
```

A **Tween** describes a gradual transition of an entity's position, rotation or scale over time. Here `Tween.setScale()` shrinks the avocado from full size (`Vector3.One()`) to nothing (`Vector3.Zero()`) over 500 milliseconds, using a bouncy easing curve. Learn more about tweens in [move entities](/creator/scenes-sdk7/3d-content-essentials/move-entities.md).

Notice we put the tween in a separate `collect()` method instead of writing it inside the click function. If your AI wrote the tween directly into the click function, that's also fine. Methods let you organize your code and reuse the same logic from different places.

Run the preview and click the avocado: it should vanish with style.

{% hint style="warning" %}
**📔 Note**: The avocado shrinks to a size of 0, but the entity still exists. In a real scene you should delete the entity after the tween is over, to keep your scene performant. See [On tween finished](/creator/scenes-sdk7/3d-content-essentials/move-entities.md#on-tween-finished).
{% endhint %}

### Run code every frame

So far all our code ran in `start()`. Let's use `update()` to make the avocado spin continuously. Replace the constructor and `update()` with:

```ts
	constructor(
		public src: string,
		public entity: Entity,
		public speed: number = 45,
	) {}

	update(dt: number) {
		const transform = Transform.getMutable(this.entity)
		transform.rotation = Quaternion.multiply(
			transform.rotation,
			Quaternion.fromAngleAxis(this.speed * dt, Vector3.Up())
		)
	}
```

You'll need to add `Transform` to the imports from `@dcl/sdk/ecs`, and `Quaternion` to the imports from `@dcl/sdk/math`.

On every frame, this rotates the avocado a little further. Multiplying by `dt` makes the movement smooth and frame-rate independent: the avocado spins at 45 degrees per second, no matter how fast the player's machine runs.

Because `speed` is a constructor parameter, it also appears as a field on the Script component in the Creator Hub. Click the refresh icon on the top-right of the Script component to see it, then tweak the value without touching any code. If you attach this script to several items, each can have its own speed.

<img src="/files/a4ThERIIrKfO8e2VpYnm" alt="Refresh button" width="360">

Scripts can do a lot more, like exposing actions that other smart items can trigger. See [Script component](/creator/scene-editor/extend-with-code/script-component.md) for the full picture.

## Reference an item from the Scene Editor

The Script component is the easiest way to give behavior to a single item, but there's an alternative: your code in `index.ts` can fetch any item you added visually, by name, using `engine.getEntityOrNullByName()`. This is handy when one piece of logic involves several items, or when you want everything in one place. Use the name that appears on the [entity tree](/creator/scene-editor/get-started/scene-editor-essentials.md#the-entity-tree).

In this example, we use an entity named **Yellow Crate**. You can use any item, just write its name exactly as it appears on the entity tree.

{% hint style="info" %}
**💡 Tip**: You can rename entities by doing right-click and selecting **Rename** on the entity tree.
{% endhint %}

```ts
export function main() {
	// avocado2 code from before
	// (...)

	const crate = engine.getEntityOrNullByName('Yellow Crate')

	if (crate) {
		pointerEventsSystem.onPointerDown(
			{
				entity: crate,
				opts: { button: InputAction.IA_POINTER, hoverText: 'Open' },
			},
			function () {
				console.log('CLICKED CRATE')
			}
		)
	}
}
```

Here `engine.getEntityOrNullByName()` fetches a reference to the entity named *Yellow Crate*. The `if (crate)` check ensures the entity really exists in the scene; if there's no entity by that name, `crate` is `null`. See [Reference Items](https://github.com/decentraland/docs/tree/main/creator/sdk7/code/reference-items.md) for more info.

{% hint style="info" %}
**💡 Tip**: All entities added via the Scene Editor are already loaded by the time `main()` runs, so it's safe to reference them there or on functions indirectly called by `main()`.
{% endhint %}

## More Tutorials

Read [Coding scenes](/creator/scenes-sdk7/getting-started/coding-scenes.md) for a high-level understanding of how Decentraland scenes function.

For examples built with SDK7, check out the [Examples page](https://studios.decentraland.org/resources?sdk_version=SDK7), which contains several small scenes.

See the **Development guide** section for more instructions about adding content to your scene.

## Engage with other developers

Visit the [Decentraland Discord](https://dcl.gg/discord) and the [Decentraland DAO Discord](https://discord.gg/bxHtcMxUs4) to join a lively discussion about what's possible and how in the Decentraland Discord's **Creators** section.

To debug any issues, check the [Troubleshooting](/creator/scenes-sdk7/debugging/troubleshooting.md) and [debug](/creator/scenes-sdk7/debugging/debug-in-preview.md) sections. An AI assistant with the [SDK skills](/creator/scenes-sdk7/getting-started/vibe-coding.md) installed is also a great debugging companion: paste the error message from the console, or describe what's not behaving as expected, and it can usually find the problem in your code. If you don't find a solution, you can post to the [SDK Support category](https://forum.decentraland.org/c/support-sdk/11) on the Decentraland Forum.

## 3D Art Assets

A good experience will have great 3D art to go with it. If you're keen on creating those 3D models yourself, see the [3D Modeling section](/creator/3d-modeling-and-animations/3d-models.md). But if you prefer to focus on the coding or game design side of things, you don't need to create your own assets!

Here are a few sources for 3D models you can use in a Decentraland scene:

* [IWB Catalog](https://dcl-iwb.co/)
* [Asset Ovi](https://assetovi.com/)
* [SketchFab](https://sketchfab.com/)
* [Clara.io](https://clara.io/)
* [Archive3D](https://archive3d.net/)
* [SketchUp 3D Warehouse](https://3dwarehouse.sketchup.com/)
* [Thingiverse](https://www.thingiverse.com/)
* [ShareCG](https://www.sharecg.com/)
* [CGTrader](https://cgtrader.com)

You can also use Generative AI tools to generate your own 3D models. Check out:

* [Blender MCP](https://github.com/ahujasid/blender-mcp) + [Claude Desktop](https://claude.ai/download): connect an AI assistant directly to [Blender](https://www.blender.org/), so you can create and edit 3D models by describing what you want. All free tools.
* [Meshy](https://www.meshy.ai/)
* [Luma AI](https://lumalabs.ai/genie)
* [Tripo3D](https://www.tripo3d.ai/app)
* [Rodin](https://hyper3d.ai/rodin)

{% hint style="warning" %}
**📔 Note**: Models must be in the supported `.gltf` or `.glb` formats, and must have a number of triangles, textures and materials that adhere to the [scene limitations](/creator/scenes-sdk7/optimizing/scene-limitations.md). If getting models from a third party site, pay attention to the license restrictions of the content you download.
{% endhint %}

## Publish your scene

If you own a Decentraland NAME, an ETH ENS name, or LAND, or have permissions given by someone that does, you can upload your scene to Decentraland. See [publishing](/creator/scenes-sdk7/publishing/publishing.md).

## Other useful information

* [Vibe Coding with AI](/creator/scenes-sdk7/getting-started/vibe-coding.md)
* [Development workflow](/creator/scenes-sdk7/getting-started/dev-workflow.md)
* [Editing Scenes](/creator/scene-editor/get-started/about-editor.md)
* [Scene editor essentials](/creator/scene-editor/get-started/scene-editor-essentials.md)
* [Design constraints for games](/creator/scenes-sdk7/designing-the-experience/design-games.md)
* [3D modeling](/creator/3d-modeling-and-animations/3d-models.md)
* [Scene limitations](/creator/scenes-sdk7/optimizing/scene-limitations.md)


---

# 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, and the optional `goal` query parameter:

```
GET https://docs.decentraland.org/creator/scenes-sdk7/getting-started/sdk-101.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
