Essenciais de programação
Este conjunto vai ajudá-lo a compreender como as coisas funcionam no client e no SDK do Decentraland.
As ferramentas de desenvolvimento
A um nível muito alto, o Decentraland Software Development Kit (SDK) permite fazer o seguinte:
Gerar um projeto padrão contendo uma scene do Decentraland, incluindo todos os assets necessários para renderizar e executar o teu conteúdo.
Construir, testar e pré-visualizar o conteúdo da tua scene localmente no teu navegador web — completamente offline, e sem ter de fazer quaisquer transações Ethereum ou possuir LAND.
Escrever código TypeScript usando a API do Decentraland para adicionar comportamento interativo e dinâmico à scene.
Fazer upload do conteúdo da tua scene para o content server.
Associar os teus tokens LAND ao URL do conteúdo que carregaste.
O nosso SDK inclui o seguinte:
O Creator Hub: Uma aplicação autónoma que, entre outras coisas, te permite criar scenes com uma interface fácil de drag-and-drop. Podes executar previews, debug, editar código e publicar. Ler mais
O Decentraland ECS: Um pacote TypeScript que contém a framework de methods auxiliares que te permite criar experiências interativas. Usa-o para criar e manipular objects na scene e também para facilitar transações in-world entre players ou outras applications. ( referência mais recente do ECS)
Exemplos de scenes: Inspira-te e obtém boas práticas de código a partir dos exemplos de scenes.
Outras ferramentas legacy:
O Web Editor: Uma ferramenta baseada na web para criar scenes simples e publicá-las.
Requirements
Para desenvolver uma scene localmente, não precisas de possuir tokens LAND. Desenvolver e testar uma scene pode ser feito completamente offline, sem necessidade de deployar uma scene para a rede Ethereum (o sistema que o Decentraland usa para estabelecer a propriedade de LAND, de um Decentraland Name), ou para o content server.
Deves ter:
O Creator Hub: Uma aplicação autónoma que, entre outras coisas, te permite criar scenes com uma interface fácil de drag-and-drop. Podes executar previews, debug, editar código e publicar. Ler mais.
Se planeias editar o código da scene, também vais precisar de instalar um dos seguintes:
Visual Studio Code: Faz download aqui. Ajuda-te a escrever código muito mais depressa e com menos errors. Um editor de source code assinala erros de sintaxe, faz autocomplete enquanto escreves e até mostra sugestões inteligentes que dependem do contexto em que te encontras. Também podes clicar num object no código para ver a definição completa da sua class e quais attributes ela suporta.
Cursor AI: Faz download aqui. Um poderoso code editor integrado com IA. Permite-te escolher diferentes modelos de IA para te ajudar a escrever código, todos eles gratuitos. O assistente de IA não faz apenas autocomplete enquanto escreves; também lhe podes pedir para refatorar uma grande code base, escrever documentação e muito mais.
💡 Dica: Podes usar assistentes de IA como Cursor, OpenDCL ou Claude Code para construir scenes inteiras a partir de descrições em linguagem natural — não é necessária experiência em TypeScript. Vê Vibe Coding com IA para começares.
Linguagens e sintaxe suportadas
O Decentraland utiliza TypeScript (.ts) como language padrão para escrever scenes.
TypeScript é um superset de JavaScript, por isso, se estiveres familiarizado com JavaScript, vais achar que é quase o mesmo, mas TypeScript inclui type declarations. Graças às type declarations, é possível ter features como autocomplete e melhores dicas de debugging; isto acelera os tempos de desenvolvimento e permite a criação de uma codebase mais sólida. Estas features são componentes essenciais para uma boa developer experience.
Quando uma scene é construída, o código Typescript que escreveste é compiled para Javascript minificado, para o tornar mais leve. O source code original em Typescript nunca é uploaded para os servers, apenas a versão compilada em Javascript.
Outras languages
Podes usar outra ferramenta ou language em vez de TypeScript e compiled para JavaScript, desde que os teus scripts compilados estejam contidos num único ficheiro JavaScript chamado game.js. Todas as type declarations fornecidas são feitas em TypeScript, e outras languages e transpilers não são oficialmente supported.
Scenes
O conteúdo que fazes deploy para o teu LAND chama-se uma scene. Uma scene é um programa interativo que renderiza conteúdo 3D; isto pode ser um jogo, uma experiência interativa, uma galeria de arte, o que quiseres!
As scenes são deployadas para LAND virtual no Decentraland. LAND é um asset escasso e non-fungible mantido num Ethereum smart contract. Faz deploy para um único parcel, um terreno de LAND de 16 metros por 16 metros, ou para múltiplos parcels adjacentes.
Quando os players visitam Decentraland, fazem download e renderizam o conteúdo de cada scene à medida que percorrem o mapa. As scenes são descarregadas quando se afastam delas.
Também podes correr uma scene localmente na tua máquina executando um preview a partir da CLI.
Entities e Components
As scenes tridimensionais no Decentraland baseiam-se numa Entity-Component-System architecture, onde tudo numa scene é uma entityentity. As entities têm components; cada component dá à entity a que pertence propriedades específicas. É provável que uma entity de uma door tenha, pelo menos, um component Transform (que define position, rotation e scale) e outro para lhe fornecer uma shape. Os components são apenas um lugar para armazenar data; não executam quaisquer actions por si próprios.

As entities podem estar aninhadas dentro de outras entities para formar uma estrutura em árvore. Se estiveres familiarizado com web development, pode ser útil pensar nas entities como elements numa DOM tree e nos components como os attributes de cada um desses elements.

As entities são um conceito abstracto. Uma entity é apenas um id, usado como referência para agrupar diferentes components.
Veja Entities e components para uma análise aprofundada destes dois conceitos e de como são usados pelas scenes do Decentraland.
Custom components
O conjunto padrão de components (como Transform, GltfContainer, Material, etc) é interpretado pelo engine e tem consequências diretas em como a entity vai parecer, qual é a sua position, se emite sounds, etc.
Também podes definir custom components para armazenar data que possa ser útil para a mecânica da tua scene. O engine não saberá como interpretar o que os values destes components significam; eles não terão quaisquer consequências diretas na forma como a scene é rendered. No entanto, podes escrever lógica no código da tua scene para monitorizar esses values e responder a eles. Por exemplo, podes definir um component custom "doorState" para acompanhar o estado aberto/fechado da door. Neste caso, o component não é mais do que um lugar para armazenar um value que acompanha este estado. Para veres a door abrir e fechar na tua scene, tens então de implementar separadamente a lógica que usa estes values para afetar a rotation da door, um value do Transform component que o engine sabe interpretar.
Veja Custom Components para mais informações.
Obter entities pelo nome
As entities adicionadas por drag-and-drop no Scene Editor no Creator Hub também podem ser acedidas via código para as editares mais e adicionares comportamento.
Use engine.getEntityOrNullByName() para obter uma entity, passando o nome atribuído à entity na UI do Scene Editor. Cada uma deve ter um nome único.
Depois podes fazer o que quiseres com essa entity, como adicionar novos components, modificar os seus components existentes, duplicá-la ou apagá-la.
Veja Obter entity pelo nome para mais informações.
Se a entity for um Smart item, também podes chamar o seu Actions ou subscrever o seu Triggers via código. Vê Reference Items.
Systems
Entities e components são lugares para armazenar information sobre os objects numa scene. Systems contêm functions que mudam a information armazenada nos components ao longo do tempo.
Os Systems são o local onde implementamos a game logic; eles executam as actions que precisam de ser updated ou verificadas periodicamente a cada tick do game loop.
Um system é uma função pura e simples que é chamada uma vez em cada tick (até 30 vezes por segundo), seguindo o update pattern.
Uma única scene pode ter 0 ou muitos systems a correr ao mesmo tempo. Os systems podem ser ligados ou desligados em diferentes momentos durante a duração da scene. Geralmente, é uma boa prática manter comportamentos independentes em systems separados.
Veja Systems para mais detalhes sobre como os systems são usados numa scene.
O game loop
O game loop é a espinha dorsal do código de uma scene do Decentraland. Ele percorre parte do código num intervalo regular e faz o seguinte:
Ouvir input do player
Update a scene
Re-render a scene
Na maioria dos programas de software tradicionais, todos os events são acionados diretamente pelas actions do player. Nada no estado do programa mudará até o player clicar num button, abrir um menu, etc.
Mas os ambientes interativos e os jogos são diferentes disso. Nem todas as alterações na scene são necessariamente causadas pelas actions de um player. A tua scene pode ter objects animados que se movem por si próprios ou até non-player characters que têm a sua própria IA. Algumas actions do player também podem levar vários ticks a ser concluídas; por exemplo, se a abertura de uma door precisar de um segundo inteiro, a rotation da door tem de ser updated incrementalmente cerca de 30 vezes à medida que se move.
Chamamos a cada iteração do loop um tick. As scenes do Decentraland são rendered a 30 ticks por segundo, sempre que possível. Se a máquina estiver com dificuldade em renderizar cada tick, isso pode resultar em updates menos frequentes.
Em cada tick, a scene é updated; depois a scene é re-rendered, com base nos values updated.
Nas scenes do Decentraland, não existe um game loop explicitamente declarado, mas sim os Systems da scene que compõem o game loop.
O compiling e o rendering da scene são realizados no backend; não precisas de lidar com isso enquanto desenvolves a tua scene.
Consultar components
Podes consultar components com o método engine.getEntitiesWith(...components) para acompanhar todas as entities na scene que têm certos components.
Muitas vezes faz sentido consultar components dentro de um system, para depois iterar sobre cada uma das entities devolvidas e executar o mesmo conjunto de actions em cada uma.
Se tentares iterar sobre todas as entities na scene em cada tick do game loop, isso pode ter um custo significativo de performance. Ao referires apenas as entities devolvidas por uma query, garantes que estás apenas a lidar com aquelas que são relevantes.
Ciclo de vida da scene
Se começares a escrever linhas soltas de código diretamente em index.ts, o teu código pode estar a faltar algum contexto importante. Por exemplo, vai faltar informação sobre o player entity, ou sobre entities que foram adicionadas via drag and drop no Creator Hub. No momento em que as tuas linhas de código são lidas, essas coisas ainda não estão carregadas.
Para evitar esse cenário, é sempre recomendado escrever o código de carregamento inicial da tua scene usando a main() function (no index.ts ficheiro) como entrypoint. Esta function só é executada depois de todo o contexto inicial da scene já estar carregado, incluindo tudo o que foi adicionado via a UI do Scene Editor.
Podes escrever o teu código fora da main() function quando:
O código é chamado indiretamente por
main()O código define um system, ou adiciona um system ao engine
O código está dentro de um async function
📔 Nota: Quando o código dentro de uma async function ou de um system é executado pela primeira vez, tudo na scene já está devidamente inicializado.
As definições de Custom Component são uma exceção; estas devem ser sempre escritas fora da main() function, num ficheiro separado. Precisam de ser interpretadas antes de main() ser executado.
Mutabilidade
Podes escolher lidar com versões mutáveis ou imutáveis (read-only) de um component. A .get() function num component devolve uma versão imutável do component. Só podes ler os seus values, mas não podes alterar nenhuma das suas properties.
O .getMutable() function devolve uma representação do component que te permite alterar os seus values. Usa versões mutáveis apenas quando pretendes fazer changes a um component. Lidar com versões imutáveis de components resulta num enorme ganho de performance.
Veja dados mutáveis para mais detalhes.
Juntando tudo
O engine é o que fica entre entitiese components por um lado e systems por outro.

Todos os values armazenados nos components da scene representam o estado da scene naquele ponto no tempo. A cada tick do game loop, o engine executa as functions de cada um dos systems para update os values armazenados nos components.
Depois de todos os systems serem executados, os components de cada entity terão novos values. Quando o engine renderiza a scene, usará estes novos values updated e os players verão as entities mudar para corresponder aos seus novos states.
No exemplo acima, uma cube entity e um rotationSystem system são adicionados ao engine. A cube entity tem um Transform, e um MeshRenderer component. Em cada tick do game loop, o rotationSystem system é chamado, e altera os values de rotation no Transform component da cube entity.
Nota que a maior parte do código acima é executada apenas uma vez, ao carregar a scene. A exceção é o rotationSystem system, que é chamado a cada tick do game loop.
Desacoplamento da Scene
As tuas scenes não correm no mesmo context que o engine (também conhecido como a main thread). Criámos o SDK de uma forma totalmente desacoplada do rendering engine. Desenhámo-lo assim tanto por razões de segurança como de performance.
Devido a este desacoplamento, o código da tua scene não tem access ao DOM nem ao window object, por isso não podes aceder a data como o browser do player ou a localização geográfica.
O desacoplamento funciona através do uso do protocolo RPC; este protocolo atribui uma pequena parte do client apenas para renderizar a scene e controlar events.
Também abstraímos o communication protocol. Isto permite-nos correr as scenes localmente num WebWorker.
Não queremos que os developers intervenham com os internals do engine, nem sequer que precisem de saber o que existe dentro do engine. Precisamos de garantir uma experiência consistente para os players em todo o mapa do Decentraland, e os errors são mais prováveis de acontecer a esse nível "baixo".
Este desacoplamento também é importante para impedir que scenes vizinhas interfiram com a experiência dos players enquanto estão na scene de outra pessoa. Um player pode ter várias scenes próximas carregadas ao mesmo tempo, cada uma a correr o seu próprio código. Algumas actions (como abrir links externos, ou mover o player) só são permitidas quando o player está em cima dessa scene específica, e não se a scene estiver carregada mas o player estiver fora.
Tree Shaking
Ao converter o source code em TypeScript para o compiled code em JavaScript minificado, o processo realiza tree shaking para garantir que apenas as partes do código que estão realmente a ser used são convertidas. Isto ajuda a manter o código final da scene o mais leve possível. É especialmente útil quando se usam external libraries, já que muitas vezes essas libraries incluem muita functionality que não é usada e que, de outra forma, aumentaria o tamanho da scene.
Como consequência do tree shaking, qualquer código que queiras que a tua scene execute precisa de ser referenced de alguma forma pelos entry points do teu código: a main() function no index.ts. Os systems também podem, em alternativa, ser added ao engine no index.ts ficheiro, sem referencing main(). Qualquer código que não seja explicitamente ou indiretamente referenced por estes ficheiros não fará parte da scene.
Por exemplo, suponhamos que tens um ficheiro chamado extraContent.ts com o seguinte conteúdo; a entity não será rendered e o system não começará a correr:
Para o fazer correr como parte da tua scene, podes reference a partir de index.ts da seguinte forma:
A exceção a esta regra são as definições de custom components. Estas não devem ser acedidas através do main() function entry point, pois precisam de ser interpretadas antes de tudo o resto.
Imports
Todas as functions, objects, components e outros elements usados pela scene devem ser imported para cada ficheiro para poder usá-los. Isto é uma consequência de tree-shaking, pois evita empacotar o SDK inteiro e, em vez disso, inclui apenas as partes que a scene usa.
Os snippets ao longo da documentação omitem as linhas de import no início de cada ficheiro para os manter limpos, mas para funcionarem tens de adicioná-las à scene.
Quando usas o VS Studio Code para escrever as tuas scenes, as opções inteligentes de autocomplete devem tratar dos imports por ti enquanto escreves, sem precisares de estar consciente disso.
No entanto, quando colas um snippet na tua scene, provavelmente vais ver alguns elements assinalados a vermelho, que não estão imported para esse ficheiro. Para corrigir isto:
Clica em cada palavra sublinhada
Clica no ícone da lâmpada à esquerda da linha
Selecione Add Import From
Uma linha de import aparece no início do ficheiro.

Se houver muitas coisas diferentes para importar, também podes selecionar Add all missing imports no mesmo dropdown.
Nota que os imports têm de ser feitos em cada ficheiro onde um element é used.
O VS Studio Code deve conseguir resolver por si próprio os paths corretos para os teus imports. Se, por qualquer razão, estiver com dificuldades em fazê-lo, uma dica é colar as seguintes empty import statements no início do teu ficheiro. O VS Studio deverá conseguir tratar do resto.
Versões do SDK
Ao desenvolver uma nova scene, usas a release estável @latest do SDK por padrão.
Podes instalar a release @next do SDK se quiseres aproveitar ou pré-visualizar features futuras que ainda não chegaram à latest stable release.
Para o fazer, abre o package.json ficheiro da tua scene e altera as seguintes linhas:
Depois executa o seguinte command na pasta do projeto da tua scene:
Veja gerir dependências para mais detalhes.
📔 Nota: Tem em atenção que a versão @next pode sofrer issues de tempos a tempos. A syntax e o nome de novas features podem mudar antes de ser lançada numa versão estável.
Atualizado