<?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: Gift Mugweni</title>
    <description>The latest articles on DEV Community by Gift Mugweni (@gift_mugweni_1c055b418706).</description>
    <link>https://dev.to/gift_mugweni_1c055b418706</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%2F1493199%2Fb35fcc77-ac5f-48f7-b0b9-f340e4ed1abc.jpg</url>
      <title>DEV Community: Gift Mugweni</title>
      <link>https://dev.to/gift_mugweni_1c055b418706</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gift_mugweni_1c055b418706"/>
    <language>en</language>
    <item>
      <title>Is It Necessary to Create a Website for Every App?</title>
      <dc:creator>Gift Mugweni</dc:creator>
      <pubDate>Sat, 30 Nov 2024 17:54:27 +0000</pubDate>
      <link>https://dev.to/gift_mugweni_1c055b418706/is-it-necessary-to-create-a-website-for-every-app-48d0</link>
      <guid>https://dev.to/gift_mugweni_1c055b418706/is-it-necessary-to-create-a-website-for-every-app-48d0</guid>
      <description>&lt;p&gt;Hello 👋👋. Ive been away for a while, but I thought Id get back into writing again. To ease into it, I decided to start by asking a question thats been on my mind recently.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does every app need to be on a website?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To give context to my self-indulgent question, Ill start by saying Im primarily a Web Developer. Whilst Ive done a bit of systems programming, I do not claim to be deeply knowledgeable, and the bulk of my professional experience lies in Web Development and all it entails.&lt;/p&gt;

&lt;p&gt;With this foundation in mind, its not unreasonable to say that I often find myself around other web developers and also consuming content on social media platforms regarding web development so that I always stay informed and up to date. From these interactions, Ive naturally picked up on a fair number of often-said topics like serverless computing, the framework wars, micro-services vs monoliths etc and whilst theres much to be said about any of these debates, I found myself in an interesting situation.&lt;/p&gt;

&lt;p&gt;As I listened to these debates and seriously contemplated their ramifications, I noticed a growing group of people who seemed to believe that the only way to make apps was via websites. If you listened to this group of people, youd think that if you were not spinning up lambda functions or deciding which service provider youll be saving your files to then youre not doing real programming and your solution wont scale.&lt;/p&gt;

&lt;p&gt;I must confess, I didnt arrive at this observation by some big-brain thinking or other nonsense. I came to it by realizing this mindset in myself when I was working on a side project.&lt;/p&gt;

&lt;p&gt;To summarize a long story. Whilst working on my game engine, I got stuck in a rut. I didnt know what features to add to it and a recent bug Id discovered and fixed had made me question some of the foundational architectural decisions Id made. Since I couldnt find a way to break through, I decided to learn from others and see if I could get inspiration by looking at different more standard game engines. This led to me messing with &lt;a href="https://godotengine.org/" rel="noopener noreferrer"&gt;Godot&lt;/a&gt; and making a few toy games to familiarize myself with the engine.&lt;/p&gt;

&lt;p&gt;During one of these toy projects, I got inspired by the wild niche of stickman fight videos on YouTube. A few personal favourites of mine are &lt;a href="https://www.youtube.com/watch?v=d_qGO4GrbQM&amp;amp;t=224s&amp;amp;ab_channel=Jhanzou" rel="noopener noreferrer"&gt;Combat Gods&lt;/a&gt;, &lt;a href="https://www.youtube.com/watch?v=XEtHpGSSTOU&amp;amp;ab_channel=Jhanzou" rel="noopener noreferrer"&gt;Combat Gods II&lt;/a&gt;, &lt;a href="https://www.youtube.com/watch?v=B1J6Ou4q8vE&amp;amp;ab_channel=AlanBecker" rel="noopener noreferrer"&gt;Animation vs Math&lt;/a&gt;, and &lt;a href="https://www.youtube.com/watch?v=vJ-jvxStlpM&amp;amp;ab_channel=Hyun%27sDojoCommunity" rel="noopener noreferrer"&gt;Nhazul - Weapons Demo&lt;/a&gt;. All this led to me wanting to make a stickman fighter game that can try to replicate some of the crazy moves you see in the video clips.&lt;/p&gt;

&lt;p&gt;I remember someone saying that Game Development is just solving a series of problems and boy were they right. I immediately ran into my first problem when I needed animations for my character. Luckily I got a great asset pack from &lt;a href="https://overcrafted.itch.io/stickman-fighter-spine-2d-game-character-sprites" rel="noopener noreferrer"&gt;itch.io&lt;/a&gt; which would do the job for me but there was a catch. I initially bought it thinking it used a &lt;a href="https://en.wikipedia.org/wiki/Skeletal_animation" rel="noopener noreferrer"&gt;Skeletal Animation rigging model&lt;/a&gt; which the pack does include. Sadly, I couldnt get it working in Godot. Thankfully, he also included a bunch of image sequences which I could use with the traditional animation model but this also ended up being a problem.&lt;/p&gt;

&lt;p&gt;It turns out, I had so many images for both my animations and the various skins that I effectively broke Godot and my editor became unusable because it frequently froze and crashed a lot. Naturally, I thought the simple solution was to just group all the separate images into a single or a few sprite sheets. After much Googling and begging on Stack Overflow, I eventually figured out how to write a basic program that could do this. At this point, I had forgotten about the game and was quite interested in this world of texture packing when I noticed that there werent any simple one-stop solutions that you could easily use to pack textures.&lt;/p&gt;

&lt;p&gt;This didnt mean that there were no solutions, there were plenty of command line applications that did it but I found my options quite limited if all I wanted was something that quickly and simply did what I wanted without going crazy in the configuration. So I figured, I already had a dodgy script that fit the bill, why dont I polish it slightly and release it for free for people to use if anyone cared for it?&lt;/p&gt;

&lt;p&gt;It was at this specific point in time I saw myself almost do something incredibly stupid. As I stated earlier, I didnt intend to make any money with this tool, yet here I was about to spin up a website, deciding whether to use AWS or Azure for temporarily storing the files and all in all going crazy by thinking how to make a simple serverless solution to achieve all this. It was during these planning sessions that I came to a scary realization.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I WAS PLAYING WITH FIRE!!!!! Why would I use all this services if I didnt expect to earn any money?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Maybe Id gotten too used to the free tiers. I didnt need to do all this. I had tricked myself into believing this was the only way to do things. The problem I wanted to solve would have led to lots of files being stored and significantly long processing times if the particular user had a lot of files of particularly high resolution. Both these things correlated with higher costs for bucket storage and serverless functions which meant if I had gone ahead with this incredibly idiotic plan I could have bankrupted myself if this site got any decent amount of traffic.&lt;/p&gt;

&lt;p&gt;And so, I found myself wondering&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does every app need to be on a website?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The clearly obvious answer is&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NO!!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes its worth thinking about the ramifications of what youre doing and remembering any sufficiently complex task will have multiple solutions with pros and cons.&lt;/p&gt;

&lt;p&gt;In my situation, the potential incurred costs werent worth it and so I decided to do a hard pivot and make my solution a desktop app instead of a web based app. This ironically led to a much simpler and saner solution which given the time constraints and budget allocated to it($0.00) left me satisfied. You can check out the app &lt;a href="https://giftmugweni.itch.io/images-to-sprite-sheet" rel="noopener noreferrer"&gt;here&lt;/a&gt; if youre interested. Its very much a version 1 product but feel free to let me know if you like it and maybe I can improve it and add to it if there are enough requests.&lt;/p&gt;

&lt;p&gt;So yeah, I thought Id share this little story in case it might interest anyone. Although we rarely feel it sometimes, it is worth remembering that Software Development is a form of engineering and like any good engineer we should always assess the sanity of our actions if only for the sake of not giving our bank accounts a heart attack, especially in these economic times.&lt;/p&gt;

&lt;p&gt;]]&amp;gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>appdevelopment</category>
      <category>tools</category>
      <category>controversy</category>
    </item>
    <item>
      <title>How to Set Up a Simple Rendering Loop in WebGPU</title>
      <dc:creator>Gift Mugweni</dc:creator>
      <pubDate>Tue, 24 Sep 2024 10:00:29 +0000</pubDate>
      <link>https://dev.to/gift_mugweni_1c055b418706/how-to-set-up-a-simple-rendering-loop-in-webgpu-2ba6</link>
      <guid>https://dev.to/gift_mugweni_1c055b418706/how-to-set-up-a-simple-rendering-loop-in-webgpu-2ba6</guid>
      <description>&lt;p&gt;Hello 🙋🙋 you good? How have you been 😁? I'm great and all, sorry for the delayed article but I think we both know my release consistency by now. So with that out the way lets get down to business.&lt;/p&gt;

&lt;p&gt;In my last article, I showed how to set up the WebGPU project for TypeScript which I find to be a nicer working experience but your mileage may vary. It worked great and we got to see our lovely, beautiful, one-of-a-kind triangle aaaaaannnnndddd thats the problem.&lt;/p&gt;

&lt;p&gt;As I mentioned previously, we're making a game engine and well, we need to do a loooottt more than just drawing a single triangle on the screen but hey, baby steps you know. So, lets add more features to our rendering class to make it a bit more interesting.&lt;/p&gt;

&lt;p&gt;By the end of this article, you should have done the following&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Implemented automatic canvas resizing to fill the window&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Learned a bit more about WebGPU features (uniforms, vertex buffers, bind groups, etc)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Created slightly more complex shaders that render arbitrary shapes and colours&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Created a rendering loop using RequestAnimationFrame&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Created a wrapper class for our Game Engine features&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Canvas Resizing
&lt;/h2&gt;

&lt;p&gt;This is a simple piece of code which will automatically resize the canvas to fill the screen. Its not perfect but I found it works well enough for my purpose.&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;// Renderer.ts&lt;/span&gt;
   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;setupCanvasResizing&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Renderer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;renderer&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;width&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="nf"&gt;max&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="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;limits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxTextureDimension2D&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="nx"&gt;renderer&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;height&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="nf"&gt;max&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="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientHeight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;limits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxTextureDimension2D&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&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;As seen from the function, it detects when the window resizing event occurs and sets the canvas to fill the window but it has a min of 1 and a max value based on the maximum texture dimension supported by the GPU device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rendering Abitrary Shapes
&lt;/h2&gt;

&lt;p&gt;At the moment our shaders look like this&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="cm"&gt;/** Vertext Shader **/&lt;/span&gt;
            &lt;span class="c1"&gt;// data structure to store output of vertex function&lt;/span&gt;
            &lt;span class="nx"&gt;struct&lt;/span&gt; &lt;span class="nx"&gt;VertexOut&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;builtin&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="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vec4f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;location&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="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vec4f&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;

            &lt;span class="c1"&gt;// process the points of the triangle&lt;/span&gt;
            &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;vertex&lt;/span&gt; 
            &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;vs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vertex_index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;vertexIndex&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;u32&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;VertexOut&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;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nf"&gt;vec2f&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.8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;// top center&lt;/span&gt;
                    &lt;span class="nf"&gt;vec2f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;// bottom left&lt;/span&gt;
                    &lt;span class="nf"&gt;vec2f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// bottom right&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;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nf"&gt;vec4f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&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="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="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="nf"&gt;vec4f&lt;/span&gt;&lt;span class="p"&gt;(&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;1&lt;/span&gt;&lt;span class="p"&gt;.,&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="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="nf"&gt;vec4f&lt;/span&gt;&lt;span class="p"&gt;(&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="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;1&lt;/span&gt;&lt;span class="p"&gt;.,&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="p"&gt;);&lt;/span&gt;

                &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;VertexOut&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;vec4f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;vertexIndex&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;vertexIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/** Fragment Shader **/&lt;/span&gt;
            &lt;span class="c1"&gt;// set the colors of the area within the triangle&lt;/span&gt;
            &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;fragment&lt;/span&gt; 
            &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;VertexOut&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;location&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="nx"&gt;vec4f&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&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 issue with the shader is that it is not configurable. Once youve run it youll always get back the same triangle with the same color. To resolve this, we need to use more functionality of the GPU namely, Uniforms and Vertex Buffers. Now you might ask what are these things?&lt;/p&gt;

&lt;h3&gt;
  
  
  What are Uniforms and Vertex Buffers?
&lt;/h3&gt;

&lt;p&gt;Lets start by explaining vertex buffers. As you recall from one of my prior posts, when the GPU is rendering things, it uses the vertex and fragment shader. The vertex shader defines the bounds of where the rendering will occur and the fragment shader is responsible for filling in the shape with the appropriate colors.&lt;/p&gt;

&lt;p&gt;Whilst an oversimplification of the process, it gets the idea across and if you want to learn more, check out this &lt;a href="https://webgpufundamentals.org/webgpu/lessons/webgpu-fundamentals.html" rel="noopener noreferrer"&gt;article&lt;/a&gt;. As you can imagine, the vertex buffer is probably gonna get used by the vertex shader but for what? Well in short, we use the vertex buffer to pass in whatever information we want to the vertex shader but you might typically add in all the vertices that define the boundary of the shape we want to render. To learn more about vertex buffers check out this &lt;a href="https://webgpufundamentals.org/webgpu/lessons/webgpu-vertex-buffers.html" rel="noopener noreferrer"&gt;article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Moving on to uniforms, theyre also a facility offered by GPUs where we can pass in information to the GPU but whose contents will remain constant across each render. They can also be used by both the vertex and fragment shaders and can be thought of as global variables. This is again an oversimplification and you can learn more from this &lt;a href="https://webgpufundamentals.org/webgpu/lessons/webgpu-uniforms.html" rel="noopener noreferrer"&gt;article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With this all said, lets now refactor our code to use uniforms and vertex buffers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rewriting the shaders
&lt;/h3&gt;

&lt;p&gt;Create a new file called &lt;code&gt;shaders.ts&lt;/code&gt; and you can dump in the following new shader code.&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Uniforms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="cm"&gt;/* wgsl */&lt;/span&gt; &lt;span class="s2"&gt;`
    @group(0) @binding(0) var&amp;lt;uniform&amp;gt; color: vec4f;
`&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SimpleVS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="cm"&gt;/* wgsl */&lt;/span&gt; &lt;span class="s2"&gt;`
    struct VertexIn {
        @location(0) pos: vec2f,
        @builtin(vertex_index) index: u32
    }

    &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;Uniforms&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;

    @vertex
    fn vs(in: VertexIn) -&amp;gt; @builtin(position) vec4f {
        return vec4f(in.pos, .0, 1.);
    }
`&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SimpleFS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="cm"&gt;/* wgsl */&lt;/span&gt; &lt;span class="s2"&gt;`
    &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;Uniforms&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;

    @fragment
    fn fs() -&amp;gt; @location(0) vec4f {
        return color;
    }
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first thing youll notice is the new uniform that I defined that will store the colour information of my final output. For my purposes, I only care about rendering things with a constant colour and not an interpolated colour because itll make things easier to predict as time goes by. Im also passing in the input into the vertex shader as a struct because itll keep things neater.&lt;/p&gt;

&lt;p&gt;An interesting thing you might notice is the &lt;code&gt;@group(0) @binding(0)&lt;/code&gt; and the &lt;code&gt;@location(0)&lt;/code&gt; in the struct. These will be used in TypeScript land to map the information we want to pass into our uniform and vertex buffer respectively as is shown below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring the buffers
&lt;/h3&gt;

&lt;p&gt;In our &lt;code&gt;Renderer.ts&lt;/code&gt; we now need to rewrite some of our code to allow the loading and setting up of the shaders and buffers.&lt;/p&gt;

&lt;p&gt;First, we rewrite our function for loading in the shaders.&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;public&lt;/span&gt; &lt;span class="nf"&gt;loadShaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vertexShader&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fragmentShader&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadVertexShader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vertexShader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadFragmentShader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fragmentShader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureBindGroupLayout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configurePipeline&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;Youll notice that we now also have the ability to pass in our vertex and fragment shaders respectively. We also introduced the configuring of the pipeline and something called the bind group layout. This is because we need to reconfigure the pipeline to reference the new shaders.&lt;/p&gt;

&lt;p&gt;Moving on, lets look at the loading of the vertex and fragment shaders&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;private&lt;/span&gt; &lt;span class="nf"&gt;loadVertexShader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shader&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertexShader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createShaderModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Vertex Shader&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;shader&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="cm"&gt;/* wgsl */&lt;/span&gt;&lt;span class="s2"&gt;`
                @vertex
                fn vs() -&amp;gt; @builtin(position) vec4f {
                    return vec4f(.0);
                }
            `&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;loadFragmentShader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;shader&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fragmentShader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createShaderModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fragment Shader&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;shader&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="cm"&gt;/* wgsl */&lt;/span&gt;&lt;span class="s2"&gt;`
                @fragment
                fn fs() -&amp;gt; @location(0) vec4f {
                    return vec4f(.0);
                }
            `&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;As you can see, these functions are relatively simple with the addition of default shaders shaders that effectively render nothing.&lt;/p&gt;

&lt;p&gt;Next lets configure the pipeline&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;private&lt;/span&gt; &lt;span class="nf"&gt;configureBindGroupLayout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bindGroupLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createBindGroupLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bind Group Layout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;entries&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="na"&gt;binding&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;visibility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GPUShaderStage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VERTEX&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;GPUShaderStage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FRAGMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;uniform&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;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipelineLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createPipelineLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Pipeline Layout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;bindGroupLayouts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bindGroupLayout&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;private&lt;/span&gt; &lt;span class="nf"&gt;configurePipeline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRenderPipeline&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Render Pipeline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipelineLayout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;vertex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertexShader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;buffers&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="na"&gt;arrayStride&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="na"&gt;attributes&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="na"&gt;shaderLocation&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;offset&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;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;float32x2&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;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;fragment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fragmentShader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;presentationFormat&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;Something to take note of now is that we are specifically creating a layout for the pipeline instead of passing in the &lt;code&gt;auto&lt;/code&gt; keyword that tries to generate the layout automatically. This is no longer possible because we have uniforms that need specific mappings. Aside from that, we also set provisions for the vertex buffer in the vertex pipeline. Now there are a lot of moving parts here but you can find out why we need to do this by reading &lt;a href="https://webgpufundamentals.org/webgpu/lessons/webgpu-inter-stage-variables.html" rel="noopener noreferrer"&gt;this&lt;/a&gt;, &lt;a href="https://webgpufundamentals.org/webgpu/lessons/webgpu-uniforms.html" rel="noopener noreferrer"&gt;this&lt;/a&gt;, and &lt;a href="https://webgpufundamentals.org/webgpu/lessons/webgpu-vertex-buffers.html" rel="noopener noreferrer"&gt;that&lt;/a&gt; article. 😁 Enjoy yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rendering Loop
&lt;/h2&gt;

&lt;p&gt;To lay the ground work for more complex rending, were gonna need to set up a rendering loop. This will allow us to add things like animation in due time but baby steps as they say. So lets rewrite the &lt;code&gt;init&lt;/code&gt; function to do this.&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;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getGPUDevice&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setupCanvasResizing&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configCanvas&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadShaders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;confiureBuffers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureBindGroup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureRenderPassDescriptor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startAnimation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&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;Most of the functions should look familiar from the previous article but we do now have a few new kids in the block namely, &lt;code&gt;configureBuffers&lt;/code&gt;, &lt;code&gt;configureBindGroup&lt;/code&gt;, and &lt;code&gt;startAnimation&lt;/code&gt;. Lets check them out.&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;private&lt;/span&gt; &lt;span class="nf"&gt;confiureBuffers&lt;/span&gt;&lt;span class="p"&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;vertices&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;Float32Array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
          &lt;span class="c1"&gt;// X     Y&lt;/span&gt;
            &lt;span class="o"&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="o"&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="mf"&gt;0.5&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="o"&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="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="o"&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="o"&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="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&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="mf"&gt;0.5&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fillColor&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;Float32Array&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="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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadVertexBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vertices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configFillColorUniform&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFillColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fillColor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;loadVertexBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Float32Array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertexData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertexBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createBuffer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Vertex Buffer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertexData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;byteLength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GPUBufferUsage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VERTEX&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;GPUBufferUsage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COPY_DST&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertexBuffer&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertexData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;configFillColorUniform&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillColorBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createBuffer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Color Fill Uniform Buffer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GPUBufferUsage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UNIFORM&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;GPUBufferUsage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COPY_DST&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;setFillColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Float32Array&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Data must have 4 elements&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&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;entry&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Data values must be between 0 and 1&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillColorBuffer&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillColor&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 code should look pretty straightforward. Here, were asking the GPU to create a Vertex Buffer and a Uniform Buffer of a known fixed size of 16 bytes (i.e 4 elements * 4 bytes/element) for the uniform buffer and 48 bytes(i.e. 12 elements * 4 bytes/element) for the vertex buffer. This is because memory allocation is not handled automatically in WebGPU and we are responsible for the allocating and freeing up of allocated memory.&lt;/p&gt;

&lt;p&gt;At the moment were planning on rendering a purple square hence, the all ones for the fill colour and the symmetrical vertex positions. An interesting thing you may notice is that some of the &lt;code&gt;(x,y)&lt;/code&gt; are duplicated. This is because GPUs only generate fragments using triangles hence to draw a square, we need to use two triangles.&lt;/p&gt;

&lt;p&gt;Lets move on to the &lt;code&gt;configureBindGroup&lt;/code&gt; function.&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;private&lt;/span&gt; &lt;span class="nf"&gt;configureBindGroup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bindGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createBindGroup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bind Group&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bindGroupLayout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;entries&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="na"&gt;binding&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;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillColorBuffer&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;This function creates our bind group which is the glue between our uniforms in GPU land and the Buffer weve created in TypeScript land. As you might notice, the fillColorBuffer is mapped to a binding value of 0. This corresponds to the &lt;code&gt;@binding(0)&lt;/code&gt; value in our shaders.&lt;/p&gt;

&lt;p&gt;Lastly, lets set up our animation loop and connect all these moving parts.&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;private&lt;/span&gt; &lt;span class="nf"&gt;startAnimation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetFps&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="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Renderer&lt;/span&gt;&lt;span class="p"&gt;)&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;start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targetFrameTime&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="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;targetFps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeStep&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;start&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;timeStep&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;elapsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;timeStep&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;start&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;elapsed&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;targetFrameTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;
                &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animate&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;private&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for &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;colorAtachments&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderPassDescriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colorAttachments&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;colorAtachments&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;colorAtachments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentTexture&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;createView&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCommandEncoder&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;render encoder&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;pass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginRenderPass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderPassDescriptor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setPipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setVertexBuffer&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertexBuffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setBindGroup&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bindGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertexData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finish&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;This now looks a bit more complex but were essentially using the &lt;code&gt;requestAnimationFrame&lt;/code&gt; function to call the render function at our ideal target framerate. Aside from this, were also adding the vertex buffer and the bindGroup to our render pass. Lastly, we now call the draw function based on the number of points in the vertex buffer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Game Engine Wrapper
&lt;/h2&gt;

&lt;p&gt;As you might now appreciate, there are a lot of moving parts going on in the rendering and for the potential game developer, they dont need to care about this so lets create a wrapper around all these things that will be visible to the developer.&lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;EngineCore.ts&lt;/code&gt; and add the following code.&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Renderer&lt;/span&gt; &lt;span class="p"&gt;}&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;./Renderer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;gEngine&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;constructor&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;// graphics context for drawing&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;_Renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Renderer&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nc"&gt;GL&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_Renderer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;initializeWebGPU&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;htmlCanvasId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backgroundColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;black&lt;/span&gt;&lt;span class="dl"&gt;"&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;htmlCanvasId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLCanvasElement&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_Renderer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_Renderer&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;Renderer&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="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_Renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&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;This sets up a global static class that initializes the renderer and also exposes the renderers public functions.&lt;/p&gt;

&lt;p&gt;We also need to rewrite our &lt;code&gt;main.ts&lt;/code&gt; file to use our new code structure.&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="p"&gt;}&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;./MyGame&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;MyGame&lt;/code&gt; folder in the &lt;code&gt;index.ts&lt;/code&gt; the following is added&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;gEngine&lt;/span&gt; &lt;span class="p"&gt;}&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;../EngineCore&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SimpleVS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SimpleFS&lt;/span&gt; &lt;span class="p"&gt;}&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;../shaders&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;gEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializeWebGPU&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GLCanvas&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;gEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadShaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SimpleVS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SimpleFS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;gEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFillColor&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;Float32Array&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="mi"&gt;0&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, this is a much cleaner code for the developer and they need not worry about all the wizardry we had to do to get this to work. and now BEHOLD your beautiful square.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqw2l4tjgzn256so5lrp3.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqw2l4tjgzn256so5lrp3.jpeg" alt="rendered square" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔🤔&lt;/p&gt;

&lt;p&gt;Some of you might be thinking That aint a square Gift. Did you make a mistake?. Well, not quite, the issue is that our screen is not a square and as such, although coordinates range from -1 to +1 in clip space for the horizontal and vertical axis, in actuality, the horizontal axis is longer and as such, the final output looks like a rectangle. This isnt a big issue and can be fixed by taking the canvas resolution into account which well see in a future article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;🎉🎉 Congrats for finishing the article. Although the visual might look underwhelming, weve learnt many powerful concepts about WebGPU such as buffers, bind groups, bindgroup layouts, the rendering loop, etc. I hope you enjoyed the process and in the next article, well add more and more functionality to our engine as we continue to learn more about WebGPU and other things. 👋👋&lt;/p&gt;

&lt;p&gt;]]&amp;gt;&lt;/p&gt;

</description>
      <category>webgpu</category>
      <category>gamedev</category>
      <category>typescript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Set Up WebGPU with TypeScript and Vite: A Simplified Guide</title>
      <dc:creator>Gift Mugweni</dc:creator>
      <pubDate>Sat, 24 Aug 2024 14:31:27 +0000</pubDate>
      <link>https://dev.to/gift_mugweni_1c055b418706/how-to-set-up-webgpu-with-typescript-and-vite-a-simplified-guide-jkn</link>
      <guid>https://dev.to/gift_mugweni_1c055b418706/how-to-set-up-webgpu-with-typescript-and-vite-a-simplified-guide-jkn</guid>
      <description>&lt;p&gt;Hello 👋, how are you doing? It's a lovely day right? In my last post, I said I was making a game engine and thought instead of writing documentation for it I might as well make blog articles to document my journey (I mean it's basically free content).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd93h9g6qghoq0ydqbd3h.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd93h9g6qghoq0ydqbd3h.gif" alt="Thinking image" width="498" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm &lt;a href="https://github.com/Stelele/web-game-engine" rel="noopener noreferrer"&gt;decently far in the project&lt;/a&gt; at present but, it didn't feel right to start from my current point as there's too much missing context. So let's use the power of time travel and go way back to when I started the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the project
&lt;/h2&gt;

&lt;p&gt;So far, we've been using vanilla JavaScript to work with WebGPU and I probably could make the entire engine that way. I didn't want to though as I feel more comfortable working with TypeScript because of its sweet sweet useless types that operate on the "Trust me bro" ethos. As such, we're gonna have to create a basic build setup. I used to use Webpack but thought I'd give Vite a try for a change as I'd heard good things about it.&lt;/p&gt;

&lt;p&gt;To create a project you run the below command in your terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;npm&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;vite&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're not making anything extra so the &lt;code&gt;vanilla-ts&lt;/code&gt; template will do just fine. Here's a screenshot of the options selected in the setup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu0p7n6amom2pj7q3dt7i.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu0p7n6amom2pj7q3dt7i.JPG" alt="Setup Screenshot" width="583" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When opening the project you should have the following files present more or less.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqa97j05rlvo2khd32e3t.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqa97j05rlvo2khd32e3t.JPG" alt="folder structure" width="207" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We don't need the &lt;code&gt;counter.ts&lt;/code&gt;, &lt;code&gt;style.css&lt;/code&gt;, and &lt;code&gt;typescript.svg&lt;/code&gt; files so you're free to delete those at your pleasure.&lt;/p&gt;

&lt;p&gt;The next thing we need is to add the types for WebGPU since they do not come pre-added at the moment. To download the types run the below command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;npm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;webgpu/types&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This downloads the package but we still need to link it to our project so modify the &lt;code&gt;tsconfig.json&lt;/code&gt; to look as below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ES2020"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"useDefineForClassFields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ESNext"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lib"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"ES2020"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"DOM"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"DOM.Iterable"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"skipLibCheck"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;/*********************THIS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;IMPORTANT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;PART!!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;******/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"types"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"@webgpu/types"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;/******************************************************/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Bundler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;mode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"moduleResolution"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bundler"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allowImportingTsExtensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"resolveJsonModule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"isolatedModules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"moduleDetection"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"force"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noEmit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;/*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Linting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*/&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noUnusedLocals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noUnusedParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noFallthroughCasesInSwitch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"src"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I did this my types still weren't showing and after some googling, I also modified the &lt;code&gt;vite-env.d.ts&lt;/code&gt; file to look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;/// &lt;span class="nt"&gt;&amp;lt;reference&lt;/span&gt; &lt;span class="na"&gt;types=&lt;/span&gt;&lt;span class="s"&gt;"vite/client"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
/// &lt;span class="nt"&gt;&amp;lt;reference&lt;/span&gt; &lt;span class="na"&gt;types=&lt;/span&gt;&lt;span class="s"&gt;"@webgpu/types"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're using the VSCode IDE, you can also download these extensions that introduce some much-needed syntax highlighting in the wgsl shader code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=PolyMeilex.wgsl" rel="noopener noreferrer"&gt;&lt;strong&gt;WGSL by&lt;/strong&gt; PolyMeilex&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=ggsimm.wgsl-literal" rel="noopener noreferrer"&gt;WGSL Literal by ggsimm&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, replace the &lt;code&gt;index.html&lt;/code&gt; and &lt;code&gt;main.ts&lt;/code&gt; files with the below code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt; &lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/svg+xml"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/vite.svg"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Web Game Engine&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
      html, body {
        margin: 0px;
        padding: 0px;
        width: 100%;
        height: 99.74%;
      }
    &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;canvas&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"GLCanvas"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      Your browser does not support the HTML5 canvas.
     &lt;span class="nt"&gt;&amp;lt;/canvas&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/src/main.ts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;main.ts&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Renderer&lt;/span&gt; &lt;span class="p"&gt;}&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;./Renderer&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;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GLCanvas&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLCanvasElement&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;render&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;Renderer&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;render&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;index.html&lt;/code&gt; file should look familiar. Its main point is to set up a canvas where the output will be displayed. The canvas has also been resized to fill the window.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;main.ts&lt;/code&gt; file contains code that will make sense as we go further down. To understand this, we need to ask a basic foundational question.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the purpose of a game engine?
&lt;/h2&gt;

&lt;p&gt;Fundamentally, a game engine exists to make developing games easier by abstracting away important but unessential parts of the game-making process. For better context on what this means let's use a basic example of a like &lt;a href="https://en.bandainamcoent.eu/elden-ring/elden-ring" rel="noopener noreferrer"&gt;FromSoftware's Elden Ring&lt;/a&gt; game.&lt;/p&gt;

&lt;p&gt;As far as the player is concerned, they are playing Elden Ring to enjoy exploring the open world, overcoming tough bosses, and getting lost in the scenery, music, and breathtaking visuals. All these things are difficult to get right and require a lot of effort and time from the game designers to perfect.&lt;/p&gt;

&lt;p&gt;What the player forgets is that they are interacting with the game via their controller or keyboard and mouse. They might be playing the game on drastically different screens, using devices with varying ranges of specifications. Aside from this, Elden Ring is a 3D game but they are playing it on a 2D screen so how does that work? How does the animation work? What about the lighting? How does the game handle the multiplayer aspects to ensure no one is cheating or that multiple players see the same thing? Now that we're down this rabbit hole, how even is that music getting played in the first place?&lt;/p&gt;

&lt;p&gt;All these questions must be answered before we start dealing with anything the player cares about and as I'm learning, they have no easy answers. As a game designer, you don't want to worry about these things. You're trying to make a game and provide memorable experiences. Could you make these things yourself? Yes, but that needs time, people, and money.&lt;/p&gt;

&lt;p&gt;This is where game engines come in. They don't guarantee you've got a good game and aren't all you need either. They're a small part of the bigger process of making games that focus primarily on key things like rendering, audio, networking, input, physics, lighting, modelling, etc. Hence my initial explanation of them abstracting away important but unessential elements.&lt;/p&gt;

&lt;p&gt;Now that we've answered this question we'll start working on the first element of the game engine, the rendering system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the basic rendering system
&lt;/h2&gt;

&lt;p&gt;What is a rendering system? In short, it's the thing responsible for drawing stuff on the screen. Practically speaking, this is where we'll be putting most of our WebGPU and shader logic as it directly relates to drawing stuff.&lt;/p&gt;

&lt;p&gt;To start, we'll be remaking our triangle example as that's the foundational building block. The implementation will be slightly different as I chose to wrap up this logic in a class so it is more compact and makes it easier to add more features.&lt;/p&gt;

&lt;h3&gt;
  
  
  The init func
&lt;/h3&gt;

&lt;p&gt;The first thing is to define the &lt;code&gt;Renderer&lt;/code&gt; class in a new file we'll call &lt;code&gt;Renderer.ts&lt;/code&gt; that will house all this logic.&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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Renderer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GPUDevice&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GPUCanvasContext&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;presentationFormat&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GPUTextureFormat&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;vertexShader&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GPUShaderModule&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;fragmentShader&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GPUShaderModule&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GPURenderPipeline&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;renderPassDescriptor&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GPURenderPassDescriptor&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&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;HTMLCanvasElement&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;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getGPUDevice&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configCanvas&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadShaders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configurePipeline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureRenderPassDescriptor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&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;When we instantiate the class, we pass in a canvas reference. This allows the class to work with any canvas which could be handy in the future maybe🤷‍♂️. The &lt;code&gt;init&lt;/code&gt; function is responsible for setting up the rendering loop which I'll now explain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting a GPU device and configuring canvas
&lt;/h3&gt;

&lt;p&gt;The first thing we need is access to the GPU device on the host machine.&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;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getGPUDevice&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gpu&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;requestAdapter&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;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;requestDevice&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Browser does not support WebGPU&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;device&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;H1&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/H1&amp;gt;`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to set up the canvas to accept the output from our GPU.&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;private&lt;/span&gt; &lt;span class="nf"&gt;configCanvas&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&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="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;webgpu&lt;/span&gt;&lt;span class="dl"&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to get canvas context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;presentationFormat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPreferredCanvasFormat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;device&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;presentationFormat&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;
  
  
  Loading shaders
&lt;/h3&gt;

&lt;p&gt;After setting up the canvas, we load in the vertex and fragment shaders.&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;private&lt;/span&gt; &lt;span class="nf"&gt;loadShaders&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadVertexShader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadFragmentShader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;loadVertexShader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertexShader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createShaderModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Vertex Shader&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="cm"&gt;/* wgsl */&lt;/span&gt; &lt;span class="s2"&gt;`
            // data structure to store output of vertex function
            struct VertexOut {
                @builtin(position) pos: vec4f,
                @location(0) color: vec4f
            };

            // process the points of the triangle
            @vertex 
            fn vs(
                @builtin(vertex_index) vertexIndex : u32
            ) -&amp;gt; VertexOut {
                let pos = array(
                    vec2f(   0,  0.8),  // top center
                    vec2f(-0.8, -0.8),  // bottom left
                    vec2f( 0.8, -0.8)   // bottom right
                );

                let color = array(
                    vec4f(1.0, .0, .0, .0),
                    vec4f( .0, 1., .0, .0),
                    vec4f( .0, .0, 1., .0)
                );

                var out: VertexOut;
                out.pos = vec4f(pos[vertexIndex], 0.0, 1.0);
                out.color = color[vertexIndex];

                return out;
            }
         `&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;loadFragmentShader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fragmentShader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createShaderModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fragment Shader&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="cm"&gt;/* wgsl */&lt;/span&gt; &lt;span class="s2"&gt;`
            // data structure to input to fragment shader
            struct VertexOut {
                @builtin(position) pos: vec4f,
                @location(0) color: vec4f
            };

            // set the colors of the area within the triangle
            @fragment 
            fn fs(in: VertexOut) -&amp;gt; @location(0) vec4f {
                return in.color;
            }
            `&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;You'll notice I've now split the vertex and fragment shaders into separate variables. This will allow us to easily change the vertex and fragment shaders on the fly as we go forward. A downside of this is the duplication of the VertexOut struct but that's not so bad right?&lt;/p&gt;

&lt;p&gt;Another important point is that the &lt;code&gt;@builtin(position) pos: vec4f&lt;/code&gt; in the vertex and fragment shaders do not contain the same values. For the vertex shader, the pos effectively only contains three values. These three points form a region that encompasses some pixels which are determined by a process called rasterization. The fragment shader is then executed for every pixel. What this means in practice is that the pos variable in the fragment shader contains the respective pixel coordinates and has as many elements as pixels in the defined region. This is an important point to remember if you want to do any fancy shader stuff and you can find more details about it in this &lt;a href="https://webgpufundamentals.org/webgpu/lessons/webgpu-inter-stage-variables.html" rel="noopener noreferrer"&gt;article&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring pipeline
&lt;/h3&gt;

&lt;p&gt;Our pipeline is still pretty basic so it hasn't changed from our last version&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;private&lt;/span&gt; &lt;span class="nf"&gt;configurePipeline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRenderPipeline&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Render Pipeline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;vertex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vertexShader&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;fragment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fragmentShader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;presentationFormat&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="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;configureRenderPassDescriptor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderPassDescriptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Render Pass Description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;colorAttachments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
                &lt;span class="na"&gt;clearValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="na"&gt;loadOp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clear&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;storeOp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentTexture&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;createView&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;
  
  
  Rendering function
&lt;/h3&gt;

&lt;p&gt;This too is still the basic implementation with nothing special&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;private&lt;/span&gt; &lt;span class="nf"&gt;render&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderPassDescriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colorAttachments&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&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="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentTexture&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;createView&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;encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCommandEncoder&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;render encoder&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;pass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginRenderPass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderPassDescriptor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setPipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finish&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;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations 👏👏👏. You just spent all this effort to recreate the same thing you made last time. But, now you have TYPES 🎉🎉. I recognize that this might be a bit annoying but I felt it important to show all this so that we can start on the same page moving forward. Sadly I'll have to stop here for now as this article is already pretty long but next, we'll begin refining this foundation and shaping it into our wonderful dodgy engine.&lt;br&gt;
]]&amp;gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>webdev</category>
      <category>gameengine</category>
      <category>vite</category>
    </item>
    <item>
      <title>I'm making a game engine with WebGPU</title>
      <dc:creator>Gift Mugweni</dc:creator>
      <pubDate>Sun, 18 Aug 2024 07:03:23 +0000</pubDate>
      <link>https://dev.to/gift_mugweni_1c055b418706/im-making-a-game-engine-with-webgpu-2ffc</link>
      <guid>https://dev.to/gift_mugweni_1c055b418706/im-making-a-game-engine-with-webgpu-2ffc</guid>
      <description>&lt;p&gt;Background&lt;/p&gt;

&lt;p&gt;In my last graphics article, I showed the relatively straightforward process of drawing a triangle on the screen. Whilst not perfect, practical, scalable, or all that interesting, I felt it important to help set the scene of what you can expect when working with the WebGPU API. From my experience, it's a relatively low-level API which means two things in practice.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;It can be quite verbose when you want to do some simple things&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It's surprisingly flexible and customizable owing to all the freedom it gives you.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, why don't I think of a use case that seems more realistic and allows me to explore more of what WebGPU can do?&lt;/p&gt;

&lt;p&gt;As should be apparent at this stage, I'm new to the world of graphics programming but, it has sunk its claws deep into me and I can't stop because it's just too much fun. Hence, I decided to go with the flow and learn how to make a Game Engine.&lt;/p&gt;

&lt;h1&gt;
  
  
  But why a Game Engine?
&lt;/h1&gt;

&lt;p&gt;Gift, why would you make a game engine? Do you not know how hard that is? Have you not seen those horror stories about how long those things take? Who's even going to use the engine anyway?&lt;/p&gt;

&lt;p&gt;Are all these valid questions? yes, they are. But, I remembered a &lt;a href="https://www.youtube.com/watch?v=DZkbDCSdC1Q" rel="noopener noreferrer"&gt;video&lt;/a&gt; I watched by the YouTuber ThePrimeagen where he talked about the importance of taking the hard road sometimes even when there's no reason. I had also learnt about the &lt;a href="https://handmadehero.org/" rel="noopener noreferrer"&gt;Handmade Hero&lt;/a&gt; series by Casey Muratori where he made an entire game from scratch with no dependencies and that just looked fun. The nail in the coffin though was that I wanted to know if I could do it. I've heard the horror stories of it all and couldn't help diving into the fire to see if I'd come out the other side. So yeah, do I need to make a game engine? No. Do I want to make a game engine? Absolutely!!!!&lt;/p&gt;

&lt;h1&gt;
  
  
  How am I going to make it?
&lt;/h1&gt;

&lt;p&gt;This was an interesting question to answer. I knew nothing about making a game engine and I didn't know anyone who did so Google was my friend.&lt;/p&gt;

&lt;p&gt;The first question I had to answer was will my engine be for 2D or 3D games. From my initial runnings with Graphics Programming, I knew that the complexity increased exponentially when you moved from 2D to 3D so I humbled myself and decided I'd have to make a 2D engine for now.&lt;/p&gt;

&lt;p&gt;This helped a bit but not much since I still didn't know where to start. My problem was extra interesting owing to WebGPU still being so new there didn't seem to be any resources out there that I could find for making a game engine using it so I had to use tangential resources to accomplish my goal.&lt;/p&gt;

&lt;p&gt;Surprisingly, there are many good resources in different languages such as the &lt;a href="https://handmadehero.org/" rel="noopener noreferrer"&gt;Handmade Hero&lt;/a&gt; series which is wonderful when you're using C++ or the &lt;a href="https://www.youtube.com/playlist?list=PLtrSb4XxIVbp8AKuEAlwNXDxr99e3woGE" rel="noopener noreferrer"&gt;Coding a 2D Engine in Java&lt;/a&gt; series. Sadly, there were too many differences between these and my potential TypeScript-based implementation so I had to keep searching. Eventually, I found this wonderful book called "&lt;a href="https://www.amazon.com/Build-Engine-Create-Great-Games-ebook/dp/B01HXLYAHC/ref=sr_1_2?crid=2PAUDTDKS28Y7&amp;amp;dib=eyJ2IjoiMSJ9.ZIlhDSJftGNza2H6ShApw_Lx9xNc0G3Z5-yU02BnzEHGjHj071QN20LucGBJIEps.8Npu3dhW6v0xMkvYhbWHzwnOAjUMwpcl3kbYQvhwv8s&amp;amp;dib_tag=se&amp;amp;keywords=Build+Your+Own+2D+Game+Engine+and+Create+Great+Web+Games&amp;amp;qid=1723962549&amp;amp;s=books&amp;amp;sprefix=%2Cstripbooks-intl-ship%2C404&amp;amp;sr=1-2" rel="noopener noreferrer"&gt;Build your own 2D Game Engine and Create Great Web Games using HTML5, JavaScript, and WebGL&lt;/a&gt;". I mean, the title practically speaks for itself. It was also a bonus that it was written using WebGL which precedes WebGL2 which precedes WebGPU.&lt;/p&gt;

&lt;p&gt;So yeah, I haven't finished making my engine and there's still a lot of stuff I need to work on but I feel I've made decent progress on it. You can find the code &lt;a href="https://github.com/Stelele/web-game-engine" rel="noopener noreferrer"&gt;here&lt;/a&gt; and in the following graphics articles, I'll give rundowns on what all that code is doing and what I had to modify to get it working for the WebGPU API.&lt;/p&gt;

&lt;p&gt;]]&amp;gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>gameengine</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why do I write?</title>
      <dc:creator>Gift Mugweni</dc:creator>
      <pubDate>Sat, 27 Jul 2024 14:51:23 +0000</pubDate>
      <link>https://dev.to/gift_mugweni_1c055b418706/why-do-i-write-6lb</link>
      <guid>https://dev.to/gift_mugweni_1c055b418706/why-do-i-write-6lb</guid>
      <description>&lt;p&gt;In the past few weeks, I found myself struggling to write an article. It's interesting how easily one can begin a task and as time passes by, slowly, ever so slowly, you find your motivation diminishing. You question who you are to do this action. What information could you possibly know? What people would want to read your writings?&lt;/p&gt;

&lt;p&gt;I had the analytics that showed me that although not crazy numbers, my words had indeed been read more than I thought possible. And although I told myself this, I found my convictions crumbling little by little. It didn't start strong, merely a slight procrastination in my starting time, or the words not quite coming to mind as they should. The writing became less and less appealing and I found my hands getting weaker and weaker as a voice grew stronger and stronger that asked a question I increasingly could not ignore. "Why am I writing?".&lt;/p&gt;

&lt;p&gt;Why am I writing? Why am I writing? Why am I writing? This one single question gripped me. It's a simple question at its face but not to me. To me, this question grew grander and grander. It encompassed my mind and invaded my dreams. It asked and asked and asked. It lingered, it festered and it scared. Initially, I wanted to impart what I've learned and share it with others. But that wasn't right. The answer whilst not quite wrong also didn't feel right. Maybe I'll write and make this a side hustle business, I've heard such stories. Again that didn't feel right for I know how statistically unlikely that is. The odds didn't seem in my favor and I always knew that. Do I do it for fun? Do I do it for reflection? Do I do it for attention? Do I do it for spite?&lt;/p&gt;

&lt;p&gt;I looked at my last posts and re-read my first post, and as I did a growing realization dawned on me. In my first article, I was emotional and animated. I spoke from my heart and told a tale that whilst not unique and unheard of, felt right to me. As I went on, to my next article, I adopted the framework of a textbook. A cold, factual, unfeeling textbook. I pushed my personality aside in favor of getting straight to the point and being informative. I told myself articles should get to the point and tried to game the SEO with the help of AI. I chose images to intrigue what I might not have felt. I presented words of fact but no worlds with meaning could be found. I made a site with my name, and I couldn't be found in it.&lt;/p&gt;

&lt;p&gt;So my strength faded and the words stopped coming. Sadly, I failed to be the bringer of information for it seems, I could never truly be that to begin with. Why can I not be that I asked and the answer was self-evident. I do not enjoy reading textbooks, I enjoy reading stories. Sadly I cannot be clinical in my writing and I have a bad habit of getting lost in my ramblings. Information it seems is not my passion, nor is it my desire, nor is it my goal. A story I seek to tell. A story I seek to share. To speak and maybe be heard. To speak, even when not heard.&lt;/p&gt;

&lt;p&gt;And so, I abandon the land of facts for it seems not to be my home. I continue my journey, through the great unknown. I'll wander into the land of dreams, and hopefully tell tales of the sights I see. Facts it seems are not where I am meant to be. Facts it seems, do not call to me.&lt;/p&gt;

&lt;p&gt;With all this said, the question comes to me again. "Why do I write?". I do not know why. But I will continue to try. I'll write tales. I'll write articles. I'll write poems. I'll write nonsense. But write I must, for it seems, that writing is for me.&lt;/p&gt;

</description>
      <category>writing</category>
      <category>reflection</category>
      <category>story</category>
    </item>
    <item>
      <title>What is recursion?</title>
      <dc:creator>Gift Mugweni</dc:creator>
      <pubDate>Sat, 22 Jun 2024 19:26:48 +0000</pubDate>
      <link>https://dev.to/gift_mugweni_1c055b418706/what-is-recursion-1o34</link>
      <guid>https://dev.to/gift_mugweni_1c055b418706/what-is-recursion-1o34</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/cs"&gt;DEV Computer Science Challenge v24.06.12: One Byte Explainer&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Explainer
&lt;/h2&gt;

&lt;p&gt;Recursion is solving a problem by breaking it into smaller simpler problems that follow a set pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Context
&lt;/h2&gt;

</description>
      <category>devchallenge</category>
      <category>cschallenge</category>
      <category>computerscience</category>
      <category>beginners</category>
    </item>
    <item>
      <title>WebGPU Basics: How to Create a Triangle</title>
      <dc:creator>Gift Mugweni</dc:creator>
      <pubDate>Sat, 22 Jun 2024 19:19:16 +0000</pubDate>
      <link>https://dev.to/gift_mugweni_1c055b418706/webgpu-basics-how-to-create-a-triangle-447m</link>
      <guid>https://dev.to/gift_mugweni_1c055b418706/webgpu-basics-how-to-create-a-triangle-447m</guid>
      <description>&lt;p&gt;Hello 👋, it's been a minute. How's life and all that good stuff? Anyway to get myself back into the groove I thought I'd start where I left off, Graphics Programming specifically using WebGPU.&lt;/p&gt;

&lt;p&gt;In this series, I'll give semi-tutorials on working with WebGPU and the shading language WGSL which I'll explain as and when is necessary so hopefully you can also dive into this crazy world of making art with code and maths.&lt;/p&gt;

&lt;p&gt;To keep things simple, this article will teach you how to make the equivalent of a "Hello World" in shader land which is a triangle because drawing text to screen turns out to be really hard. See this &lt;a href="https://www.youtube.com/watch?v=SO83KQuuZvg&amp;amp;pp=ygUWY29kaW5nIGFkdmVudHVyZXMgdGV4dA%3D%3D"&gt;video&lt;/a&gt; if you think I'm lying. With this example, you'll fully get to experience the basic flow of working with WebGPU and I'll also point to some resources I came across that you can read up on that helped me start this journey.&lt;/p&gt;

&lt;p&gt;Before we begin, let's answer a few obvious questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question: What is WebGPU?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer:&lt;/strong&gt; It's a graphics API&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question: What does that mean?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer:&lt;/strong&gt; It is software that helps you utilize the Graphics Card(GPU) that comes with every modern computer/smartphone to either draw stuff on the screen or do more general computations on the graphics card e.g. matrix math.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question: Why would I ever need to use a GPU can't my CPU do all that already?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer:&lt;/strong&gt; Yes it can but because of how a CPU is designed, as you get more sophisticated with your graphics or you need to do a lot of simple stuff in parallel, it will struggle a lot and not be efficient. That's where we use GPUs that have been purpose-built for such tasks.&lt;/p&gt;

&lt;p&gt;With that preamble in place, let us talk about browser support. As I mentioned in my previous article, WebGPU is still relatively new so, browser support hasn't fully rolled out yet at the time of writing, you can only use the API on the latest Chrome, Edge, Opera, Chrome for Android, Samsung Internet and Opera Mobile browsers. Safari support is present in the Technical Preview only so far. So yeah, as you can see, it hasn't rolled out fully yet but the rollout is being actively worked on and you can check on this &lt;a href="https://caniuse.com/webgpu"&gt;site&lt;/a&gt;, where support will be as time goes on. I don't think this browser support state is much of an issue but, it is something to be aware of.&lt;/p&gt;

&lt;p&gt;Now that's done, let's see what we will be drawing today.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3stw4wr8zztezz1x0xu.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3stw4wr8zztezz1x0xu.JPG" alt="Triangle Image" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looks beautiful right? This triangle and all the following code come from this wonderful site called &lt;a href="https://webgpufundamentals.org/"&gt;WebGPU Fundamentals&lt;/a&gt; that goes in-depth into WebGPU and is a great resource to learn about Web GPU but, it does look a bit intimidating when you first visit it so I thought I'd make this series to give an easier entry point to jump off from.&lt;/p&gt;

&lt;p&gt;Although I did say it's an easier entry point, I still need to make some assumptions for brevity. The first assumption is that you are familiar with modern JavaScript and are comfortable with basic HTML and CSS though we won't use the latter two all that much. If you are not familiar with any of these, here are some great playlists made by the YouTuber &lt;a href="https://www.youtube.com/@NetNinja"&gt;The Net Ninja&lt;/a&gt; that will get you up to speed. He also makes other great videos in general so feel free to check him out.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=Y1BlT4_c_SU&amp;amp;list=PL4cUxeGkcC9ibZ2TSBaGGNrgh4ZgYE6Cc"&gt;Learning HTML&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=I9XRrlOOazo&amp;amp;list=PL4cUxeGkcC9gQeDH6xYhmO-db2mhoTSrT"&gt;Learning CSS&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=iWOYAxlnaww&amp;amp;list=PL4cUxeGkcC9haFPT7J25Q9GRB_ZkFrQAc"&gt;Learning Modern JavaScript&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=ZcQyJ-gxke0&amp;amp;list=PL4cUxeGkcC9jx2TTZk3IGWKSbtugYdrlu"&gt;Learning Async JavaScript&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Assuming you have explored those resources or already have the basics covered, let's set up our basic HTML page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;WebGPU&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
            html, body {
                height: 100%;
                margin: 0;
            }

            .container {
                display: flex;
                min-width: 100%;
                min-height: 100%;
                align-items: center;
                justify-content: center;
                background-color: black;
            }

            .display {
                min-width: 100%;
                min-height: 100%;
            }
        &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;script&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"main.js"&lt;/span&gt; &lt;span class="err"&gt;defer&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;canvas&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"webgpu-output"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"display"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So there's nothing fancy with this code snippet here. Just make a basic page and resize the canvas element to which we will be drawing to to fill the entire page. Aside from that, we also include a "main.js" file which will contain all of our code from here on out.&lt;/p&gt;

&lt;p&gt;Before I begin though, look at this meme and internalize it for the rest of this article.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuzm3b8d5q93zmscms0t5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuzm3b8d5q93zmscms0t5.jpg" alt="Drawing Meme" width="651" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The GPU exists in a different world from the CPU. In GPU land, many things are different and some things that might be simple in the CPU are a nightmare in the GPU and vice versa. Because of this, drawing a triangle ends up being a bit involved.&lt;/p&gt;

&lt;p&gt;Having set your expectations, let us draw our lovely triangle.&lt;/p&gt;

&lt;p&gt;First, we need to get permission to use the GPU. For that, we enter the below code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// get GPU device&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gpu&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;requestAdapter&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;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;requestDevice&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;need a browser that supports WebGPU&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&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;Now, I could go in-depth into the fine details going on here but this is a beginners' course so all we need to know is that if the &lt;code&gt;device&lt;/code&gt; variable is not &lt;code&gt;undefined&lt;/code&gt;, congratulations 👏👏👏 we now have our GPU device and can continue forward. For a more in-depth explanation, check out the &lt;a href="https://webgpufundamentals.org/webgpu/lessons/webgpu-fundamentals.html"&gt;Fundamentals Article&lt;/a&gt; on the WebGPU Fundamentals website.&lt;/p&gt;

&lt;p&gt;Moving on, we need to prepare the canvas so that it understands the eventual commands we will send to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="c1"&gt;// Get a WebGPU context from the canvas and configure it&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;webgpu-output&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;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;webgpu&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;presentationFormat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPreferredCanvasFormat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;presentationFormat&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 main role of this section of code is to ensure that the canvas understands the draw commands it will eventually get from our drawing code.&lt;/p&gt;

&lt;p&gt;Moving on, let's set up our shader code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createShaderModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;our hardcoded triangle shaders&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
            // data structure to store output of vertex function
            struct VertexOut {
                @builtin(position) pos: vec4f,
                @location(0) color: vec4f
            };

            // process the points of the triangle
            @vertex 
            fn vs(
                @builtin(vertex_index) vertexIndex : u32
            ) -&amp;gt; VertexOut {
                let pos = array(
                    vec2f(   0,  0.8),  // top center
                    vec2f(-0.8, -0.8),  // bottom left
                    vec2f( 0.8, -0.8)   // bottom right
                );

                let color = array(
                    vec4f(1.0, .0, .0, .0),
                    vec4f( .0, 1., .0, .0),
                    vec4f( .0, .0, 1., .0)
                );

                var out: VertexOut;
                out.pos = vec4f(pos[vertexIndex], 0.0, 1.0);
                out.color = color[vertexIndex];

                return out;
            }

            // set the colors of the area within the triangle
            @fragment 
            fn fs(in: VertexOut) -&amp;gt; @location(0) vec4f {
                return in.color;
            }
        `&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;This right here is the meat of the topic. I understand that this code can be overwhelming so, let's make broad strokes for now. To understand this code, we need a basic understanding of how GPUs draw stuff on the screen.&lt;/p&gt;

&lt;p&gt;The first important point is when drawing, GPUs only understand points, lines and triangles. Thats it. Everything that appears on the screen is decomposed into these fundamental elements. Hence, we need to think of things from this perspective to get our lovely visual showing.&lt;/p&gt;

&lt;p&gt;The next important point is the order in which the GPUs carry out the drawing. First, it establishes all the points(vertices) of the shape we want to draw. Then it groups all three points into triangles. Afterwards, it colours in all the grouped triangles.&lt;/p&gt;

&lt;p&gt;With this framework in mind, we can see a function called &lt;code&gt;vs&lt;/code&gt; and another called &lt;code&gt;fs&lt;/code&gt; . The &lt;code&gt;vs&lt;/code&gt; function is where we process all our points and do any transformations if we want to whilst the &lt;code&gt;fs&lt;/code&gt; function is responsible for the colouring of the respective triangles. For our starting point, I think this is good enough and if you want to know more, check out the &lt;a href="https://webgpufundamentals.org/webgpu/lessons/webgpu-fundamentals.html"&gt;Fundamentals Article&lt;/a&gt; on the WebGPU Fundamentals website.&lt;/p&gt;

&lt;p&gt;Now that we've had our meat, it's time to face the bone and that's us doing all the necessary plumbing to actually draw the triangle. Right now, we're still writing stuff in CPU land and we need to send this information to GPU land. and for that, we use the below code to do that transfer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRenderPipeline&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;our hardcoded red triangle pipeline&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;vertex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;fragment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;presentationFormat&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;renderPassDescriptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;our basic canvas renderPass&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;colorAttachments&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;// view: &amp;lt;- to be filled out when we render&lt;/span&gt;
            &lt;span class="na"&gt;clearValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.3&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="na"&gt;loadOp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clear&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;storeOp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;store&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;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Get the current texture from the canvas context and&lt;/span&gt;
        &lt;span class="c1"&gt;// set it as the texture to render to.&lt;/span&gt;
        &lt;span class="nx"&gt;renderPassDescriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;colorAttachments&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="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentTexture&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;createView&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// make a command encoder to start encoding commands&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCommandEncoder&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;our encoder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="c1"&gt;// make a render pass encoder to encode render specific commands&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginRenderPass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;renderPassDescriptor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setPipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// call our vertex shader 3 times.&lt;/span&gt;
        &lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&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;commandBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;commandBuffer&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, quite a chunky bit of code here but at its core, we're just setting things up so that we can transfer our shader code to the GPU. You'd be correct to feel that this feels like too much work for such a basic triangle but bear in mind that our current use case isn't what WebGPU was made for. It's designed for drawing multiple objects moving in potentially complex patterns. At that point, it helps to think of drawing stuff in batches and the above code structure helps support that method of thinking.&lt;/p&gt;

&lt;p&gt;And with that, we're done. You, my friend, if you've followed along now have your first-ever triangle on screen and you are destined for greatness. So what's next after this?&lt;/p&gt;

&lt;p&gt;If you're hooked, try out the &lt;a href="https://codelabs.developers.google.com/your-first-webgpu-app#0"&gt;Google Codelab project&lt;/a&gt; where you get to recreate the classic Conway's Game of Life and learn more about WebGPU.&lt;/p&gt;

&lt;p&gt;I've placed all the code discussed here in a GitHub repo &lt;a href="https://github.com/Stelele/blog-webgpu-hello-world"&gt;here&lt;/a&gt;. I'd recommend you write it yourself instead. You always learn more that way instead.&lt;/p&gt;

&lt;p&gt;In my next article, I'll talk about making much nicer visuals and hopefully get deeper into exploring shaders now that we've gotten the foundation in place.&lt;/p&gt;

</description>
      <category>webgpu</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>A Beginner's Journey into Graphics Programming</title>
      <dc:creator>Gift Mugweni</dc:creator>
      <pubDate>Sat, 08 Jun 2024 21:34:08 +0000</pubDate>
      <link>https://dev.to/gift_mugweni_1c055b418706/a-beginners-journey-into-graphics-programming-4p9p</link>
      <guid>https://dev.to/gift_mugweni_1c055b418706/a-beginners-journey-into-graphics-programming-4p9p</guid>
      <description>&lt;p&gt;One fateful night, I was scrolling through my YouTube feed when I came across an interesting &lt;a href="https://www.youtube.com/watch?v=f4s1h2YETNY&amp;amp;t=2s&amp;amp;ab_channel=kishimisu"&gt;Kishimisu channel video&lt;/a&gt; introducing me to the wild world of graphics programming. In the video, I saw a beautiful visual created with nothing but mathematical concepts and I got hooked. Here I was, lamenting my horrible hand-eye coordination and thinking I was doomed in art when I could have put all those years of learning linear algebra and calculus to good use. Here was an excuse to use maths for entertainment that I could get behind. So, I decided to see what happens in this strange world of drawing stuff on the screen.&lt;/p&gt;

&lt;p&gt;To start my exploration, I thought it'd be great if I could reproduce the visual I saw in the Kishimisu video. In the video I watched, he made the visual on this amazing website called &lt;a href="https://www.shadertoy.com/"&gt;Shadertoy&lt;/a&gt; where a bunch of incredibly smart people make visualizations and share the code on how they made them. For reference, these are some of the visuals on the site that blew me away.&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;a href="https://www.shadertoy.com/view/Wt33Wf" rel="noopener noreferrer"&gt;
      shadertoy.com
    &lt;/a&gt;
&lt;/div&gt;



&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;a href="https://www.shadertoy.com/view/XfyXRV" rel="noopener noreferrer"&gt;
      shadertoy.com
    &lt;/a&gt;
&lt;/div&gt;
 


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;a href="https://www.shadertoy.com/view/4XVGWh" rel="noopener noreferrer"&gt;
      shadertoy.com
    &lt;/a&gt;
&lt;/div&gt;



&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;a href="https://www.shadertoy.com/view/DsBczR" rel="noopener noreferrer"&gt;
      shadertoy.com
    &lt;/a&gt;
&lt;/div&gt;
 

&lt;p&gt;Now, you'd think that since I wanted to reproduce the visual I'd create a Shadertoy account and start coding away right? Well, that was my plan at the beginning. As I was in the process of staring at those visuals, I found myself wondering how the Shadertoy website worked. As such, I found myself entering much deeper waters.&lt;/p&gt;

&lt;p&gt;From my research, I learnt about the magic of shaders. Now, what are shaders? As far as I understood, shaders are just programs that run on your graphics card which is one of the key gadgets that allows you to play all the new amazing games these days. Like any programming language, shaders can be written in various languages like OpenGL, DirectX, Vulkan or Metal. However, strangely enough, when it comes to websites, there seems to be only one language at its core which is called WebGL which is just a port of OpenGL.&lt;/p&gt;

&lt;p&gt;In a wild twist of fate, as I was learning about WebGL, I learned that a new graphics API was released last year called &lt;a href="https://developer.chrome.com/blog/webgpu-io2023/"&gt;WebGPU&lt;/a&gt; that is meant to succeed WebGL considering it was initially released in the early 2010s. This felt amazing as that means we are possibly at the cusp of a graphics revolution for the web. This means I can get an opportunity to experience a potentially new world-shaking technology regarding computer visuals on the web in real-time and experience the technology evolve with me.&lt;/p&gt;

&lt;p&gt;So, I instantly pivoted and started to see if I could reproduce the initial visual not in WebGL on Shadertoy but in WebGPU using my hacky code. Below are some visuals I made using WebGPU.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz35rr805pi28lslplh8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz35rr805pi28lslplh8g.png" alt="Shader image 1" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthqwwwo5cttvaa9vukmg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fthqwwwo5cttvaa9vukmg.png" alt="Shader image 2" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5bj8xusqw9hrweu2ce4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5bj8xusqw9hrweu2ce4m.png" alt="Shader image 3" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

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

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

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

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

&lt;p&gt;Having played around with the new API I have to say I was greatly impressed so, I decided to make this a series where I talk about my learnings in graphics programming and hopefully I get to show you all more and more amazing visuals and also explanations of my learnings as I go on.&lt;/p&gt;

</description>
      <category>webgpu</category>
      <category>graphics</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Transform Game Visuals Using Meta AI</title>
      <dc:creator>Gift Mugweni</dc:creator>
      <pubDate>Sat, 01 Jun 2024 22:03:03 +0000</pubDate>
      <link>https://dev.to/gift_mugweni_1c055b418706/transform-game-visuals-using-meta-ai-1hn5</link>
      <guid>https://dev.to/gift_mugweni_1c055b418706/transform-game-visuals-using-meta-ai-1hn5</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;In my last article, I ended with a promise to explain how I prepared the assets for the Flappy Bird clone I made. The game is simple, so basic features like sound and fonts could be easily sourced or created. As such, the true difficulty for me lay in the visual assets.&lt;/p&gt;

&lt;p&gt;Now, I have a confession to make. I have zero art skills and it might lean in the negative. For some reason, I find the field more difficult than any engineering or calculus classes I attended with many difficult topics like colouring, proportions, framing, lighting, symmetry, placement, and probably other things I don't even know I don't know.&lt;/p&gt;

&lt;p&gt;This was a problem considering I in my infinite wisdom gave myself the challenge of producing my assets for the games I would be making within reason. So what to do?... what to do? This was the question that troubled me as I explored the rabbit hole of learning pixel art. Initially, I just stuck to my guns and continued learning about pixel art. And for my effort, I obtained these wonderful images as assets for my Flappy Bird game.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Background
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5uljpslqsokuiqhug8lf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5uljpslqsokuiqhug8lf.png" alt="background image" width="800" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Bird
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqdt3w94h6dtybp9eg3s0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqdt3w94h6dtybp9eg3s0.png" alt="the bird" width="208" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Pipe
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8n0pqtwei74agiym7jum.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8n0pqtwei74agiym7jum.png" alt="pipe" width="49" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🤔🤔🤔 Now I don't know about you but I was mighty pleased with my pipe image ... Though the bird and background left a lot to be desired.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;As I was coding forward and ignoring the funky visuals, I habitually opened the WhatsApp app on my phone and after getting annoyed by the new update that changed the layout of things, I noticed the new shiny blue button for conversing with the Meta AI bot.&lt;/p&gt;

&lt;p&gt;Like everyone, I was very aware of the current hype regarding AI tools like ChatGPT, and Github Copilot. I even remembered about the image generation models like Stable Diffusion. Though I personally never found much practical use with them, and hence ended up not using them all that much, Something about the Llama model being just there on my WhatsApp without me having to go to separate sites or download dodgy apps just compelled me to test it out.&lt;/p&gt;

&lt;p&gt;Initially, I just typed random messages and tried conversing with the bot. I quickly realized that was a dead end and gave up on that vector. I then learnt that it can also generate images which was great and so I gave it a prompt to test it out.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;/imagine&lt;/strong&gt; &lt;em&gt;an anime fight scene between superman and micky mouse&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To which I got.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcyjw8v77otmnnnvjiqve.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcyjw8v77otmnnnvjiqve.jpg" alt="meta ai" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At that moment, it clicked for me. Why don't I use this bot to generate my game assets? It obviously wouldn't be perfect but I was sure if I prompted it just right I should be able to get something reasonably decent.&lt;/p&gt;

&lt;p&gt;To test if my idea was feasible, I proudly asked the bot.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;/imagine a pixel sprite of a dog&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To which it fully complied and gave me the below image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F405i4blmhmrs0yvftxu2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F405i4blmhmrs0yvftxu2.jpg" alt="pixel dog 1" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;😅Yeah this one was on me. I should have seen it coming but I refused to give up and made a follow-up response.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use only 8 of color bits&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This finally gave me what I was looking for.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxm9hopntpzc69z4fdefa.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxm9hopntpzc69z4fdefa.jpg" alt="pixel dog 2" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After this point, there's not much more to tell really. I just went about prompting the bot and tweaking my responses to get images more aligned with what I wanted. I found this strategy worked great for big background scenes which was truly a sight to behold.&lt;/p&gt;

&lt;h3&gt;
  
  
  The New Background
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;/imagine an 8 bit image background showing clouds floating in the air and mountains down below... There's bright green grass with trees and flowers dotting the land scape&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn56l62psvle2qfcxy480.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn56l62psvle2qfcxy480.jpg" alt="new background 1" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;/imagine an 8 bit pixel image background of rolling hills&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flsppmgvnbbixro75r3kr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flsppmgvnbbixro75r3kr.jpg" alt="new background 2" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make the image so that it can be tilled in both left and right directions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwk31arjxnsnkwas96t91.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwk31arjxnsnkwas96t91.jpg" alt="new background 3" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last one is the image used in the game though I had to edit it a bit to remove the none nonexistent tree which was way easier than trying to draw this scene in any reasonable amount of time.&lt;/p&gt;

&lt;h3&gt;
  
  
  The New Bird
&lt;/h3&gt;

&lt;p&gt;Like the background, the bird was also relatively easy to make with only a few minor prompts here and there.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;/image an 8 bit image of a bird flying through a forest in a side scroller game&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhe43s67c7ecnxjohdkg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhe43s67c7ecnxjohdkg.jpg" alt="new bird 1" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;make the bird yellow&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvim5wchp5tofwtu7o6di.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvim5wchp5tofwtu7o6di.jpg" alt="new bird 2" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;make the bird more simplistic&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw848n0a4e7hj75zrahga.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw848n0a4e7hj75zrahga.jpg" alt="new bird 3" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;increase the pixel density&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5srpq4isn82momulnzk2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5srpq4isn82momulnzk2.jpg" alt="new bird 4" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The New Pipe
&lt;/h3&gt;

&lt;p&gt;Now for this one, I gotta be honest. It wasn't worth it. Sadly I realized belatedly that the model struggled quite a lot with creating the pipe which was likely caused by the dataset it learnt from and my use case probably falling on the fringes. In the spirit of completeness and sharing here are some of the responses I got.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;/image an 8 bit green pipe like in Mario with a forest background for a side scroller game&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiq1tv6ibthpn8gjz8xdc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiq1tv6ibthpn8gjz8xdc.jpg" alt="new pipe 1" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;/image an 8 bit green pipe shooting from the ground and sky with a forest background for a side scroller game&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn7415ym8j8xdxzigqm0x.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn7415ym8j8xdxzigqm0x.jpg" alt="new pipe 2" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This one was interesting in how it generated a watermark in front to hide the AI watermark 🤷‍♂️.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;simplify the pipe and remove the bends&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbw8x6v0igledpxs993f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbw8x6v0igledpxs993f.jpg" alt="new pipe 3" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;/image a green 8 bit vertical pipe in a side scroller game&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjl02ygyaax012iobefdd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjl02ygyaax012iobefdd.jpg" alt="new pipe 4" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anyways... these are a few of the responses I was getting and this back-and-forth went on for quite some time before I got the somewhat passable pipe I ended up using in the game.&lt;/p&gt;

&lt;p&gt;In all honesty, though I probably should have just used the one I made. It would have been quicker and more in line with what I had envisioned in my head.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Overall, I was quite impressed with how useful the Meta AI bot was in helping me create assets that are not only presentable but downright beautiful. Even when it failed to create what I had in mind, I still found myself in awe at the visuals it created.&lt;/p&gt;

&lt;p&gt;From a more utilitarian perspective though, the bot excels greatly at generating large background scenes and characters which gives some much-needed life to your game's visuals and I plan to continue using it for these use cases going forward. However, it must be noted that for much simpler objects like the pipe, it's probably best to just make those on your own.&lt;/p&gt;

</description>
      <category>whatsapp</category>
      <category>ai</category>
      <category>imagegeneration</category>
    </item>
    <item>
      <title>Achieving Success in Online Learning: A Practical Guide</title>
      <dc:creator>Gift Mugweni</dc:creator>
      <pubDate>Sat, 25 May 2024 18:43:09 +0000</pubDate>
      <link>https://dev.to/gift_mugweni_1c055b418706/achieving-success-in-online-learning-a-practical-guide-h86</link>
      <guid>https://dev.to/gift_mugweni_1c055b418706/achieving-success-in-online-learning-a-practical-guide-h86</guid>
      <description>&lt;p&gt;In my last article, I mentioned how I started my programming journey with the CS50 course. As luck would have it, in the process of going to their site so I could properly reference it, I learnt they introduced a &lt;a href="https://www.edx.org/cs50"&gt;bunch of new interesting courses&lt;/a&gt;. For me, my interest was piqued by the below courses&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.edx.org/learn/artificial-intelligence/harvard-university-cs50-s-introduction-to-artificial-intelligence-with-python?webview=false&amp;amp;campaign=CS50%27s+Introduction+to+Artificial+Intelligence+with+Python&amp;amp;source=edx&amp;amp;product_category=course&amp;amp;placement_url=https%3A%2F%2Fwww.edx.org%2Fcs50"&gt;CS50's Introduction to Artificial Intelligence with Python&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.edx.org/learn/game-development/harvard-university-cs50-s-introduction-to-game-development?webview=false&amp;amp;campaign=CS50%27s+Introduction+to+Game+Development&amp;amp;source=edx&amp;amp;product_category=course&amp;amp;placement_url=https%3A%2F%2Fwww.edx.org%2Fcs50"&gt;CS50's Introduction to Game Development&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.edx.org/learn/web-development/harvard-university-cs50-s-web-programming-with-python-and-javascript?webview=false&amp;amp;campaign=CS50%27s+Web+Programming+with+Python+and+JavaScript&amp;amp;source=edx&amp;amp;product_category=course&amp;amp;placement_url=https%3A%2F%2Fwww.edx.org%2Fcs50"&gt;CS50's Web Programming with Python and JavaScript&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although I know all the above subjects at a surface level, I thought it'd be interesting to dive deep into one of the topics and see what new stuff I could learn.&lt;/p&gt;

&lt;p&gt;Considering my current experience in programming, the courses I thought I'd learn the most from were the Game Programming and Artificial Intelligence courses. I also wasn't in the mood to learn Artificial Intelligence as I did two courses that dove deep into machine learning at university which gave me a good impression of what to expect from the course. Hence, intending to learn and have fun, I decided to do the Game Programming course.&lt;/p&gt;

&lt;p&gt;With the course decided upon, I tried determining what key things I wanted to ensure I obtained so I would approach it with the right frame of mind. For this, I considered my state of being and made the following observations.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I'll likely only be able to allocate an average of 1 to 2 hours per day to this course&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;My primary goal is entertainment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I don't need the certificate&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I'd like to be able to know how I can go about making my own unique exciting game that all my 3 users will fall in love with&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With my priorities set, I skimmed through the course to get an idea of what to expect, what I might like and what I might hate about the course. From this, I set the following constraints for myself.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I don't just want to copy the code exactly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Where I can, I should create my game assets (e.g. sounds, music, sprites) within reason.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Aside from this, I noticed the 2D game section was written using the &lt;a href="https://www.lua.org/"&gt;Lua programming language&lt;/a&gt;, and the 3D game section used the &lt;a href="https://unity.com/"&gt;Unity Game engine&lt;/a&gt;. Having played around with Lua for a bit, I realised I didn't like using it. There wasn't any rational reason for my dislike. It was mostly vibes but, considering one of my primary goals was entertainment, it was a real issue I had to resolve otherwise I'd likely drop the course as time went on.&lt;/p&gt;

&lt;p&gt;And so, I started looking into alternative tools I could use for making 2D games which would satisfy the fun factor for me. After endless Googling with a hint of Bing, Chat GPT,... and Bard, I learnt about these alternative tools I might enjoy more.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://unity.com/"&gt;Unity Game engine&lt;/a&gt; which uses C#&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.pygame.org/news"&gt;Pygame&lt;/a&gt; which uses Python&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://godotengine.org/"&gt;Godot&lt;/a&gt; which uses GDScript or C#&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://phaser.io/"&gt;Phasor&lt;/a&gt; which uses TypeScript or JavaScript&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pixijs.com/"&gt;PixiJS&lt;/a&gt; which uses TypeScript or JavaScript&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With my list present, it was time for the hard part, deciding what to use. From what I had seen from the initial course videos, the games were being built using a relatively low-level approach since they used &lt;a href="https://www.love2d.org/"&gt;Love2D&lt;/a&gt;. This meant things like physics, state machines, and event propagation were being built as we went and I got the impression that the only thing mostly abstracted was the rendering (showing stuff on the screen). This meant I'd need a tool that didn't hide too much stuff from me and allowed me to drown in complexity. This left me with Pygame and PixiJS since they were the most similar in functionality to Love2D as far as I could tell with the only difference being the language used.&lt;/p&gt;

&lt;p&gt;Of the remaining two tools, I did enjoy both so ..., I flipped a coin and ended up choosing PixiJS as my tool.&lt;/p&gt;

&lt;p&gt;With all this said, this is how I set myself up for potential success in tackling the course and I even went about finishing the first two lessons along the way. You can find the Flappy Bird game here &lt;a href="https://stelele.github.io/pixijs-flappy-bird/"&gt;(Fifty Bird (stelele.github.io))&lt;/a&gt; and here is the link to the repo &lt;a href="https://github.com/Stelele/pixijs-flappy-bird"&gt;(https://github.com/Stelele/pixijs-flappy-bird)&lt;/a&gt; though considering this is for fun, you're gonna need a keyboard to play it.&lt;/p&gt;

&lt;p&gt;Making the flappy bird was quite fun and in my next article, I look forward to explaining how I went about making it and preparing the assets for it.&lt;/p&gt;

</description>
      <category>onlinelearning</category>
      <category>gamedev</category>
      <category>planning</category>
    </item>
    <item>
      <title>How I Entered the World of Programming: A Personal History</title>
      <dc:creator>Gift Mugweni</dc:creator>
      <pubDate>Sat, 18 May 2024 20:54:05 +0000</pubDate>
      <link>https://dev.to/gift_mugweni_1c055b418706/how-i-entered-the-world-of-programming-a-personal-history-peh</link>
      <guid>https://dev.to/gift_mugweni_1c055b418706/how-i-entered-the-world-of-programming-a-personal-history-peh</guid>
      <description>&lt;p&gt;Games have always been a part of my life in some shape or form. Whether it be the Pokemon game I obsessively played on my GameBoy I got as a consolation prize for a would-be PSP, or the Tomb Raider disc a friend of mine and I broke by playing it so often that it shattered in the CD reader. As time passed, I played more games, which gave me many memorable firsts. &lt;a href="https://store.steampowered.com/app/489830/The_Elder_Scrolls_V_Skyrim_Special_Edition/"&gt;Elder Scrolls Skyrim&lt;/a&gt; made me realize the beauty of an open world that you can get lost in. &lt;a href="https://store.steampowered.com/app/8870/BioShock_Infinite/"&gt;BioShock Infinite&lt;/a&gt; is a story that I still contemplate today. &lt;a href="https://store.steampowered.com/app/48000/LIMBO/"&gt;Limbo&lt;/a&gt;, while seemingly simple, inspired awe in me at how so much can be said without any words ever being spoken. Finally, &lt;a href="https://store.steampowered.com/app/391540/Undertale/"&gt;Undertale&lt;/a&gt; gave me an interesting perspective on how I as a player might appear to the NPC characters.&lt;/p&gt;

&lt;p&gt;As time went on and I continued playing games, I found myself growing more and more curious about how they are made. How did those healing spells I spammed in Skyrim work under the hood? How can entire worlds exist in a laptop that fits on my lap? How did Flowey in Undertale mess with me so much? As these questions grew, I found myself naturally curious about this laptop, console, and phone that housed my entertainment. And so in 2014, I decided to learn about computers in high school. At the time, I never realized how much that choice would impact my future but looking back on it now, I'm surprised that I even considered not doing the course because I was afraid it'd be too hard.&lt;/p&gt;

&lt;p&gt;In high school, I had the preveladge of doing the &lt;a href="https://pll.harvard.edu/course/cs50-introduction-computer-science"&gt;CS50 course&lt;/a&gt; as our teacher at the time believed it would greatly benefit our future prospects and honestly, he was right. This one course introduced me to the field of Computer Science in a completely different way from the dry lifeless textbooks that were part of the curriculum. Through the course, I saw myself progress from struggling to print "Hello World" as we used the C programming language, to spending 2 weeks pulling late nights with my study mates trying to solve the &lt;a href="https://cs50.harvard.edu/x/2020/psets/1/mario/less/"&gt;pyramid problem&lt;/a&gt; (this was the first time I appreciated that (" ") was a real character). As time went on and I continued failing forward, I saw myself progress through the course material and learn deeper concepts like pointers, memory management, data structures, and at some point in that journey I was reading the JPEG documentation because one of the tasks in the assignment I had to do was recover deleted images from a supposedly erased storage device (Best assignment ever by the way .... took me a month to get it working somewhat though).&lt;/p&gt;

&lt;p&gt;From this course, and the expert guidance of my teacher, I got a taste of many computer science fields like low-level programming, game development, and web development which gave me a firm foundation when I later went on to study Electrical and Computer Engineering in university. It was a great program and I will always recommend it to anyone who wants to learn about Computer Science (It's free by the way).&lt;/p&gt;

&lt;p&gt;Now having shared all this, some may wonder if I am getting to any point of greater truth. The simple answer is no. I just wanted to share this story to express how strange and beautiful life can be. I never imagined that the Gift who was busy messing around with his Pokemon cartridge would later learn so much about computers and programming and even get the opportunity to create more programs that I believe help make life for a small group of people that much better. Granted, I'm not a professional game developer but, that was never really my intention. To me, games became a part of the greater body of computer science and became one of the many reasons I love this field. From those games, I learnt about computers. From computers, I learnt about the Internet. From the internet, I learnt about web development. And finally, from web development, I got to enjoy solving interesting and difficult problems at work. And to think my path in life would have been completely different if I had been afraid to take that 1 simple computer science course in high school. It made me wonder how often we leave the potential of a wonderful future because of our fear of our present-day reality. And so, I thought I'd share this post in turn so hopefully someone else might find the courage to take that first step on their journey. You never know where the road will take you.&lt;/p&gt;

&lt;p&gt;With this article. I've also decided to take my own advice and start this blog that I've been thinking of doing for over a year now. So, look forward to more completely unrelated posts or maybe they'll be related. I'm sure time will tell as they come out.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>motivation</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
