<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Decentraland</title>
    <description>The latest articles on DEV Community by Decentraland (@decentraland_2).</description>
    <link>https://dev.to/decentraland_2</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F208576%2Fcef7fe35-7229-4195-a011-853a15754874.jpg</url>
      <title>DEV Community: Decentraland</title>
      <link>https://dev.to/decentraland_2</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/decentraland_2"/>
    <language>en</language>
    <item>
      <title>Decentraland SDK Tutorial room 5: 1/2 Display a UI</title>
      <dc:creator>Decentraland</dc:creator>
      <pubDate>Tue, 17 Sep 2019 18:23:43 +0000</pubDate>
      <link>https://dev.to/decentraland_2/decentraland-sdk-tutorial-room-5-1-2-display-a-ui-43cc</link>
      <guid>https://dev.to/decentraland_2/decentraland-sdk-tutorial-room-5-1-2-display-a-ui-43cc</guid>
      <description>&lt;p&gt;Time to enter Room 5! The next videos in our tutorial series will teach you how to click an object to display a 2D UI and create an interactive number pad as a UI.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/4Q5in69Jqgw"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>tutorial</category>
      <category>typescript</category>
      <category>dapps</category>
    </item>
    <item>
      <title>Decentraland SDK Workshop Series - 101: Decentraland SDK </title>
      <dc:creator>Decentraland</dc:creator>
      <pubDate>Tue, 17 Sep 2019 09:18:33 +0000</pubDate>
      <link>https://dev.to/decentraland/decentraland-sdk-workshop-series-101-decentraland-sdk-30f7</link>
      <guid>https://dev.to/decentraland/decentraland-sdk-workshop-series-101-decentraland-sdk-30f7</guid>
      <description>&lt;p&gt;As part of The Decentraland Global Bootcamp online series, today, our very own SDK guru Nico will be live on Twitch, running you through all you need to know about the building blocks of the Metaverse. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7aMqqU0f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.steemitimages.com/DQmcmMqmZmMuwsryuyboJ52npf5jTjm6WPbFAy8YBpfEFjr/ImageJudge-Nico.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7aMqqU0f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.steemitimages.com/DQmcmMqmZmMuwsryuyboJ52npf5jTjm6WPbFAy8YBpfEFjr/ImageJudge-Nico.jpg" alt="ImageJudge-Nico.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Be sure to tune in! 5pm UTC.&lt;br&gt;
&lt;a href="https://www.twitch.tv/decentraland"&gt;https://www.twitch.tv/decentraland&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>tutorial</category>
      <category>typescript</category>
      <category>dapps</category>
    </item>
    <item>
      <title>Decentraland SDK Tutorial room 4</title>
      <dc:creator>Decentraland</dc:creator>
      <pubDate>Thu, 12 Sep 2019 16:04:16 +0000</pubDate>
      <link>https://dev.to/decentraland_2/decentraland-sdk-tutorial-room-4-74o</link>
      <guid>https://dev.to/decentraland_2/decentraland-sdk-tutorial-room-4-74o</guid>
      <description>&lt;p&gt;Some have compared Decentraland to an Inception-like dream world. Ridiculous! That said, your next Video Tutorial in Room 4 is how to spin an object. Erm, don’t forget your totem.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Z5NHJmiA0zs"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>tutorial</category>
      <category>typescript</category>
      <category>dapps</category>
    </item>
    <item>
      <title>Decentraland SDK Tutorial room 3</title>
      <dc:creator>Decentraland</dc:creator>
      <pubDate>Wed, 11 Sep 2019 14:00:36 +0000</pubDate>
      <link>https://dev.to/decentraland_2/decentraland-sdk-tutorial-room-3-33al</link>
      <guid>https://dev.to/decentraland_2/decentraland-sdk-tutorial-room-3-33al</guid>
      <description>&lt;p&gt;We’ve added another Decentraland Video Tutorial.&lt;br&gt;
Time to check out Room 3!&lt;br&gt;
Learn how to move an object and trigger an action based on player position &lt;iframe width="710" height="399" src="https://www.youtube.com/embed/lMS0me-9Ra0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>tutorial</category>
      <category>typescript</category>
      <category>dapps</category>
    </item>
    <item>
      <title>SDK Bootcamp - Building Blocks in Decentraland</title>
      <dc:creator>Decentraland</dc:creator>
      <pubDate>Wed, 11 Sep 2019 13:04:31 +0000</pubDate>
      <link>https://dev.to/decentraland_2/sdk-bootcamp-building-blocks-in-decentraland-26dp</link>
      <guid>https://dev.to/decentraland_2/sdk-bootcamp-building-blocks-in-decentraland-26dp</guid>
      <description>&lt;p&gt;If you missed yesterday's live stream SDK Workshop, Building Blocks in Decentraland, you can catch the recap here&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Vg1Ksnh8Z7w"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>gamedev</category>
      <category>typescript</category>
      <category>dapps</category>
    </item>
    <item>
      <title>
Decentraland SDK Tutorial room 2: 1/4 Add a button

</title>
      <dc:creator>Decentraland</dc:creator>
      <pubDate>Mon, 09 Sep 2019 18:30:26 +0000</pubDate>
      <link>https://dev.to/decentraland/decentraland-sdk-tutorial-room-2-1-4-add-a-button-315a</link>
      <guid>https://dev.to/decentraland/decentraland-sdk-tutorial-room-2-1-4-add-a-button-315a</guid>
      <description>&lt;p&gt;Decentraland SDK Video Tutorials continue with Room 2. &lt;/p&gt;

&lt;p&gt;Add another cool skill to your toolkit by learning how to activate a switch and open a door on a timer. &lt;/p&gt;

&lt;p&gt;Dive into the tutorial below! &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/OUfPVwVnQ8w"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>dapps</category>
      <category>typescript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Creating a Sprite Fire - Using a classic technique for the newest wave in gaming
</title>
      <dc:creator>Decentraland</dc:creator>
      <pubDate>Mon, 09 Sep 2019 11:44:01 +0000</pubDate>
      <link>https://dev.to/decentraland/creating-a-sprite-fire-using-a-classic-technique-for-the-newest-wave-in-gaming-2699</link>
      <guid>https://dev.to/decentraland/creating-a-sprite-fire-using-a-classic-technique-for-the-newest-wave-in-gaming-2699</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3Um9el8E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.steemitimages.com/DQmYuocEm3vTZgsFQRFB9qxpdVVv6e4FFE5kkqJ4LsWc8wG/image5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3Um9el8E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.steemitimages.com/DQmYuocEm3vTZgsFQRFB9qxpdVVv6e4FFE5kkqJ4LsWc8wG/image5.png" alt="image5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In the lead up to our next Game Jam, commencing September 16, participants from our June Hackathon will be taking over the Decentraland blog and revealing their design and building secrets. This week’s guest blogger is Brent Greyling from the collective Design Quarter...&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Hi all. I’m a serial 3D experimentalist, qualified product designer, full-stack web developer – specialising in 3D, VR and WebXR applications – graphic designer, 360 virtual and stereo photographer and 3D modeller.&lt;/p&gt;

&lt;p&gt;So as you can imagine, maintaining a full-time commitment to Decentraland has its challenges. But still, my dream job would be something like piloting our group’s Cyber Junk concept across the virtual world one day.&lt;/p&gt;

&lt;p&gt;The group I speak of is called Design Quarter and we formed in 2017 to inspire and present a vibey hub/hive/lab/gallery for collaboration in matters related to 3D, design, arts and other related disciplines. We’re evolving into a one-stop shop that delivers design originals.&lt;/p&gt;

&lt;p&gt;From initial concept to final product, however big or small the project, our aim is to profitably create, build and grow economically – for others and ourselves – within Decentraland.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Quarter hits the Hackathon
&lt;/h3&gt;

&lt;p&gt;In the June Decentraland Hackathon, part of the Design Quarter entry was a scene featuring a 2D sprite-based fire.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FZIazD8l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.steemitimages.com/DQmduep4S6qHsVPkhb3RSvMR5Bgk4rEnMQoEPy6GrbEtj8j/image4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FZIazD8l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.steemitimages.com/DQmduep4S6qHsVPkhb3RSvMR5Bgk4rEnMQoEPy6GrbEtj8j/image4.png" alt="image4.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As animated gifs for textures are not supported natively in the Decentraland SDK, we decided to use sprite animation. I am happy to share with you my basic understanding of this technique – a feature of video games since the late 1970s.&lt;/p&gt;

&lt;p&gt;The code reflected here can certainly be improved upon, but I have chosen to reflect it exactly as it was used at the time.&lt;/p&gt;

&lt;p&gt;The scene, exactly as entered, can be viewed at &lt;a href="https://brent-ooaissvdra.now.sh"&gt;https://brent-ooaissvdra.now.sh&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our original source files are also available for download from &lt;a href="https://drive.google.com/file/d/10r6vnytLCgc_r7Vb-9p2eWDFx3W9VL36/view"&gt;https://drive.google.com/file/d/10r6vnytLCgc_r7Vb-9p2eWDFx3W9VL36/view&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sprite Animation
&lt;/h3&gt;

&lt;p&gt;A Spritesheet adds texture to a flat planar surface while cycling sequentially through the various still images present on it. The illusion of animated movement or the appearance of three-dimensionality is then perceived, much like our flames growing and rising to the sky.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vwFTsmoQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.steemitimages.com/DQmSvWC5t2KDWj72bPqQvg3ny2Z62awc1K8zZRJAKAaVZSx/image1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vwFTsmoQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.steemitimages.com/DQmSvWC5t2KDWj72bPqQvg3ny2Z62awc1K8zZRJAKAaVZSx/image1.png" alt="image1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For economy of resources, a spritesheet is a single image file that combines multiple slightly differing images, known as frames, sequentially in ordered rows and columns. Multiple images prevent having to load a whole new texture file for each frame of animation; instead the spritesheet is re-positioned over the surface for each new render.&lt;/p&gt;

&lt;p&gt;Complex spritesheets may contain a series of character actions from different views, each action starting on a specific frame and playing out over a certain number of frames.&lt;/p&gt;

&lt;p&gt;A film reel can be viewed as a good example of the spritesheet concept that has a single column with many rows. As the film ‘scrolls’ the rows through the projector, the illusion of smooth movement is created on a planar big screen.&lt;/p&gt;

&lt;p&gt;If a .png image is used for sprites, it may contain levels of transparency to better reveal and blend in with the background.&lt;/p&gt;

&lt;p&gt;Okay, so now that we have an idea of what a sprite is. How do we actually map this spritesheet to a surface?&lt;/p&gt;

&lt;h3&gt;
  
  
  UV mapping
&lt;/h3&gt;

&lt;p&gt;When you apply a UV map to a surface, you are assigning a texture image to XYZ coordinates of your object using a new 3D space specific to that surface. This is comprised of three vertices that make up that surface triangle, which we also call a polygon.&lt;/p&gt;

&lt;p&gt;The relative co-ordinate values of this UV space are named UVW in order to distinguish them from the object-world XYZ. Since texturing requires only two dimensions on a flat surface, we use the UV coordinate axes and ignore the W.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Tip:&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;By simply reversing the order of the same UV point set of a polygon we can reverse the direction in which the surface faces. This is called polygon ‘winding’ and the surface to face normal is a direct result of clockwise or anti-clockwise winding.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Square or rectangular surfaces, i.e. plane shapes, actually comprise two triangles that lie on the same plane and share one common side and thus also two vertices from each triangle. In describing a plane, instead of stating the three UVs for one triangle and another three UVs for the other – which would then contain two duplicates – we can state the four distinct points as a kind of shorthand.&lt;/p&gt;

&lt;h5&gt;
  
  
  Detective Work
&lt;/h5&gt;

&lt;p&gt;In the comprehensive and ever-growing set of Decentraland Development Documentation, there is a section on &lt;a href="https://docs.decentraland.org/development-guide/materials/#using-textures"&gt;Materials&lt;/a&gt; which contains the following example of UV mapping:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6a8-jcw_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.steemitimages.com/DQmdXKLmhYvN3Vftdie3BFz4N7EC5PZnSHDcdPmSyHwxjPA/image3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6a8-jcw_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.steemitimages.com/DQmdXKLmhYvN3Vftdie3BFz4N7EC5PZnSHDcdPmSyHwxjPA/image3.png" alt="image3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although the example given above is correct for the spritemap originally used, I quickly got confused as to how it actually works. After all, my fire spritesheet is a different size, has a different number of rows and columns and the surface it is projected on has different proportions.&lt;/p&gt;

&lt;p&gt;Simply replacing the atlas.png image with another did not work.&lt;/p&gt;

&lt;p&gt;So I started altering the numbers, observing what they would do with my texture image as they changed. After skewing, scaling, repeating and even completely losing and then having to re-find the texture, a pattern began to emerge.&lt;/p&gt;

&lt;p&gt;A consistent pattern, which along with the concepts above, was starting to look useful. My rough findings are annotated below to give you a basic idea of what I discovered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;plane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uvs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// ONE FACE&lt;/span&gt;
    &lt;span class="mf"&gt;0.33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (B) Horizontal width right end position&lt;/span&gt;
    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (C) Vertical height bottom start position&lt;/span&gt;
    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (A) Horizontal width left start position&lt;/span&gt;
    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (C) Vertical height bottom start position&lt;/span&gt;

    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (A) Horizontal width left start position&lt;/span&gt;
    &lt;span class="mf"&gt;0.33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (D) Vertical top height end position&lt;/span&gt;
    &lt;span class="mf"&gt;0.33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (B) Horizontal width right end position&lt;/span&gt;
    &lt;span class="mf"&gt;0.33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (D) Vertical top height end position&lt;/span&gt;

    &lt;span class="c1"&gt;// OTHER FACE&lt;/span&gt;
    &lt;span class="mf"&gt;0.66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (B) Horizontal width right end position&lt;/span&gt;
    &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (C) Vertical height bottom start position&lt;/span&gt;
    &lt;span class="mf"&gt;0.33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (A) Horizontal width left start position&lt;/span&gt;
    &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (C) Vertical height bottom start position&lt;/span&gt;


    &lt;span class="mf"&gt;0.33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (A) Horizontal width left start position&lt;/span&gt;
    &lt;span class="mf"&gt;0.33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (D) Vertical top height end position&lt;/span&gt;
    &lt;span class="mf"&gt;0.66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// (B) Horizontal width right end position&lt;/span&gt;
    &lt;span class="mf"&gt;0.33&lt;/span&gt;  &lt;span class="c1"&gt;// (D) Vertical top height end position&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I noticed that, for the image not to be misaligned or skewed, I had to use the values in identical pairs in certain places. Please note, A, B, C and D are just my commented markers solely to indicate the matching pairs. Each value itself, between 0 and 1, expressing a dimension between 0 and 100% relating to my texture, be it the left, width, top, height, start or end.&lt;/p&gt;

&lt;p&gt;After some more fiddling I discovered precisely what these needed to do to make the above practical.&lt;/p&gt;

&lt;p&gt;Stepping through commented code will give you a clear and useful idea of the result.&lt;/p&gt;

&lt;p&gt;Note how I kept the spriteRow and spriteCol variables flexible as they are unique to the image used.&lt;/p&gt;

&lt;p&gt;Also, don’t get thrown by the dynamic calculations of the spritePlane.uvs. They are like this so that any User-defined variables are applied automatically without you having to worry.&lt;/p&gt;

&lt;h5&gt;
  
  
  Commented Code follows:
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// User defined variables&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;spriteCols&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;   &lt;span class="c1"&gt;// number of columns&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;spriteRows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;   &lt;span class="c1"&gt;// number of rows&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;   &lt;span class="c1"&gt;// timer speed&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currSpriteCel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;   &lt;span class="c1"&gt;// starting position&lt;/span&gt;

&lt;span class="c1"&gt;// Calculated variables&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;spriteCels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;spriteCols&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;spriteRows&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;colFactor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;spriteCols&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;rowFactor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;spriteRows&lt;/span&gt;

&lt;span class="c1"&gt;// Create material&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spriteMaterial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BasicMaterial&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;spriteMaterial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;texture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Texture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;materials/fire.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Create shape component&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spritePlane&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;PlaneShape&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Set the starting UV's&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currRowStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;spriteRows&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;currSpriteCel&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;spriteCols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currColStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;currSpriteCel&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nx"&gt;spriteCols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;spritePlane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uvs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;

        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;// Create sprite entity and assign shape and initially mapped sprite material&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spriteFire&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;spriteFire&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spritePlane&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;spriteFire&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Transform&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;7.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Euler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="nx"&gt;spriteFire&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spriteMaterial&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spriteFire&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Define system to update sprite on every frame&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;spriteAnimate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="nx"&gt;dt&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;
            &lt;span class="nx"&gt;currSpriteCel&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currSpriteCel&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;spriteCels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;currSpriteCel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;currSpriteCel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;currSpriteCel&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currRowStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;spriteRows&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;currSpriteCel&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;spriteCols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currColStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;currSpriteCel&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nx"&gt;spriteCols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;spritePlane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uvs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currColStart&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;colFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currRowStart&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;rowFactor&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Add instance of the system to the scene&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;animationSystem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;spriteAnimate&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding billboard functionality
&lt;/h3&gt;

&lt;p&gt;Our next step toward rounding off would be to make the plane always face you.&lt;/p&gt;

&lt;p&gt;Thankfully, Decentraland have made that part simple by supplying you with a &lt;code&gt;Billboard&lt;/code&gt; component that takes care of that automatically. We just need to add this component to the entity that holds our sprite.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;spriteFire&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Billboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You’ll notice that there are three arguments we’re passing here, each enables or disables the billboard mode on the x, y, and z axis of rotation. Here our billboard only rotates in the Y axis, which means it will follow the player’s movements at ground level, but will keep its upwards direction fixed.&lt;/p&gt;

&lt;p&gt;You can read more about billboards in Decentraland in the &lt;a href="https://docs.decentraland.org/development-guide/entity-positioning/#face-the-player"&gt;documentation site&lt;/a&gt;. Also, although beyond the scope of this article, to understand the math behind the Billboard a little better you are welcome to contact me. &lt;/p&gt;

&lt;h3&gt;
  
  
  In summary
&lt;/h3&gt;

&lt;p&gt;We have now covered a few fundamentals, as well as hopefully animated a texture on a plane. We did so using a generic approach that should work correctly for various individual texture images according to how many rows and columns they contain.&lt;/p&gt;

&lt;p&gt;Feel free to reach out in general, you'll find me hanging around Design Quarter or on Discord.&lt;/p&gt;

&lt;p&gt;Have fun and be sure to sign up for the Game Jam, coming soon on September 16! Design Quarter plans to be there. In the meantime, I will be sharing more of my discoveries as I continue to learn and understand.&lt;/p&gt;

&lt;p&gt;[The original fire.png is attached] This and more examples of fire can be found at: &lt;a href="https://opengameart.org/content/animated-fire"&gt;https://opengameart.org/content/animated-fire&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EGXPs430--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.steemitimages.com/DQmdygCmTqaGho5Jye6Rp4ReQFiMJdLumc8NmT9wWxX5u8m/image2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EGXPs430--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.steemitimages.com/DQmdygCmTqaGho5Jye6Rp4ReQFiMJdLumc8NmT9wWxX5u8m/image2.png" alt="image2.png"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>tutorial</category>
      <category>typescript</category>
      <category>dapps</category>
    </item>
    <item>
      <title>Building Blocks of Creation</title>
      <dc:creator>Decentraland</dc:creator>
      <pubDate>Mon, 09 Sep 2019 11:27:22 +0000</pubDate>
      <link>https://dev.to/decentraland/building-blocks-of-creation-2ba8</link>
      <guid>https://dev.to/decentraland/building-blocks-of-creation-2ba8</guid>
      <description>&lt;p&gt;This is the first instalment of a series of video tutorials that will teach you the basics of using the Decentraland SDK.&lt;/p&gt;

&lt;p&gt;We're fast approaching September 16th and the kick off of our &lt;a href="https://gamejam.decentraland.org/"&gt;Game Jam&lt;/a&gt; – a two-week event where artists and developers will create interactive 3D scenes using the Decentraland SDK and compete for over $250,000 USD of MANA and LAND prizes.&lt;/p&gt;

&lt;p&gt;In the lead up to launch, we’re unveiling two key initiatives: &lt;/p&gt;

&lt;p&gt;The first, which we’ll cover in an upcoming post, is a series of offline talks and bootcamps in multiple cities around the world. The second is the SDK Tutorial Series...&lt;/p&gt;

&lt;h3&gt;
  
  
  The building blocks of creation
&lt;/h3&gt;

&lt;p&gt;The tutorials in this series cover the basic mechanics of the Decentraland SDK. This includes: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to install the SDK&lt;/li&gt;
&lt;li&gt;How to place and animate objects&lt;/li&gt;
&lt;li&gt;How to manage click events&lt;/li&gt;
&lt;li&gt;How to implement UI&lt;/li&gt;
&lt;li&gt;How to use the new ‘utils’ library, which greatly enhances the development experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end of the series you’ll have the knowledge to complete your very own Escape Room game comprising nine different rooms (which can be found in &lt;a href="https://github.com/decentraland-scenes/Escape-Room"&gt;this GitHub repo&lt;/a&gt;), so get ready for a lot of fun!&lt;/p&gt;

&lt;p&gt;Even if you’ve never done any game development, you’ll find these videos informative and easy to follow. They can be digested as a series or as independent modules:&lt;/p&gt;

&lt;h3&gt;
  
  
  What you’ll be learning
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=j7XbiTZ9GN0&amp;amp;feature=youtu.be"&gt;Intro to the Escape Room game and the goals for the tutorial series.&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=_9-74i-1c2k"&gt;Set up your development environment, create a Decentraland scene, and place a 3D model.&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=aonEnpfKIX80"&gt;Add a 3D model to your scene and set its coordinates.&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=QHgOIh04ukY"&gt;Play an animation to open the door.&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=l7NdwToC5tg"&gt;Add a sound effect which plays when the door opens.&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=ihvRnrNusas"&gt;Move code for each room into its own file.&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Come out like a builder. Make out like a bandit
&lt;/h3&gt;

&lt;p&gt;At the conclusion of our Decentraland SDK Tutorial Series, you’ll also have everything you need to come out of the Game Jam with a qualified 3D scene which, should you submit it, could make you the recipient of 1,000 MANA, as well as LAND and prizes ranging from 25,000 to 350,000 MANA for the top 20 winners.&lt;/p&gt;

&lt;p&gt;But you gotta be in it to win it, so &lt;a href="https://gamejam.decentraland.org/"&gt;sign up&lt;/a&gt;, scroll up and start watching. Plus make sure you stay tuned to our Decentraland SDK Tutorial Series.&lt;/p&gt;

&lt;p&gt;See you in the Metaverse!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>gamedev</category>
      <category>tutorial</category>
      <category>dapps</category>
    </item>
    <item>
      <title>Learn how to add basic interactivity to an existing Builder scene</title>
      <dc:creator>Decentraland</dc:creator>
      <pubDate>Tue, 27 Aug 2019 10:15:22 +0000</pubDate>
      <link>https://dev.to/decentraland/learn-how-to-add-basic-interactivity-to-an-existing-builder-scene-l8m</link>
      <guid>https://dev.to/decentraland/learn-how-to-add-basic-interactivity-to-an-existing-builder-scene-l8m</guid>
      <description>&lt;p&gt;&lt;em&gt;In the lead up to our next Game Jam, commencing September 16, participants from our June Hackathon will be taking over the Decentraland blog and revealing their design and building secrets. This week’s guest blogger is Tak. You can find Tak at Discord or on Slack using &lt;a class="mentioned-user" href="https://dev.to/tak"&gt;@tak&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hey, I’m Tak-John Cheung and I’m a 3D Artist. In the industry I’m what you call a generalist, in that I pretty much dabble around with all areas of a computer graphics pipeline.&lt;/p&gt;

&lt;p&gt;I actually found out about Decentraland from a friend, who suggested I check it out as something that I might be interested in. Turns out he was right. Since then, Decentraland has become my new playground.&lt;/p&gt;

&lt;p&gt;In the June Hackathon, I created something called &lt;a href="https://kabloon-farm-babylon.now.sh/" rel="noopener noreferrer"&gt;Kabloom Farm&lt;/a&gt;, which came second in the Districts category. I’ll be back for the Game Jam on September 16 and gunning for a first prize this time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://builder.decentraland.org/" rel="noopener noreferrer"&gt;Builder&lt;/a&gt; provides an easy way for anyone to design a scene without having to worry about creating their own art assets, however its real strength lies in the fact that you can export these scenes for further development, taking advantage of all the tools and utilities available within Decentraland's SDK.&lt;/p&gt;

&lt;p&gt;Let’s begin with a simple garden scene created using the Builder. It features a fixed gate which means users will eventually be able to enter the garden without having to leap over the fence. By making use of the new &lt;a href="https://github.com/decentraland/decentraland-ecs-utils" rel="noopener noreferrer"&gt;Utils&lt;/a&gt; library, we'll quickly be able to have the gate open and close in response to the user's clicks and hopefully by the end of the tutorial, you'll be able to see that anyone can create a simple interactive scene with minimal effort.&lt;/p&gt;

&lt;p&gt;Check out the final code for this tutorial &lt;a href="https://github.com/takJohn/adding-functionality-to-a-builder-scene" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The set up
&lt;/h3&gt;

&lt;p&gt;Make sure you have the latest version of the Decentraland SDK installed by running the following command in the terminal:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install -g decentraland&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You will also need to download the Builder scene files from this &lt;a href="https://github.com/takJohn/adding-functionality-to-a-builder-scene/blob/master/assets/Pavilion_Stone_Fountain_-_Tutorial.zip" rel="noopener noreferrer"&gt;link&lt;/a&gt;. Once downloaded, extract them to their own folder.&lt;/p&gt;

&lt;p&gt;Feel free to use your own Builder scene to follow along. Just download your scene from the Builder itself and you will get a similar &lt;em&gt;.zip&lt;/em&gt; file. You can use the steps below as a general guide.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running the scene
&lt;/h3&gt;

&lt;p&gt;Inside the terminal, run the following command in the directory where we extracted the Builder scene:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dcl start&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will install any missing dependencies and automatically open your default browser to preview the scene. This might take a few seconds to load but once done, you should see a pavilion situated in a small garden that's surrounded by wooden fences.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.steemitimages.com%2FDQmNM66UU26YfzuDSuy54xcjVqXbTiyUo9qvwvKYniwQhRy%2Fimage1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.steemitimages.com%2FDQmNM66UU26YfzuDSuy54xcjVqXbTiyUo9qvwvKYniwQhRy%2Fimage1.jpg" alt="image1.jpg"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;As mentioned earlier, users can't access the garden without having to jump over the fence so our aim is to have the gate open and close whenever the user clicks on it. &lt;/p&gt;

&lt;h3&gt;
  
  
  Transforming items
&lt;/h3&gt;

&lt;p&gt;Let’s start by tidying up the gate so that it fills the gaps between the fences. One of the things that we can do in the code, that currently isn't possible in the Builder, is scaling items. To achieve this, we will modify the &lt;code&gt;Transform&lt;/code&gt; component of the gate by doing the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open &lt;code&gt;game.ts&lt;/code&gt; that's located in the &lt;code&gt;/src&lt;/code&gt; directory&lt;/li&gt;
&lt;li&gt;Scroll down until you find &lt;code&gt;fencePicketDoor_01&lt;/code&gt; or just perform a search for the term&lt;/li&gt;
&lt;li&gt;Modify the &lt;code&gt;Transform&lt;/code&gt; component belonging to the gate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;TIP: The code from the Builder can be really long as each item in the scene generates a new block of code. To make locating an item in the code easier, you can return to the Builder and hover your mouse cursor over an item you wish to search for within the "Item Catalog" and a tool tip will popup giving you the item’s name, which should be very similar to what’s used in the code, so you can use it as a hint when searching for it.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// --- Adding Basic Interactivity to gate ---&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fencePicketDoor_01&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;fencePicketDoor_01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setParent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gltfShape_16&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GLTFShape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;models/FencePicketDoor_01/FencePicketDoor_01.glb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;fencePicketDoor_01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addComponentOrReplace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gltfShape_16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Scale and position the gate&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transform_31&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Transform&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;6.65&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Euler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;fencePicketDoor_01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addComponentOrReplace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transform_31&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fencePicketDoor_01&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see in the example above that we adjusted the &lt;code&gt;scale&lt;/code&gt; to values that work for us in this scene. If you’re working with your own scene, you may have to play around a bit to see what works for you. In short, the gate’s position and scale has been adjusted to fit the space in between the fences. &lt;/p&gt;

&lt;p&gt;We've also replaced the &lt;a href="https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation" rel="noopener noreferrer"&gt;Quaternion rotation&lt;/a&gt; values with its &lt;a href="https://en.wikipedia.org/wiki/Euler_angles" rel="noopener noreferrer"&gt;Euler&lt;/a&gt; equivalent, which will be important later on when it comes to rotating the gate, at least in the sense that we will be able to understand it better conceptually.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: This online tool is a good help when converting from one measurement to the other &lt;a href="https://quaternions.online/" rel="noopener noreferrer"&gt;quaternions.online&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Utils library
&lt;/h3&gt;

&lt;p&gt;It’s nearly time to add some functionality to the Scene and for that we're going to be making use of the new Utils library, which includes a number of pre-built tools that simplifies the process of adding common functionality to your scene.&lt;/p&gt;

&lt;p&gt;If you haven't yet exited the preview server, then do that before installing the Utils library, which can be done by running the following command in the terminal, in your scene's project folder:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install -g decentraland-ecs-utils&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To import the library into the scene's script, add this line at the start of your &lt;code&gt;game.ts&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;utils&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.../node_modules/decentraland-ecs-utils/index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will only be using a few of the available helpers in this library, but if you're interested in learning more then follow this &lt;a href="https://github.com/decentraland/decentraland-ecs-utils" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Toggle states
&lt;/h3&gt;

&lt;p&gt;The first component from the Utils library we'll be using is the &lt;code&gt;ToggleComponent&lt;/code&gt;, which allows us to switch an entity between two possible states and in doing so, perform a function. The states are specified by the &lt;code&gt;ToggleState&lt;/code&gt;, which can either be &lt;code&gt;On&lt;/code&gt; or &lt;code&gt;Off&lt;/code&gt;. In the case of our gate, we’ll be opening the gate when the &lt;code&gt;ToggleState&lt;/code&gt; is &lt;code&gt;On&lt;/code&gt; and closing the gate when the &lt;code&gt;ToggleState&lt;/code&gt; is &lt;code&gt;Off&lt;/code&gt;, so each time the state changes, the gate will rotate to the position corresponding to one of these states.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ToggleComponent&lt;/code&gt; takes in two arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;startingState&lt;/code&gt;: Starting state of the toggle (&lt;code&gt;On&lt;/code&gt; or &lt;code&gt;Off&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onValueChangedCallback&lt;/code&gt;: Function to call every time the toggle state changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seeing as the gate starts off being closed, we’ll set the &lt;code&gt;startingState&lt;/code&gt; to the value &lt;code&gt;ToggleState.Off&lt;/code&gt;. For our first test of the toggle, on the second argument we’ll add a very simple function, whenever the state changes, the function will just log a message to the console describing the action we would like to perform. This way we can check that the toggle is working as expected before implementing the action of opening and closing the gate.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NOTE: Whenever you see &lt;code&gt;utils&lt;/code&gt;. that’s an indication that we’re accessing a helper from the Utils library.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Toggle gate to its open / close positions&lt;/span&gt;
&lt;span class="nx"&gt;fencePicketDoor_01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ToggleComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ToggleState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Off&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ToggleState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;On&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Open&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Close&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Click behaviors
&lt;/h3&gt;

&lt;p&gt;So far nothing happens when you click on the gate, we want it to switch states when clicked. We’ll add an &lt;code&gt;OnClick&lt;/code&gt; component to the gate with a function that toggles between the states each time it’s clicked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Listen for click on the gate and toggle its state&lt;/span&gt;
&lt;span class="nx"&gt;fencePicketDoor_01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OnClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fencePicketDoor_01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ToggleComponent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function that’s executed by the &lt;code&gt;OnClick&lt;/code&gt; component changes the &lt;code&gt;ToggleState&lt;/code&gt; back and forth between &lt;code&gt;On&lt;/code&gt; and &lt;code&gt;Off&lt;/code&gt;. Although you won’t be able to see any changes happening visually in the scene, if you open up your browser’s console you should see messages alternating between &lt;code&gt;Open&lt;/code&gt; and &lt;code&gt;Close&lt;/code&gt; every time you click on the gate.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;TIP: Accessing the browser’s console varies between browsers. For Chrome you use the keyboard shortcut CTRL + SHIFT + J (on Windows) or CMD + OPTION + J (on Mac). You can also open it via the menu through View &amp;gt; Developer &amp;gt;JavaScript Console.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Rotating the gate
&lt;/h3&gt;

&lt;p&gt;It's worth noting that the gate has already been rotated by &lt;code&gt;-90&lt;/code&gt; degrees in the y-axis when it was originally placed inside the Builder. Earlier we converted the &lt;code&gt;Quaternion&lt;/code&gt; values for the rotation to its &lt;code&gt;Euler&lt;/code&gt; equivalent, which now becomes our starting rotation. For our end rotation, we will need to rotate by another &lt;code&gt;-90&lt;/code&gt; degrees so that it opens inwards making its final y-axis value &lt;code&gt;-180&lt;/code&gt; degrees. Let’s define a couple of variables to reflect these values and we’ll call them &lt;code&gt;startRot&lt;/code&gt; and &lt;code&gt;endRot&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Define start and end rotations for the gate&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;startRot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Euler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;endRot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Euler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To help us rotate the gate we’re going to be using another component from the Utils library called &lt;code&gt;RotateTransformComponent&lt;/code&gt;, which lets us rotate an entity over a period of time from one orientation to another.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;RotateTransformComponent&lt;/code&gt; takes in three arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;start&lt;/code&gt;: &lt;code&gt;Quaternion&lt;/code&gt; for the start rotation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;end&lt;/code&gt;: &lt;code&gt;Quaternion&lt;/code&gt; for the end rotation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;duration&lt;/code&gt;: duration (in seconds) of the rotation &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can now delete the &lt;code&gt;log&lt;/code&gt; statements that were used as placeholders and instead have the &lt;code&gt;ToggleComponent&lt;/code&gt; add the appropriate &lt;code&gt;RotateTransformComponent&lt;/code&gt; to the gate each time it changes state. When the gate opens, we set the start and end rotation arguments as expected with our &lt;code&gt;startRot&lt;/code&gt;and &lt;code&gt;endRot&lt;/code&gt;but when the gate closes, the order is reversed, meaning our &lt;code&gt;endRot&lt;/code&gt; is now our starting rotation and the &lt;code&gt;startRot&lt;/code&gt; is our end rotation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Toggle gate to its open / closed positions&lt;/span&gt;
&lt;span class="nx"&gt;fencePicketDoor_01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ToggleComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ToggleState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Off&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ToggleState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;On&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;fencePicketDoor_01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addComponentOrReplace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RotateTransformComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;startRot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;endRot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;fencePicketDoor_01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addComponentOrReplace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RotateTransformComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;endRot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;startRot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we went with a &lt;code&gt;0.5&lt;/code&gt; second duration for the opening and closing of the gate, which feels fairly snappy but I encourage you to play around with these values so that you can choose whatever feels right.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finishing touches
&lt;/h3&gt;

&lt;p&gt;You may have spotted a slight issue when you tried to click on the gate again before it finished rotating. Instead of smoothly transitioning between the open and closed states, it snaps back to its starting position and begins rotating again. A simple fix is to only pay attention to clicks on the gate done after it has finished rotating. This can be done by comparing the gate’s y-axis rotation to see if it matches either &lt;code&gt;startRot&lt;/code&gt; or &lt;code&gt;endRot&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;TIP: It’s sometimes useful to add an intermediate variable. Although not necessary, it can help shorten your code as well as making it more readable.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Listen for click on the gate and toggle its state&lt;/span&gt;
&lt;span class="nx"&gt;fencePicketDoor_01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OnClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Adding an intermediate variable&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;doorRotY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fencePicketDoor_01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Transform&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;

    &lt;span class="c1"&gt;// Check if gate is at its start or end positions before toggling&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doorRotY&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;startRot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;doorRotY&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;endRot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;fencePicketDoor_01&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ToggleComponent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Final thoughts
&lt;/h3&gt;

&lt;p&gt;Try running the Scene. Everything should now be working as intended. If you were just reading along and would now like to explore the Scene then you can find it &lt;a href="https://simple-interactive-nearnshaw.decentraland1.now.sh/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.steemitimages.com%2FDQmY3i4ejkkbXqcNoN2ZQ8YQN7SjcAB9ibaCV1rJU34Jtn7%2Fimage2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.steemitimages.com%2FDQmY3i4ejkkbXqcNoN2ZQ8YQN7SjcAB9ibaCV1rJU34Jtn7%2Fimage2.jpg" alt="image2.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using the Builder to navigate around and position items in your scene is a lot more intuitive than doing it purely by code. Hopefully this guide has shown you the possibilities when both the Builder and the SDK are used together and how even a little interactivity can go a long way in adding interest to your Scene. &lt;/p&gt;

&lt;p&gt;In the near future, Builder assets will be optimized to load more quickly inside of Decentraland, which provides another benefit to those who wish to develop their scenes in conjunction with the Builder.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let the games begin
&lt;/h3&gt;

&lt;p&gt;The Decentraland Game Jam offers the perfect opportunity to play around with the SDK. Having participated in the June Hackathon, I can assure you that it’s one of the best ways to learn, not just because you get to build something but because you do it alongside other community members.&lt;/p&gt;

&lt;p&gt;I’ve already signed up for the September 16 kick-off and I look forward to seeing what you guys build.&lt;/p&gt;

&lt;p&gt;See you in the Metaverse!&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://builder.decentraland.org/" rel="noopener noreferrer"&gt;Decentraland's Builder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/decentraland/decentraland-ecs-utils" rel="noopener noreferrer"&gt;Decentraland's Utils library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.decentraland.org/getting-started/installation-guide/" rel="noopener noreferrer"&gt;Installation guide for Decentraland's CLI and SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.decentraland.org/development-guide/entity-positioning/" rel="noopener noreferrer"&gt;Setting entity positions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.decentraland.org" rel="noopener noreferrer"&gt;Documentation for Decentraland's SDK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>typescript</category>
      <category>tutorial</category>
      <category>gamedev</category>
      <category>dapps</category>
    </item>
    <item>
      <title>Adding a UI to your Decentraland Scene -
The steps to a basic yet dynamic in-scene interface</title>
      <dc:creator>Decentraland</dc:creator>
      <pubDate>Tue, 20 Aug 2019 15:00:46 +0000</pubDate>
      <link>https://dev.to/decentraland/adding-a-ui-to-your-decentraland-scene-the-steps-to-a-basic-yet-dynamic-in-scene-interface-53gf</link>
      <guid>https://dev.to/decentraland/adding-a-ui-to-your-decentraland-scene-the-steps-to-a-basic-yet-dynamic-in-scene-interface-53gf</guid>
      <description>&lt;p&gt;&lt;em&gt;In the lead up to our next Game Jam, commencing September 16, participants from our June Hackathon will be taking over the Decentraland blog and revealing their design and building secrets. This week’s guest blogger is community member, surz. You can find surz at Discord or on Slack using @surz.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I found out about Decentraland in 2018 and got interested in the clean, low poly design that the project adopted. A year later, I joined the &lt;a href="https://decentraland.org/blog/platform/creator-contest-highlights/"&gt;Creator Contest&lt;/a&gt; and got more involved. The Builder is a great tool for starting out and developing with pre-made 3D models. Following the Creator Contest, I got an invitation to join the June Hackathon. With some basic knowledge of Javascript, Python and C++ (mainly for scripting) and my interest in 3D modelling, I decided to join the event.&lt;/p&gt;

&lt;p&gt;I created a miniature solar system visualization, for educational and art content. The idea was to create a planetarium-type scene that provides basic information about each planet. Beyond the information, I wanted to make it immersive by creating a simple artscape of each planet's surface. In this way, the comparison between the planets and how they differ from our own becomes more authentic and engaging.&lt;/p&gt;

&lt;p&gt;You can take a look at the scene in &lt;a href="https://export.sceloglaux.now.sh"&gt;this link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or check out some screenshots below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yvYhnBOv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/preview1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yvYhnBOv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/preview1.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r_skjxLe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/preview2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r_skjxLe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/preview2.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tutorial
&lt;/h3&gt;

&lt;p&gt;I’d like to share what I used for the UI and how I built it. This tutorial will focus on three sections from my project's UI: the sun, Mercury and the Disclaimer Menu.&lt;/p&gt;

&lt;p&gt;The design of the icons and the character that I feature in my UI are both credited to my brother, Jevicho99.&lt;/p&gt;

&lt;p&gt;You can download the code, 2D images and 3D models that I use in this &lt;br&gt;
 tutorial from &lt;a href="https://github.com/surz90/dcl_UI"&gt;this link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have any doubts about how UIs work in Decentraland, or about any of the code examples, check out Decentraland's documentation &lt;a href="https://docs.decentraland.org/development-guide/onscreen-ui/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, let's get started!&lt;/p&gt;
&lt;h3&gt;
  
  
  Prepare UI assets
&lt;/h3&gt;

&lt;p&gt;We want to have several different UI menus on our scene that can be used at different times. Each of these menus has a static part that isn't clickable and a dynamic part that's clickable.&lt;br&gt;
You can find the images for this tutorial in the github page under the folder &lt;code&gt;/images&lt;/code&gt;. &lt;br&gt;
Download these and follow along as you read this tutorial if you want.&lt;/p&gt;

&lt;p&gt;Here are the static non-clickable parts of the disclaimer pages:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--28YHQMSO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/disclaimer1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--28YHQMSO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/disclaimer1.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t3E21Wx0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/disclaimer2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t3E21Wx0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/disclaimer2.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are the static, non-clickable parts of the Sun and Mercury UIs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d-oCQZED--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/sun-ui.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d-oCQZED--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/sun-ui.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0OS1Jsbk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/mercury-ui.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0OS1Jsbk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/mercury-ui.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below are the dynamic parts used in both kinds of UIs. These are added to the larger images we just saw, and serve as buttons. Each performs a specific task when clicked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Hsnfrflp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/button-close.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hsnfrflp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/button-close.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Close button: Hides all UI elements. This button will be present on all screens.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W9gGVFmH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/button-next.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W9gGVFmH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/button-next.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next button: Switches between disclaimer screens.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XUo2_Y6x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/button-facts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XUo2_Y6x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/button-facts.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Facts: Displays a little fact about the planet. When clicked again, it switches to another fact.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hPCw9bA---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/button-compare.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hPCw9bA---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/button-compare.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Compare: Displays information that compares the current planet to Earth.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Hcp74KfT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/button-artscape.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hcp74KfT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/button-artscape.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Artscape: shows a 3D landscape of the surface of the planet.&lt;/p&gt;

&lt;p&gt;When put together, the full UI layouts should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0tdo22z5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/full-layout1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0tdo22z5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/full-layout1.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0tdo22z5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/full-layout1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0tdo22z5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/full-layout1.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we're happy with the design of our screens, let's implement this in our code.&lt;/p&gt;
&lt;h3&gt;
  
  
  Add a canvas and container
&lt;/h3&gt;

&lt;p&gt;The first step of creating a UI is adding a canvas component, and a container rectangle to go in it. The rectangle will wrap every UI element that we’ll add in later and make it easier to position them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// create canvas&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;UICanvas&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// create container inside canvas&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;UIContainerRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;adaptHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;adaptWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hAlign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vAlign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;top&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice that the rectangle has an opacity of 0.8, so all of our UI will be partly transparent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add static content
&lt;/h3&gt;

&lt;p&gt;The following code adds the static part of the sun UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sunUITexture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Texture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;images/UI/UI_sun.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sunImgScreen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;UIImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sunUITexture&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;sunImgScreen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hAlign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;sunImgScreen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vAlign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;top&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nx"&gt;sunImgScreen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sourceLeft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="nx"&gt;sunImgScreen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sourceTop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="nx"&gt;sunImgScreen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sourceWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;
&lt;span class="nx"&gt;sunImgScreen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sourceHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;483&lt;/span&gt;
&lt;span class="nx"&gt;sunImgScreen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;
&lt;span class="nx"&gt;sunImgScreen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice that when we’re creating the &lt;code&gt;UIImage&lt;/code&gt; component, the first argument is &lt;code&gt;rect&lt;/code&gt;. That’s the name of the rectangle we created to wrap all the UI. By passing this argument, we’re making this image a child of that rectangle and positioning it relative to it.&lt;/p&gt;

&lt;p&gt;That there are plenty of fields, but most are quite self explanatory. You might be wondering what &lt;code&gt;sourceLeft&lt;/code&gt;, &lt;code&gt;sourceTop&lt;/code&gt;,  &lt;code&gt;sourceWidth&lt;/code&gt;, and &lt;code&gt;sourceHeight&lt;/code&gt; are there for. These are sometimes used for displaying a cropped section of an image. Since here we’re using the full image, we’re setting them to cover the full dimensions.&lt;/p&gt;

&lt;p&gt;If you’re following through, this is a good time to try your scene out with &lt;code&gt;dcl start&lt;/code&gt;. You should now see this image appear on the UI. &lt;/p&gt;

&lt;p&gt;Since we don’t want this UI to be always on, we’ll add one more line that sets the &lt;code&gt;visible&lt;/code&gt; property to false. This will keep the image invisible until its &lt;code&gt;visible&lt;/code&gt; value is changed, which we’ll go into later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;sunImgScreen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To add the rest of the information screens in our scene, we use almost identical code, except that each has a different image as texture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add a close button
&lt;/h3&gt;

&lt;p&gt;The way we’ll add buttons isn’t very different from how we just added our image, our buttons will be images with extra functionality. For example, this code adds a 'close` button to the screen.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;typescript&lt;br&gt;
let imgCloseBtn = new Texture("images/UI/close.png")&lt;br&gt;
const closeBtn = new UIImage(rect, imgCloseBtn)&lt;br&gt;
closeBtn.name = 'close_btn'&lt;br&gt;
closeBtn.width = '50px'&lt;br&gt;
closeBtn.height = '50px'&lt;br&gt;
closeBtn.sourceWidth = 112&lt;br&gt;
closeBtn.sourceHeight = 112&lt;br&gt;
closeBtn.positionX = 953&lt;br&gt;
closeBtn.positionY = -5&lt;br&gt;
closeBtn.isPointerBlocker = true&lt;br&gt;
closeBtn.onClick = new OnClick(() =&amp;gt; {        &lt;br&gt;
   log("Close Button Clicked")        &lt;br&gt;
   canvas.visible = false        &lt;br&gt;
}) &lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You'll notice the code isn't too different from the static images we added before. The only significant differences are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;isPointerBlocker&lt;/code&gt; property is set to &lt;code&gt;true&lt;/code&gt;, that allows you to click on this component, and not on things that might be behind it&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;onClick&lt;/code&gt; property, that determines what to execute when clicked. In this case, it sets the visibility of the entire UI to false&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the other buttons in our UI, we use pretty much the same code as above, but with different onClick behavior and positioning.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding UI text
&lt;/h3&gt;

&lt;p&gt;We want our UI to have text that can be changed dynamically, unlike the fixed text that we imported as part of our images. For this we will create a &lt;code&gt;UIText&lt;/code&gt; component.  The following code adds a text component that says “WELCOME”. We’ll later make our scene change this text so that it displays different facts about the current planet.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;typescript&lt;br&gt;
const factTxt = new UIText(rect)&lt;br&gt;
factTxt.outlineColor = new Color4(0.7, 1, 0.8, 1)&lt;br&gt;
factTxt.value = 'WELCOME'&lt;br&gt;
factTxt.fontSize = 22&lt;br&gt;
factTxt.width = 500&lt;br&gt;
factTxt.height = 205&lt;br&gt;
factTxt.positionX = 455&lt;br&gt;
factTxt.positionY = 0&lt;br&gt;
factTxt.color = new Color4(0.7, 1, 0.8, 1)&lt;br&gt;
factTxt.textWrapping = true&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Grouping UI objects
&lt;/h3&gt;

&lt;p&gt;What we’ve seen so far is probably good enough for many different use cases where you want a simple UI that won’t be changing too much as it’s used. But what if you want to handle several UI screens, each with various components, and that can be easily switched from one to the other? What follows is a solution I came up with that helps scale things easily.&lt;/p&gt;

&lt;p&gt;After following the examples we went over to create all the UIImage components needed for each screen, we can list them all in JSON format, grouped based on functionality. These will then be called when switching between screens.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;typescript&lt;br&gt;
const staticScreenGroup = {&lt;br&gt;
   "sun": sunImgScreen,&lt;br&gt;
   "mercury": merImgScreen,&lt;br&gt;
   "disclaimer1": discImgScreen1,&lt;br&gt;
   "disclaimer2": discImgScreen2&lt;br&gt;
}&lt;br&gt;
const closeMenuGroup = {&lt;br&gt;
   "closeBtn": closeBtn&lt;br&gt;
}&lt;br&gt;
const disclaimerMenuGroup = {&lt;br&gt;
   "nextBtn": nextBtn&lt;br&gt;
}&lt;br&gt;
const planetMenuGroup = {&lt;br&gt;
   "factBtn": factBtn,&lt;br&gt;
   "compareBtn" : compareBtn,&lt;br&gt;
   "artscapeBtn" : artscapeBtn,&lt;br&gt;
   "factTxt" : factTxt&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling grouped UI objects
&lt;/h3&gt;

&lt;p&gt;To make use of the component list we just created, we'll also write a function that parses the list and makes the required elements visible, depending on the screen.&lt;/p&gt;

&lt;p&gt;This function takes three arguments as booleans, each switching different parts of the UI on or off: planetMenu (displays the fact, compare and artscape buttons, and the fact text), disMenu (displays the next button in Disclaimer screens) and closeMenu (displays the close button)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`typescript&lt;br&gt;
function stateDynamicUI(bPlanetMenu: boolean, bDisclaimerMenu: boolean, bCloseMenu: boolean) {&lt;/p&gt;

&lt;p&gt;for (let key in planetMenuGroup) {&lt;br&gt;
      planetMenuGroup[key].visible = bPlanetMenu&lt;br&gt;
   }&lt;br&gt;
   for (let key in disclaimerMenuGroup) {&lt;br&gt;
      disclaimerMenuGroup[key].visible = bDisclaimerMenu&lt;br&gt;
   }&lt;br&gt;
   for (let key in closeMenuGroup) {&lt;br&gt;
      closeMenuGroup[key].visible = bCloseMenu&lt;br&gt;
   }&lt;br&gt;
}&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What’s missing is selecting which base static image we want to display. We will create a singleton object that includes a function that makes all static UI elements invisible except for the one we want to currently display.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;typescript&lt;br&gt;
const stateInfoUI = (&lt;br&gt;
   function () {&lt;br&gt;
     let UI_show: UIImage&lt;br&gt;
     return {&lt;br&gt;
        changeCurrentUI: function(ui_screen) {&lt;br&gt;
           if (UI_show) {&lt;br&gt;
              UI_show.visible = false&lt;br&gt;
           }&lt;br&gt;
           UI_show = ui_screen&lt;br&gt;
           UI_show.visible = true&lt;br&gt;
           canvas.visible = true&lt;br&gt;
        },&lt;br&gt;
        getCurrentUI: function () {&lt;br&gt;
           return UI_show&lt;br&gt;
        }&lt;br&gt;
     }&lt;br&gt;
}())&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Opening UIs from in-world objects
&lt;/h3&gt;

&lt;p&gt;We’ll now add a basic 3D menu made out of three 3D boxes into our scene. When each of these boxes is clicked, it will open a different UI, including all the associated elements.&lt;/p&gt;

&lt;p&gt;The desired results will look like the GIF below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L_UhqEXS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/ui-demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L_UhqEXS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://decentraland.org/blog/images/posts/2019-08-14/ui-demo.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste the code below to add the 3D entities:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`typescript&lt;br&gt;
// parent entity&lt;br&gt;
const menu3D = new Entity()&lt;br&gt;
engine.addEntity(menu3D)&lt;/p&gt;

&lt;p&gt;const sunMenu = new Entity()&lt;br&gt;
sunMenu.addComponent(new BoxShape())&lt;br&gt;
sunMenu.addComponent(new Transform({&lt;br&gt;
   position: new Vector3(8, 1.5, 8),&lt;br&gt;
   scale: new Vector3(0.1, 0.25, 0.5)&lt;br&gt;
}))&lt;br&gt;
sunMenu.setParent(menu3D)&lt;br&gt;
engine.addEntity(sunMenu)&lt;/p&gt;

&lt;p&gt;const mercuryMenu = new Entity()&lt;br&gt;
mercuryMenu.addComponent(new BoxShape())&lt;br&gt;
mercuryMenu.addComponent(new Transform({&lt;br&gt;
   position: new Vector3(8, 1, 8),&lt;br&gt;
   scale: new Vector3(0.1, 0.25, 0.5)&lt;br&gt;
}))&lt;br&gt;
mercuryMenu.setParent(menu3D)&lt;br&gt;
engine.addEntity(mercuryMenu)&lt;/p&gt;

&lt;p&gt;const disclaimerMenu = new Entity()&lt;br&gt;
disclaimerMenu.addComponent(new BoxShape())&lt;br&gt;
disclaimerMenu.addComponent(new Transform({&lt;br&gt;
   position: new Vector3(8, 0.5, 8),&lt;br&gt;
   scale: new Vector3(0.1, 0.25, 0.5)&lt;br&gt;
}))&lt;br&gt;
disclaimerMenu.setParent(menu3D)&lt;br&gt;
engine.addEntity(disclaimerMenu)&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we can add an &lt;code&gt;OnClick&lt;/code&gt; component to our 3D entities and reference the functions that display UI elements we created in the previous step.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;typescript&lt;br&gt;
menu_sun.addComponent(&lt;br&gt;
   new OnClick(e =&amp;gt; {&lt;br&gt;
      log("sun CLICKED")&lt;br&gt;
      planetMenuGroup.factTxt.value = "WELCOME"&lt;br&gt;
      stateInfoUI.changeCurrentUI(staticScreenGroup.sun)&lt;br&gt;
      stateDynamicUI(true, false, true)&lt;br&gt;
}))&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The code above works for the ‘sun’ menu, for other menus you can use almost the same code with different arguments inside the &lt;code&gt;stateInfoUI.changeCurrentUI()&lt;/code&gt; and &lt;code&gt;stateDynamicUI()&lt;/code&gt; functions. The disclaimer menu would call the &lt;code&gt;stateDynamicUI&lt;/code&gt; function with &lt;code&gt;(true, true, false)&lt;/code&gt;, to display the “close” and “next” buttons, but not the others.&lt;/p&gt;

&lt;p&gt;Now, when you click on the 3D objects, they should open the corresponding UI menu on screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add functionality to the Next button
&lt;/h3&gt;

&lt;p&gt;Now that we can easily switch between each screen with all of its elements, let’s add functionality to some more buttons from our UI screen. We already demonstrated how to give functionality to the Close button, by setting the visibility of the entire UI. To keep the tutorial short, we’ll only show the Next and the Facts buttons.&lt;/p&gt;

&lt;p&gt;Below is the &lt;code&gt;OnClick&lt;/code&gt; function for the ‘next’ button, which switches between the two disclaimer screens, using the functions we created:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`typescript&lt;br&gt;
nextBtn.onClick = new OnClick(() =&amp;gt; {&lt;br&gt;
   log("Next Button Clicked")&lt;br&gt;
   log(stateInfoUI.getCurrentUI().name)&lt;br&gt;
   if (stateInfoUI.getCurrentUI().name == 'disclaimer1_screen') {&lt;br&gt;
      stateInfoUI.changeCurrentUI(staticScreenGroup.disclaimer2)&lt;br&gt;
   }&lt;br&gt;
   else {&lt;br&gt;
      stateInfoUI.changeCurrentUI(staticScreenGroup.disclaimer1)&lt;br&gt;
   }&lt;br&gt;
})&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Add functionality to the Facts button
&lt;/h3&gt;

&lt;p&gt;Now we’ll add functionality to the "Facts" button so that it shows a fact about the current planet:&lt;/p&gt;

&lt;p&gt;First, we define an array of strings that lists the facts we want to show.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;typescript&lt;br&gt;
const sun_facts: string[] = [&lt;br&gt;
   "Sun's gravity holds the solar system together, keeping everything from the biggest planets to the smallest particles of debris in its orbit",&lt;br&gt;
   "At the equator, the Sun spins once about every 25 days, but at its poles the Sun rotates once on its axis every 35 Earth days",&lt;br&gt;
   "By mass, the Sun is about 70.6 % Hydrogen and 27.4 % Helium",&lt;br&gt;
   "Sun releases a constant stream of particles and magnetic fields called the solar wind that can slams worlds across the solar system with particles and radiation"&lt;br&gt;
]&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then we’ll create a singleton to handle the switching of UI texts. This object contains a function that loops over the predefined strings and returns one of them.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;typescript&lt;br&gt;
const FactsModule = (function () {&lt;br&gt;
    let facts_sun_ind = 0, facts_mer_ind = 0&lt;br&gt;
    let fact_arr: string[]&lt;br&gt;
    let fact_ind: number&lt;br&gt;
    return {&lt;br&gt;
        setFact: function (ui_screen) {&lt;br&gt;
            if (ui_screen.name == "sun_screen") {&lt;br&gt;
                log("fact for SUN")&lt;br&gt;
                fact_arr = sun_facts&lt;br&gt;
                facts_sun_ind = (facts_sun_ind + 1) % sun_facts.length&lt;br&gt;
                fact_ind = facts_sun_ind&lt;br&gt;
                return fact_arr[fact_ind]&lt;br&gt;
            }&lt;br&gt;
        }&lt;br&gt;
    }&lt;br&gt;
}())&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The final step is to call this function from the &lt;code&gt;OnClick&lt;/code&gt; property of the ‘Facts’ button, and change the value of the text component in the UI to what this function returns.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;typescript&lt;br&gt;
factBtn.onClick = new OnClick(() =&amp;gt; {&lt;br&gt;
   log("Fact Button Clicked")&lt;br&gt;
   let factStr = FactsModule.setFact(stateInfoUI.getCurrentUI())&lt;br&gt;
   planetMenuGroup.factTxt.value = factStr&lt;br&gt;
})&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For the final complete code of the scene, check my &lt;a href="https://github.com/surz90/dcl_UI"&gt;GitHub repository&lt;/a&gt; for this project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some closing words
&lt;/h3&gt;

&lt;p&gt;I find it interesting and challenging that Decentraland provides a platform to create a virtual world governed by the blockchain. As it develops, I would like to explore possible mechanics and use cases inside the platform to create more quality content.&lt;/p&gt;

&lt;p&gt;If you have any ideas about how to make the above code more efficient or want to talk about it, please join the discussion and share your thoughts in the #sdk channel of Discord. I’d love to hear your feedback!&lt;/p&gt;

&lt;p&gt;And of course, if you are interested in building things, get involved in the GameJam which starts September 16th. Join &lt;a href="https://gamejam.decentraland.org/"&gt;here&lt;/a&gt; and I’ll see you in the Metaverse!&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>tutorial</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Building Blocks in Decentraland
</title>
      <dc:creator>Decentraland</dc:creator>
      <pubDate>Sun, 18 Aug 2019 10:27:43 +0000</pubDate>
      <link>https://dev.to/decentraland/building-blocks-in-decentraland-1o5a</link>
      <guid>https://dev.to/decentraland/building-blocks-in-decentraland-1o5a</guid>
      <description>&lt;h3&gt;
  
  
  A simple experiment with in-scene content creation
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;In the lead up to our next Game Jam, commencing September 16, participants from our June Hackathon will be taking over the Decentraland blog and revealing their design and building secrets. This week’s guest blogger is Interweaver (aka &lt;a href="https://share.decentraland.org/avatars/email%7C5d234157027519401391c79d"&gt;noah&lt;/a&gt;, in-world).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hey everyone. Interweaver here. By day I build interactive educational websites, but also have a long-standing interest in online multiplayer Metaverses. This stretches back to a childhood spent chopping trees in RuneScape and pulling all-nighters hacking around as a &lt;a href="https://my.secondlife.com/emondrell.raymaker"&gt;leet scripter&lt;/a&gt; in Second Life.&lt;/p&gt;

&lt;p&gt;I encountered Decentraland, like many of us, towards the end of 2017, and was very excited to finally see the dream of a true peer-to-peer, trustless virtual world beginning to be realized. Content creation and community are absolutely at the heart of any Metaverse, and so I jumped at the opportunity to participate in the recent Creator Contest and SDK Hackathon as a way of really diving into DCL’s new building tools.&lt;/p&gt;

&lt;h4&gt;
  
  
  Playing with blocks
&lt;/h4&gt;

&lt;p&gt;As a community Hackathon participant, I worked on several exciting projects, including an &lt;a href="https://export.dmitry1987.now.sh/?position=-51%2C50"&gt;educational recycling game&lt;/a&gt; for the EcoGames District. In this blog post I’ll be talking about how I designed and implemented my &lt;a href="https://buildingblocks.noah7.now.sh"&gt;Decentrablocks&lt;/a&gt; project. The idea for this scene was simple: I wanted to be able to intuitively build things while actually standing in the scene, not in a separate Builder or with an external text editor and modeling software (as one does with the SDK). Also, I’m not a 3D artist, so it had to be made entirely of primitive shapes.&lt;/p&gt;

&lt;p&gt;In true Hackathon fashion, the scene came together between about 8pm one night and 5am the next morning (&lt;i&gt;on a work day – sigh&lt;/i&gt;). The end result was a little rough around the edges, but achieved my objectives. The scene allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grab a new block from the pile of various blocks by clicking it&lt;/li&gt;
&lt;li&gt;Carry it wherever you want just by moving and looking around&lt;/li&gt;
&lt;li&gt;Place a carried block by clicking again&lt;/li&gt;
&lt;li&gt;Pick up any placed block by clicking it&lt;/li&gt;
&lt;li&gt;Delete a block by placing it on a  symbol on the floor&lt;/li&gt;
&lt;li&gt;Pick the color of new blocks&lt;/li&gt;
&lt;li&gt;Choose the block-moving mode:

&lt;ul&gt;
&lt;li&gt;Carry Mode, where the block tries to stay a fixed distance away from you&lt;/li&gt;
&lt;li&gt;Ray Mode, where the block goes to the nearest solid object along your line of sight&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--54mFe5Sw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ereg6ers1w0jlptgx69i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--54mFe5Sw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ereg6ers1w0jlptgx69i.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IYQAC1Yq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/fc3qd99ixt9l1ke1c5b3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IYQAC1Yq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/fc3qd99ixt9l1ke1c5b3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make lining the blocks up easy, they snap to a half-meter grid, and they are prevented from intersecting, just like real blocks 😁.&lt;/p&gt;

&lt;p&gt;Overall, the scene has a bit of a Minecraft feel, but where most of the blocks are bigger than the grid size, and are carried around in front of you rather than in an inventory. Per my main goal, you can totally build some fun things without ever leaving the scene.&lt;/p&gt;

&lt;p&gt;Feel free to &lt;a href="https://buildingblocks.noah7.now.sh"&gt;try it out for yourself&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9a7bdcnO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/fa1amcfrfpvmxpy06gp4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9a7bdcnO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/fa1amcfrfpvmxpy06gp4.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lDip8KAe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/whbodbawt1obaz4kaj04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lDip8KAe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/whbodbawt1obaz4kaj04.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gvsNUphG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/uvpbd7qq9i0xakh1l9mp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gvsNUphG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/uvpbd7qq9i0xakh1l9mp.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Implementing Decentrablocks
&lt;/h4&gt;

&lt;p&gt;Okay, now that the introductions are out of the way, let’s talk about how it works! If you want to check out the code yourself, &lt;a href="https://github.com/NoahWarnke/DCLBlocks"&gt;it’s all on GitHub&lt;/a&gt;. Note: To keep the math easy to visualize, I’ll sometimes only describe the 2D case, but the 3D case is equivalent.&lt;/p&gt;

&lt;h4&gt;
  
  
  Free Carry
&lt;/h4&gt;

&lt;p&gt;The core mechanic for the scene is being able to pick something up, carry it around, and put it back down again with some degree of precision. Now, making a good system for positioning things in 3D can be tricky. Fortunately, walking and looking around in Decentraland already provides a significant degree of spatial control, and so I decided to leverage that to make carrying objects easy. The very first part of the project I implemented was free carry. Simply having an object stay exactly where it is, relative to your screen, while you walk around and rotate the camera, without any snapping or intersection prevention or anything.&lt;/p&gt;

&lt;p&gt;The math behind this is pretty simple, once you understand the difference between &lt;em&gt;world space&lt;/em&gt; and &lt;em&gt;local space&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;World space&lt;/strong&gt; is the global X, Y, Z coordinate system. In Decentraland scenes, +X goes in the direction of increasing parcel X coordinates on the Genesis City map, +Y goes in the vertical upward direction, and +Z goes in the direction of increasing parcel Y coordinates on the map. (I think that this is confusing, and wish they had chosen to align the Y coordinates and have Z be vertical, but it is what it is). When you describe an object's location according to this coordinate system, you are giving its location in world space.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local space&lt;/strong&gt;, by contrast, is a coordinate system relative to some transform (the combination of position, rotation, and scale). It still has X, Y, Z coordinates and you can describe the location of objects in local space by giving those three numbers, just like in world space. The actual values will be different though. You usually talk about the local space of a particular object; for example, &lt;strong&gt;user space&lt;/strong&gt; is the local space of a given user. It's the space where the user's camera is at the origin &lt;strong&gt;&amp;lt;0, 0, 0&amp;gt;&lt;/strong&gt;, the +X direction is along the user's line of sight, the +Y direction is the upwards direction on the user's screen, and distance is the same as in world space (scale = 1).&lt;/p&gt;

&lt;p&gt;With this understanding, free carry is really easy to define. If &lt;strong&gt;ObjPosWorld&lt;/strong&gt; is the position of the object you want to carry in world space (&lt;strong&gt;bold&lt;/strong&gt; denotes a &lt;a href="https://www.mathsisfun.com/algebra/vectors.html"&gt;vector&lt;/a&gt;), and &lt;strong&gt;ObjPosUser&lt;/strong&gt; is its position in user space, you simply want &lt;strong&gt;ObjPosUser&lt;/strong&gt; to remain constant while the object is being carried! This will result in the object not appearing to move on the user’s screen while they are moving around. Note that &lt;strong&gt;ObjPosWorld&lt;/strong&gt; will not be constant if the user moves around. Our goal here is to calculate &lt;strong&gt;ObjPosWorld&lt;/strong&gt;, so that we can update it on every frame using a &lt;a href="https://docs.decentraland.org/development-guide/systems/"&gt;System&lt;/a&gt;, and therefore keep &lt;strong&gt;ObjPosUser&lt;/strong&gt; constant. This will involve transforming between world space and user space (in both directions).&lt;/p&gt;

&lt;p&gt;When the object is first picked up, we know &lt;strong&gt;ObjPosWorld&lt;/strong&gt; and want to use it to get &lt;strong&gt;ObjPosUser&lt;/strong&gt;. The math is pretty simple. Let’s take &lt;strong&gt;UserPos&lt;/strong&gt; to be the position of the user (in world space), and &lt;strong&gt;UserRot&lt;/strong&gt; to be a &lt;a href="https://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/"&gt;quaternion&lt;/a&gt; that represents the rotation of their camera. Quaternions sound scarier than they are – you can simply think of them as a set of four numbers that can represent any possible rotation in 3D.&lt;/p&gt;

&lt;p&gt;If you multiply a vector by a quaternion, it essentially gives you a new vector that is the old vector, but rotated by the rotation that the quaternion represents. You can also take the inverse or conjugate of a quaternion, and get a new quaternion that represents the opposite rotation of the old one. These pieces of information are all we need to know to transform from a position in world space (&lt;strong&gt;ObjPosWorld&lt;/strong&gt;) to a position in user space (&lt;strong&gt;ObjPosUser&lt;/strong&gt;):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ObjPosUser&lt;/strong&gt; = (&lt;strong&gt;ObjPosWorld&lt;/strong&gt; - &lt;strong&gt;UserPos&lt;/strong&gt;) * conjugate(&lt;strong&gt;UserRot&lt;/strong&gt;)&lt;/p&gt;

&lt;p&gt;Basically, you’re subtracting the user’s position from the object’s position, and then reversing the user’s rotation from the object’s position. The end result is the local user space coordinates of the object.&lt;/p&gt;

&lt;p&gt;As a programmer, I am always frustrated when someone writes out a bunch of math for an algorithm and leaves the code as an exercise for the reader, so let’s avoid that 😁. Here’s what the above equation looks like in TypeScript, using the Decentraland SDK, and where entity is the object you’re carrying:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Run this once, when you first pick up the object.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;objPosWorld&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Transform&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objPosUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;objPosWorld&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Camera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;              &lt;span class="c1"&gt;// Subtract UserPos&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Camera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;conjugate&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;    &lt;span class="c1"&gt;// Unrotate by UserRot&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now that we have our constant ObjPosUser, we just need to use it, along with the latest UserPos and UserRot values, to recalculate ObjPosWorld at each frame and move the carried object there. Remember that UserPos and UserRot change when the user moves around. This is the same equation as above, but solved for ObjPosWorld instead of ObjPosUser:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ObjPosWorld&lt;/strong&gt; = (&lt;strong&gt;ObjPosUser&lt;/strong&gt; * &lt;strong&gt;UserRot&lt;/strong&gt;) + &lt;strong&gt;UserPos&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Or, in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Run this once per frame, in order to move the object as the player moves.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;objPosWorld&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;objPosUser&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                           &lt;span class="c1"&gt;// (Clone stops the .rotate from changing objPosUser)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Camera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Rotate by UserRot&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Camera&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;// Add UserPos&lt;/span&gt;

&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Transform&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;objPosWorld&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Also, as a visual thinker, I am always frustrated when someone writes out a bunch of words and leaves drawing pictures as an exercise for the reader, so let’s avoid that too. Here’s a drawing of the situation (in this case, the user happens to be looking straight at the object):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2JqMaw44--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/h3nszvp7tsz0tubdkdbb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2JqMaw44--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/h3nszvp7tsz0tubdkdbb.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well that pretty much covers free carry. I’ve made a simple, dependency-free implementation of this as a &lt;a href="https://github.com/NoahWarnke/carryable/blob/master/src/carryable.ts"&gt;Component and System pair&lt;/a&gt; available on my GitHub, along with a &lt;a href="https://github.com/NoahWarnke/carryable/blob/master/src/game.ts"&gt;tiny example game.ts&lt;/a&gt; showing its use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Aligning with Snap-to
&lt;/h3&gt;

&lt;p&gt;A design decision I made for this scene was to snap block locations to half-meter increments. This makes aligning blocks a lot easier. My initial implementation of this was basically as simple as calling Math.round() on each of the components of the objPosWorld variable before actually updating the object’s position, but multiplied by 2 first, and then divided by 2 after, to round to the nearest 0.5m instead of 1m:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;objPosWorld&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;objPosWorld&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;objPosWorld&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;objPosWorld&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now users can carry blocks around and their positions are discrete for easy placement! But blocks can still be moved inside of each other – a pretty unrealistic situation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Detecting Overlaps (or, The Grid)
&lt;/h3&gt;

&lt;p&gt;The next challenge was to detect when a position is already occupied, and prevent moving a block there. A natural way to accomplish this was to have a big multidimensional array that I’ll call The Grid, where every element represents one 0.5m-cubed cell in the single-parcel scene (so a 32x32x32 array.) Then you simply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check each element of The Grid that a block would occupy before moving it&lt;/li&gt;
&lt;li&gt;If they’re all free, move the block and mark them as occupied in The Grid&lt;/li&gt;
&lt;li&gt;If the user moves the block away again, mark them as unoccupied again&lt;/li&gt;
&lt;li&gt;If they’re not all free, we’ll need to resolve the overlap somehow (see below)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A nice side effect of this mechanism is that when we check our array indices to make sure they’re in bounds (between 0 and 31) before reading from the array, if they’re not, we can also prevent overlaps in those cases, and avoid the block going underground or outside our parcel’s boundaries.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pHBaJD2o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/vjgq8zroom89lje3v30n.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pHBaJD2o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/vjgq8zroom89lje3v30n.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Resolving Overlaps
&lt;/h3&gt;

&lt;p&gt;So what do you do when the user tries to move a block while carrying it, prompting an overlap? Simply not moving the block would be one option, but would feel unresponsive to the user. A better solution would be to move the block to a &lt;strong&gt;different unoccupied spot that’s still along the user’s line of sight&lt;/strong&gt;. This means that the block would appear to move as expected (remaining directly in front of the user), but also no longer overlap with another block or the edge of the scene.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rasterizing with the Bresenham Algorithm
&lt;/h3&gt;

&lt;p&gt;To achieve this, I needed some way to determine all the possible positions along the user’s line of sight that the block could be in. After a few minutes of Googling, I came across the &lt;a href="https://www.geeksforgeeks.org/bresenhams-algorithm-for-3-d-line-drawing/"&gt;Bresenham 3D algorithm&lt;/a&gt;, which &lt;a href="https://en.wikipedia.org/wiki/Line_drawing_algorithm"&gt;rasterizes a line segment&lt;/a&gt; between two integer points in 3D space; that is to say, it converts the line segment into a &lt;strong&gt;set of voxels that are all along that line segment&lt;/strong&gt;. There are definitely other algorithms I could have used, but this one served my purpose well enough. You can check out the repo to see my &lt;a href="https://github.com/NoahWarnke/DCLBlocks/blob/master/src/carryable.ts#L204"&gt;TypeScript implementation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zjJwKHZ8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6hrt4cpf3yy8h9x9kxuk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zjJwKHZ8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/6hrt4cpf3yy8h9x9kxuk.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the Rasterization
&lt;/h3&gt;

&lt;p&gt;With the set of voxels along the user’s line of sight in hand, we can now resolve overlaps. If you’ll recall, there are two different block-moving modes to account for, Carry Mode and Ray Mode.&lt;/p&gt;

&lt;p&gt;In Carry Mode, the block tries to stay at a fixed distance from you as you walk and look around. When an overlap is detected, simply iterate through the voxel set, using The Grid to check for overlaps at each spot, starting with the &lt;em&gt;farthest&lt;/em&gt; voxel (the carry position) and &lt;a href="https://github.com/NoahWarnke/DCLBlocks/blob/master/src/carryable.ts#L167"&gt;moving inwards&lt;/a&gt;. The first available spot you encounter is where you move the block. This makes sure the block is as close as possible to the carry position.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x5CGAksO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tk8m70qtx2f09fovvn8j.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x5CGAksO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tk8m70qtx2f09fovvn8j.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Ray Mode, the block goes as far as it can without hitting anything (another block or the edge of the scene), and then stops there. So simply iterate through the voxel set, again using The Grid to check for overlaps, but this time starting with the &lt;em&gt;nearest voxel&lt;/em&gt; (the user’s position) and &lt;a href="https://github.com/NoahWarnke/DCLBlocks/blob/master/src/carryable.ts#L168"&gt;moving outwards&lt;/a&gt;. The last available spot before the first unavailable spot you encounter is where you move the block. This makes sure the block is right in front of the first solid object along the user’s line of sight.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z0axVOmz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1pc59g61gn9slpg2d0cv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z0axVOmz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1pc59g61gn9slpg2d0cv.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  In Conclusion
&lt;/h3&gt;

&lt;p&gt;And that’s pretty much it. We can carry blocks naturally by walking and looking around, they snap to a grid for easy placement, and they can’t intersect with each other. For a nine-hour project, I was pretty happy with the outcome. It certainly showed me that while Decentraland’s SDK is still in the early stages of its evolution, you can already accomplish a great deal with it.&lt;/p&gt;

&lt;p&gt;I’m looking forward to the many new features coming out soon! In particular, Decentrablocks would have been a lot less buggy and easier to write if global click events had been available, instead of always needing to click on an actual object, and this feature is planned for SDK v6.3 or earlier.&lt;/p&gt;

&lt;p&gt;Going forward, I look forward to being an active member of the Decentraland scene-building community. There’s another &lt;a href="https://gamejam.decentraland.org/?with=interweaver"&gt;Decentraland Game Jam&lt;/a&gt; coming up in September, and after my experience with this past Hackathon, starting from zero knowledge of the SDK, I can confirm that they’re a great opportunity to familiarize yourself with it while working with some really skilled creators!&lt;/p&gt;

&lt;p&gt;I plan on participating, and if you’re at all interested in building content for a decentralized online world, I hope you’ll join me.&lt;/p&gt;

&lt;p&gt;See you in the Metaverse!&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>tutorial</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Decentraland Game Jam, $250,000 USD in prizes, September 16-30
</title>
      <dc:creator>Decentraland</dc:creator>
      <pubDate>Thu, 08 Aug 2019 13:27:35 +0000</pubDate>
      <link>https://dev.to/decentraland/decentraland-game-jam-250-000-usd-in-prizes-september-16-30-f79</link>
      <guid>https://dev.to/decentraland/decentraland-game-jam-250-000-usd-in-prizes-september-16-30-f79</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/AIiiScI0YNE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;A two-week online event, building interactive 3D content for Decentraland – the first blockchain-based virtual world.&lt;/p&gt;

&lt;p&gt;Blockchain is transforming the gaming industry, adopted by established companies such as Samsung, Ubisoft, HTC and Kakao Games.&lt;/p&gt;

&lt;p&gt;The blockchain allows for unprecedented mechanics in gaming, such as &lt;/p&gt;

&lt;p&gt;earn-to-play, allowing players to monetize their skills;&lt;br&gt;
true ownership of virtual goods, which lets you trade what you own in global open markets;&lt;/p&gt;

&lt;p&gt;verified scarcity and provable fairness, meaning you can verify the exact supply and rules that affect your items and the games you play;&lt;/p&gt;

&lt;p&gt;and interoperability of virtual items, so that the skins you purchased for one game can be used in a different franchise&lt;br&gt;
Sign up at &lt;a href="https://gamejam.decentraland.org/"&gt;gamejam.decentraland.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more details, read the &lt;a href="https://docs.decentraland.org/getting-started/game-jam/"&gt;Game Jam Survival Guide&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dapps</category>
      <category>hackathon</category>
      <category>gamejam</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
