<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Arelvox</title>
    <description>The latest articles on DEV Community by Arelvox (@arelvox).</description>
    <link>https://dev.to/arelvox</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4204802%2F2cf0d6f8-6ca7-4313-942b-d5126ea91231.png</url>
      <title>DEV Community: Arelvox</title>
      <link>https://dev.to/arelvox</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arelvox"/>
    <language>en</language>
    <item>
      <title>I Built a One-Tap Stacking Game in Vanilla JS: The Tiny Details That Make It Addictive</title>
      <dc:creator>Arelvox</dc:creator>
      <pubDate>Sun, 25 Oct 2026 02:21:52 +0000</pubDate>
      <link>https://dev.to/arelvox/i-built-a-one-tap-stacking-game-in-vanilla-js-the-tiny-details-that-make-it-addictive-1jpi</link>
      <guid>https://dev.to/arelvox/i-built-a-one-tap-stacking-game-in-vanilla-js-the-tiny-details-that-make-it-addictive-1jpi</guid>
      <description>&lt;p&gt;&lt;a href="https://arelvox.com/sky-stack/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frtqdxl70jhybarmlr4se.jpg" alt="Sky Stack, a one-tap stacking game" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One-tap games look trivial. You tap, a block drops, done. But when I built &lt;strong&gt;Sky Stack&lt;/strong&gt;, a small stacking game in plain JavaScript and canvas, the fun turned out to depend on a few tiny decisions. Here is how it works and what made it feel good to play.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Play it first (30 seconds):&lt;/strong&gt; &lt;a href="https://arelvox.com/sky-stack/" rel="noopener noreferrer"&gt;arelvox.com/sky-stack&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The whole game in one idea
&lt;/h2&gt;

&lt;p&gt;The tower is an array of blocks, and each block is only an &lt;code&gt;x&lt;/code&gt; position and a width:&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;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;}];&lt;/span&gt;     &lt;span class="c1"&gt;// the base&lt;/span&gt;
&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cur&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;     &lt;span class="c1"&gt;// the block sliding across the screen&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every frame the current block moves left or right and bounces at the edges. When you tap, you compare it with the top of the tower.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core: intersecting two ranges
&lt;/h2&gt;

&lt;p&gt;Dropping a block is just the overlap of two 1D ranges:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;topBlock&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;overlap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;overlap&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;gameOver&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// missed the tower completely&lt;/span&gt;

  &lt;span class="c1"&gt;// the part that hangs over the edge becomes a falling piece&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cutX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;falls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cutX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;c&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="nx"&gt;overlap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;yOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;vy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;overlap&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nf"&gt;nextBlock&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;That is the entire game logic. Everything else is about feel.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. A "perfect" zone that forgives you
&lt;/h2&gt;

&lt;p&gt;Pixel-perfect drops are almost impossible on a phone, so anything within &lt;strong&gt;5 pixels&lt;/strong&gt; counts as perfect. A perfect drop cuts nothing off:&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;if &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;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;combo&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;grow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;combo&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// reward streaks&lt;/span&gt;
  &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;grow&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="na"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;t&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="nx"&gt;grow&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 &lt;code&gt;grow&lt;/code&gt; line matters most. In most stacking games your tower only shrinks, so every run feels like a slow loss. Here, from the third perfect drop in a row, the block &lt;strong&gt;grows back&lt;/strong&gt; a little. Suddenly a bad drop is something you can recover from, and that is what makes people tap "play again".&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Sound that climbs with your combo
&lt;/h2&gt;

&lt;p&gt;No audio files, just the Web Audio API. Each perfect drop plays a note one step higher than the last:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;tone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;freq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dur&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createOscillator&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createGain&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;triangle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;frequency&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;freq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValueAtTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exponentialRampToValueAtTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dur&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dur&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;tone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;440&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.122&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;combo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mf"&gt;0.18&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// roughly one whole tone per step&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You &lt;em&gt;hear&lt;/em&gt; your streak building before you look at the score. On a miss, a dull low note plays and the pitch resets. It costs about ten lines and changes the game a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Juice: falling pieces, particles, a little shake
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The piece you cut off keeps falling and rotating instead of disappearing.&lt;/li&gt;
&lt;li&gt;A perfect drop throws white particles from the edges.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;navigator.vibrate(15)&lt;/code&gt; gives a tiny buzz on phones that support it.&lt;/li&gt;
&lt;li&gt;The camera eases upward as the tower grows, so you never see a hard jump.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this changes the rules, but without it the game felt dead in testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. A restart bug I almost shipped
&lt;/h2&gt;

&lt;p&gt;The first version had a nasty bug: the tap that &lt;em&gt;ended&lt;/em&gt; the game also counted as a tap on the "play again" overlay, so a new run started instantly and players never saw their score. The fix was to keep the two states strictly apart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onTap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;playing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;over&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="c1"&gt;// ignore taps while the game-over screen is up&lt;/span&gt;
  &lt;span class="nf"&gt;drop&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 overlay has its own handler that only restarts once the game is really over. Keyboard Space and Enter only restart when the overlay is visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. It has to fit anywhere
&lt;/h2&gt;

&lt;p&gt;The game is a single self-contained block of HTML, CSS and JS. No framework, no build step, no external requests. It runs inside a WordPress "Custom HTML" block. One tip if you ever do the same: WordPress can mangle &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; inside inline scripts, so the code uses ternaries instead. Annoying, but it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it and beat my score
&lt;/h2&gt;

&lt;p&gt;Drop your best score in the comments. Anything over 50 is already good, and 100+ means your timing is seriously sharp.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://arelvox.com/sky-stack/" rel="noopener noreferrer"&gt;Play Sky Stack →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you like small browser games, there are a few more on the same site: a daily number puzzle with a &lt;a href="https://arelvox.com/crack-the-code/" rel="noopener noreferrer"&gt;Time Attack mode&lt;/a&gt; and a &lt;a href="https://arelvox.com/bug-hunt-typing-game/" rel="noopener noreferrer"&gt;typing game with boss bugs&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>gamedev</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How to Calculate Subnets by Hand: A Step-by-Step Guide</title>
      <dc:creator>Arelvox</dc:creator>
      <pubDate>Sat, 24 Oct 2026 19:40:57 +0000</pubDate>
      <link>https://dev.to/arelvox/how-to-calculate-subnets-by-hand-a-step-by-step-guide-3eh8</link>
      <guid>https://dev.to/arelvox/how-to-calculate-subnets-by-hand-a-step-by-step-guide-3eh8</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://arelvox.com/how-to-calculate-subnets/" rel="noopener noreferrer"&gt;Arelvox&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Knowing how to calculate subnets is one of the most useful networking skills you can learn. It comes up in certification exams, in home labs and whenever you plan a network for an office. The good news is that you do not need complex binary math. With one simple trick, you can find the network address, broadcast address and host range of any IPv4 address in under a minute.&lt;/p&gt;

&lt;p&gt;In this guide you will learn how to calculate subnets by hand, step by step, with real examples. When you finish, you can check every answer with our free &lt;a href="https://arelvox.com/subnet-calculator/" rel="noopener noreferrer"&gt;subnet calculator&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhgh0xme4bkb9uzfar6gb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhgh0xme4bkb9uzfar6gb.png" alt="How to calculate subnets by hand: network, broadcast and host range for 192.168.10.75/26" width="799" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Need to Know First
&lt;/h2&gt;

&lt;p&gt;Before you learn how to calculate subnets, you only need a few basic ideas. Every IPv4 address has 32 bits, split into four groups of 8 bits called octets. A subnet mask, or a prefix like /24, tells you how many of those bits belong to the network. The remaining bits identify individual devices, called hosts.&lt;/p&gt;

&lt;p&gt;For example, in 192.168.1.10/24 the first 24 bits are the network part and the last 8 bits are the host part. If these ideas are new to you, first read our guide to &lt;a href="https://arelvox.com/the-ultimate-guide-to-your-home-network-ips-routers-and-dns/" rel="noopener noreferrer"&gt;IP addresses, routers and DNS&lt;/a&gt;, and then come back here.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prefix&lt;/th&gt;
&lt;th&gt;Subnet mask&lt;/th&gt;
&lt;th&gt;Block size&lt;/th&gt;
&lt;th&gt;Usable hosts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;/24&lt;/td&gt;
&lt;td&gt;255.255.255.0&lt;/td&gt;
&lt;td&gt;256&lt;/td&gt;
&lt;td&gt;254&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/25&lt;/td&gt;
&lt;td&gt;255.255.255.128&lt;/td&gt;
&lt;td&gt;128&lt;/td&gt;
&lt;td&gt;126&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/26&lt;/td&gt;
&lt;td&gt;255.255.255.192&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;td&gt;62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/27&lt;/td&gt;
&lt;td&gt;255.255.255.224&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/28&lt;/td&gt;
&lt;td&gt;255.255.255.240&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/29&lt;/td&gt;
&lt;td&gt;255.255.255.248&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/30&lt;/td&gt;
&lt;td&gt;255.255.255.252&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Magic Number Method
&lt;/h2&gt;

&lt;p&gt;The fastest way to calculate subnets by hand is the &lt;strong&gt;magic number&lt;/strong&gt;, also called the block size. Subnets always start at multiples of this number, so once you know it, everything else falls into place.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find the &lt;strong&gt;interesting octet&lt;/strong&gt;: the first octet of the mask that is not 255.&lt;/li&gt;
&lt;li&gt;Calculate the magic number: &lt;strong&gt;256 minus the mask value&lt;/strong&gt; in that octet.&lt;/li&gt;
&lt;li&gt;List the multiples of the magic number. The &lt;strong&gt;network address&lt;/strong&gt; is the multiple that is equal to or just below your IP.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;broadcast address&lt;/strong&gt; is the next multiple minus one.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;usable hosts&lt;/strong&gt; are everything between the network and broadcast addresses.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Example 1: 192.168.10.75/26
&lt;/h2&gt;

&lt;p&gt;Let us see how to calculate subnets with a common exam question. First, convert /26 into a mask: 255.255.255.192. The interesting octet is the fourth one, because it is the first that is not 255.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Magic number: 256 − 192 = &lt;strong&gt;64&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Multiples of 64: 0, 64, 128, 192. Our IP ends in 75, so it sits between 64 and 128.&lt;/li&gt;
&lt;li&gt;Network address: &lt;strong&gt;192.168.10.64&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Broadcast address: 128 − 1 = &lt;strong&gt;192.168.10.127&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Usable host range: &lt;strong&gt;192.168.10.65 to 192.168.10.126&lt;/strong&gt;, which is 62 hosts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the whole calculation. As a result, you can solve most subnetting questions without writing a single binary number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 2: 172.16.45.200/20
&lt;/h2&gt;

&lt;p&gt;This second example shows how to calculate subnets when the interesting octet is not the last one. A /20 prefix gives the mask 255.255.240.0, so this time the interesting octet is the third.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Magic number: 256 − 240 = &lt;strong&gt;16&lt;/strong&gt;, applied to the third octet.&lt;/li&gt;
&lt;li&gt;Multiples of 16: 0, 16, 32, 48. The third octet is 45, so it falls between 32 and 48.&lt;/li&gt;
&lt;li&gt;Network address: &lt;strong&gt;172.16.32.0&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Broadcast address: &lt;strong&gt;172.16.47.255&lt;/strong&gt;, because the fourth octet is all ones.&lt;/li&gt;
&lt;li&gt;Usable hosts: 172.16.32.1 to 172.16.47.254, or 4,094 addresses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice that the fourth octet is 0 for the network and 255 for the broadcast. This happens whenever the interesting octet is not the last one.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Split a Network into Subnets
&lt;/h2&gt;

&lt;p&gt;Knowing how to calculate subnets also lets you do the opposite: take one network and divide it into smaller ones. To do that, you borrow host bits. Each borrowed bit doubles the number of subnets and halves their size.&lt;/p&gt;

&lt;p&gt;For example, to split 192.168.1.0/24 into four subnets, you borrow 2 bits, because 2² = 4. The new prefix is /26, with a magic number of 64:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192.168.1.0/26     hosts .1   to .62
192.168.1.64/26    hosts .65  to .126
192.168.1.128/26   hosts .129 to .190
192.168.1.192/26   hosts .193 to .254
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similarly, if you start from the number of hosts you need, choose the smallest subnet that fits. Remember that you lose two addresses in every subnet, one for the network and one for the broadcast. For 50 devices you need a /26 (62 usable hosts), and for 500 devices you need a /23 (510 usable hosts).&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes When You Calculate Subnets
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting the two reserved addresses.&lt;/strong&gt; A /26 has 64 addresses but only 62 usable hosts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using the wrong octet.&lt;/strong&gt; Always apply the magic number to the first octet of the mask that is not 255.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mixing up the broadcast address.&lt;/strong&gt; It is the next network address minus one, not the next network itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ignoring the special cases.&lt;/strong&gt; A /31 is used for point-to-point links and has two usable addresses, as described in &lt;a href="https://datatracker.ietf.org/doc/html/rfc3021" rel="noopener noreferrer"&gt;RFC 3021&lt;/a&gt;, while a /32 is a single host.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best way to avoid these mistakes is practice. Pick random addresses, calculate the subnets by hand and then confirm your results with the &lt;a href="https://arelvox.com/subnet-calculator/" rel="noopener noreferrer"&gt;subnet calculator&lt;/a&gt;. After ten or twenty examples, the method becomes automatic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practice Questions
&lt;/h2&gt;

&lt;p&gt;Try these on your own before checking the answers with the calculator:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;10.0.5.130/25: what is the network address?&lt;/li&gt;
&lt;li&gt;192.168.50.17/28: what is the broadcast address?&lt;/li&gt;
&lt;li&gt;172.20.100.9/22: how many usable hosts are there?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Answers: 10.0.5.128, 192.168.50.31 and 1,022 hosts. If you got all three right, you now know how to calculate subnets by hand. For the full background on CIDR prefixes, the &lt;a href="https://en.wikipedia.org/wiki/Subnetwork" rel="noopener noreferrer"&gt;Wikipedia article on subnetworks&lt;/a&gt; is a good next read.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ: How to Calculate Subnets
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the easiest way to calculate subnets?
&lt;/h3&gt;

&lt;p&gt;The easiest way is the magic number method: subtract the interesting mask octet from 256 and list its multiples. The network address is the multiple at or below your IP, and the broadcast is the next multiple minus one.&lt;/p&gt;

&lt;h3&gt;
  
  
  How many hosts are in a /26 subnet?
&lt;/h3&gt;

&lt;p&gt;A /26 subnet has 64 addresses and 62 usable hosts, because the network address and the broadcast address cannot be assigned to devices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need to know binary to calculate subnets?
&lt;/h3&gt;

&lt;p&gt;No. Binary helps you understand why the method works, but for day-to-day subnetting and most exam questions the magic number method is faster and less error-prone.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Want to check your answers? Try the free &lt;a href="https://arelvox.com/subnet-calculator/" rel="noopener noreferrer"&gt;IP subnet calculator&lt;/a&gt; on Arelvox.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>networking</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
