<?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>Forem: Bijan Boustani</title>
    <description>The latest articles on Forem by Bijan Boustani (@bijanbwb).</description>
    <link>https://forem.com/bijanbwb</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%2F223783%2F24a912ce-289f-4e65-b440-4f1c39725707.jpg</url>
      <title>Forem: Bijan Boustani</title>
      <link>https://forem.com/bijanbwb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bijanbwb"/>
    <language>en</language>
    <item>
      <title>Recreating Breakout for the Web</title>
      <dc:creator>Bijan Boustani</dc:creator>
      <pubDate>Mon, 23 Nov 2020 14:46:23 +0000</pubDate>
      <link>https://forem.com/bijanbwb/recreating-breakout-for-the-web-4c7f</link>
      <guid>https://forem.com/bijanbwb/recreating-breakout-for-the-web-4c7f</guid>
      <description>&lt;p&gt;Last time, we took a look at &lt;a href="https://dev.to/bijanbwb/recreating-pong-for-the-web-with-elm-2bi8"&gt;creating a web version of &lt;em&gt;Pong&lt;/em&gt;&lt;/a&gt;, the classic Atari game. Here is an animation of what we ended up with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi3b40bzjq77hf1hhg1by.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi3b40bzjq77hf1hhg1by.gif" alt="Pong Implementation" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pretty cool! It's a fun game to play, even after all these years. And it was even more fun &lt;strong&gt;figuring out all the little things that made &lt;em&gt;Pong&lt;/em&gt; so compelling&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this post, I'll share some of the steps I took to adapt the &lt;em&gt;Pong&lt;/em&gt; implementation into &lt;em&gt;Breakout&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Filz66klx0y73h2ajc447.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Filz66klx0y73h2ajc447.gif" alt="Breakout Implementation" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The original goal for these blog posts was to share step-by-step tutorials of how to recreate classic games. But &lt;strong&gt;the intent has evolved into sharing some interesting notes, ideas, and takeaways about the process of building these games&lt;/strong&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  ⏳ tl;dr
&lt;/h2&gt;

&lt;p&gt;In the last blog post, I buried the links to the playable demo and the source code all the way at the bottom of the post. It was my devious intention to force everyone to take hours of their precious time to scroll through my &lt;del&gt;shoddy&lt;/del&gt; writing. This time, I'll link to them here in case you want to try the game out before reading on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🕹 &lt;a href="https://bijanbwb.github.io/#/breakout" rel="noopener noreferrer"&gt;&lt;strong&gt;Playable Demo&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;a href="https://github.com/create-with/games/blob/master/assets/elm/src/Breakout.elm" rel="noopener noreferrer"&gt;&lt;strong&gt;Source Code on GitHub&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🛸 Why Breakout?
&lt;/h2&gt;

&lt;p&gt;After working on &lt;em&gt;Pong&lt;/em&gt; for a while, I was dying to move on to a different game genre. I've always wanted to learn how to create platform games like &lt;em&gt;Super Mario Bros.&lt;/em&gt; and adventure games like &lt;em&gt;The Legend of Zelda&lt;/em&gt;. But I decided to try &lt;em&gt;Breakout&lt;/em&gt; for a couple reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Breakout&lt;/em&gt; was my favorite Atari game. I grew up during the &lt;a href="https://en.wikipedia.org/wiki/History_of_video_games" rel="noopener noreferrer"&gt;Nintendo era of video game history&lt;/a&gt;, so the Atari 2600 console was a little before my time. &lt;strong&gt;But games like &lt;em&gt;Breakout&lt;/em&gt; felt timeless in their appeal&lt;/strong&gt;. I also remember being blown away by some sort of "fancy" &lt;em&gt;Breakout&lt;/em&gt; version in the arcade. I only recently found out that was a game called &lt;a href="https://en.wikipedia.org/wiki/Arkanoid" rel="noopener noreferrer"&gt;&lt;em&gt;Arkanoid&lt;/em&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I already had most of the core components of the game figured out like the ball, paddle, and game window. &lt;strong&gt;With the basic mechanics in place, I'd be able to focus on other fun features like particle effects, pixel art, animation, music, etc.)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🤔 What's Interesting About Breakout?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Breakout&lt;/em&gt; consists of similar elements we saw last time like a game window, a paddle, and a ball. While &lt;em&gt;Pong&lt;/em&gt; was meant as a two-player game, &lt;em&gt;Breakout&lt;/em&gt; could be played solo since the objective was to break through the rows of stationary bricks at the top of the screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5vuowpu46lnzzz7plmag.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5vuowpu46lnzzz7plmag.jpg" alt="Breakout Sketch" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Beyond the gameplay itself, &lt;em&gt;Breakout&lt;/em&gt; has an interesting history. &lt;strong&gt;Before &lt;a href="https://en.wikipedia.org/wiki/Steve_Jobs" rel="noopener noreferrer"&gt;Steve Jobs&lt;/a&gt; went on to found some company called Apple, he worked on &lt;em&gt;Breakout&lt;/em&gt; at Atari&lt;/strong&gt;. The story goes that he would invite his friend Steve Wozniak, who worked at Hewlett-Packard, to help him design and build the game. I find it fascinating to think that &lt;em&gt;Breakout&lt;/em&gt; had some influence on the design of the &lt;a href="https://en.wikipedia.org/wiki/Apple_II" rel="noopener noreferrer"&gt;Apple II&lt;/a&gt; computer, given its place in the history of computing.&lt;/p&gt;

&lt;p&gt;If you're interested in reading more about this, the &lt;a href="https://en.wikipedia.org/wiki/Breakout_(video_game)" rel="noopener noreferrer"&gt;Breakout Wikipedia entry&lt;/a&gt; is a great place to start. And there are some fun videos on YouTube like &lt;a href="https://www.youtube.com/watch?v=p5IaCTJdVuM&amp;amp;t" rel="noopener noreferrer"&gt;&lt;em&gt;Before Apple: Steve Jobs at Atari&lt;/em&gt;&lt;/a&gt; from Gaming Historian.&lt;/p&gt;

&lt;p&gt;But what's most interesting to me about Breakout is how &lt;strong&gt;we can layer features and "game feel" elements on top of the simple core mechanics&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤯 Game Feel and "Juice"
&lt;/h2&gt;

&lt;p&gt;When I started working on a &lt;em&gt;Breakout&lt;/em&gt; implementation, I knew I already had most of the features I needed for the game window and the paddle and the ball. You can see &lt;a href="https://dev.to/bijanbwb/recreating-pong-for-the-web-with-elm-2bi8"&gt;my previous blog post&lt;/a&gt; for an overview of how I implemented those features.&lt;/p&gt;

&lt;p&gt;I knew I'd have to figure out how to implement the rows of breakable bricks at the top of the screen, but &lt;strong&gt;one of the first things I wanted to do was add a "screen shake" feature&lt;/strong&gt;. When the ball hit one of the bricks, I wanted the window to shake to give the &lt;em&gt;feeling&lt;/em&gt; that it was an impactful collision.&lt;/p&gt;

&lt;p&gt;A screen shake is &lt;strong&gt;one of those features where you kind of don't notice it's there, but you can "feel" it when you play&lt;/strong&gt;. It's used commonly in games, but proved surprisingly hard to find for browser games.&lt;/p&gt;

&lt;p&gt;While looking for resources about how to accomplish this, I stumbled on this talk called &lt;a href="https://www.youtube.com/watch?v=AJdEqssNZ-U" rel="noopener noreferrer"&gt;&lt;em&gt;The Art of Screenshake&lt;/em&gt;&lt;/a&gt;, and I became fascinated by this idea of adding seemingly small details to a game that add up to a lot in terms of game feel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fut0h7y7cs62bzwyl7q0t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fut0h7y7cs62bzwyl7q0t.png" alt="The Art of Screenshake" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Just fill your game with love and tiny details."&lt;br&gt;
Jan Willem Nijman&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This guided a lot of the work I ended up putting into building &lt;em&gt;Breakout&lt;/em&gt;. In addition to the core game mechanics and a screen shake, I added things particle effects, pixel art, and music to make the game more fun and appealing.&lt;/p&gt;

&lt;p&gt;For more on the topic of Game Feel, there's also a great video from Game Maker's Toolkit called &lt;a href="https://www.youtube.com/watch?v=216_5nu4aVQ" rel="noopener noreferrer"&gt;&lt;em&gt;Secrets of Game Feel and Juice&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔄 Implementing a Screenshake
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;So how does a screenshake work?&lt;/strong&gt; Thankfully we're working with a simple 2D game (as opposed to 3D or VR), so we only need to worry about moving the game window and then putting it back to restore its original position.&lt;/p&gt;

&lt;p&gt;We start with our rectangular game window that's rendered with SVG. I've been working with the Elm programming language for these games, so I started with a type and set some initial values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;Window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;backgroundColor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;initialWindow&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Window&lt;/span&gt;
&lt;span class="n"&gt;initialWindow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;backgroundColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;black"&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;800.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;600.0&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;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; represent the top left position of the game window. What we need to do is shift the &lt;code&gt;x&lt;/code&gt; value to move the window left and right, and shift the &lt;code&gt;y&lt;/code&gt; value to move the window up and down.&lt;/p&gt;

&lt;p&gt;Then, after we shift the game window out of place, we restore its position back to the original position at &lt;code&gt;(0, 0)&lt;/code&gt;. Its kind of subtle if you don't know to look for it, but obvious once you see it. Here's what it looks like with the game elements in place so the window shake is visible:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frb8xlpldetyw1oyael12.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frb8xlpldetyw1oyael12.gif" alt="Screen Shake" width="1598" height="1196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you go &lt;a href="https://bijanbwb.github.io/#/breakout" rel="noopener noreferrer"&gt;play the game in the production environment&lt;/a&gt;, you can actually click anywhere in the game window to simulate the screen shake feature.&lt;/p&gt;

&lt;p&gt;I used a random number generator (which can be surprisingly hard to work with in Elm) so the screen shake didn't seem so predictable or jarring. And it does add a lot when the ball collides with a brick to trigger a screen shake.&lt;/p&gt;

&lt;p&gt;If you're interested in learning more about screen shakes and more involved implementations, there's an amazing series of talks from the Game Developer's Conference called &lt;em&gt;Math for Game Programmers&lt;/em&gt;. One of the talks is called &lt;a href="https://www.youtube.com/watch?v=tu-Qe66AvtY" rel="noopener noreferrer"&gt;&lt;em&gt;Juicing Your Cameras With Math&lt;/em&gt;&lt;/a&gt; and it's really fun to see the code you can use to implement your own amazing screen shake features.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎉 Particle Effects
&lt;/h2&gt;

&lt;p&gt;Next, I wanted to add some particle effects to the game. Particles are usually things like fireworks, explosions, smoke, etc. I already had the screen shake working, but &lt;strong&gt;I thought it would be cool to create an explosion of particles when the ball collided with a brick&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I can't take credit for how awesome this feature looks, because I used an existing Elm package that makes these kinds of particles easy to work with. &lt;a href="https://package.elm-lang.org/packages/BrianHicks/elm-particle/latest/" rel="noopener noreferrer"&gt;&lt;code&gt;elm-particle&lt;/code&gt;&lt;/a&gt; is a package from &lt;a href="https://github.com/BrianHicks" rel="noopener noreferrer"&gt;Brian Hicks&lt;/a&gt;, who not only organizes the yearly Elm conference called &lt;a href="https://elm-conf.com/" rel="noopener noreferrer"&gt;elm-conf&lt;/a&gt;, but is also the nicest person you'll ever meet.&lt;/p&gt;

&lt;p&gt;Here's an animation that shows what the particles look like during gameplay:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Filz66klx0y73h2ajc447.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Filz66klx0y73h2ajc447.gif" alt="Particles" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can tinker with all sorts of settings for the particles. I ended up spawning ten small particles from the top left of the ball whenever it collides with a brick. In addition to the position, you can also tinker with things like how gravity affects the particles, how quickly they move and rotate, and how long they last before going away.&lt;/p&gt;

&lt;p&gt;If you're interested in seeing more of the specifics of how the particle effects are implemented, check out the &lt;a href="https://github.com/create-with/games/blob/master/assets/elm/src/Breakout.elm" rel="noopener noreferrer"&gt;&lt;code&gt;Breakout.elm&lt;/code&gt; file&lt;/a&gt; in the source code. The &lt;code&gt;elm-particle&lt;/code&gt; package documentation also has some fun examples of how to use it for fun things like water and fireworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎨 Assets and Pixel Art
&lt;/h2&gt;

&lt;p&gt;For the &lt;em&gt;Pong&lt;/em&gt; game I worked on, all the elements of the game were just based on simple shapes. So SVG rectangles were sufficient to represent things like the game window and the paddles and the ball.&lt;/p&gt;

&lt;p&gt;But for &lt;em&gt;Breakout&lt;/em&gt;, &lt;strong&gt;I wanted to incorporate some pixel art assets into the game to make it look a little nicer&lt;/strong&gt;. I ended up using an iPad App called &lt;a href="https://apps.apple.com/gb/app/pixel-studio-for-pixel-art/id1404203859#?platform=ipad" rel="noopener noreferrer"&gt;Pixel Studio&lt;/a&gt; to create the assets, but you might also want to check out &lt;a href="https://www.aseprite.org/" rel="noopener noreferrer"&gt;Aseprite&lt;/a&gt; if you're interested in creating pixel art.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft8cg3n6afn7ykr15vvvi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft8cg3n6afn7ykr15vvvi.png" alt="Pixel Art Paddle" width="256" height="64"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So instead of using &lt;code&gt;Svg.rect&lt;/code&gt; to create a rectangle, I used &lt;code&gt;Svg.image&lt;/code&gt; and linked to &lt;a href="https://github.com/create-with/games/tree/master/assets/static/images" rel="noopener noreferrer"&gt;the static assets in the repository&lt;/a&gt;. The &lt;code&gt;viewBall&lt;/code&gt; and &lt;code&gt;viewPaddle&lt;/code&gt; functions use familiar attributes for the size and position, and also use the &lt;code&gt;xlinkHref&lt;/code&gt; attribute to pull in the pixel art images.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;viewBall&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ball&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
&lt;span class="n"&gt;viewBall&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xlinkHref&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/images/pixel-ball.png"&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;Util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getX&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;Util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getY&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;viewPaddle&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Paddle&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
&lt;span class="n"&gt;viewPaddle&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xlinkHref&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/images/pixel-paddle.png"&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;Util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getX&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;Util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getY&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&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;Mozilla's Developer Network (MDN) is great for looking up how to work with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG" rel="noopener noreferrer"&gt;SVG elements and attributes&lt;/a&gt;. And then it's just a matter of translating it into Elm using the &lt;a href="https://package.elm-lang.org/packages/elm/svg/latest" rel="noopener noreferrer"&gt;&lt;code&gt;elm/svg&lt;/code&gt; package&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎮 Updating the Game Platform
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;I ended up spending some time creating a new back-end for this project as well&lt;/strong&gt;. I had originally built &lt;em&gt;Pong&lt;/em&gt; and used a tool called &lt;a href="https://parceljs.org/" rel="noopener noreferrer"&gt;Parcel&lt;/a&gt; to bundle the project. But I ended up running into trouble as soon as I started working with static assets, so I replaced it with the &lt;a href="https://www.phoenixframework.org/" rel="noopener noreferrer"&gt;Phoenix Framework&lt;/a&gt;, which is way more familiar to me.&lt;/p&gt;

&lt;p&gt;It may be overkill to use Phoenix to serve a couple of small image files, but it also gives me some freedom to add back-end features like tracking scores as I build more games. I've also been playing with Phoenix's LiveView capability and love working with it:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1296919592237969409-622" src="https://platform.twitter.com/embed/Tweet.html?id=1296919592237969409"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1296919592237969409-622');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1296919592237969409&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Given that I was going from one game to multiple games, I wanted to add an index page to serve as a game selection screen. I also added some simple routing features to navigate between the different games. And I imported the &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt; framework to start with a simple design and add a footer area with some helpful links.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgabatg0ilu9ilz31tvmx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgabatg0ilu9ilz31tvmx.png" alt="Game Platform" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🎼 Music
&lt;/h2&gt;

&lt;p&gt;For &lt;em&gt;Pong&lt;/em&gt;, I had a couple of files called &lt;code&gt;beep.wav&lt;/code&gt; and &lt;code&gt;boop.wav&lt;/code&gt; that I was using for simple sound effects. I left those out of &lt;em&gt;Breakout&lt;/em&gt;, but I wanted to add some background music.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1131530464727064577-989" src="https://platform.twitter.com/embed/Tweet.html?id=1131530464727064577"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1131530464727064577-989');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1131530464727064577&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;In the past, I had tinkered with creating some custom "chiptune" style music using programs like &lt;a href="https://www.lexaloffle.com/pico-8.php" rel="noopener noreferrer"&gt;PICO-8&lt;/a&gt; and &lt;a href="https://boscaceoil.net" rel="noopener noreferrer"&gt;Bosca Ceoil&lt;/a&gt;. They can be fun to play with, but my &lt;em&gt;Breakout&lt;/em&gt; implementation was already getting complicated enough, so I tried finding existing music online.&lt;/p&gt;

&lt;p&gt;After Googling a bit, I came across &lt;a href="https://playonloop.com" rel="noopener noreferrer"&gt;PlayOnLoop.com&lt;/a&gt; and found a royalty-free, upbeat song I liked and created a new &lt;a href="https://github.com/create-with/games/blob/master/CREDITS.md" rel="noopener noreferrer"&gt;&lt;code&gt;CREDITS.md&lt;/code&gt; file&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To play the music, I use the &lt;a href="https://howlerjs.com/" rel="noopener noreferrer"&gt;howler.js&lt;/a&gt; JavaScript library. It required using &lt;a href="https://guide.elm-lang.org/interop/ports.html" rel="noopener noreferrer"&gt;Elm ports&lt;/a&gt; to sync up the JavaScript and Elm code, but howler.js has some great features that I'll likely continue to use as I create more games. &lt;/p&gt;

&lt;h2&gt;
  
  
  🧱 Implementing the Bricks (Finally)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcpq9242dl4zmjy9btuua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcpq9242dl4zmjy9btuua.png" alt="Bricks" width="800" height="601"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The rows of breakable bricks at the top of the screen were the most important feature&lt;/strong&gt;, so naturally I procrastinated on implementing them.&lt;/p&gt;

&lt;p&gt;Somewhere in the commit history on GitHub, there was a range of commits where I used various combinations of several data structures (&lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Dict&lt;/code&gt;, &lt;code&gt;Array&lt;/code&gt;) in hopes of finding something that felt right to work with. I won't bore you with the details, but I can at least share how some of the fun parts work.&lt;/p&gt;

&lt;h3&gt;
  
  
  🏗 Individual Bricks
&lt;/h3&gt;

&lt;p&gt;This is what the fields look like for the &lt;code&gt;Brick&lt;/code&gt; type along with the data for a default brick:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;Brick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hitCount&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hitThreshold&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Vector&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strokeColor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;defaultBrick&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Brick&lt;/span&gt;
&lt;span class="n"&gt;defaultBrick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;white"&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hitCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hitThreshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strokeColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;black"&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One of the first things that might stand out is the &lt;code&gt;position&lt;/code&gt;. For &lt;em&gt;Pong&lt;/em&gt;, I was using separate &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; fields to store &lt;code&gt;Float&lt;/code&gt; values. But I've been working towards learning Linear Algebra a little better for the next games that I plan to work on.&lt;/p&gt;

&lt;p&gt;For &lt;em&gt;Breakout&lt;/em&gt;, I used a custom &lt;code&gt;Vector&lt;/code&gt; type, but for the next games I work with I'll likely use the &lt;a href="https://package.elm-lang.org/packages/elm-explorations/linear-algebra/latest/Math-Vector2" rel="noopener noreferrer"&gt;&lt;code&gt;elm-explorations/linear-algebra&lt;/code&gt;&lt;/a&gt; package. Khan Academy also has great lessons on &lt;a href="https://www.khanacademy.org/math/linear-algebra" rel="noopener noreferrer"&gt;Linear Algebra&lt;/a&gt; if you're looking to learn more.&lt;/p&gt;

&lt;p&gt;The other thing you might have noticed is that I added &lt;code&gt;hitCount&lt;/code&gt; and &lt;code&gt;hitThreshold&lt;/code&gt; fields. This allows for setting some breaks as "hard" bricks that take multiple hits to break.&lt;/p&gt;

&lt;h3&gt;
  
  
  🤔 Data Structures
&lt;/h3&gt;

&lt;p&gt;After some initial thrashing about which data structure to use, I settled on using a Dictionary because it would allow for identifying bricks by their row and column. In this type alias, we create a &lt;code&gt;Dict&lt;/code&gt; of bricks where the two &lt;code&gt;Int&lt;/code&gt; types represent the row number and column number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;Bricks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Dict&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;Brick&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The implementation for the bricks may have ended up somewhat complicated, and it's possible a normal &lt;code&gt;List&lt;/code&gt; would have sufficed. But I knew I wanted to adjust things like the &lt;code&gt;hitCount&lt;/code&gt; and &lt;code&gt;color&lt;/code&gt; for specific rows or bricks, and using a &lt;code&gt;Dict&lt;/code&gt; made that a little easier.&lt;/p&gt;

&lt;p&gt;Here are some of the important functions I used for constructing the rows of bricks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;buildRow&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bricks&lt;/span&gt;
&lt;span class="n"&gt;buildRow&lt;/span&gt; &lt;span class="n"&gt;rowNumber&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="n"&gt;strokeColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foldr&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;insertBrick&lt;/span&gt; &lt;span class="n"&gt;rowNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;Dict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;setRowColors&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="n"&gt;strokeColor&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;setRowPosition&lt;/span&gt;


&lt;span class="n"&gt;insertBrick&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Bricks&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bricks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;insertBrick&lt;/span&gt; &lt;span class="n"&gt;rowNumber&lt;/span&gt; &lt;span class="n"&gt;columnNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Dict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;rowNumber&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;columnNumber&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;defaultBrick&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm glossing over the details, but definitely check out the &lt;a href="https://github.com/create-with/games/blob/master/assets/elm/src/Breakout/Brick.elm" rel="noopener noreferrer"&gt;&lt;code&gt;Breakout.Brick&lt;/code&gt; module&lt;/a&gt; if you want to see how it all comes together.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎨 Styles and Animation
&lt;/h3&gt;

&lt;p&gt;For the brick colors, I used the &lt;a href="https://tailwindcss.com/docs/background-color" rel="noopener noreferrer"&gt;color palette from Tailwind CSS&lt;/a&gt; and looked up the corresponding hex values to create a &lt;a href="https://en.wikipedia.org/wiki/ROYGBIV" rel="noopener noreferrer"&gt;"ROYGBIV"&lt;/a&gt; rainbow for the rows.&lt;/p&gt;

&lt;p&gt;The "hard" row of bricks at the top takes multiple hits to break. So it has a different stroke color as a visual indicator that there's something different about those bricks, even if it's not obvious until the ball hits them.&lt;/p&gt;

&lt;p&gt;Another cool feature that isn't obvious is that the opacity of each brick is calculated as the percentage of hits remaining to break the brick. In other words, if we made a brick that took ten hits to break, the brick would start out opaque and subtract 10% of its opacity after each hit. If we were to create new levels, this would be a great feature to consider.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpfgb1h8vrw57h1uymbem.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpfgb1h8vrw57h1uymbem.gif" alt="Brick Animation" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One of the most fun features to add was the drop-in animation for the bricks&lt;/strong&gt; when the game first loads. The &lt;a href="https://animate.style" rel="noopener noreferrer"&gt;Animate.css&lt;/a&gt; library has tons of amazing examples for this kind of thing.&lt;/p&gt;

&lt;p&gt;I used those examples to create a "bounceInDown" animation that you can find in the &lt;a href="https://github.com/create-with/games/blob/master/assets/css/animations.scss" rel="noopener noreferrer"&gt;&lt;code&gt;assets/css/animations.scss&lt;/code&gt; file&lt;/a&gt;. Then, in the Elm code, I added that &lt;code&gt;bounce-in-down&lt;/code&gt; class to the bricks to get the animation working.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✨ Wishlist
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It's amazing how many cool features you can add to a small game like &lt;em&gt;Breakout&lt;/em&gt;&lt;/strong&gt;. But I wanted to find a good stopping point and move on to a new game. One of the big takeaways from this project was how distracted I can get while trying to finish something. I actually finished writing the code for the game months before I was able to publish this blog post.&lt;/p&gt;

&lt;p&gt;But there are some known bugs and wishlist items that would be great to add to the game:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create Multiple Levels&lt;/li&gt;
&lt;li&gt;Improve Collisions&lt;/li&gt;
&lt;li&gt;Add Sound Effects&lt;/li&gt;
&lt;li&gt;Incorporate Randomness&lt;/li&gt;
&lt;li&gt;Save High Scores&lt;/li&gt;
&lt;li&gt;Expand Particle Effects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're looking for inspiration and more features to think about, here are some other great places to look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Arkanoid" rel="noopener noreferrer"&gt;Arkanoid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/playlist?list=PLea8cjCua_P0qjjiG8G5FBgqwpqMU7rBk" rel="noopener noreferrer"&gt;LazyDevs PICO-8 Breakout&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  📈 What's Next?
&lt;/h2&gt;

&lt;p&gt;I've been having fun building a little arcade cabinet lately. At some point, I'd love to see one of the games I build running on it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flxmnrrczipihu1ewpt5p.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flxmnrrczipihu1ewpt5p.jpg" alt="Arcade Cabinet Front" width="800" height="1066"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5gwobppi020e1rl4xq5s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5gwobppi020e1rl4xq5s.jpg" alt="Arcade Cabinet Rear" width="800" height="1066"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've also loved getting to explore things like WebGL and Unity recently. But the next game I'm going to focus on building is the classic game &lt;a href="https://en.wikipedia.org/wiki/Adventure_(1980_video_game)" rel="noopener noreferrer"&gt;&lt;em&gt;Adventure&lt;/em&gt;&lt;/a&gt;. And my plan is to &lt;em&gt;hopefully&lt;/em&gt; incorporate both 2D &lt;em&gt;and&lt;/em&gt; 3D features if I can get it all figured out.&lt;/p&gt;

&lt;p&gt;If you're learning functional programming and game development, feel free to &lt;a href="https://bijanbwb.github.io" rel="noopener noreferrer"&gt;get in touch with me&lt;/a&gt; and I'd be happy to hear from you. You can also &lt;a href="https://twitter.com/bijanbwb" rel="noopener noreferrer"&gt;find me on Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And here are links to the game and the source code!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🕹 &lt;a href="https://bijanbwb.github.io/#/breakout" rel="noopener noreferrer"&gt;&lt;strong&gt;Play the Game!&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;a href="https://github.com/create-with/games" rel="noopener noreferrer"&gt;&lt;strong&gt;View the Source Code on GitHub&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>elm</category>
      <category>functional</category>
      <category>elixir</category>
    </item>
    <item>
      <title>Recreating Pong for the Web with Elm</title>
      <dc:creator>Bijan Boustani</dc:creator>
      <pubDate>Mon, 20 Apr 2020 14:02:55 +0000</pubDate>
      <link>https://forem.com/bijanbwb/recreating-pong-for-the-web-with-elm-2bi8</link>
      <guid>https://forem.com/bijanbwb/recreating-pong-for-the-web-with-elm-2bi8</guid>
      <description>&lt;p&gt;Let's take a tour of the process for creating a web version of the classic Atari game, &lt;em&gt;Pong&lt;/em&gt;! In case you missed it, here is the &lt;a href="https://dev.to/bijanbwb/recreating-classic-games-for-the-web-series-intro-4pm7"&gt;introductory post for this series&lt;/a&gt;. &lt;strong&gt;The goal is to rebuild classic interactive games and learn a little bit along the way&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🏓 Pong
&lt;/h2&gt;

&lt;p&gt;Before we dive in, let's set the context for what &lt;em&gt;Pong&lt;/em&gt; looks like.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffyto190ar8h4rqg7x9ql.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffyto190ar8h4rqg7x9ql.jpg" alt="Pong Sketch" width="800" height="625"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pong&lt;/em&gt; is an abstract representation of table tennis, consisting of these basic shapes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;ball&lt;/strong&gt; that moves and bounces around the screen&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;left paddle&lt;/strong&gt; that moves up and down, controlled by the player&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;right paddle&lt;/strong&gt; that moves up and down, controlled by the computer&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;score&lt;/strong&gt; indicator for each paddle&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;window&lt;/strong&gt; rectangle with a black background and a "net" in the middle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There have been many versions of &lt;em&gt;Pong&lt;/em&gt; released over the years, but we'll use these elements as a model for our version. But let's start with some fun history.&lt;/p&gt;

&lt;h2&gt;
  
  
  📖 History
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk71jg3s8w7tqfuf4ne3o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk71jg3s8w7tqfuf4ne3o.png" alt="Pong Marketing Material" width="800" height="1040"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the fascinating things about &lt;em&gt;Pong&lt;/em&gt; is that it was released in the early 1970s to a public that had little context for the idea of a digital video game.&lt;/p&gt;

&lt;p&gt;Atari would need to "productize" arcade games at a time when coin-operated pinball games were probably the closest corollary.&lt;/p&gt;

&lt;p&gt;Games like &lt;a href="https://en.wikipedia.org/wiki/Spacewar!" rel="noopener noreferrer"&gt;&lt;em&gt;Spacewar!&lt;/em&gt;&lt;/a&gt; predate the release of &lt;em&gt;Pong&lt;/em&gt; by a decade, but they were only available to academics and too complicated for the public. &lt;strong&gt;So Atari would have to use skills from several disciplines like engineering, design, and entrepreneurship to create something accessible&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The result was the game cabinet pictured in the marketing material above. And below we can see how straightforward they made the instructions and affordances.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyguk5hwqkdle784idxjr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyguk5hwqkdle784idxjr.jpg" alt="Pong Arcade Cabinet UI" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our version, we'll use the arrow keys on a keyboard to control the paddles. But it's easy to see how people could take to the simple controls on the cabinet.&lt;/p&gt;

&lt;p&gt;The story goes that Atari put their prototype in a local bar named &lt;em&gt;Andy Capp's Tavern&lt;/em&gt; in the heart of Silicon Valley. And the machine was so popular that it would overflow with quarters.&lt;/p&gt;

&lt;p&gt;As I was doing "research" for this project, I bought an &lt;a href="https://en.wikipedia.org/wiki/Atari_2600" rel="noopener noreferrer"&gt;Atari 2600&lt;/a&gt; emulator called &lt;em&gt;RetroN 77&lt;/em&gt; thinking it would be a good way to simulate the original. But it turns out &lt;em&gt;Pong&lt;/em&gt; may have been considered passé by the time the Atari 2600 was released. After the arcade cabinet, there was a dedicated &lt;a href="https://en.wikipedia.org/wiki/Pong#Home_version" rel="noopener noreferrer"&gt;home console version&lt;/a&gt; that predated the cartridge-based Atari 2600.&lt;/p&gt;

&lt;p&gt;The emulator was still fun to share with my daughter:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpjzqjdr1ntrw7fdmr2zz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpjzqjdr1ntrw7fdmr2zz.jpg" alt="Playing the Atari 2600 Emulator" width="800" height="1067"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Due to its cultural relevance, &lt;em&gt;Pong&lt;/em&gt; is even part of the Smithsonian museum. If you're interested in learning more about the history, the &lt;a href="https://en.wikipedia.org/wiki/Pong" rel="noopener noreferrer"&gt;&lt;em&gt;Pong&lt;/em&gt; Wikipedia page&lt;/a&gt; is a good place to start. And there's a fun documentary called &lt;a href="http://www.worldoneonemovie.com/" rel="noopener noreferrer"&gt;&lt;em&gt;World 1-1&lt;/em&gt;&lt;/a&gt; you might like too.&lt;/p&gt;

&lt;h2&gt;
  
  
  🕹 Rebuilding Pong for the Web
&lt;/h2&gt;

&lt;p&gt;My original intention for this series was to rebuild classic games, and then post step-by-step walkthroughs of how to do the same.&lt;/p&gt;

&lt;p&gt;After taking the time to work out the mechanics of &lt;em&gt;Pong&lt;/em&gt;, I realized that approach would be exhausting to read 😅. It would take a whole course to do justice to the content. So this post will be a tour of the process and the interesting bits, and I'll share all the source code on GitHub at the end.&lt;/p&gt;

&lt;p&gt;Plus, I'm still learning game development, and I don't want to steer you in the wrong direction. I'll try to stick with clear explanations in plain terms without relying on jargon that can be scary when you're first getting started.&lt;/p&gt;

&lt;p&gt;My goal is still to create faithful reproductions of these classic games. So I worked hard to figure out what made &lt;em&gt;Pong&lt;/em&gt; so fun to play. But I'll also add little features and interesting bits where it makes sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 Why Pong is Perfect
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It turns out &lt;em&gt;Pong&lt;/em&gt; is a perfect place to get started with game development&lt;/strong&gt;. Like most software projects, the first 90% is straightforward. And then the last 10% that makes &lt;em&gt;all&lt;/em&gt; the difference.&lt;/p&gt;

&lt;h3&gt;
  
  
  👏 Simple But Amazing
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnflq032yrtm5az5jut3j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnflq032yrtm5az5jut3j.jpg" alt="Pong Elements with Labels" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can start by sketching all the elements that make up &lt;em&gt;Pong&lt;/em&gt; to get an idea of what we want to put on the screen. It involves all the basics, and has everything you need to make for a surprisingly fun game:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rules:&lt;/strong&gt; Clear rules for controlling paddles and scoring make the game accessible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Game Loop:&lt;/strong&gt; A loop allows us to continuously:

&lt;ul&gt;
&lt;li&gt;listen for input&lt;/li&gt;
&lt;li&gt;adjust objects over time&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Input Handling:&lt;/strong&gt; We'll use the keyboard to handle player input and move the left paddle.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Competition:&lt;/strong&gt; Player scoring adds some fun and a win state.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Rendering:&lt;/strong&gt; We'll use SVG to create a game window and render all the elements.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Game States:&lt;/strong&gt; We'll transition between different states:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;StartingScreen&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PlayingScreen&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EndingScreen&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;AI:&lt;/strong&gt; We'll simulate simple AI for the computer-controlled right paddle.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Basic Physics:&lt;/strong&gt; We'll use basic physics to keep the ball and paddles moving with position and velocity.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Collisions:&lt;/strong&gt; When the ball collides with a paddle or the edge of the screen, we can handle the collisions and responding accordingly.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Assets:&lt;/strong&gt; Most games will incorporate external assets like sprites and sounds. We won't need any sprites since we're using simple SVG shapes. But we'll use an external sound library to incorporate simple sound effects.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Some of these can be tricky for those of us with a background in web development. When we're building web applications, our app is doing nothing most of the time. We occasionally need to load a new page or make a request to the database, but for the most part the content is static. Even now, you're reading this post but all the hard work of loading the text on the page is already done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With game development, there is a constant stream of activity&lt;/strong&gt;. We use a game loop to handle input from players. And, even when there's no input, we still move objects around the screen over time.&lt;/p&gt;

&lt;p&gt;When I started learning some of these concepts, I was scared off by terms like "delta time" and "velocity" and "vector." And it's understandable if you feel that way too. It can also get confusing to think about the coordinates and which way is up and down.&lt;/p&gt;

&lt;p&gt;One helpful technique is to think of words you're more comfortable with. For instance, you could think of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;horizontalPosition&lt;/code&gt; instead of an &lt;code&gt;x&lt;/code&gt; position&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;verticalSpeed&lt;/code&gt; instead of &lt;code&gt;vy&lt;/code&gt; velocity&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;changeInTime&lt;/code&gt; instead of &lt;code&gt;deltaTime&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once we get a working mental model, we can work towards using common terms and find out why they're more fitting.&lt;/p&gt;

&lt;h3&gt;
  
  
  💊 Deeper Levels
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;After getting the basic game elements worked out, it turns out there's a much deeper level to games&lt;/strong&gt;. Beyond getting things to show up on the screen and move around, we can start to take an interest in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Game Design:&lt;/strong&gt; The major takeaway from this project is how little changes can make a big difference in game-play. The game elements mentioned above will get things up and running. Then, you can tinker with all kinds of little settings like ball speed and angles and scoring to make it fun.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk and Reward:&lt;/strong&gt; Hitting the ball closer to the edge of your paddle is a "risky" move, because you're more likely to miss it. A "safe" approach would be to hit the ball with the center of the paddle. But we can change the ball angle coming off the paddle, so your risky move turns into reward because the other paddle will have a much more difficult time returning it. &lt;strong&gt;Without this, &lt;em&gt;Pong&lt;/em&gt; turns out to be surprisingly boring and predictable&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed:&lt;/strong&gt; We can start by tinkering to set a fast ball speed that's fun to play, but not so fast that it's too difficult. But we also speed up the ball slightly every time it hits a paddle. The result is a feeling that the game speed increases with volleys and adds much more fun to the game.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Randomness:&lt;/strong&gt; We start with a simple serve from the same location and in the same direction. Then, we can add randomness to the ball location and direction so you have to keep paying attention and build your skills to consistently return the serve.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fairness:&lt;/strong&gt; It turns out some changes will feel unfair. Between the ball speed and the randomness, the serves can feel unfair and it gets too easy to get scored on. And without capping the ball speed to an upper bound, it starts to feel unfair if a successful return is impossible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Playtesting and Tinkering:&lt;/strong&gt; I didn't know all this before building the game. &lt;strong&gt;It was a long process of adding features and playing the game to see the (often unintended) consequences&lt;/strong&gt;. Tinkering with the values can lead to a lot of fun and interesting ideas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aesthetics and UI:&lt;/strong&gt; I spent some time trying to recreate the feel of the arcade cabinet. I ended up throwing out some of the work, but adding a little color and polish adds a lot to the experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning and Skill Development:&lt;/strong&gt; &lt;strong&gt;Games can be so compelling because we're learning as we play&lt;/strong&gt;. We're wired to recognize patterns, and it's fun to feel the sense of improvement and progress as we get better. There's a book called &lt;a href="https://www.theoryoffun.com/" rel="noopener noreferrer"&gt;&lt;em&gt;A Theory of Fun for Game Design&lt;/em&gt;&lt;/a&gt; you might like if you're interested in reading more about this topic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🌳 Working with Elm
&lt;/h2&gt;

&lt;p&gt;If you haven't worked with the Elm programming language before, &lt;a href="https://guide.elm-lang.org/" rel="noopener noreferrer"&gt;&lt;em&gt;An Introduction to Elm&lt;/em&gt;&lt;/a&gt; is a good place to get started. It's a short book, and the examples give you everything you need to start building front-end web applications with Elm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://guide.elm-lang.org/architecture/" rel="noopener noreferrer"&gt;The Elm Architecture&lt;/a&gt; is also well-suited for building games too. At a glance, you can see the similar pattern between The Elm Architecture functions (&lt;code&gt;init&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;view&lt;/code&gt;) and a simple game development platform like &lt;a href="https://www.lexaloffle.com/pico-8.php" rel="noopener noreferrer"&gt;PICO-8&lt;/a&gt; (&lt;code&gt;init&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;draw&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Furhpdsyhpjhzsyg2yvkf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Furhpdsyhpjhzsyg2yvkf.png" alt="The Elm Archtecture" width="800" height="885"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fl0n7lmb91nt74j034rdo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fl0n7lmb91nt74j034rdo.png" alt="PICO-8" width="800" height="830"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;init&lt;/code&gt;: We can &lt;strong&gt;model our game using types&lt;/strong&gt; and &lt;strong&gt;provide initial values&lt;/strong&gt;. For example, where should the ball and paddles be located when we start the game?&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;update&lt;/code&gt;: This allows us to continuously change the model values over time. We'll update player scores, move the ball, and transition between game states. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;view&lt;/code&gt;: This will continuously draw the updated model on the screen using SVG.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll dive into Elm code throughout the rest of this post. But if you don't know Elm yet, feel free to skim through the content to see the process. And hopefully it will inspire you to go learn more about Elm and functional programming!&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 Modeling the Game Components
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When you're coming up with an initial version of the data model, it doesn't have to be perfect&lt;/strong&gt;. We can start with a handful of elements we know we'll need. Then we can pull those into the &lt;code&gt;view&lt;/code&gt; function so we have something to look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Window&lt;/li&gt;
&lt;li&gt;Ball&lt;/li&gt;
&lt;li&gt;Left Paddle&lt;/li&gt;
&lt;li&gt;Right Paddle&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⬛️ Window
&lt;/h3&gt;

&lt;p&gt;Here is a &lt;code&gt;Window&lt;/code&gt; type alias we can use to create a SVG rectangle element that will hold the game. Keep in mind that SVG uses the top left as the starting point. When we start with &lt;code&gt;0&lt;/code&gt; values for &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; we're starting at the top left.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As the &lt;code&gt;x&lt;/code&gt; value increases, we move right ➡️&lt;/li&gt;
&lt;li&gt;As the &lt;code&gt;y&lt;/code&gt; value increases, we move down ⬇️&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using values for &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, &lt;code&gt;height&lt;/code&gt;, and &lt;code&gt;width&lt;/code&gt; we can draw the rectangle for our game window.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fubf8l6f0jd8ho21pn29l.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fubf8l6f0jd8ho21pn29l.jpg" alt="SVG Rectangle Sketch" width="800" height="606"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;Window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;backgroundColor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we'll set some initial values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;initialWindow&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Window&lt;/span&gt;
&lt;span class="n"&gt;initialWindow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;backgroundColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;black"&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;800.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;600.0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These values will correspond to an SVG &lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/rect" rel="noopener noreferrer"&gt;rect&lt;/a&gt; element, and Elm has an &lt;a href="https://package.elm-lang.org/packages/elm/svg/latest/Svg" rel="noopener noreferrer"&gt;Svg package&lt;/a&gt; that contains all the same elements and attributes we'll need.&lt;/p&gt;

&lt;p&gt;Here is the corresponding view function that calls &lt;code&gt;Svg.rect&lt;/code&gt;. We can pass our &lt;code&gt;initialWindow&lt;/code&gt; into this function and it produces the rectangle we need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;viewGameWindow&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Window&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Svg&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
&lt;span class="n"&gt;viewGameWindow&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rect&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backgroundColor&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&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;And we can even add another view function for the "net" in the middle of the screen. Some Googling turned up this &lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray" rel="noopener noreferrer"&gt;stroke-dasharray&lt;/a&gt; doc from MDN, which worked well for placing a dashed line in the middle of the game window.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;viewNet&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Window&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
&lt;span class="n"&gt;viewNet&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stroke&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;white"&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strokeDasharray&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;14, 14"&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strokeWidth&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4"&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y2&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&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;&lt;strong&gt;It's not much to look at so far, but it works!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F69ojaaszi9bznijvl1si.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F69ojaaszi9bznijvl1si.png" alt="Game Window Rectangle" width="800" height="693"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🎾 Ball
&lt;/h3&gt;

&lt;p&gt;The ball is like the window because we're still using &lt;code&gt;Svg.rect&lt;/code&gt;, but in this case it'll be much smaller. We add a &lt;code&gt;vx&lt;/code&gt; and &lt;code&gt;vy&lt;/code&gt; that we'll use to indicate the horizontal and vertical velocity. We could just push the position of the ball around over time using &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;. But these velocity values allow us to do things like change the speed and negate the values to get the ball moving the other way when it strikes a paddle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;Ball&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vx&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here are the initial values I ended up with for the &lt;code&gt;initialBall&lt;/code&gt;. It was basically a matter of tinkering until it was somewhere near the middle of the screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;initialBall&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ball&lt;/span&gt;
&lt;span class="n"&gt;initialBall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;white"&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;395.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;310.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;350.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;350.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also could have represented the same data with a &lt;code&gt;position&lt;/code&gt; value to hold the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt;. And a &lt;code&gt;velocity&lt;/code&gt; to hold the &lt;code&gt;vx&lt;/code&gt; and &lt;code&gt;vy&lt;/code&gt;. For this first game, I wanted to stick with a "flat" model that didn't involve any nesting so that updating values would be easy. But I'll likely change that approach in the next game I build.&lt;/p&gt;

&lt;p&gt;I should also mention that I used &lt;code&gt;Int&lt;/code&gt; values when I started. I later switched to using &lt;code&gt;Float&lt;/code&gt; values to avoid having to perform conversions and round the integers. I'm not sure, but I think the precision of &lt;code&gt;Float&lt;/code&gt; values also makes the animation look a little smoother too.&lt;/p&gt;

&lt;p&gt;And here's the view function to render the ball on the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;viewBall&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ball&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
&lt;span class="n"&gt;viewBall&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rect&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&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;
  
  
  🏓 Paddles
&lt;/h3&gt;

&lt;p&gt;The paddles are rectangles like the window and ball. Both paddles have the same fields, but we can add a &lt;code&gt;PaddleId&lt;/code&gt; type to differentiate between them.&lt;/p&gt;

&lt;p&gt;We add a &lt;code&gt;score&lt;/code&gt; for each paddle that we can increment. Also note that we only need a &lt;code&gt;vy&lt;/code&gt; for the vertical speed since the paddle doesn't need to move horizontally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;PaddleId&lt;/span&gt;
    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Left&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;Right&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;Paddle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;PaddleId&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we can set initial values to locate the paddles near the left and right edges of the game window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;initialLeftPaddle&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Paddle&lt;/span&gt;
&lt;span class="n"&gt;initialLeftPaddle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lightblue"&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Left&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;48.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;200.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;600.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;60.0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;initialRightPaddle&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Paddle&lt;/span&gt;
&lt;span class="n"&gt;initialRightPaddle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lightpink"&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Right&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;740.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;300.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;475.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;60.0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here are the view functions for the paddles and paddle scoring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;viewPaddle&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Paddle&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
&lt;span class="n"&gt;viewPaddle&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rect&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="n"&gt;viewPaddleScore&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Window&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;
&lt;span class="n"&gt;viewPaddleScore&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="n"&gt;positionOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;white"&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fontFamily&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;monospace"&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fontSize&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;80"&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fontWeight&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bold"&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;positionOffset&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100"&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;Svg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromInt&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I first started, I hard-coded some of these values to keep things simple. For instance, the &lt;code&gt;positionOffset&lt;/code&gt; for the scores is something I added in later as a way to use this same function to display both scores and pass in a number to move the score over within the SVG window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We pull all that together into the model and we have all the basic elements for our game!&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ball&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;leftPaddle&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Paddle&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rightPaddle&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Paddle&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Window&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;initialModel&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
&lt;span class="n"&gt;initialModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;initialBall&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;leftPaddle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;initialLeftPaddle&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rightPaddle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;initialRightPaddle&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;initialWindow&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0tw21i5w6nj37giehnst.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0tw21i5w6nj37giehnst.png" alt="Pong Elements in the Browser" width="800" height="693"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The game isn't "alive" yet, but we have everything we need and it's all in roughly the correct location.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔁 Update
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;update&lt;/code&gt; function is where a lot of the magic happens for our game. &lt;strong&gt;This is how we update the ball position, move the paddles around, update player scores, etc&lt;/strong&gt;. It's also where things get a little more complicated. The source code for this project is available at the bottom of this post, so I'll try to keep this section at a high level without diving into the details.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⏱ Subscriptions
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;subscriptions&lt;/code&gt; function is a good place to start, and we'll handle these in our &lt;code&gt;update&lt;/code&gt;. We use subscriptions for two major features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⌨️ handling keyboard input&lt;/li&gt;
&lt;li&gt;✨ adding animation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the code snippet below, we use the &lt;a href="https://package.elm-lang.org/packages/elm/browser/latest/Browser-Events" rel="noopener noreferrer"&gt;&lt;code&gt;Browser.Events&lt;/code&gt;&lt;/a&gt; module from Elm's &lt;code&gt;Browser&lt;/code&gt; package to handle browser animation and key events from the player.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;subscriptions&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Sub&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt;
&lt;span class="n"&gt;subscriptions&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="kt"&gt;Sub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;Browser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Events&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onAnimationFrameDelta&lt;/span&gt; &lt;span class="kt"&gt;BrowserAdvancedAnimationFrame&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Browser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Events&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onKeyDown&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="kt"&gt;PlayerPressedKeyDown&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="n"&gt;keyDecoder&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Browser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Events&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onKeyUp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="kt"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Decode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="kt"&gt;PlayerPressedKeyUp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="n"&gt;keyDecoder&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This produces a steady stream of data we can use for our game. And a &lt;code&gt;Msg&lt;/code&gt; type allows us to indicate how we want to handle them in our &lt;code&gt;update&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt;
    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BrowserAdvancedAnimationFrame&lt;/span&gt; &lt;span class="kt"&gt;Time&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;PlayerPressedKeyDown&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;PlayerReleasedKey&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm admittedly glossing over a lot of details as this blog post grows much larger than I intended. But the important part is that we'll use &lt;code&gt;BrowserAdvancedAnimationFrame&lt;/code&gt; to animate the ball and paddles so they move over time. &lt;code&gt;PlayerPressedKeyDown&lt;/code&gt; will give us a way to know when a player is pressing an arrow key to move the left paddle.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✏️ Sketching Updates with Pseudocode
&lt;/h3&gt;

&lt;p&gt;When I started writing the &lt;code&gt;update&lt;/code&gt; function, I mapped out a quick plan with the pseudocode below.&lt;/p&gt;

&lt;p&gt;Thinking this way with conditionals turned out to be a huge mistake 👎. Every time I wanted to add a feature, it meant adding yet another condition. And the order of the conditions ended up being important too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if nothing is happening
    move ball
    move right AI paddle
if player input
    move left paddle
if ball hits right paddle
    negate ball.vx
    update ball position
if ball hits left paddle
    negate ball.vx
    update ball position
if ball hits left window edge
    increment right player score
    reset ball to initial position
    set ball in motion
if ball hits right window edge
    increment left player score
    reset ball to initial position
    set ball in motion
if ball hits top or bottom window edge
    negate ball.vy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At least it gave me a rough idea of the events in the game of &lt;em&gt;Pong&lt;/em&gt;. But for the next game I work on I'll sketch this out on paper before I dive into the code. &lt;strong&gt;And instead of thinking about if-this-then-that, I'll try to come up with union types for different states&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 Getting the Ball Moving
&lt;/h3&gt;

&lt;p&gt;At this point, it's fun to set the ball in motion and see what happens. We can use something like this to adjust the position based on the &lt;code&gt;time&lt;/code&gt; we're getting from &lt;code&gt;BrowserAdvancedAnimationFrame&lt;/code&gt;. In other words, as time advances, the ball's &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; position will increase, which means the ball will move down ⬇️ and to the right ➡️.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vy&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's fun to see the ball start moving, but we quickly realize it won't know to stop at the bottom of the window.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuvz9pulxl703emcq9isi.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuvz9pulxl703emcq9isi.gif" alt="Working Ball Movement" width="1594" height="1518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll need to check out the source code at the bottom of this post to see the complete example. But the basic idea at this point is to invert the ball's vertical direction when it hits the bottom of the window. The ball has a positive &lt;code&gt;vy&lt;/code&gt; value as it's moving downward. Hitting the bottom edge of the window (which we know because it's the value of the &lt;code&gt;window.height&lt;/code&gt;) means we take the &lt;code&gt;vy&lt;/code&gt; value and turn it into a negative value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- ball hits bottom edge of window&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;edge&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
    &lt;span class="kt"&gt;Window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Bottom&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;vy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;negate&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vy&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv16lqew7gt3s3j57fnpz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv16lqew7gt3s3j57fnpz.gif" alt="Ball Collides with Bottom Edge of Window" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From here, the development starts to flow a bit. When the ball collides with the top or bottom of the window, we negate the &lt;code&gt;vy&lt;/code&gt; value. When the ball hits the left or right edge of the window, we increment the player score by 1 and we reset the ball back to its original position.&lt;/p&gt;

&lt;h3&gt;
  
  
  💥 Paddle Collisions
&lt;/h3&gt;

&lt;p&gt;Handling the ball collisions with the edges of the window is somewhat straightforward since we can use the window's &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, &lt;code&gt;width&lt;/code&gt;, and &lt;code&gt;height&lt;/code&gt; values. Paddles are a little more difficult, because we have to compare the ball's location and the paddle's location to see if they intersect. Here are the boolean checks I used to determine if the ball had collided with one of the paddles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;ballHitLeftPaddle&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ball&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Paddle&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;
&lt;span class="n"&gt;ballHitLeftPaddle&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vx&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="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ballHitRightPaddle&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ball&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Paddle&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;
&lt;span class="n"&gt;ballHitRightPaddle&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vx&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🚦 Game States
&lt;/h3&gt;

&lt;p&gt;After getting some of the initial features up and running, we realize that games aren't always in a "playing" state. &lt;em&gt;Super Mario Bros.&lt;/em&gt; is a memorable example where there is an initial screen and you have to press the start button to begin playing the game.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwexd1wkswsnndy3lbp6u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwexd1wkswsnndy3lbp6u.jpg" alt="Mario Start Screen" width="800" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So we can begin with a &lt;code&gt;StartingScreen&lt;/code&gt; state, and transition to a &lt;code&gt;PlayingScreen&lt;/code&gt; state after a player is ready. For &lt;em&gt;Pong&lt;/em&gt;, I added brief instructions below the game window (which are visible at the bottom of this post) and used the spacebar key to start the game.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Super Mario Bros.&lt;/em&gt; also has a memorable "Game Over" screen. When one of the players reaches the winning score, we'll transition from &lt;code&gt;PlayingScreen&lt;/code&gt; to an &lt;code&gt;EndingScreen&lt;/code&gt; state where we can display the winner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiocd90qml7n9dil0opl8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiocd90qml7n9dil0opl8.png" alt="Mario Game Over Screen" width="760" height="666"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;GameState&lt;/span&gt;
    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;StartingScreen&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;PlayingScreen&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;EndingScreen&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can create a custom type like this to handle the different game states and transition between them. It also ensures that players are only in one state at a time, since we shouldn't still be playing the game in the "game over" screen. We can disable to movement of the ball and paddles in the start and end states. And we also handle keyboard input to start or restart the game from those states.&lt;/p&gt;

&lt;h3&gt;
  
  
  🦉 Draw the Owl
&lt;/h3&gt;

&lt;p&gt;Take a look at the source code because there's actually a lot going on in the &lt;code&gt;update&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frezocbbat7kwh44rdont.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frezocbbat7kwh44rdont.png" alt="Draw the Owl" width="640" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hate to say "draw the owl" here. But I wanted to make sure I cover the more interesting aspects of &lt;strong&gt;what sets this implementation of &lt;em&gt;Pong&lt;/em&gt; apart from many others&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  😍 The Interesting Bits
&lt;/h2&gt;

&lt;p&gt;Once you get a working version of the game up and running, it's time to figure out what makes it interesting, compelling, and fun.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚡️ Changing the Ball Angle
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;If I had to pick one feature that makes a big difference in the game, it's this one&lt;/strong&gt;. When the ball collides with a paddle, it initially makes sense to invert the ball's &lt;code&gt;vx&lt;/code&gt; value and send it back the other way. It would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- ball hits paddle&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;vx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;negate&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vx&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That works well for the ball to hit the paddle and change the horizontal direction. As it turns out, having the ball follow a slow, predictable path can make the game &lt;em&gt;so&lt;/em&gt; boring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The solution is to give players a way to control the angle of the ball off the paddle&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is better explained visually, so here are a couple of quick sketches. Instead of having the ball follow a predictable path, the location where the ball hits the paddle determines the angle. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhfgdqfrr5syhvt9kzbet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhfgdqfrr5syhvt9kzbet.png" alt="Ball Angle Change" width="800" height="1316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fen2lswgxp5em859x56im.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fen2lswgxp5em859x56im.png" alt="Another Ball Angle Change" width="800" height="1311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That might not seem like a big difference, but the result is that one paddle can make it way harder for the other paddle to return the ball.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd3yu585crnk0x46sprff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd3yu585crnk0x46sprff.png" alt="Result of Ball Angle Change" width="800" height="1092"&gt;&lt;/a&gt;&lt;br&gt;
We can also add a small amount to the ball speed whenever it hits a paddle to make the game feel quicker. Whenever the ball collides with a paddle, add to the &lt;code&gt;vx&lt;/code&gt; value to increase the horizontal speed. Elm's &lt;code&gt;clamp&lt;/code&gt; function is useful to set an upper bound, because the ball can end up moving so fast that it becomes difficult to play.&lt;/p&gt;

&lt;p&gt;Adjusting things like the ball angle and speed has a &lt;em&gt;huge&lt;/em&gt; impact on playability. &lt;strong&gt;It also adds an element of strategy to the game that gives the player options&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Conservative Option:&lt;/strong&gt; Be conservative and hit the ball with the middle of the paddle. The speed will increase with each hit and eventually the right paddle will struggle to keep up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risky Option:&lt;/strong&gt; Or, take on the risk of hitting the ball closer to the edge of the paddle, which returns it at a harder angle for the AI paddle.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  🤖 "AI" for the Right Paddle
&lt;/h3&gt;

&lt;p&gt;My first attempt at getting a computer-controlled paddle working was to just have the &lt;code&gt;paddle.y&lt;/code&gt; position match the &lt;code&gt;ball.y&lt;/code&gt; position. It works well as a starting point, because the ball and right paddle end up in sync with one another and allows the right paddle to consistently return the ball.&lt;/p&gt;

&lt;p&gt;The only problem is that makes it impossible for the left paddle to score, because the right paddle will always meet the ball.&lt;/p&gt;

&lt;p&gt;I ended up finding a solution that seems to work pretty well where the right paddle tries to "catch up" with the ball's location:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;updateRightPaddle&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ball&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Paddle&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Paddle&lt;/span&gt;
&lt;span class="n"&gt;updateRightPaddle&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vy&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;paddle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vy&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;paddle&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the ball is higher on the screen, then the paddle will "chase" upward. If the ball is lower, then the paddle will "chase" downward. Then, you can tinker with the right paddle's &lt;code&gt;vy&lt;/code&gt; value to increase or decrease the difficulty. I ended up finding a value that works well in that it's difficult to score but not impossible. So it feels rewarding to score points against the "AI" paddle.&lt;/p&gt;

&lt;h3&gt;
  
  
  🏆 Winning
&lt;/h3&gt;

&lt;p&gt;Speaking of scoring, it was surprisingly difficult to figure out what the winning score was supposed to be for the arcade game. Was it 10? 11? 15? Or whoever scored the most within a certain time frame?&lt;/p&gt;

&lt;p&gt;Then I found this sticker:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa7mzm1e2dbct0lclrwx9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa7mzm1e2dbct0lclrwx9.png" alt="Winning Score Sticker on Arcade Cabinet" width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;First player to score 15 points WINS&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But I was curious about why the score on this arcade cabinet was on a sticker instead of located with the rest of the instructions.&lt;/p&gt;

&lt;p&gt;It turns out there was a physical switch arcade owners could use to adjust the winning score.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqch7vv5d0lxpmbxy1u9e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqch7vv5d0lxpmbxy1u9e.png" alt="Arcade Cabinet Instructions" width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This felt like low-hanging fruit, so I added it as an option to the game.&lt;/p&gt;

&lt;h3&gt;
  
  
  💯 Ball Path History
&lt;/h3&gt;

&lt;p&gt;This felt like the "killer app" for this version of &lt;em&gt;Pong&lt;/em&gt;. I saw Bret Victor's &lt;a href="https://vimeo.com/36579366" rel="noopener noreferrer"&gt;Inventing on Principle&lt;/a&gt; talk years ago and loved the idea that game elements have a past and future. But I never thought about how something like that works.&lt;/p&gt;

&lt;p&gt;With Elm, it's a little more obvious because the Elm debugger gives a glimpse of what the stream of values looks like over time.&lt;/p&gt;

&lt;p&gt;To visualize the ball history, we can start by creating an empty list. And then every time the ball changes position, we prepend the ball to the list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;updateBallPath&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Ball&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;BallPath&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Maybe&lt;/span&gt; &lt;span class="kt"&gt;WindowEdge&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
&lt;span class="n"&gt;updateBallPath&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt; &lt;span class="n"&gt;ballPath&lt;/span&gt; &lt;span class="n"&gt;maybeWindowEdge&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;showBallPath&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
        &lt;span class="kt"&gt;Pong&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Off&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;model&lt;/span&gt;

        &lt;span class="kt"&gt;Pong&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Ball&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;On&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;maybeWindowEdge&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
                &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="kt"&gt;Pong&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Left&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ballPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="kt"&gt;Pong&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Right&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ballPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="n"&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="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ballPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;|&lt;/span&gt; &lt;span class="n"&gt;ball&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="n"&gt;ballPath&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the ball hits the left or right edge of the game window, we clear the history by setting &lt;code&gt;ballPath = []&lt;/code&gt;. The rest of the time, we're collecting new positions by prepending the &lt;code&gt;ball&lt;/code&gt; to &lt;code&gt;ballPath&lt;/code&gt;. Instead of "prepend" the &lt;code&gt;::&lt;/code&gt; operator is usually called "cons" in languages like LISP and Elm.&lt;/p&gt;

&lt;p&gt;Lastly, we can pipe to &lt;code&gt;List.take 99&lt;/code&gt; to limit the amount of history and avoid potential performance pitfalls. Having said that, I'd be curious how much history it could handle before slowing down, and you might even be able to build a whole new game around that idea.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi3b40bzjq77hf1hhg1by.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi3b40bzjq77hf1hhg1by.gif" alt="Show Ball Path History" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  📈 Performance
&lt;/h3&gt;

&lt;p&gt;Game development can be pretty tricky. If I write an inefficient function for most applications, it's only going to run here and there and probably won't be noticeable. If I write an inefficient function for a game, it will run about 60 times per second. The whole time 😅.&lt;/p&gt;

&lt;p&gt;As I continue to make more games, I'd like to find better ways to profile performance and benchmark. I recorded some performance profiles using my browser's DevTools, but it's difficult to see where inefficiencies are.&lt;/p&gt;

&lt;p&gt;It's also interesting to try different machines and browsers. I wrote this on &lt;a href="https://dev.to/bijanbwb/how-i-set-up-a-new-macbook-pro-dev-environment-9hd"&gt;my relatively new MacBook Pro laptop&lt;/a&gt;, but it likely wouldn't run as smoothly on my older laptop.&lt;/p&gt;

&lt;p&gt;For now, I added a &lt;code&gt;viewFps&lt;/code&gt; function in the &lt;code&gt;Util&lt;/code&gt; module that takes a list of times and allows you to use a toggle to display and hide the current frames per second.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎨 Polish and Sound
&lt;/h3&gt;

&lt;p&gt;As some final polish, I added some color to the background to pay homage to the original game cabinet. And I used SVG to recreate the &lt;em&gt;Pong&lt;/em&gt; lettering at the top of the screen. I had other fun ideas to create more cabinet affordances in the UI, but it would've taken some time to get right.&lt;/p&gt;

&lt;p&gt;There's also a great JavaScript library called &lt;a href="https://howlerjs.com/" rel="noopener noreferrer"&gt;howler.js&lt;/a&gt; for adding audio to the game. Some of the howler demos are really amazing. Elm provides "ports" to integrate with JavaScript libraries in a safe way. So I added simple &lt;code&gt;beep.wav&lt;/code&gt; and &lt;code&gt;boop.wav&lt;/code&gt; sounds for when the ball hits the paddles and edges. When the collisions occur, it triggers the port and plays the sound in the browser. Check out the source code if you want to see an example of how this works.&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Ideas
&lt;/h2&gt;

&lt;p&gt;One of the most fun parts of game development is stumbling on little ideas that would be intriguing to implement.&lt;/p&gt;

&lt;p&gt;Sometimes you have an idea you want to see come to life, and &lt;strong&gt;sometimes you accidentally write some bad code that produces an interesting result&lt;/strong&gt;. For instance, I made a mistake where the ball's motion was stopped unless I was moving the paddle. But that got me thinking of a game like &lt;em&gt;Superhot&lt;/em&gt;, where "time moves only when you move".&lt;/p&gt;

&lt;p&gt;The ball path history feature I mentioned above is a good example of this kind of "+1" feature that's not core to the game but adds a lot to it.&lt;/p&gt;

&lt;p&gt;Here are a few more ideas of varying complexity that I would've loved to implement given the time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change the ball's color.&lt;/li&gt;
&lt;li&gt;Add particle effects for collisions.&lt;/li&gt;
&lt;li&gt;Add a pause state.&lt;/li&gt;
&lt;li&gt;Dynamically change the ball's width and height.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=GpTPm1R4_AM" rel="noopener noreferrer"&gt;Multiball&lt;/a&gt; mode.&lt;/li&gt;
&lt;li&gt;Multipaddle mode.&lt;/li&gt;
&lt;li&gt;"Superhot" mode, where the ball moves only when you move.&lt;/li&gt;
&lt;li&gt;Replay winning shots in the ending screen state.&lt;/li&gt;
&lt;li&gt;Local multiplayer where one paddle uses the keyboard and one paddle uses the mouse.&lt;/li&gt;
&lt;li&gt;Online multiplayer (if you build something like this I'd love to see it!).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🎓 Lessons Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Little things make &lt;em&gt;all&lt;/em&gt; the difference. Adjusting settings like the ball speed and path has a huge impact on playability. Polish!&lt;/li&gt;
&lt;li&gt;Think in states (with union types) instead of conditionals. You can start small with &lt;a href="https://www.youtube.com/watch?v=6TDKHGtAxeg" rel="noopener noreferrer"&gt;moving away from &lt;code&gt;Bool&lt;/code&gt; values&lt;/a&gt; to an &lt;code&gt;On&lt;/code&gt; and &lt;code&gt;Off&lt;/code&gt; switch, then add additional custom states.&lt;/li&gt;
&lt;li&gt;Refactoring has its ups and downs. It's great to clean up the code and add clarity. But I split the application code into &lt;a href="https://www.youtube.com/watch?v=XpDsk374LDE" rel="noopener noreferrer"&gt;separate files and modules&lt;/a&gt;, which didn't improve the development experience.&lt;/li&gt;
&lt;li&gt;Find balance.

&lt;ul&gt;
&lt;li&gt;Gently resist the urge to move on and work on something  else that's new and different. &lt;strong&gt;It's easy to get the first 90% done, but the interesting bits are in the final stretch&lt;/strong&gt;. Adding polish can move it from a lark to a genuinely interesting project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Having said that, find a good stopping point&lt;/strong&gt;. I could probably keep building different versions of &lt;em&gt;Pong&lt;/em&gt; with fancy features for a year. And it's tempting to implement those fun ideas in the list above. But it's important to find a good place to stop and ship it if we want to keep moving and growing. 🚀&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  📈 What's Next?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc7zd5ybj7v8dlxebuxn1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc7zd5ybj7v8dlxebuxn1.jpg" alt="That's Just Pong" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While rebuilding &lt;em&gt;Pong&lt;/em&gt;, there were a bunch of times where I wanted to bail and work on something more complex and impressive. And other times where I just wanted to "quickly" build other games like Tetris and Snake. But I'm going to try sticking with the approach I outlined in the &lt;a href="https://dev.to/bijanbwb/recreating-classic-games-for-the-web-series-intro-4pm7"&gt;intro post for this series&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Breakout&lt;/em&gt; was always my favorite Atari game when I was a kid, so it'll be fun to figure it out. Plus I have all the basic mechanics built for this project, so it'll give me an opportunity to try different data structures and add some more interesting features like particle effects that I didn't get to do for &lt;em&gt;Pong&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🏫 Resources
&lt;/h2&gt;

&lt;p&gt;If you're learning functional programming and game development, feel free to &lt;a href="https://bijanbwb.github.io" rel="noopener noreferrer"&gt;get in touch with me&lt;/a&gt; and I'd be happy to hear from you. You can also &lt;a href="https://twitter.com/bijanbwb" rel="noopener noreferrer"&gt;find me on Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As promised, here are links to the game and the source code!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🕹 &lt;a href="https://bijanbwb.github.io/#/pong" rel="noopener noreferrer"&gt;&lt;strong&gt;Play the Game!&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;a href="https://github.com/create-with/games" rel="noopener noreferrer"&gt;&lt;strong&gt;View the Source Code on GitHub&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>elm</category>
      <category>functional</category>
    </item>
    <item>
      <title>Recreating Classic Games for the Web (Series Intro)</title>
      <dc:creator>Bijan Boustani</dc:creator>
      <pubDate>Sun, 01 Mar 2020 04:30:26 +0000</pubDate>
      <link>https://forem.com/bijanbwb/recreating-classic-games-for-the-web-series-intro-4pm7</link>
      <guid>https://forem.com/bijanbwb/recreating-classic-games-for-the-web-series-intro-4pm7</guid>
      <description>&lt;p&gt;I've always been fascinated by the level of interactivity and fun that classic console games were able to offer. I grew up playing games like &lt;em&gt;Super Mario Bros.&lt;/em&gt; for the Nintendo Entertainment System. And it's been a silly dream of mine over the years to create similar games for the web.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwqof4n46u2t4iihivwre.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwqof4n46u2t4iihivwre.jpg" alt="Super Mario Bros. Start Screen" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've been working with web applications in recent years, but game development was a different world I always wanted to learn more about. And while I've tinkered with building a few demos here and there, I never got very far with it.&lt;/p&gt;

&lt;p&gt;My goal for this series is to recreate classic console games from scratch with the Elm programming language, and to share the process as I go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Games?
&lt;/h2&gt;

&lt;p&gt;When I mention "classic games" in the title of this post, I'm primarily referring to console games for the &lt;a href="https://en.wikipedia.org/wiki/Atari_2600" rel="noopener noreferrer"&gt;Atari 2600&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Nintendo_Entertainment_System" rel="noopener noreferrer"&gt;Nintendo Entertainment System&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In other words, I'd love to recreate games like &lt;em&gt;Pong&lt;/em&gt;, &lt;em&gt;Super Mario Bros.&lt;/em&gt;, and &lt;em&gt;The Legend of Zelda&lt;/em&gt;. But I don't plan to work on games like Tic-tac-toe or Hangman. And it's also unlikely that I'll be able to recreate the modern AAA game titles that are developed by hundreds of talented people.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fknog5zaojhjdaut33a7c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fknog5zaojhjdaut33a7c.jpg" alt="The Simpsons Pong Reference" width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The plan is to get started with relatively simple &lt;strong&gt;Atari games&lt;/strong&gt; (although I've found even simple games can take a fair amount of work to polish and get right).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(Atari) &lt;em&gt;Pong&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;(Atari) &lt;em&gt;Breakout&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Assuming I don't rage quit after building those, I'll move on to &lt;strong&gt;Platformer&lt;/strong&gt; games. This is where the list already gets a little hazy because &lt;em&gt;Celeste&lt;/em&gt; is a modern take on some of these classic mechanics.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(Atari) &lt;em&gt;Pitfall!&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;(NES) &lt;em&gt;Super Mario Bros.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;(Indie) &lt;em&gt;Celeste&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd also really love to build &lt;strong&gt;Adventure&lt;/strong&gt; games, with &lt;em&gt;The Legend of Zelda: A Link to the Past&lt;/em&gt; being my childhood favorite.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(Atari) &lt;em&gt;Adventure&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;(NES) &lt;em&gt;The Legend of Zelda&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;(SNES) &lt;em&gt;The Legend of Zelda: A Link to the Past&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Scope
&lt;/h3&gt;

&lt;p&gt;Admittedly, I won't be able to clone all the amazing artwork and music and features from these games. So &lt;strong&gt;the idea is to at least figure out the primary game mechanic from each genre&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fglslte92wzm3ifzdnxym.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fglslte92wzm3ifzdnxym.jpg" alt="Pong Arcade Game Instructions" width="512" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are also &lt;strong&gt;subtle aspects of these games that make all the difference&lt;/strong&gt;. Mario's jump has to feel just right. And when a ball strikes a paddle in &lt;em&gt;Pong&lt;/em&gt;, hits toward the edge of the paddle make the ball come off at a steeper angle. So you take on more risk hitting it closer to the edge of the paddle, but you also increase the difficulty for your opponent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plan
&lt;/h2&gt;

&lt;p&gt;My background is in web development, not game development. So I'll likely make mistakes and run into problems that other smart people solved a long time ago.&lt;/p&gt;

&lt;p&gt;But it feels like a good way to learn and a good time to get into game programming. There are awesome tools and learning resources available these days.&lt;/p&gt;

&lt;p&gt;You can download &lt;a href="https://unity.com" rel="noopener noreferrer"&gt;Unity&lt;/a&gt; for free and there are books and tutorials out there for creating both 2D and 3D games. There are also projects like &lt;a href="https://www.lexaloffle.com/pico-8.php" rel="noopener noreferrer"&gt;PICO-8&lt;/a&gt; and &lt;a href="https://love2d.org" rel="noopener noreferrer"&gt;LÖVE 2D&lt;/a&gt; for a language called &lt;a href="https://www.lua.org" rel="noopener noreferrer"&gt;Lua&lt;/a&gt; that are super fun to try out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Elm?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"As with any time you fall in love, it's difficult to explain why. It just worked the way I work."&lt;br&gt;
&lt;strong&gt;Dave Thomas&lt;/strong&gt; &lt;em&gt;Programming Elixir&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://elm-lang.org/" rel="noopener noreferrer"&gt;Elm&lt;/a&gt; is a fun language to work with, and it's become my favorite for front-end web development. Most languages involve a workflow where we write code, run our program, find errors, and debug them. With Elm, we write types and code with feedback from a compiler, and then run it with confidence that it won't catch fire.&lt;/p&gt;

&lt;p&gt;Although the options I mentioned above are likely better for most game development, Elm will be a fun way to build things from scratch and a good way to learn. It also means I can start with simple Elm and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG" rel="noopener noreferrer"&gt;SVG&lt;/a&gt; for the first couple games, and then learn more about WebGL and other technologies as needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivations
&lt;/h2&gt;

&lt;p&gt;Beyond the motivation to create fun, interactive games; there's also a lot to learn. I'm excited to learn more about game design and development (like working with an &lt;a href="https://en.wikipedia.org/wiki/Entity_component_system" rel="noopener noreferrer"&gt;Entity Component System&lt;/a&gt;). I find it fascinating to learn about how the game industry evolved. And it's amazing how far the medium has come considering that the 1970s (Atari) and 1980s (NES) weren't that long ago.&lt;/p&gt;

&lt;p&gt;It's a good opportunity to continue improving functional programming skills and solve problems we don't usually come across when building web application features. And it would be cool to pull some of those ideas from games back into web application development. I'm personally interested in how ideas from the world of game design can be used to improve educational content.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1fe05am2ncbixthmpp52.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1fe05am2ncbixthmpp52.jpg" alt="Cube Slam" width="598" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are some fascinating directions to go once we learn the basics. Creative coding projects and experiments like &lt;a href="https://www.cubeslam.com/tech" rel="noopener noreferrer"&gt;Cube Slam&lt;/a&gt; that combine web technologies like WebRTC and &lt;a href="https://threejs.org" rel="noopener noreferrer"&gt;three.js&lt;/a&gt; for a fun multiplayer game.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;p&gt;In the next post, I'll get started creating a Pong game from scratch. If you're interested in learning more in the meantime, here is a collection of resources you might like.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Books:&lt;/strong&gt; &lt;a href="https://guide.elm-lang.org" rel="noopener noreferrer"&gt;An Introduction to Elm&lt;/a&gt;, &lt;a href="https://mitpress.mit.edu/books/racing-beam" rel="noopener noreferrer"&gt;Racing the Beam&lt;/a&gt;, &lt;a href="https://www.theoryoffun.com" rel="noopener noreferrer"&gt;A Theory of Fun for Game Design&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Movies:&lt;/strong&gt; &lt;a href="http://buy.indiegamethemovie.com" rel="noopener noreferrer"&gt;Indie Game&lt;/a&gt;, &lt;a href="http://www.worldoneonemovie.com" rel="noopener noreferrer"&gt;World 1-1&lt;/a&gt;, &lt;a href="https://www.thenew8bitheroes.com/the-film.html" rel="noopener noreferrer"&gt;The New 8-bit Heroes&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Talks:&lt;/strong&gt; &lt;a href="https://vimeo.com/36579366" rel="noopener noreferrer"&gt;Bret Victor: Inventing on Principle&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>elm</category>
      <category>functional</category>
    </item>
    <item>
      <title>How I Set Up a New MacBook Pro Dev Environment</title>
      <dc:creator>Bijan Boustani</dc:creator>
      <pubDate>Wed, 08 Jan 2020 15:10:52 +0000</pubDate>
      <link>https://forem.com/bijanbwb/how-i-set-up-a-new-macbook-pro-dev-environment-9hd</link>
      <guid>https://forem.com/bijanbwb/how-i-set-up-a-new-macbook-pro-dev-environment-9hd</guid>
      <description>&lt;p&gt;🎆 New year!&lt;br&gt;
💼 New job!&lt;br&gt;
💻 New laptop!&lt;/p&gt;

&lt;p&gt;I'm so excited for this brand new decade. It feels like an opportunity for a fresh start.&lt;/p&gt;

&lt;p&gt;I had been working at the same company for years. So, I'm eager to start my new job and work with a distributed team of talented people at &lt;a href="https://www.enbala.com/" rel="noopener noreferrer"&gt;Enbala Power Networks&lt;/a&gt;. It's a perfect mix of technology I love (&lt;a href="https://elixir-lang.org/" rel="noopener noreferrer"&gt;Elixir&lt;/a&gt; and &lt;a href="https://elm-lang.org/" rel="noopener noreferrer"&gt;Elm&lt;/a&gt;), fascinating work, and people I admire.&lt;/p&gt;
&lt;h2&gt;
  
  
  💻 Setting up a New Laptop
&lt;/h2&gt;

&lt;p&gt;The timing worked out well. Apple recently released the new &lt;a href="https://www.apple.com/macbook-pro-16/" rel="noopener noreferrer"&gt;16-inch MacBook Pro&lt;/a&gt; models, and I had been dying for a new setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I figured I would take this opportunity to write down a checklist of applications I use and preferences I have for setting up a new laptop.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some of my settings are eccentric (like having a plain black background instead of a fancy photograph). But my hope for this post is that you'll at least take away one or two helpful ideas that might get you unstuck from a rut.&lt;/p&gt;
&lt;h2&gt;
  
  
  🙉 Creating a Distraction-free Environment
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Almost all my preferences are all about limiting distractions and enabling focus.&lt;/strong&gt; I've always been prone to distraction. So, creating an environment where I can stay focused on a single task for an extended period  is critical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Otherwise, I make tiny amounts of  progress in many directions without finishing anything.&lt;/strong&gt; The result is that all the time and energy and effort I put in is  wasted.&lt;/p&gt;
&lt;h3&gt;
  
  
  🧹 Cleaning up the Dock
&lt;/h3&gt;

&lt;p&gt;Out of the box, macOS comes with &lt;em&gt;so&lt;/em&gt; many applications in the Dock. But it's more efficient to use the native Spotlight search (or &lt;a href="https://www.alfredapp.com/" rel="noopener noreferrer"&gt;Alfred&lt;/a&gt;) to open applications with the keyboard. For example, you can type &lt;code&gt;Command + Space + Sys&lt;/code&gt; and then press &lt;code&gt;Enter&lt;/code&gt; to open the System Preferences.&lt;/p&gt;

&lt;p&gt;So, I opt for a minimalist Dock area with only the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Firefox Developer Edition&lt;/li&gt;
&lt;li&gt;Visual Studio Code&lt;/li&gt;
&lt;li&gt;Downloads Folder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3u8fssqcd9w0ahwtdps3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3u8fssqcd9w0ahwtdps3.png" alt="Minimal Dock" width="800" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also like to hide the Dock when I'm not using it, and I disable the option to remember recent applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finq3qe16vhtsq7f8h5ss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finq3qe16vhtsq7f8h5ss.png" alt="Dock Settings" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  ⚡️ Speeding up the Trackpad, Mouse, and Keyboard
&lt;/h3&gt;

&lt;p&gt;One of the first things I like to do for a new laptop is comb through the System Preferences. There are some default settings that slow you down. For example, the default Trackpad speed is slow, which can make it tough to navigate the cursor around, especially on large displays.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Command + Space ➡️ Trackpad ➡️ Tracking Speed ➡️ Fast
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhmd1128d2ug0o525lv40.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhmd1128d2ug0o525lv40.png" alt="Trackpad Settings" width="800" height="643"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This can take some getting used to if you're accustomed to the slower setting. But it's worth it to adjust, because it's way faster to navigate with the faster setting.&lt;/p&gt;

&lt;p&gt;🖱 Next, you can do the same for the mouse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Command + Space ➡️ Mouse ➡️ Tracking Speed ➡️ Fast
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⌨️ Similarly, you can speed up your Keyboard settings with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Command + Space ➡️ Keyboard ➡️ Key Repeat ➡️ Fast
Command + Space ➡️ Keyboard ➡️ Delay Until Repeat ➡️ Fast
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This might seem like a silly place to start, but the idea is to find small changes we can make that add up to a lot over time.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🖤 Background and Menu Bar
&lt;/h3&gt;

&lt;p&gt;This setting might be a little odd, but I use a plain black color for my background. The macOS background pictures are beautiful, but this is the least distracting option for me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Command + Space ➡️ Desktop &amp;amp; Screen Saver ➡️ Apple ➡️ Colors ➡️ Black
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7l72yi1mmddpvo98jxlm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7l72yi1mmddpvo98jxlm.png" alt="Desktop Background" width="800" height="691"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is also an application called &lt;a href="https://www.macbartender.com/" rel="noopener noreferrer"&gt;Bartender&lt;/a&gt; I love for cleaning up the menu bar area. After installing several applications, the menu bar area tends to look cluttered. Bartender allows you to show or hide menu bar applications, and I tend to prefer hiding everything except the date and time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7t35trttjd8f3oe9n8i4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7t35trttjd8f3oe9n8i4.png" alt="Uncluttered Menu Bar" width="584" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🖥 Adding Virtual Desktops
&lt;/h3&gt;

&lt;p&gt;I also like to set up virtual desktop spaces to create separation between applications. This way, I can have my IDE running in a separate space from my browser.&lt;/p&gt;

&lt;p&gt;To set this up, you can do a three finger swipe upward on the Trackpad to enter &lt;em&gt;Mission Control&lt;/em&gt; mode. From here, you can click the ➕ icon at the top right to create new virtual desktop spaces.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqn78a18cf7wbvjvcmft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqn78a18cf7wbvjvcmft.png" alt="Virtual Desktop Spaces with Mission Control" width="800" height="60"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This allows you to keep dedicated spaces for things like your IDE, browser, and task manager. And you have a couple options for switching between these spaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use &lt;code&gt;Command + Tab&lt;/code&gt; to switch between open applications.&lt;/li&gt;
&lt;li&gt;use a three finger swipe left or right to switch to the next virtual space. You can also use &lt;code&gt;Control + ⬅️&lt;/code&gt; or &lt;code&gt;Control + ➡️&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;use a three finger swipe upward to open Mission Control. You can also use &lt;code&gt;Control + ⬆️&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;use &lt;code&gt;Control + N&lt;/code&gt; to switch to a particular space based on the number (&lt;code&gt;N&lt;/code&gt;). This option requires enabling keyboard shortcuts with the following:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Command + Space ➡️ Keyboard ➡️ Shortcuts ➡️ Enable Switch to Desktop N
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9pasc8eiguy29byxuhfl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9pasc8eiguy29byxuhfl.png" alt="Mission Control Keyboard Shortcuts" width="800" height="710"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you plan to dedicate spaces for a particular use, you can also disable the option to &lt;em&gt;"Automatically rearrange Spaces based on most recent use."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw2v4mjs01rwwm3xz3bt5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw2v4mjs01rwwm3xz3bt5.png" alt="Mission Control Settings" width="800" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🔕 Limiting Notifications
&lt;/h3&gt;

&lt;p&gt;macOS comes with a Do Not Disturb mode that can help to reduce the number of interruptions. One way to turn this on is to hold down the &lt;code&gt;Option&lt;/code&gt; key on your keyboard and click the Notification Center icon in the menu bar.&lt;/p&gt;

&lt;p&gt;You can also set a time range for when to enable Do Not Disturb mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Command + Space ➡️ Notifications ➡️ Turn on Do Not Disturb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📱 It's not a bad idea to check your phone too for apps that are bombarding you with notifications. If you're using an iOS device, you can check the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Settings ➡️ Screen Time ➡️ See All Activity ➡️ Notifications
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Disabling unneeded notifications from even a couple of apps can have a big impact and cut down on distractions throughout your day. 😌&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended Applications
&lt;/h2&gt;

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

&lt;h3&gt;
  
  
  General
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;🦊 &lt;a href="https://www.mozilla.org/en-US/firefox/developer/" rel="noopener noreferrer"&gt;&lt;strong&gt;Firefox Developer Edition&lt;/strong&gt;&lt;/a&gt; for web browsing.&lt;/li&gt;
&lt;li&gt;✅ &lt;a href="https://culturedcode.com/things/" rel="noopener noreferrer"&gt;&lt;strong&gt;Things&lt;/strong&gt;&lt;/a&gt; for a well-designed project and task manager.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Utilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;🔒 &lt;a href="https://1password.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;1Password&lt;/strong&gt;&lt;/a&gt; for password management.&lt;/li&gt;
&lt;li&gt;⌨️ &lt;a href="https://www.alfredapp.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Alfred&lt;/strong&gt;&lt;/a&gt; for keyboard-based productivity and automation.&lt;/li&gt;
&lt;li&gt;🍻 &lt;a href="https://www.macbartender.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Bartender&lt;/strong&gt;&lt;/a&gt; for de-cluttering the macOS menu bar.&lt;/li&gt;
&lt;li&gt;📦 &lt;a href="https://www.dropbox.com/basic" rel="noopener noreferrer"&gt;&lt;strong&gt;Dropbox&lt;/strong&gt;&lt;/a&gt; for cloud file storage across devices.&lt;/li&gt;
&lt;li&gt;🦊 &lt;a href="https://gifox.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;Gifox&lt;/strong&gt;&lt;/a&gt; for a well-designed menu bar application to quickly record animated gifs.&lt;/li&gt;
&lt;li&gt;🔍 &lt;a href="https://manytricks.com/moom/" rel="noopener noreferrer"&gt;&lt;strong&gt;Moom&lt;/strong&gt;&lt;/a&gt; for moving and arranging your windows with &lt;code&gt;Option + Tab&lt;/code&gt; keyboard shortcuts.&lt;/li&gt;
&lt;li&gt;⏱ &lt;a href="https://www.seense.com/the_clock/" rel="noopener noreferrer"&gt;&lt;strong&gt;The Clock&lt;/strong&gt;&lt;/a&gt; for replacing the default date and time in the menu bar. This is particularly helpful if you're on a distributed team where your teammates are in different time zones (&lt;a href="https://twitter.com/bijanbwb/status/1208043476455247872" rel="noopener noreferrer"&gt;demo&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Web Applications
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✍️ &lt;a href="https://750words.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;750words&lt;/strong&gt;&lt;/a&gt; for a simple, daily writing habit.&lt;/li&gt;
&lt;li&gt;💌 &lt;a href="https://www.google.com/gmail/about/" rel="noopener noreferrer"&gt;&lt;strong&gt;Gmail&lt;/strong&gt;&lt;/a&gt; for email.&lt;/li&gt;
&lt;li&gt;🗓 &lt;a href="https://www.google.com/calendar/about/" rel="noopener noreferrer"&gt;&lt;strong&gt;Google Calendar&lt;/strong&gt;&lt;/a&gt; for shared calendars.&lt;/li&gt;
&lt;li&gt;📝 &lt;a href="http://www.hemingwayapp.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Hemingway App&lt;/strong&gt;&lt;/a&gt; for quick recommendations on how to simplify your writing.&lt;/li&gt;
&lt;li&gt;💰 &lt;a href="https://www.youneedabudget.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;YNAB&lt;/strong&gt;&lt;/a&gt; for budgeting.&lt;/li&gt;
&lt;li&gt;🎼 &lt;a href="https://www.spotify.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Spotify&lt;/strong&gt;&lt;/a&gt; for music.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  💻 Development Environment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🐙 &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;GitHub&lt;/strong&gt;&lt;/a&gt; for code repositories.

&lt;ul&gt;
&lt;li&gt;Set up &lt;code&gt;ssh&lt;/code&gt; access.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;🆚 &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;VSCode&lt;/strong&gt;&lt;/a&gt; for my coding environment.

&lt;ul&gt;
&lt;li&gt;Set up ability to launch from command line with &lt;code&gt;code&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Disable "Scroll Beyond Last Line" option.&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://github.com/tonsky/FiraCode" rel="noopener noreferrer"&gt;Firacode&lt;/a&gt; for a font with fancy ligatures.&lt;/li&gt;
&lt;li&gt;Set up &lt;a href="https://marketplace.visualstudio.com/items?itemName=MS-vsliveshare.vsliveshare" rel="noopener noreferrer"&gt;LiveShare&lt;/a&gt; for pair programming.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;🎛 &lt;a href="https://github.com/asdf-vm/asdf" rel="noopener noreferrer"&gt;&lt;strong&gt;asdf&lt;/strong&gt;&lt;/a&gt; for installing and managing multiple versions of programming languages.

&lt;ul&gt;
&lt;li&gt;Erlang&lt;/li&gt;
&lt;li&gt;Elixir&lt;/li&gt;
&lt;li&gt;Ruby&lt;/li&gt;
&lt;li&gt;Node&lt;/li&gt;
&lt;li&gt;Elm&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;👨‍💻 &lt;a href="https://iterm2.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;iTerm&lt;/strong&gt;&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;homebrew&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ohmyz.sh/" rel="noopener noreferrer"&gt;oh-my-zsh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;dotfiles&lt;/li&gt;
&lt;li&gt;aliases&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;🐘 &lt;a href="https://postgresapp.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;

&lt;li&gt;🏃‍♂️ &lt;a href="https://kapeli.com/dash" rel="noopener noreferrer"&gt;&lt;strong&gt;Dash&lt;/strong&gt;&lt;/a&gt; for quick access to documentation.&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  🕹 Gamedev
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.lexaloffle.com/pico-8.php" rel="noopener noreferrer"&gt;PICO-8&lt;/a&gt; for minimalist, retro game development.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://unity.com/" rel="noopener noreferrer"&gt;Unity&lt;/a&gt; for a fancy, batteries-included game development environment.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.aseprite.org/" rel="noopener noreferrer"&gt;Asesprite&lt;/a&gt; for pixel art.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🤖 Automation
&lt;/h2&gt;

&lt;p&gt;Even if you only have to set up a new laptop every few years, it's worth investing some time in automation. If you're interested in automating your laptop setup process, consider the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;dotfiles&lt;/code&gt; repo on GitHub to save your favorite configuration files.&lt;/li&gt;
&lt;li&gt;Use &lt;a href="https://github.com/Homebrew/homebrew-bundle" rel="noopener noreferrer"&gt;Brewfiles&lt;/a&gt; for installing applications and common system dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  😌 Next?
&lt;/h2&gt;

&lt;p&gt;You can probably tell I love to nerd out about all these little applications and preferences. If you have any tips and tricks or recommendations, reach out to me on Twitter (&lt;a href="https://twitter.com/bijanbwb" rel="noopener noreferrer"&gt;@bijanbwb&lt;/a&gt;) and I'd love to hear from you!&lt;/p&gt;

&lt;p&gt;I love when people create a "&lt;code&gt;/uses&lt;/code&gt;" page (like &lt;a href="https://wesbos.com/uses/" rel="noopener noreferrer"&gt;this one from Wes Bos&lt;/a&gt;) to list the applications and the physical gear they use to be productive. I'm considering writing a future post about how I organize my home office, so let me know if there is something you'd like to see!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
