<?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: Jeff Puls</title>
    <description>The latest articles on Forem by Jeff Puls (@jpuls).</description>
    <link>https://forem.com/jpuls</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%2F490041%2Fb227a880-de1b-44ba-aa6b-5b8c1f5bdc3c.png</url>
      <title>Forem: Jeff Puls</title>
      <link>https://forem.com/jpuls</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jpuls"/>
    <language>en</language>
    <item>
      <title>Is React Holding You Back?</title>
      <dc:creator>Jeff Puls</dc:creator>
      <pubDate>Sun, 31 Jan 2021 19:06:38 +0000</pubDate>
      <link>https://forem.com/jpuls/is-react-holding-you-back-4mno</link>
      <guid>https://forem.com/jpuls/is-react-holding-you-back-4mno</guid>
      <description>&lt;p&gt;React.js is perhaps one of the most controversial topics among web developers in recent years. Some love it, some hate it, some can't live without it. This post aims to toe the line of both sides as I  share my experience thus-far and explain what I learned by converting my React-based portfolio back to a bog-standard HTML/CSS/JavaScript page.&lt;/p&gt;

&lt;p&gt;Strap in, this might be a long one...&lt;/p&gt;

&lt;h2&gt;
  
  
  The Alluring Trap of React
&lt;/h2&gt;

&lt;p&gt;So you're like myself, a freshly self-taught developer who has spent &lt;del&gt;months&lt;/del&gt; years working from the ground up, building your development knowledgebase and skillset from absolutely nothing. HTML and CSS are finally your bread-and-butter, you can craft a stylish (albeit plain-as-a-pancake) TO-DO list in no time flat. With your rudimentary JavaScript knowledge, you've made it interactive, perhaps it even talks to an Express server for that extra zest.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Now what?&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Back to the land of tutorial-hell to try and pick up the next tool for your belt. You really enjoy the logical programming paradigms you learned in vanilla JavaScript, so you venture down that rabbit hole once again, this time looking to learn a framework. You quickly smash the keywords into Google.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;best javascript framework to get rich quick&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Instantly, you're bombarded with a never-ending wall of different catchy names and logos, but one stands out among the crowd, a sleek light-blue atom... it's calling to you, promising you fame, promising fortune... promising the future...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;TIME MACHINE ENGAGED!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;Six long months have passed. You've watched endless YouTube tutorial videos and read various blog posts about React and its many spinoff-frameworks. You're now able to wield &lt;code&gt;Hooks&lt;/code&gt; and &lt;code&gt;Context Providers&lt;/code&gt; like it's nobody's business. You've even assembled an impressive (at least to the lay-person) &lt;a href="https://www.github.com/j-puls" rel="noopener noreferrer"&gt;catalogue of React-based applications&lt;/a&gt;. Time to share your new-found mastery with the world, time to bring your personal portfolio into &lt;strong&gt;&lt;em&gt;THE FUTURE&lt;/em&gt;&lt;/strong&gt;™.&lt;/p&gt;

&lt;p&gt;The next few months are spent designing and building the most incredible site you've created to date. I'm talking a global Context system, real-time updated personal stats from your &lt;em&gt;npm&lt;/em&gt; and &lt;em&gt;GitHub&lt;/em&gt; profiles (with lazy-loaded components!), and it's even got a custom &lt;a href="https://thorium-ui.jpuls.dev/" rel="noopener noreferrer"&gt;Context-based multi-theme UI framework&lt;/a&gt; you built to drastically reduce the amount of CSS you need to write and load in. You're convinced it's the second coming, or at least the third.&lt;/p&gt;

&lt;p&gt;Head now properly over-inflated, you decide to &lt;a href="https://dev.to/jpuls/i-need-your-critique-to-become-a-better-developer-269k"&gt;share your creation&lt;/a&gt; with your favorite online community to get some proper feedback.&lt;/p&gt;

&lt;p&gt;Feedback quickly rolls in... It's got potential they say, but falls well short of expectations. Lethal bugs are discovered that you overlooked. Questionable design choices are picked apart. The worst part of all, your page's &lt;em&gt;Lighthouse Performance Score&lt;/em&gt; on anything but your own machine &lt;strong&gt;SUCKS&lt;/strong&gt;. It stings, but don't forget... you literally asked for this.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  What Went Wrong?
&lt;/h2&gt;

&lt;p&gt;Well, it turns out that the foundation of your website is made of some sort of radioactive &lt;small&gt;(React's logo is an atom, get it? Get it...?)&lt;/small&gt; elements. And such as irradiated things tend to do, a tumor had quietly begun to grow at the heart of your project. A nasty little bugger known as the &lt;code&gt;node_modules&lt;/code&gt; directory, and it was sapping the life out of your pride-and-joy.&lt;/p&gt;

&lt;p&gt;If you're not aware, React applications are based on the idea of building your project by cobbling together bits and pieces of open-source code in the form of modules to bring developer-friendly functionality to different things. While a well experienced and season development team will likely have found ways to mitigate the shortfalls inherent to this development style, it can quickly swallow a green solo-dev alive.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  The Ultimate Decision
&lt;/h2&gt;

&lt;p&gt;Bloodied and beaten by the constructive criticism you received, you crawl back into your development lair, dim the lights and take a good hard look at your &lt;del&gt;life&lt;/del&gt; code. A suggestion had been made to you by someone much more experienced in the field, and it has stuck in your mind.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Why even use React for a single-page portfolio... it's overkill. Do it all over again, but this time, just use HTML/CSS/JavaScript like the good-old-days.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;"React is cool though... I WAS PROMISED IT WAS THE FUTURE!™"&lt;/em&gt;&lt;/strong&gt;, you maniacally howl at the gray mid-winter sky.&lt;/p&gt;

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

&lt;p&gt;After sobbing yourself to sleep, you wake up the next morning and a decision has been made.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;TEAR IT DOWN.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next week or so is spent looking over notes taken from your original public showing (don't forget, constructive criticism is worthless if you don't utilize it!). The entire project needs to be re-written in the archaic, primitive language you haven't spoken in what feels like eons. So with the steadily thumping melodies of &lt;strong&gt;&lt;em&gt;Retrowave | Synthwave&lt;/em&gt;&lt;/strong&gt; radio in the background, you set to work, relearning the basics (and picking up a few new tricks along the way that never occurred to you before, since React took care of things behind the scenes for you).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Result
&lt;/h2&gt;

&lt;p&gt;You're exhausted. You're dehydrated. You haven't seen the sun in days... but it's complete. You take a tentative step back and prepare to gaze upon what now lies breathing on your Dr. Frankenstein's table, prepared to quickly avert your eyes from the horrors you're sure to find...&lt;/p&gt;

&lt;p&gt;You throw back the curtains...&lt;/p&gt;

&lt;p&gt;And...&lt;br&gt;
&lt;br&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
✧･ﾟ: &lt;em&gt;✧･ﾟ:&lt;/em&gt; &lt;strong&gt;I T ' S    A M A Z I N G&lt;/strong&gt; &lt;em&gt;:･ﾟ✧&lt;/em&gt;:･ﾟ✧&lt;/p&gt;

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

&lt;p&gt;Your music choice has clearly had a profound impact on the style choices this time round (in perhaps the best way possible). The buggy-ness inherent in your original project nearly eradicated, thanks to no longer needing to worry about a million &lt;code&gt;npm&lt;/code&gt; modules playing nicely together. The interface simplified and more intuitive. The layout, ironically, now properly reactive to different screen sizes. And The code base... &lt;/p&gt;

&lt;p&gt;Literally 10% the size of its React counterpart.&lt;/p&gt;

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

&lt;p&gt;Okay, okay. So you've made something that &lt;em&gt;looks&lt;/em&gt; better and is physically a fraction of the size... But how does that translate to metered performance...&lt;/p&gt;

&lt;p&gt;Well, I'll just let Chrome speak on that front.&lt;/p&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4bcjoan1qkvmwxuqxbc3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4bcjoan1qkvmwxuqxbc3.png" alt="react"&gt;&lt;/a&gt;&lt;br&gt;
After:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3o23vd6chzoy7hueoybo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3o23vd6chzoy7hueoybo.png" alt="html/css/javascript"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So my friends, as someone who is still deeply in love with the concept of React.js and the development and scalability advantages it provides, I can confidently tell you that it definitely has it's place in anyone's toolkit. However, that place does not appear to be a website as simple as a developer portfolio (even one who is actively pursuing work in this specific discipline)!&lt;/p&gt;

&lt;p&gt;If you currently use React for your own small-scale website, I strongly urge you to take a good hard look at your project, and consider cutting off the tumor before it grows too large and ends up killing you in the long run!&lt;/p&gt;

&lt;p&gt;Want to check out the differences first-hand?&lt;/p&gt;

&lt;p&gt;Here is the original:&lt;br&gt;
&lt;a href="https://zealous-nightingale-a86d4a.netlify.app/" rel="noopener noreferrer"&gt;React-based portfolio&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here is the new-and-improved:&lt;br&gt;
&lt;a href="https://jpuls.dev" rel="noopener noreferrer"&gt;Jeff Puls | Front End Developer&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Have you had a similar experience to my own? Want to crucify me for daring to speak out against the usage of THE FUTURE™ of web development?&lt;/p&gt;

&lt;p&gt;Let's talk about it in the comments below 🙂&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>portfolio</category>
      <category>react</category>
      <category>html</category>
    </item>
    <item>
      <title>I Need Your Critique to Become a Better Developer!</title>
      <dc:creator>Jeff Puls</dc:creator>
      <pubDate>Mon, 18 Jan 2021 18:01:20 +0000</pubDate>
      <link>https://forem.com/jpuls/i-need-your-critique-to-become-a-better-developer-269k</link>
      <guid>https://forem.com/jpuls/i-need-your-critique-to-become-a-better-developer-269k</guid>
      <description>&lt;h2&gt;
  
  
  Calling all web dev professionals and aficionados, I need your help!
&lt;/h2&gt;

&lt;p&gt;As anyone in the tech space who has gone the self-taught route can tell you, there are several times when you hit a mental brick wall on your journey. I have once again unfortunately found myself slamming face-first into this proverbial mental blockade, but this time I'm trying a different approach to getting over it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgifimage.net%2Fwp-content%2Fuploads%2F2017%2F09%2Fbanging-head-on-keyboard-gif-10.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgifimage.net%2Fwp-content%2Fuploads%2F2017%2F09%2Fbanging-head-on-keyboard-gif-10.gif" alt="bang head gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Being the only tech-minded one among my family and friends, I spend much of my time learning and processing things on my own. While as an introvert this seclusion can be nice, I've come to realize that it has severely crippled my opportunity to advance to the next stage in my quest for knowledge. For the past few years, I have very much had only myself &lt;small&gt;(with the exception of one semester with a very poor community college professor)&lt;/small&gt; to provide any sort of feedback on the work I have done up to this point.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Ask
&lt;/h2&gt;

&lt;p&gt;What I need from the wonderful &lt;strong&gt;&lt;em&gt;DEV&lt;/em&gt;&lt;/strong&gt; community is some constructive, creative criticism and critique of what I have done thus far. Without any outside review, I'm afraid I have no idea where my time is best spent improving. &lt;/p&gt;

&lt;p&gt;If you can spare a few moments, I would greatly appreciate anyone who is willing to take a look at my work from both an overall conceptual design standpoint, as well as a more technical "behind the scenes" perspective focusing on things like performance and code cleanliness. Am I doing something consistently right? Wrong? Absolutely unheard of?&lt;/p&gt;

&lt;p&gt;You can view the &lt;em&gt;major&lt;/em&gt; projects I've done / am currently working on at &lt;strong&gt;&lt;a href="https://jpuls.dev" rel="noopener noreferrer"&gt;my website&lt;/a&gt;&lt;/strong&gt;, as well as everything on &lt;strong&gt;&lt;a href="https://github.com/J-Puls" rel="noopener noreferrer"&gt;my GitHub&lt;/a&gt;&lt;/strong&gt;. &lt;small&gt;(Try to keep chronology in mind, as these things span back to the beginning of my journey.)&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Please leave any feedback you have &lt;small&gt;(positive or negative, I'm not looking for only sugarcoated praise, although that's always appreciated 😉)&lt;/small&gt; in the comments here, at the email listed on my GitHub, or through the contact form on my website.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.tinypulse.com%2Fhs-fs%2Fhubfs%2Fgiphy%2520%2836%29.gif%3Ft%3D1483196485084%26width%3D400%26name%3Dgiphy%2520%2836%29.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.tinypulse.com%2Fhs-fs%2Fhubfs%2Fgiphy%2520%2836%29.gif%3Ft%3D1483196485084%26width%3D400%26name%3Dgiphy%2520%2836%29.gif" alt="pretty please gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;em&gt;Help me DEV.to, you're my only hope!&lt;/em&gt;
&lt;/h4&gt;

</description>
      <category>mentalhealth</category>
      <category>discuss</category>
      <category>feedback</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Quick and Easy 2D Spatial Audio with Howler.js</title>
      <dc:creator>Jeff Puls</dc:creator>
      <pubDate>Mon, 11 Jan 2021 20:58:21 +0000</pubDate>
      <link>https://forem.com/jpuls/quick-and-easy-2d-spatial-audio-with-howler-js-4nih</link>
      <guid>https://forem.com/jpuls/quick-and-easy-2d-spatial-audio-with-howler-js-4nih</guid>
      <description>&lt;p&gt;Creating immersion within a web application is hard. Unless a lot of effort is put into the UI/UX design, these apps end up feeling very &lt;em&gt;flat&lt;/em&gt; and lifeless. As such, even the smallest feature that adds an organic touch can vastly improve the "feel" of the app.&lt;/p&gt;

&lt;p&gt;If your application is very audio-centric (a game for instance), one such feature you can easily add is spatial audio. Giving your sound effect an &lt;em&gt;origin&lt;/em&gt; within the application can make the whole thing feel &lt;strong&gt;bigger&lt;/strong&gt;. Let's take a quick look at how this can be achieved using a &lt;code&gt;JavaScript&lt;/code&gt; audio library called &lt;code&gt;Howler&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I won't go into details about how &lt;code&gt;Howler&lt;/code&gt; itself works, but you can read up on the subject in their docs &lt;a href="https://github.com/goldfire/howler.js#documentation" rel="noopener noreferrer"&gt;here.&lt;/a&gt; For now, all you need to know is that we use the &lt;code&gt;Howl&lt;/code&gt; constructor to instantiate a simple sound effect object, and that this object takes an optional parameter called &lt;code&gt;stereo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;stereo&lt;/code&gt; parameter accepts a number ranging anywhere between -1 and 1, which corresponds to the left/right channel bias for the stereo sound (-1 being full left, 1 being full right). For this example, we simply want to play a sound effect when the mouse is clicked, and we want it to &lt;em&gt;feel&lt;/em&gt; as though that sound originates from the cursor.&lt;/p&gt;

&lt;p&gt;Below is the basic setup for use in a &lt;code&gt;React&lt;/code&gt; component. This will play the specified sound effect normally whenever the mouse is clicked within the component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Howl&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;howler&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mySound&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./sounds/mySound.webm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// our fictitious audio file, replace this with whatever sound you want to play&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Howl&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mySound&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// instantiate a new Howl here, passing it the path to our sound effect&lt;/span&gt;
      &lt;span class="nx"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;play&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//  as soon as the object is created, we can play the sound effect&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//  once the component has been rendered and saved to a variable, add the EventListener&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//  if the component is removed, remove the EventListener&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;
      &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100vw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100vh&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="c1"&gt;//  adding the styling ensures that our component will cover the entire viewport&lt;/span&gt;
      &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="c1"&gt;// save the rendered element to a ref variable we can manipulate&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now, to figure out where the sound is &lt;em&gt;coming from&lt;/em&gt;, we need to do some simple calculations based on coordinates of the cursor in relation to the width of the component. We will do so by adding the following function to the top of the &lt;code&gt;useEffect&lt;/code&gt; callback.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getStereoBias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientWidth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// grab the component's width&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&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="nx"&gt;mouseX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// calculate a value of -1 to 1 based on the cursor position within the component&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;bias&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 finally, we will use this function whenever a sound effect is generated to tell &lt;code&gt;Howler&lt;/code&gt; where the sound is &lt;em&gt;coming from&lt;/em&gt; by modifying the &lt;code&gt;handleClick&lt;/code&gt; function as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stereoBias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getStereoBias&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientX&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//  calculate the "position" of the sound's origin&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Howl&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mySound&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;stereo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;stereoBias&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// instantiate a new Howl here, passing it the path to our sound effect and stereo bias "position"&lt;/span&gt;
    &lt;span class="nx"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;play&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;//  as soon as the object is created, we can play the sound effect&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And just like that, whenever our sound effect is played, it will follow the cursor around the screen (handy for things like particle effects in games)!&lt;/p&gt;

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

&lt;p&gt;To view a fleshed-out example of this concept in action, check out my &lt;a href="https://domain-destroyer-demo-95ini.ondigitalocean.app/" rel="noopener noreferrer"&gt;Domain Destroyer Demo&lt;/a&gt; project.&lt;/p&gt;

&lt;p&gt;If you make something cool like this, drop it in the comments, I'd love to see what you come up with!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>gamedev</category>
      <category>ux</category>
    </item>
    <item>
      <title>How to Destroy a Web Page - (Digital Ocean Hackathon Blog: Part 3 - Finale)</title>
      <dc:creator>Jeff Puls</dc:creator>
      <pubDate>Sat, 02 Jan 2021 19:48:45 +0000</pubDate>
      <link>https://forem.com/jpuls/how-to-destroy-a-web-page-digital-ocean-hackathon-blog-part-3-finale-5flj</link>
      <guid>https://forem.com/jpuls/how-to-destroy-a-web-page-digital-ocean-hackathon-blog-part-3-finale-5flj</guid>
      <description>&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;&lt;em&gt;domain-destroyer&lt;/em&gt;&lt;/strong&gt; &lt;code&gt;npm&lt;/code&gt; package and its accompanying React demo application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Category Submission:
&lt;/h3&gt;

&lt;p&gt;Random Roulette&lt;/p&gt;

&lt;h3&gt;
  
  
  App Link
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://domain-destroyer-demo-95ini.ondigitalocean.app/" rel="noopener noreferrer"&gt;https://domain-destroyer-demo-95ini.ondigitalocean.app/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

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

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

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

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

&lt;h3&gt;
  
  
  Description
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Welcome back to 1995!
&lt;/h4&gt;

&lt;p&gt;As anyone who was into computers throughout the 90s will know, there was one type of software commonplace in every household. Shareware games. There were free-to-play versions of everything from AAA blockbuster titles like the &lt;strong&gt;&lt;em&gt;Duke Nukem&lt;/em&gt;&lt;/strong&gt; series and (literal) hidden gems like &lt;strong&gt;&lt;em&gt;Crystal Caves&lt;/em&gt;&lt;/strong&gt;, to one-man-band side projects, all available free of charge. One such program that spread like wildfire in this time was &lt;strong&gt;&lt;em&gt;Desktop Destroyer&lt;/em&gt;&lt;/strong&gt; (which went by several pseudonyms, depending who you ask and from which region they resided).&lt;/p&gt;

&lt;p&gt;And so, I would like to introduce &lt;strong&gt;&lt;em&gt;domain-destroyer&lt;/em&gt;&lt;/strong&gt;, a (limited) clone of that iconic program, this time catering to stressed-out web devs who need to blow off some steam. Written in TypeScript, and available for hassle-free inclusion with &lt;code&gt;Node&lt;/code&gt; based projects via &lt;code&gt;npm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In addition to the development of the &lt;code&gt;npm&lt;/code&gt; package itself which contains the core game logic, assets, and mechanics, I developed an accompanying demo application utilizing React to showcase the game in all its intended nostalgic glory.&lt;/p&gt;

&lt;p&gt;Brandishing 3 of the original 8 (well, 9 if you count the "washing" tool) implements of destruction, use your mouse to mercilessly inflict damage to the web page before you! Personal project got you stressed out? Quickly implement the &lt;code&gt;npm&lt;/code&gt; package and smash it to smithereens with the &lt;em&gt;Hammer&lt;/em&gt;, blast it to bits with the &lt;em&gt;Machine Gun&lt;/em&gt;, or decimate it with the defacing powers of the giant &lt;em&gt;Stamp&lt;/em&gt;. You'll feel better in no time, I promise!&lt;/p&gt;

&lt;h4&gt;
  
  
  Hotkeys:
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;key&lt;/th&gt;
&lt;th&gt;function&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mouse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;fire weapon&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1 key&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;hammer&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;2 key&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;machine gun&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3 key&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;stamp&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;c key&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;clear screen&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;- key&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;previous weapon&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;= key&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;next weapon&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;; key&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;volume down&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;' key&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;volume up&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Link to Source Code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/J-Puls/domain-destroyer" rel="noopener noreferrer"&gt;domain-destroyer source code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/J-Puls/domain-destroyer-demo" rel="noopener noreferrer"&gt;demo application source code&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Permissive License
&lt;/h3&gt;

&lt;p&gt;MIT License&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;I wanted to build something unique from the sea of &lt;em&gt;TODO List&lt;/em&gt; apps and recycled &lt;em&gt;Web Dev Bootcamp&lt;/em&gt; blogs that will no doubt be present. In addition, and in light of what an absolute horror-show stress-fest that 2020 was for nearly everyone (myself included), I figured I would take this opportunity to harken back to simpler times, if only for a fleeting moment. What better way I thought, than with a game that lets you literally take out your aggressions, while hitting you with a wave of nostalgia for those rose-tinted glory days at the same time.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I built it
&lt;/h3&gt;

&lt;p&gt;The core &lt;strong&gt;&lt;em&gt;domain-destroyer&lt;/em&gt;&lt;/strong&gt; package was written from scratch in TypeScript, and made publicly available via &lt;code&gt;npm&lt;/code&gt; &lt;a href="https://www.npmjs.com/package/domain-destroyer" rel="noopener noreferrer"&gt;here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The demo application was created utilizing React and is hosted via the Digital Ocean App Platform. The process of importing the React application via GitHub could not have been more straight-forward.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources/Info
&lt;/h3&gt;

&lt;p&gt;I would like to give credit to the developer of the original &lt;strong&gt;&lt;em&gt;Desktop Destroyer&lt;/em&gt;&lt;/strong&gt; game, Miroslav Němeček (and any others involved, this being the only name I could find in direct association). &lt;/p&gt;

&lt;p&gt;The spatial audio effect was achieved using &lt;a href="https://howlerjs.com/" rel="noopener noreferrer"&gt;Howler.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you love this project, and would like to help improve it (sadly I wasn't able to implement all the weapons/features from the original that I had intended), please feel free to fork the repositories and make it happen!&lt;/p&gt;

</description>
      <category>dohackathon</category>
      <category>gamedev</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Making Animated Sprites Interactive with JavaScript! -  (Digital Ocean Hackathon Blog: Part 2)</title>
      <dc:creator>Jeff Puls</dc:creator>
      <pubDate>Thu, 31 Dec 2020 20:25:08 +0000</pubDate>
      <link>https://forem.com/jpuls/making-animated-sprites-interactive-with-javascript-digital-ocean-hackathon-blog-part-2-4fhb</link>
      <guid>https://forem.com/jpuls/making-animated-sprites-interactive-with-javascript-digital-ocean-hackathon-blog-part-2-4fhb</guid>
      <description>&lt;p&gt;If you haven't yet read my &lt;a href="https://dev.to/jpuls/simple-sprite-animations-for-games-on-the-web-digitalocean-hackathon-blog-part-1-ndb"&gt;previous post&lt;/a&gt; in this series, I would highly recommend doing so before you continue with this post, things will make a lot more sense!&lt;/p&gt;

&lt;p&gt;So, if all has gone according to plan, we now have our &lt;em&gt;Link&lt;/em&gt; sprite marching bravely in place in the center of the screen. 10/10 graphics, but it falls short in the gameplay category. Luckily, interacting with our hero is only a couple HTML/CSS tweaks and a JavaScript file away!&lt;/p&gt;

&lt;p&gt;Below are the new sprite sheets I will be using in this project, feel free to save them to your project directory and code along!&lt;/p&gt;

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

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

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

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

&lt;h2&gt;
  
  
  Modifying the HTML/CSS
&lt;/h2&gt;

&lt;p&gt;Okay, we will start off super simple with a couple of tweaks to our original HTML file. In order to keep our spritely friend from wandering off screen, let's give him some boundaries.&lt;/p&gt;

&lt;p&gt;To do this, simply wrap the &lt;code&gt;sprite-view-frame&lt;/code&gt; div element with another div, this one with a class of &lt;code&gt;container&lt;/code&gt;. The body of your HTML should now look as such.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sprite-view-frame"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sprite-renderer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That will do it for the HTML, now to change some things around in the CSS. &lt;/p&gt;

&lt;p&gt;Let's begin with introducing a few new variables under &lt;code&gt;:root&lt;/code&gt;. These are &lt;code&gt;--sprite-top&lt;/code&gt;, &lt;code&gt;--sprite-left&lt;/code&gt; and &lt;code&gt;--sprite-sheet-url&lt;/code&gt;. The names of which should be a pretty obvious giveaway as to their purpose. Make sure your code looks like the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--sprite-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;64px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--sprite-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;64px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--sprites&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--animation-length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c"&gt;/* these are the values that we will modify via JavaScript to interact with the sprite */&lt;/span&gt;
  &lt;span class="py"&gt;--sprite-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--sprite-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--sprite-sheet-url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("./link-spritesheet-down.png")&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;Next, let's style our new &lt;code&gt;container&lt;/code&gt; element. Make special note that it purposely does not fill the entire width of the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;90%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;90%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5%&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;After that, we need to make a slight modification to the &lt;code&gt;sprite-renderer&lt;/code&gt;. Here, we will replace the hard-coded &lt;code&gt;background-image&lt;/code&gt; with the variable we set in &lt;code&gt;:root&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt; &lt;span class="nt"&gt;background-image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;var&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;--sprite-sheet-url&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c"&gt;/* the sprite sheet */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, move the animation property to a new selector, this time only being active when the &lt;code&gt;sprite-renderer&lt;/code&gt; also has a class of &lt;code&gt;.animating&lt;/code&gt;;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* the sprite will only animate when the 'animating' class has been set */&lt;/span&gt;
&lt;span class="nc"&gt;.sprite-renderer.animating&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;animateSprites&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--animation-length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;infinite&lt;/span&gt;
    &lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--sprites&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;One last modification to note is the addition of a short &lt;code&gt;transition-duration&lt;/code&gt; to the &lt;code&gt;sprite-view-frame&lt;/code&gt;. This will help smooth out the movement of the sprite across the screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;transition-duration&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;05&lt;/span&gt;&lt;span class="nt"&gt;s&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* adding a short duration here will smooth out the animation when moving the sprite */&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;That wraps up the modifications to the HTML/CSS!&lt;/p&gt;

&lt;h2&gt;
  
  
  Making it interactive with JavaScript
&lt;/h2&gt;

&lt;p&gt;Alright, we made it to the meat-and-potatoes of the post once again! It's finally time to take this animation and turn it into an interactive "game" (I use that term very lightly here).&lt;/p&gt;

&lt;p&gt;&lt;small&gt;It will be assumed here that you have working knowledge of basic vanilla JavaScript&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;After creating a &lt;code&gt;script.js&lt;/code&gt; file in your project directory, we need to start with setting up some variables. We need to gain access to our &lt;code&gt;container&lt;/code&gt; element, as this will be our &lt;code&gt;:root&lt;/code&gt; in CSS. We also need to be able to modify the &lt;code&gt;classList&lt;/code&gt; of the &lt;code&gt;sprite-renderer&lt;/code&gt; element, so we will grab that too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// grab our elements to be modified&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spriteRenderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.sprite-renderer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let's set some variables to track where our sprite is positioned within the &lt;code&gt;container&lt;/code&gt;. For this, we will use three built-in functions &lt;code&gt;parseInt()&lt;/code&gt;, &lt;code&gt;getComputedStyle()&lt;/code&gt; and &lt;code&gt;getPropertyValue()&lt;/code&gt; to get the numerical value of our initial &lt;code&gt;--sprite-top&lt;/code&gt; and &lt;code&gt;--sprite-left&lt;/code&gt; CSS variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// grab the initial values where we placed the sprite in CSS&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;spriteTop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;getComputedStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getPropertyValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--sprite-top&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;spriteLeft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;getComputedStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getPropertyValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--sprite-left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last variable we need to track is the direction our friend &lt;em&gt;Link&lt;/em&gt; is facing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;spriteDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;down&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// set an initial direction for the character to face&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make &lt;em&gt;Link&lt;/em&gt; react to the standard W A S D movement keys, let's add a &lt;code&gt;keydown&lt;/code&gt; listener to the &lt;code&gt;document&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keydown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The following code will be within the callback function of the &lt;code&gt;EventListener&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a key is pressed, we want to begin by checking if that key is one of our desired directional keys. If not, we ignore the keypress, this saves on computation resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// the following code will only run if we have pressed one of our directional keys&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;w&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the key pressed is valid, we move to a switch block to decide what variables need to be changed, depending on the intended direction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// set up directional keys for moving the sprite (w, a, s, d)&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;w&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;spriteDirection&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;up&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;spriteDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;up&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// change direction if not already facing up&lt;/span&gt;
      &lt;span class="nx"&gt;spriteTop&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="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spriteTop&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// move the character up if not at the edge&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;s&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;spriteDirection&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;down&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;spriteDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;down&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// change direction if not already facing down&lt;/span&gt;
      &lt;span class="nx"&gt;spriteTop&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;100&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="nx"&gt;spriteTop&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// move the character down if not at the edge&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;spriteDirection&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;spriteDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// change direction if not already facing left&lt;/span&gt;
      &lt;span class="nx"&gt;spriteLeft&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="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spriteLeft&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// move the character left if not at the edge&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;spriteDirection&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;right&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;spriteDirection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;right&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// change direction if not already facing right&lt;/span&gt;
      &lt;span class="nx"&gt;spriteLeft&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;100&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="nx"&gt;spriteLeft&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// move the character right if not at the edge&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;break&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;Next, we will tell the CSS which sprite sheet it should be using (note that we need to set the entire &lt;code&gt;url()&lt;/code&gt; string here due to the way CSS parses variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--sprite-sheet-url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;`url(./link-spritesheet-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;spriteDirection&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.png)`&lt;/span&gt; &lt;span class="c1"&gt;// tell the CSS what sprite sheet to use based on direction&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With our sprite now facing the correct direction, we'll let the CSS know to start animating the sprite.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;spriteRenderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;animating&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// tell the CSS that we want to animate the sprite&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last but not least, we will tell the CSS to move the sprite to the new coordinates calculated in the &lt;code&gt;switch&lt;/code&gt; statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// move our sprite to the new coordinates&lt;/span&gt;
  &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--sprite-top&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;spriteTop&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--sprite-left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;spriteLeft&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The finish line is in sight! Just one more piece of JavaScript to take care of. This time, we just need to tell the CSS to stop animating the sprite when we release the key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keyup&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;spriteRenderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;animating&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// when the key is released, stop animating the sprite sheet&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  WHEW!
&lt;/h3&gt;

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

&lt;p&gt;If all has gone according to plan, you should now be able to make &lt;em&gt;Link&lt;/em&gt; walk in all 4 directions across the screen! How's that for gameplay!? (I told you I was using "game" very lightly here 😂)&lt;/p&gt;

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

&lt;p&gt;In the third and final post to this series, I will be introducing what I have created with all of these concepts for the &lt;strong&gt;Digital Ocean Hackathon&lt;/strong&gt;. (Spoiler alert: if you were a kid growing up in the 90s with access to a computer running Windows 3.1 or higher, there's a good chance you've played this before!)&lt;/p&gt;

&lt;h2&gt;
  
  
  Stay Tuned!
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;DISCLAIMER:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;I did not create, nor do I own any of the pixel art depicted in this post, I simply edited it such that it meets the requirements for this project. Credit for the sprites used goes to &lt;a href="https://retrogamezone.co.uk/" rel="noopener noreferrer"&gt;RetroGameZone&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>animation</category>
      <category>gamedev</category>
      <category>javascript</category>
      <category>css</category>
    </item>
    <item>
      <title>Simple Sprite Animations for Games on The Web - (Digital Ocean Hackathon Blog: Part 1)</title>
      <dc:creator>Jeff Puls</dc:creator>
      <pubDate>Wed, 30 Dec 2020 22:28:56 +0000</pubDate>
      <link>https://forem.com/jpuls/simple-sprite-animations-for-games-on-the-web-digitalocean-hackathon-blog-part-1-ndb</link>
      <guid>https://forem.com/jpuls/simple-sprite-animations-for-games-on-the-web-digitalocean-hackathon-blog-part-1-ndb</guid>
      <description>&lt;p&gt;One of the greatest advantages to building applications for the web is the low barrier to entry when it comes to easy, yet powerful graphics and animation.&lt;/p&gt;

&lt;p&gt;It's no secret, &lt;strong&gt;HTML&lt;/strong&gt; and &lt;strong&gt;CSS&lt;/strong&gt; make up the backbone of everything you see and interact with on the Web. Once you add a splash of JavaScript, you can have your own fully-featured application, able to be used by anyone all over the world. What goes great with simple, powerful graphics and an intuitive programming language? Video games, naturally!&lt;/p&gt;

&lt;p&gt;&lt;small&gt;(a quick preface here, I don't want you to expect to crank out the next Call of Duty in your web browser after reading this series of tutorials, but something akin to a basic NES-style game? Sure, why not!)&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;If you don't care about the background and want to get to the meat-and-potatoes of this post, skip to this section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background: The Humble Sprite
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is a sprite anyways?
&lt;/h3&gt;

&lt;p&gt;There are two basic categories when it comes to video game graphics: &lt;strong&gt;2D&lt;/strong&gt; and &lt;strong&gt;3D&lt;/strong&gt;. This post focuses on the prior, as it is the quickest and easiest to get going without needing any additional libraries, software, or prior graphics knowledge.&lt;/p&gt;

&lt;p&gt;The most basic method of creating graphics and the illusion of motion for 2D games is by implementing a special set of images, known as sprites. At the core, a sprite is just an image which can be used to represent an entire object, or cleverly combined with other sprites as part of a larger whole. In the olden days of video game development, this was the go-to method for rendering graphics before 3D graphics tech had matured.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.gifer.com%2FXz1C.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.gifer.com%2FXz1C.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A sprite can be anything you want. Something as simple as a single-pixel square can represent the flying ball in Pong, or an elaborately illustrated character of your own design, the limits are only that of your own imagination. &lt;/p&gt;

&lt;h3&gt;
  
  
  How does sprite animation work?
&lt;/h3&gt;

&lt;p&gt;We humans like to believe that we are super intelligent beings, that nothing can fool us. In reality, that couldn't be farther from the truth, especially when it comes to how we process visual information. If we view a series of similar images displayed in rapid succession, our brains have a hard time deciphering what is going on, and simply assumes it is the same object, just moving.&lt;/p&gt;

&lt;p&gt;Sprite animation exploits this phenomenon at the most basic of levels. Typically, sprites for similar objects are all combined into one, larger image known as a sprite sheet, each individual sprite can be thought of as individual frames of a video. All the computer has to do to trick our meager caveman brains is to rapidly switch which part of the sprite sheet is displayed. Done right, we think we see our game's hero bravely marching into battle for instance, when in reality, its just the same two images being rapidly flipped back-and-forth.&lt;/p&gt;

&lt;p&gt;For the purposes of this post, I am going to limit the examples to 8-frame, single-row sprite sheet examples, however you can in theory use as many frames as you'd like!&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Here is a very simple example of how the walking animation for &lt;em&gt;Link&lt;/em&gt; from &lt;em&gt;The Legend of Zelda&lt;/em&gt; on the NES works. Note how there are two distinct frames side-by-side in one image, this is the sprite sheet. (If you're coding along, you can save the sprite sheet PNG below to the same directory as your HTML and CSS files).&lt;/p&gt;

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

&lt;p&gt;By rapidly switching between sprites, you get the basic walking animation!&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Getting set up
&lt;/h2&gt;

&lt;p&gt;&lt;a id="meat-and-taters"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The HTML
&lt;/h3&gt;

&lt;p&gt;This post assumes that you possess a basic working knowledge of HTML/CSS, although if not, the concepts here should be pretty easy to follow.&lt;/p&gt;

&lt;p&gt;We will begin with the basic HTML5 boilerplate, with the inclusion of a &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag to our CSS and &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag to a JavaScript file that we will create in the next part of this series:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"styles.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Sprite Animation Demo&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
The following elements will all be included within the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; of the document, before the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sprite-view-frame"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sprite-renderer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
Here, you can imagine the &lt;code&gt;sprite-view-frame&lt;/code&gt; as a picture frame that crops the visible portion of the image (a single sprite). The &lt;code&gt;sprite-renderer&lt;/code&gt; will be the element that holds the entire full-size sprite sheet. &lt;/p&gt;

&lt;p&gt;That's it for the HTML... no, really!&lt;/p&gt;
&lt;h3&gt;
  
  
  The CSS
&lt;/h3&gt;

&lt;p&gt;Animating sprites in this manner only requires some very basic CSS properties to be set, I will explain what is necessary and why below. Begin by creating a &lt;code&gt;styles.css&lt;/code&gt; file in the same directory as your HTML file. The sprite sheet we will be using in this example contains two 32px by 32px sprites, giving us total dimensions of 64px by 32px.&lt;/p&gt;

&lt;p&gt;First, lets set some basic properties to make the body a bit nicer to look at.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#222222&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* this allows us to center the sprite-view-frame on the page */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can set some CSS variables to keep our code DRY later in the project. Simply adjust these values based on the sprite sheet in use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--sprite-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--sprite-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--sprites&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--animation-length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;.5s&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;Next, we will style the &lt;code&gt;sprite-view-frame&lt;/code&gt; element. Note that the &lt;code&gt;position&lt;/code&gt;, &lt;code&gt;top&lt;/code&gt;, &lt;code&gt;left&lt;/code&gt;, and &lt;code&gt;transform&lt;/code&gt; properties will become more important later when we make our sprites interactive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.sprite-view-frame&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--sprite-width&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--sprite-height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* this will hide any sprites outside of the frame*/&lt;/span&gt;

  &lt;span class="c"&gt;/* position the view frame on the page */&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translate3d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-50%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;-50%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c"&gt;/* ********************************** */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After we have a frame to display the sprites, we can style the &lt;code&gt;sprite-renderer&lt;/code&gt; element itself, which will be used to display and animate the sprite sheet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.sprite-renderer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--sprite-width&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--sprite-height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("./link-spritesheet-1.png")&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* the sprite sheet */&lt;/span&gt;
  &lt;span class="nl"&gt;background-repeat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;no-repeat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c"&gt;/* this prevents the browser from aliasing our pixel art image and making it blurry */&lt;/span&gt;
  &lt;span class="nl"&gt;-ms-interpolation-mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nearest-neighbor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="nl"&gt;image-rendering&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;-webkit-optimize-contrast&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;image-rendering&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;-moz-crisp-edges&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;image-rendering&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;-o-pixelated&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;image-rendering&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pixelated&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c"&gt;/* this is where the magic happens! */&lt;/span&gt;
   &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;animateSprites&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--animation-length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;infinite&lt;/span&gt; &lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--sprites&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;Finally, the most important part: the animation itself!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;animateSprites&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background-position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nl"&gt;background-position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--sprite-width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--sprites&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basically, all our CSS needs to do is rapidly shift the background image of the &lt;code&gt;sprite-renderer&lt;/code&gt; to display each sprite. The initial state of the animation will bring the first sprite (on the left) into view. Then, it will shift the image to the left by the total width of the sprite sheet, thus displaying the last sprite (on the right).&lt;/p&gt;

&lt;p&gt;Here is a breakdown of what the &lt;code&gt;animation&lt;/code&gt; property within &lt;code&gt;.sprite-renderer&lt;/code&gt; is doing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;animation

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;animateSprites&lt;/code&gt;&lt;/strong&gt; | the name of the keyframes we defined&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;var(--animation-length)&lt;/code&gt;&lt;/strong&gt; | the entire animation lasts .5 seconds, or .25 per frame&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;infinite&lt;/code&gt;&lt;/strong&gt; | the animation will loop forever&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;steps(var(--sprites))&lt;/code&gt;&lt;/strong&gt; | &lt;strong&gt;This is the most important part!&lt;/strong&gt; This tells CSS that for each sprite, render that stage of the animation as a distinct frame, rather than interpolating between start and end states.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  That's it!
&lt;/h3&gt;

&lt;p&gt;If you open your HTML file in the browser, you should now have an animated &lt;em&gt;Link&lt;/em&gt; marching in place on your screen.&lt;/p&gt;

&lt;p&gt;The process for creating more detailed, higher frame rate sprite animations is largely the same. The only differences you need to account for in the CSS are the variables &lt;code&gt;--sprite-width&lt;/code&gt;, &lt;code&gt;--sprite-height&lt;/code&gt;, &lt;code&gt;--sprites&lt;/code&gt; and optionally &lt;code&gt;--animation-length&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Below is an example of an 8-frame sprite sheet, again featuring our friend &lt;em&gt;Link&lt;/em&gt;, this time from &lt;em&gt;A Link to the Past&lt;/em&gt; on the SNES. This sprite sheet is a bit larger than our previous example, featuring eight 64px by 64px sprites, for total dimensions of 512px by 64px:&lt;/p&gt;

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

&lt;p&gt;We need only to tweak the CSS as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--sprite-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;64px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--sprite-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;64px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--sprites&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--animation-length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;.8s&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;And when animated, you get this!&lt;/p&gt;

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

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

&lt;p&gt;You now possess the knowledge needed to animate your very own sprites, using some very basic HTML and CSS!&lt;/p&gt;

&lt;p&gt;In my following post, we will dive into the code behind making your characters interactive with JavaScript!&lt;/p&gt;

&lt;h3&gt;
  
  
  Stay tuned!
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;DISCLAIMER:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;I did not create, nor do I own any of the pixel art depicted in this post, I simply edited it such that it meets the requirements for this project. Credit for the sprites used goes to &lt;a href="https://retrogamezone.co.uk/" rel="noopener noreferrer"&gt;RetroGameZone&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>animation</category>
      <category>gamedev</category>
      <category>css</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
