<?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: Muhammad Usman</title>
    <description>The latest articles on DEV Community by Muhammad Usman (@web_dev-usman).</description>
    <link>https://dev.to/web_dev-usman</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%2F2467689%2F7cef2b13-fd64-49a8-b296-bac4c5962ec3.png</url>
      <title>DEV Community: Muhammad Usman</title>
      <link>https://dev.to/web_dev-usman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/web_dev-usman"/>
    <language>en</language>
    <item>
      <title>Hostinger vs Namecheap 2026: 20% Extra Discount Promo Code</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Thu, 13 Aug 2026 10:54:55 +0000</pubDate>
      <link>https://dev.to/web_dev-usman/hostinger-vs-namecheap-2026-20-extra-discount-promo-code-4pnm</link>
      <guid>https://dev.to/web_dev-usman/hostinger-vs-namecheap-2026-20-extra-discount-promo-code-4pnm</guid>
      <description>&lt;p&gt;In this detailed &lt;strong&gt;Hostinger VS Namecheap&lt;/strong&gt; comparison, we are putting both hosting providers side by side so you can clearly see which one gives you the best value for your money in &lt;strong&gt;2026&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We are going to be testing several things, including pricing, performance, speed, uptime, customer support, and real features. And by the end of this comparison, I will tell you exactly which one I would choose if I had to start a brand new website today.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Get up to 20% extra off Hostinger using this special deal:&lt;br&gt;
&lt;a href="https://hostinger.pk?REFERRALCODE=USISTUDIOHE1" rel="noopener noreferrer"&gt;Hostinger special deal&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Why You Should Trust This Hostinger VS Namecheap Comparison
&lt;/h3&gt;

&lt;p&gt;Over the past couple of years, I have built and managed dozens of websites and online businesses. From small blogs to multi page funnels, SaaS projects, and ecommerce websites, I have handled all of them.&lt;/p&gt;

&lt;p&gt;Navigating and jumping from one hosting provider to another has honestly been hell. But thank God I survived.&lt;/p&gt;

&lt;p&gt;The fact that I have personally used both Hostinger and Namecheap, not just for testing but for real businesses, is exactly why this review is coming from personal experience, not from reading feature lists or blog posts.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Is Hostinger Known&amp;nbsp;For?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpzyg9d59iiaaqm2g0xq3.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%2Fpzyg9d59iiaaqm2g0xq3.png" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hostinger Dashboard&lt;/strong&gt;Hostinger is well known for its speed (lightspeed servers), affordability, and beginner friendly tools. One major feature that stands out is the free AI website builder.&lt;/p&gt;

&lt;p&gt;This allows you to literally create a professional website in minutes just by describing your business. That alone makes Hostinger very attractive for beginners.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Namecheap Is Best&amp;nbsp;At
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbp9opekopgc4ltsy42p5.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%2Fbp9opekopgc4ltsy42p5.png" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Namecheap started as a domain registrar, and from my experience, that is still where their biggest strength lies.&lt;/p&gt;

&lt;p&gt;Most of my domain names are with Namecheap, and I honestly love sticking with a company where their biggest strength is very clear. That is exactly what I will most likely continue using Namecheap for going forward.&lt;/p&gt;

&lt;p&gt;But here is the real question.&lt;/p&gt;

&lt;p&gt;If you find a better option for hosting, will you still stick with Namecheap?&lt;/p&gt;

&lt;p&gt;Hold on. I will get to that as we continue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hostinger VS Namecheap Pricing Breakdown in&amp;nbsp;2026
&lt;/h3&gt;

&lt;p&gt;This is where the difference really starts to show.&lt;/p&gt;

&lt;p&gt;At this particular point in time, Hostinger launched special deals on its hosting plans. With long term deals you can get a 24–48 month plan for an introductory price of around &lt;strong&gt;$1.99 to $2.99 per month&lt;/strong&gt;, depending on the exact plan and discount applied. For many of these plans, a &lt;strong&gt;free domain name is included&lt;/strong&gt; with the hosting.&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%2Flrr2cvw6lvpo5f5m4h9y.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%2Flrr2cvw6lvpo5f5m4h9y.png" width="800" height="625"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hostinger pricing&amp;nbsp;plans&amp;gt; Grab Hostinger’s discounted plan here, click the link below:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://hostinger.pk?REFERRALCODE=USISTUDIOHE1" rel="noopener noreferrer"&gt;Hostinger special discount&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now let us compare that with Namecheap.&lt;/p&gt;

&lt;p&gt;Namecheap’s shared hosting &lt;strong&gt;Stellar plan starts at about $1.98 per month&lt;/strong&gt; when billed annually.&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%2F12kha7gj4a5sipctxeeq.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%2F12kha7gj4a5sipctxeeq.png" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Namecheap pricing&amp;nbsp;plansHere is the catch.&lt;/p&gt;

&lt;p&gt;With Hostinger’s introductory pricing, you also get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A free domain name&lt;/li&gt;
&lt;li&gt;Unlimited bandwidth&lt;/li&gt;
&lt;li&gt;Professional email accounts&lt;/li&gt;
&lt;li&gt;AI website builder&lt;/li&gt;
&lt;li&gt;24/7 live customer support&lt;/li&gt;
&lt;li&gt;And many more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Namecheap you get a lower introductory price, but domain registration and email may still cost extra after the first year depending on the exact offer.&lt;/p&gt;

&lt;p&gt;On pricing and value alone, Hostinger still gives more bundled features for what you pay upfront.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hostinger VS Namecheap Speed and Performance Test
&lt;/h3&gt;

&lt;p&gt;Now let us talk about speed.&lt;/p&gt;

&lt;p&gt;In multiple tests, Hostinger consistently loads websites in under &lt;strong&gt;one second&lt;/strong&gt;. This is thanks to their LiteSpeed servers and built in caching.&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%2F57828wrn8ylzzj5vetrj.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%2F57828wrn8ylzzj5vetrj.png" width="800" height="851"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the speed of Hostinger even with a complete custom&amp;nbsp;website.&amp;gt; This level of optimization is part of what Hostinger includes on its shared hosting plans.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👉 Link &lt;a href="https://hostinger.pk?REFERRALCODE=USISTUDIOHE1" rel="noopener noreferrer"&gt;Hostinger includes on its shared hosting plans&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Namecheap, on the other hand, averages around &lt;strong&gt;1.8 to 2.5 seconds&lt;/strong&gt; on shared hosting plans.&lt;/p&gt;

&lt;p&gt;That speed is still decent, but it is not as optimized.&lt;/p&gt;

&lt;p&gt;If performance matters to you, especially if you run an ecommerce business or you care about SEO, then Hostinger wins again at this level.&lt;/p&gt;

&lt;h3&gt;
  
  
  SSL, Uptime, and Security Comparison
&lt;/h3&gt;

&lt;p&gt;Both Hostinger and Namecheap offer free SSL certificates and a 99.9 percent uptime guarantee.&lt;/p&gt;

&lt;p&gt;However, Hostinger goes a step further by including automated weekly backups and Cloudflare protection by default.&lt;/p&gt;

&lt;p&gt;With Namecheap, most of these things need to be configured manually.&lt;/p&gt;

&lt;p&gt;So once again, Hostinger is clearly more beginner friendly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hostinger VS Namecheap Customer Support Experience
&lt;/h3&gt;

&lt;p&gt;This is where a lot of budget hosting providers usually struggle.&lt;/p&gt;

&lt;p&gt;Hostinger offers 24/7 live chat support that is fast, friendly, and actually helpful.&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%2Fq6fqk7w4pewata3yc2rk.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%2Fq6fqk7w4pewata3yc2rk.png" width="800" height="1484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hostinger With AI IntegratedNow, Namecheap support is also very decent. Honestly, I would even say they have one of the best customer support teams out there.&lt;/p&gt;

&lt;p&gt;There have been many times when I needed things fixed quickly, and I did not want to start racking my brain. I contacted Namecheap support, and most times they helped me resolve the issue directly.&lt;/p&gt;

&lt;p&gt;That is a huge plus for them.&lt;/p&gt;

&lt;p&gt;But that was before I started using Hostinger.&lt;/p&gt;

&lt;p&gt;Hostinger also has very good response times, and I would definitely give them credit for that.&lt;/p&gt;

&lt;p&gt;At this level, I would honestly call it a draw. Both companies are really good when it comes to customer support.&lt;/p&gt;

&lt;h3&gt;
  
  
  Control Panel and Ease of&amp;nbsp;Use
&lt;/h3&gt;

&lt;p&gt;If you are new to building websites, this part matters a lot.&lt;/p&gt;

&lt;p&gt;Hostinger uses its own custom control panel called hPanel. It is clean, modern, and built specifically for beginners. They also guide you through setups in real time, which makes the whole process very smooth.&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%2Fq1wqvvs34hw6qgxtlb0y.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%2Fq1wqvvs34hw6qgxtlb0y.png" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hostinger HPanelTheir AI website builder allows you to create a professional site in minutes just by explaining what your business does.&lt;/p&gt;

&lt;p&gt;Namecheap still uses cPanel, which is fine for technical users, but it is not as simple visually.&lt;/p&gt;

&lt;p&gt;If you want something plug and play, Hostinger wins again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Total Cost Comparison Over Two&amp;nbsp;Years
&lt;/h3&gt;

&lt;p&gt;If you are building a brand website, blog, or ecommerce store, the numbers matter.&lt;/p&gt;

&lt;p&gt;With Hostinger’s long-term plan, your total cost for two years, including the domain, comes down to a very competitive price compared to similar hosted packages.&lt;/p&gt;

&lt;p&gt;With Namecheap, once you add domain registration, email hosting, and other extras, you will likely spend more over two years even with their own introductory prices.&lt;/p&gt;

&lt;p&gt;That means &lt;strong&gt;more savings upfront with Hostinger&lt;/strong&gt; and often &lt;strong&gt;faster load times over time&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Verdict: Hostinger VS Namecheap
&lt;/h3&gt;

&lt;p&gt;Both Hostinger and Namecheap are legit, secure, and affordable.&lt;/p&gt;

&lt;p&gt;But here is my honest take.&lt;/p&gt;

&lt;p&gt;I would go with &lt;strong&gt;Hostinger&lt;/strong&gt; if you want speed, simplicity, and long term savings.&lt;/p&gt;

&lt;p&gt;You should only choose &lt;strong&gt;Namecheap&lt;/strong&gt; if you already have your domain there and you just need basic hosting for small projects.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;2026 and beyond, Hostinger takes the win&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let me know your thoughts and concerns in the comments, and you can also join my community through the link provided.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For those comparing Hostinger VS Namecheap in 2026, Hostinger remains a strong choice for performance, ease of use, and overall value. If you want, you can get an extra 20% discount using my code directly with your plan.&lt;br&gt;
👉 &lt;a href="https://hostinger.pk?REFERRALCODE=USISTUDIOHE1" rel="noopener noreferrer"&gt;Extra 20% discount using this LINK&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>web</category>
      <category>discuss</category>
    </item>
    <item>
      <title>7 Habits of Developers Who Never Have to Optimize Later</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Fri, 07 Aug 2026 07:19:47 +0000</pubDate>
      <link>https://dev.to/web_dev-usman/7-habits-of-developers-who-never-have-to-optimize-later-30gc</link>
      <guid>https://dev.to/web_dev-usman/7-habits-of-developers-who-never-have-to-optimize-later-30gc</guid>
      <description>&lt;p&gt;Open DevTools right now. Go to the Network tab, find the throttling dropdown, and set it to Slow 3G. Now reload something you built.&lt;/p&gt;

&lt;p&gt;Watch the blank white screen sit there for a few seconds. Watch the layout jump around as fonts and images land out of order. Somewhere in the world, someone is looking at that exact screen on that exact connection, right now, and they don't have a throttling dropdown to turn back off.&lt;/p&gt;

&lt;p&gt;"Optimize later" is one of the most common plans in web development, and it's also one of the most misleading. It suggests performance is a separate phase, something you schedule after the feature is done, the way you'd schedule a coat of paint after the walls go up. In practice it rarely gets scheduled at all. The feature ships, the next feature starts, and the page just keeps getting a little heavier, a little slower, until a Lighthouse score forces the conversation nobody planned for.&lt;/p&gt;

&lt;p&gt;The developers who never have that conversation aren't smarter or more disciplined in some abstract way. They just built a handful of habits into how they write code every day, so performance was never a separate phase to schedule in the first place. None of what follows costs extra time once it's automatic. Most of it saves time, because catching a heavy dependency while you're still deciding whether to add it is faster than ripping it out after six other things depend on it.&lt;/p&gt;

&lt;p&gt;Here are the seven that stuck.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Check what the page already ships before adding to it
&lt;/h2&gt;

&lt;p&gt;For a long time my instinct was to reach for whatever solved the immediate problem. Need a date picker, install a date picker. Need icons, install an icon library. The Network tab was something I opened when something was already slow, not before I made it slower.&lt;/p&gt;

&lt;p&gt;Now it's the other way around. Before adding anything, I check what's already going out over the wire.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DevTools → Network tab → reload → look at the size column at the bottom
Total: 847 KB transferred, 2.1 MB resources
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That number is the actual starting condition for anything I'm about to add. A 40 KB date picker library means something different on a page that's already shipping 200 KB than on one shipping 2 MB. Checking first doesn't mean never adding a dependency. It means the decision is made with the real number in front of you, not a vague sense that "it's probably fine."&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Reach for the platform before reaching for a library
&lt;/h2&gt;

&lt;p&gt;Modals used to be one of the more expensive things I'd casually build: a backdrop div, a focus trap, an escape key handler, scroll locking on the body, all wired together by hand or, more often, pulled in from a library that did all of it plus a hundred features I didn't need.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; element has had solid cross-browser support since 2022, and it handles most of that for free.&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="c"&gt;&amp;lt;!-- What used to require a library --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dialog&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"confirm-dialog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Delete this item?&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"cancel"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"confirm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Delete&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dialog&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"open-dialog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Delete item&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dialog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;confirm-dialog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open-dialog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&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="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showModal&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="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cancel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&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="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling &lt;code&gt;dialog.showModal()&lt;/code&gt; gets you the backdrop, focus trapping, top-layer rendering above everything else on the page, and Escape-to-close, all handled by the browser. No z-index war, no focus trap library, no separate accessibility audit finding what the hand-built version missed. The habit isn't "never use a library." It's checking whether the platform already solved this specific problem before adding forty KB to solve it again.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Load what's needed, not what might be needed
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; with no attributes blocks the browser from doing anything else until that file downloads and runs. I used to write those by default and only notice the blocking behavior once a page felt sluggish enough to investigate.&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="c"&gt;&amp;lt;!-- Blocks rendering until this loads and executes --&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;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"analytics.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;/head&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Downloads in parallel, runs after the HTML is parsed --&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;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"analytics.js"&lt;/span&gt; &lt;span class="na"&gt;defer&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;defer&lt;/code&gt; alone fixes the render-blocking problem for most scripts. For code that isn't needed until later, like a component behind a click or a tab that's not visible on load, a dynamic import defers the actual download 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;// Only fetched when someone actually opens the settings panel&lt;/span&gt;
&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;openSettingsPanel&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./settings-panel.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;openSettingsPanel&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;Neither of these is a refactor I do after noticing a slow load. They're the default way I write a script tag or an import now, the same way &lt;code&gt;const&lt;/code&gt; became the default over &lt;code&gt;var&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Treat images as a budget, not an afterthought
&lt;/h2&gt;

&lt;p&gt;Images are usually the single biggest thing on a page, and for a long time I treated them as a last step: drop the file in, write the &lt;code&gt;src&lt;/code&gt;, move on. The size, format, and dimensions all got decided by whatever the design file happened to export.&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="c"&gt;&amp;lt;!-- What I used to ship --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"hero-photo.jpg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- What I check for now, every time an image goes in --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"hero-photo.jpg"&lt;/span&gt;
  &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"hero-photo-480.jpg 480w, hero-photo-960.jpg 960w, hero-photo-1600.jpg 1600w"&lt;/span&gt;
  &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"(max-width: 600px) 480px, (max-width: 1200px) 960px, 1600px"&lt;/span&gt;
  &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"1600"&lt;/span&gt;
  &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"900"&lt;/span&gt;
  &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt;
  &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"A description of what's actually in the photo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;srcset&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt; mean a phone downloads a 480px image instead of the same 1600px file a desktop gets. &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; reserve the space before the image loads, which is most of what keeps Cumulative Layout Shift under the 0.1 threshold Google treats as good. &lt;code&gt;loading="lazy"&lt;/code&gt; skips the download entirely for images below the fold until someone scrolls near them. None of this is exotic. It's four attributes and a &lt;code&gt;srcset&lt;/code&gt;, decided at the moment the image goes in rather than discovered later in a performance audit.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Measure before you guess
&lt;/h2&gt;

&lt;p&gt;I used to have strong opinions about what was slow on a page, and they were usually wrong. The animation felt janky, so I'd assume it was the animation. The page felt sluggish on load, so I'd assume it was the biggest image. Guessing feels like progress. It's usually just motion in a random 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;// A real measurement instead of a guess&lt;/span&gt;
&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-fetch-start&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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchDashboardData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-fetch-end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-fetch&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="s1"&gt;data-fetch-start&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="s1"&gt;data-fetch-end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEntriesByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-fetch&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the metrics that actually matter to real users, DevTools' Performance panel will show the specific element responsible for Largest Contentful Paint, the metric for how long the biggest visible piece of content takes to render. Good is under 2.5 seconds. If that element turns out to be a font-loading heading instead of the hero image I assumed was the problem, the fifteen minutes I would have spent compressing that image was going to fix nothing. Measuring first means the time spent optimizing actually goes toward the thing that was slow.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Let the browser do the layout work it's already good at
&lt;/h2&gt;

&lt;p&gt;For years I animated position the same way I'd set it in a stylesheet: &lt;code&gt;top&lt;/code&gt; and &lt;code&gt;left&lt;/code&gt;, sometimes &lt;code&gt;margin&lt;/code&gt;. All three trigger the same layout recalculation. It worked, but "worked" and "smooth" aren't the same thing, especially on a mid-range phone with a dozen other things competing for the main thread.&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;/* Forces the browser to recompute layout on every frame */&lt;/span&gt;
&lt;span class="nc"&gt;.card&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;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;top&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.card&lt;/span&gt;&lt;span class="nd"&gt;:hover&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;-8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Handled entirely by the compositor, no layout recalculation */&lt;/span&gt;
&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt; &lt;span class="m"&gt;0.3s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.card&lt;/span&gt;&lt;span class="nd"&gt;:hover&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;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-8px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;top&lt;/code&gt; and &lt;code&gt;left&lt;/code&gt; sit in the layout stage of the rendering pipeline: the browser has to recompute where every affected element sits, then repaint, on every single frame. &lt;code&gt;transform&lt;/code&gt; and &lt;code&gt;opacity&lt;/code&gt; skip both steps and get handled on the compositor, which is why the second version stays smooth even when the main thread is busy with something else. Same visual result, one version asks the browser to do far less work to produce it.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Run one performance budget check before every commit
&lt;/h2&gt;

&lt;p&gt;Performance regressions almost never arrive as one dramatic change. They arrive as a 30 KB dependency here, an unoptimized image there, each one individually reasonable, none of them ever really addressed until a bundle analyzer or a Lighthouse run several months later delivers the bad news all at once.&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;// A budget check that runs as part of the build, not as a separate audit&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;readFileSync&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="s1"&gt;fs&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;bundle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist/main.js&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;sizeInKB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&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;budget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;150&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;sizeInKB&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;budget&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Bundle is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sizeInKB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; KB, budget is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;budget&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; KB`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few lines like this, wired into a build script or a CI step, turn "the bundle got big somehow" into "this specific commit added 40 KB, here's why." It doesn't catch everything. It won't tell you if an interaction feels laggy or if your Largest Contentful Paint element is the wrong one. But it catches the slow, compounding kind of regression while it's still one commit, back when the fix is removing a line instead of untangling six months of small additions.&lt;/p&gt;




&lt;p&gt;None of these habits are big undertakings on their own. Checking a Network tab before adding a dependency takes ten seconds. Writing &lt;code&gt;defer&lt;/code&gt; instead of leaving it off costs nothing. That's really the point: optimizing later feels necessary because performance got treated as a separate concern from the actual writing of the code. Treat it as part of the same decision you're already making, when you add the script tag, when you drop in the image, when you write the transition, and there's no separate phase left to schedule.&lt;/p&gt;

&lt;p&gt;Go throttle your connection again sometime, on something you're building right now. Not to feel bad about what you find. Just to see it once, the way someone on a slower connection already does, every day, whether you ever open that dropdown or not.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Did you learn something good today as a developer?&lt;br&gt;
Then show some love.&lt;br&gt;
© &lt;a href="https://www.linkedin.com/in/muhammad-usman-strategist/" rel="noopener noreferrer"&gt;Muhammad Usman&lt;/a&gt;&lt;br&gt;
Don’t forget to subscribe to &lt;a href="https://developersjourney.substack.com/" rel="noopener noreferrer"&gt;Developer’s Journey&lt;/a&gt; to show your support.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" alt="Developer's Journey" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>performance</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Cursor: The One Element in Your Web Almost Nobody Designs</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Thu, 06 Aug 2026 10:53:36 +0000</pubDate>
      <link>https://dev.to/web_dev-usman/cursor-the-one-element-in-your-web-almost-nobody-designs-305k</link>
      <guid>https://dev.to/web_dev-usman/cursor-the-one-element-in-your-web-almost-nobody-designs-305k</guid>
      <description>&lt;p&gt;Did you know that if you add this little snippet of code to your website, you can replace your mouse cursor with pretty much anything?&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;button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("cursor.png")&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;pointer&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;Instead of the default arrow, you can turn it into an emoji, an icon, or a tiny custom graphic. That comma before &lt;code&gt;pointer&lt;/code&gt; matters. The browser tries to load &lt;code&gt;cursor.png&lt;/code&gt; first. If it fails, or the browser doesn't support custom cursors, it falls back to the normal pointer. Never skip that fallback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Each element below is fully interactive. Hover over any of them and watch the cursor change on the spot.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/web-strategist/embed/LExqzOd?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I wouldn’t recommend replacing the cursor for your entire website. Keep it close to what people already expect. But scoped to one interaction, at one moment, it turns something completely ignored into a small detail people notice. Here’s where it actually earns its place.&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%2Fdbglz1fmnfwjpi1f6t4t.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%2Fdbglz1fmnfwjpi1f6t4t.png" alt="Zoom icons will show up when hover over the main image&lt;br&gt;
" width="799" height="311"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Say what the click does, not just that it's clickable
&lt;/h2&gt;

&lt;p&gt;A pointer only tells someone "this is interactive." A custom cursor can tell them what interacting does.&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;.zoom-image&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("magnifier.png")&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zoom-in&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.crop-tool&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("scissors.png")&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;crosshair&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.drag-card&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grab&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.drag-card&lt;/span&gt;&lt;span class="nd"&gt;:active&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grabbing&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;Those two numbers after the URL, &lt;code&gt;12 12&lt;/code&gt;and &lt;code&gt;4 4&lt;/code&gt;, set the cursor's hotspot. That's the exact pixel inside your image that lines up with the actual click point. Skip them and the browser defaults to the top left corner of the image, which looks wrong almost every time, especially on anything shaped like scissors or a pointing hand.&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%2Fnysgarwqsu6blpj0tlnn.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%2Fnysgarwqsu6blpj0tlnn.png" alt="The grabbing hand will show once we hover the white background card" width="800" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a bit of personality to your main call to&amp;nbsp;action
&lt;/h2&gt;

&lt;p&gt;This is the fun one. Swap the cursor for a tiny branded icon right on the button you most want someone to click.&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;.cta-button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("rocket.png")&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't even need an image file for this. An SVG data URI does the same job with zero extra requests:&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%2Foo4hl6nxq1k71d41mka5.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%2Foo4hl6nxq1k71d41mka5.png" alt="Rocket will show up once we hover over the button" width="800" height="243"&gt;&lt;/a&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;.like-button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url('data:image/svg+xml;utf8,&amp;lt;svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"&amp;gt;&amp;lt;text y="24" font-size="24"&amp;gt;❤️&amp;lt;/text&amp;gt;&amp;lt;/svg&amp;gt;')&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;pointer&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;It's one line, nothing to host, and the emoji scales cleanly since it's just text sitting inside SVG markup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give portfolios and case studies a signature feel
&lt;/h2&gt;

&lt;p&gt;Designers and agencies get away with a lot more here, because a custom cursor reads as craft instead of gimmick when the whole site is already built around visual work.&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;.project-thumb&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("view-pill.png")&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2F55i2p56id9e6ibrb0t1x.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%2F55i2p56id9e6ibrb0t1x.png" alt="A view eye image will show up once we hover over the card" width="800" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A small pill-shaped cursor that says "View" while hovering a thumbnail does more work than a caption ever could. People move their mouse before they read anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn it into a small&amp;nbsp;warning
&lt;/h2&gt;

&lt;p&gt;Right before a destructive action, a cursor change adds one extra beat of friction.&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;.delete-account-btn&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("warning.png")&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;not-allowed&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 person still has to move their mouse over the button and register that something changed. That half second is sometimes enough to make them pause and reconsider.&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%2Fl783b4h0baxnrjjnpqag.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%2Fl783b4h0baxnrjjnpqag.png" alt="Warning icon will show up once we hover over the delete button" width="798" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a world for exploration-based sites
&lt;/h2&gt;

&lt;p&gt;Interactive stories, narrative scrollers, and portfolio sites built around a theme can carry that theme into the cursor 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="nc"&gt;.map-section&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("compass.png")&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.dark-mode&lt;/span&gt; &lt;span class="nc"&gt;.story-panel&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("torch.png")&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt; &lt;span class="m"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2Fo9kwobzpl4c0col8xq1a.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%2Fo9kwobzpl4c0col8xq1a.png" alt="Compus cursor will show up once we hover over the image" width="800" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's a small thing, but it reinforces that the visitor is inside something built with intention, not just scrolling a normal page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep these rules in&amp;nbsp;mind
&lt;/h2&gt;

&lt;p&gt;Size your cursor images small. Most browsers cap custom cursors around 128x128 pixels, and anything bigger gets ignored or scaled down badly. 32x32 or 48x48 is usually the sweet spot.&lt;/p&gt;

&lt;p&gt;Always include a fallback keyword after your URL, whether that's &lt;code&gt;pointer&lt;/code&gt;, &lt;code&gt;grab&lt;/code&gt;, &lt;code&gt;zoom-in&lt;/code&gt;, or &lt;code&gt;not-allowed&lt;/code&gt;. Some browsers and some users won't load the custom image at all, and you don't want the button falling back to nothing.&lt;/p&gt;

&lt;p&gt;And keep it local. One button, one thumbnail, one section. The moment your entire site runs on a custom cursor, it stops feeling like a surprise and starts feeling like a bug.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy designing.&lt;/strong&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Did you learn something good today as a developer?&lt;br&gt;
Then show some love.&lt;br&gt;
© &lt;a href="https://www.linkedin.com/in/muhammad-usman-strategist/" rel="noopener noreferrer"&gt;Muhammad Usman&lt;/a&gt;&lt;br&gt;
Don’t forget to subscribe to &lt;a href="https://developersjourney.substack.com/" rel="noopener noreferrer"&gt;Developer’s Journey&lt;/a&gt; to show your support.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" alt="Developer's Journey" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>design</category>
    </item>
    <item>
      <title>JavaScript ES2026 Just Shipped What Developers Have Been Asking for Years</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Fri, 31 Jul 2026 19:16:15 +0000</pubDate>
      <link>https://dev.to/web_dev-usman/javascript-es2026-just-shipped-what-developers-have-been-asking-for-years-2eml</link>
      <guid>https://dev.to/web_dev-usman/javascript-es2026-just-shipped-what-developers-have-been-asking-for-years-2eml</guid>
      <description>&lt;p&gt;For 30 years, JavaScript developers have been quietly suffering. Date object had a lot of limitations, and every developer knows it. Time zone issue came, and it had to be a lot of calculation just for the expected date. Every time you built a regular expression from user input, you had to remove special characters yourself first. Every time you weren’t sure if a function was synchronous or asynchronous, you wrote two code paths just to be safe.&lt;/p&gt;

&lt;p&gt;All that is over now.&lt;/p&gt;

&lt;p&gt;ES2026, the 17th edition of the language, just got finalized, and it brings the Temporal API into the spec alongside a handful of smaller fixes that already landed the year before. JavaScript is finally getting smarter day by day. Not louder, not flashier, but smarter. These are real, spec-confirmed features you can use today, and this article shows exactly why each one is worth your time, with production-level code for every single one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Don’t just read about it. Try it.&lt;br&gt;
Everything below runs live in your browser, no copying code required.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/web-strategist/embed/WbRJBQK?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Let’s go through it, feature by feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Temporal API: Dates Finally Stop Being a Nightmare
&lt;/h3&gt;

&lt;p&gt;Let’s start with the big one, because this is the fix people have wanted for three decades.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Date&lt;/code&gt; object was never designed well. It was copied from Java in 1995, during the original 10-day sprint to build JavaScript, and it came with problems baked in from day one. Months start counting from zero but days don't. Date objects are mutable, so passing one into a function can quietly change it without you knowing. And time zone support was basically an afterthought, so anything involving daylight saving time turned into manual math that broke constantly.&lt;/p&gt;

&lt;p&gt;Here’s what that pain actually looks like in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Months are zero-indexed. December is 11. Everyone gets this wrong at least once.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;christmas&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;christmas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMonth&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 11&lt;/span&gt;

&lt;span class="c1"&gt;// Date objects are mutable, so this is a silent trap.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;meeting&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;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;reschedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFullYear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1900&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// this changes the original object, not a copy&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;reschedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;meeting&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;meeting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFullYear&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 1900, and you didn't ask for that&lt;/span&gt;
&lt;span class="c1"&gt;// There was never a clean way to ask "what time is it in Tokyo right now"&lt;/span&gt;
&lt;span class="c1"&gt;// without writing your own offset math, and that math breaks the moment DST hits.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because Date was this limited, the whole ecosystem built an industry around fixing it. Moment.js, date-fns, and Day.js combined pull in tens of millions of downloads every single week, just to patch a hole that should never have existed in the language.&lt;/p&gt;

&lt;p&gt;That’s exactly what the &lt;a href="https://blog.stackademic.com/javascript-temporal-api-vs-date-object-02adf616d0a5?sharedUserId=pixicstudio" rel="noopener noreferrer"&gt;Temporal API&lt;/a&gt; solves. It reached &lt;strong&gt;TC39 Stage 4&lt;/strong&gt; and is now officially part of &lt;strong&gt;ES2026&lt;/strong&gt;, the 17th edition of the spec, approved on June 30, 2026. It isn’t a patch on top of &lt;code&gt;Date&lt;/code&gt;, it's a completely new global namespace, similar to &lt;code&gt;Math&lt;/code&gt; or &lt;code&gt;Intl&lt;/code&gt;, with a set of purpose-built, immutable types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Temporal.PlainDate&lt;/code&gt; for a calendar date with no time zone attached&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Temporal.PlainTime&lt;/code&gt; for a wall-clock time with no date attached&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Temporal.ZonedDateTime&lt;/code&gt; as the real replacement for &lt;code&gt;Date&lt;/code&gt;, time zone aware from the start&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Temporal.Duration&lt;/code&gt; for representing spans of time properly&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Temporal.Instant&lt;/code&gt; for an exact point on the UTC timeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s the same logic from before, rewritten with Temporal:&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;// Every operation returns a brand new object. Nothing gets mutated behind your back.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;meeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Temporal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PlainDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-03-15&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;rescheduled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;meeting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1900&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;meeting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "2026-03-15", untouched&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rescheduled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "1900-03-15", the new one&lt;/span&gt;
&lt;span class="c1"&gt;// Time zones are explicit now, not something you calculate by hand.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokyoNow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Temporal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zonedDateTimeISO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Asia/Tokyo&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;nycNow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Temporal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zonedDateTimeISO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;America/New_York&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokyoNow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nycNow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="c1"&gt;// Duration math without converting everything to milliseconds yourself.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Temporal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PlainDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-01-10&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;projectEnd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Temporal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PlainDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-07-22&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;timeSpent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;projectStart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;until&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectEnd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;largestUnit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;month&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeSpent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "P6M12D" - 6 months and 12 days&lt;/span&gt;
&lt;span class="c1"&gt;// Daylight saving time is handled correctly instead of silently breaking.&lt;/span&gt;
&lt;span class="c1"&gt;// On March 29, 2026, clocks in London jump forward and 00:30 to 01:30 doesn't exist.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;beforeDST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Temporal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ZonedDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-03-29T00:30[Europe/London]&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;afterOneHour&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;beforeDST&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="na"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;afterOneHour&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// correctly resolves to 02:30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frsjv02tesd53e8hexsh4.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%2Frsjv02tesd53e8hexsh4.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Firefox and Chromium-based browsers already ship this natively, and Safari has partial support in Technology Preview right now. If you need it in older environments today, the &lt;code&gt;@js-temporal/polyfill&lt;/code&gt; package gives you the exact same API, so your code doesn't need to change later.&lt;/p&gt;

&lt;p&gt;If your app deals with scheduling, bookings, financial timestamps, or anything international, this single feature alone justifies paying attention to JavaScript again.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Promise.try: Now You Can Handle Sync and Async the Same&amp;nbsp;Way
&lt;/h3&gt;

&lt;p&gt;Now here’s a problem almost every JavaScript developer runs into. You’re calling a function, but you don’t know if it’s synchronous or asynchronous. So if it throws synchronously instead of rejecting a promise, your&amp;nbsp;&lt;code&gt;.catch()&lt;/code&gt; never even fires, and the error just crashes things instead of being handled properly.&lt;/p&gt;

&lt;p&gt;Before this, people wrote their own wrapper to force consistent behavior:&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 old defensive wrapper everyone rewrote in their own codebase&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;safelyRun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;safelyRun&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;riskyOperation&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Handled:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It worked fine, but it’s the kind of thing every project reinvented slightly differently. &lt;code&gt;Promise.try&lt;/code&gt; turns this into a native method:&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;// Whether validateUser is sync or async, this handles both the same way&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Missing email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// synchronous throw&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/verify/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// asynchronous path&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;validateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Validated:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Validation failed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// A real use case: a plugin system where you don't control how plugins are written&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;runPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;logPluginError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// fail gracefully instead of crashing everything&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2Fyjd2bwg7hkdv2aun07du.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%2Fyjd2bwg7hkdv2aun07du.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Throw synchronously&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%2Fdcz9wnkroaz6c66wd5u7.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%2Fdcz9wnkroaz6c66wd5u7.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reject asynchronouslySo now you can handle synchronous and asynchronous functions both in the same way, without maintaining your own wrapper just to be safe.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. RegExp.escape: Now You Don’t Have to Remove Special Characters Yourself
&lt;/h3&gt;

&lt;p&gt;Now, if you take input from a user and you have to convert it into a regular expression, you already know this problem. Regex has its own special characters, things like&amp;nbsp;&lt;code&gt;. * +&amp;nbsp;? ( ) [ ] { } | ^ $&lt;/code&gt;, and if user input contains any of them, your regex either throws an error or quietly matches the wrong thing. Normally, you had to remove the special characters yourself before you could convert it into a regular expression.&lt;/p&gt;

&lt;p&gt;The old approach usually looked like this, hand-rolled or pulled in from an npm package:&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 old way, written from scratch or installed as a dependency&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;escapeRegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;.*+?^${}()|[&lt;/span&gt;&lt;span class="se"&gt;\]\\]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s1"&gt;$&amp;amp;&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;const&lt;/span&gt; &lt;span class="nx"&gt;userSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Price: $5.00 (on sale!)&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;pattern&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;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;escapeRegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userSearch&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gi&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;Now there’s a new method introduced, called &lt;code&gt;escape&lt;/code&gt;, and it automatically removes the guesswork for you:&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;userSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Price: $5.00 (on sale!)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// RegExp.escape neutralizes every special character for you&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;safePattern&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;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userSearch&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userSearch&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// "Price:\x205\.00\x20\(on\x20sale!\)"&lt;/span&gt;
&lt;span class="c1"&gt;// Spaces become \x20 hex escapes, and actual regex syntax characters like&lt;/span&gt;
&lt;span class="c1"&gt;// $ . ( ) get a simple backslash. Plain punctuation like : and ! is left alone,&lt;/span&gt;
&lt;span class="c1"&gt;// since it has no special meaning in a regex pattern to begin with.&lt;/span&gt;
&lt;span class="c1"&gt;// Real use case: highlighting a search term safely&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;highlightMatches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pattern&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;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;mark&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/mark&amp;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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;highlightMatches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Get 20% off (limited time)&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="s1"&gt;20% off (limited time)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// safely matches the literal string, special characters included&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8qc9pqm7qvxx3ri80cad.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%2F8qc9pqm7qvxx3ri80cad.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RegExp.escapeOne thing worth being clear about: &lt;code&gt;RegExp.escape&lt;/code&gt; protects you from regex injection specifically. It's not protection against HTML injection or SQL injection. If matched text is going into the DOM, you still need proper HTML escaping on top of this. Different problem, different fix.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Now You Can Use Map, Filter, and Take on Iterators Too
&lt;/h3&gt;

&lt;p&gt;This is the one that shows JavaScript getting smarter day by day, and it’s easy to miss at first glance. Before this, if you wanted to use&amp;nbsp;&lt;code&gt;.map()&lt;/code&gt; or&amp;nbsp;&lt;code&gt;.filter()&lt;/code&gt; on a generator, a &lt;code&gt;Set&lt;/code&gt;, or any custom iterable, you had two options. Convert it into an array first, which means loading everything into memory even if you only need the first few results, or write your own manual loop every single time.&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 old way: force it into an array just to use familiar methods&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;readLogLines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INFO: server started&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ERROR: connection refused&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INFO: request received&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ERROR: timeout on request 442&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INFO: request completed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// imagine this generator streams millions of lines from a real log file&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;firstThreeErrors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;readLogLines&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ERROR&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="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// the whole log still gets loaded into memory first&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can chain&amp;nbsp;&lt;code&gt;.map()&lt;/code&gt;,&amp;nbsp;&lt;code&gt;.filter()&lt;/code&gt;,&amp;nbsp;&lt;code&gt;.take()&lt;/code&gt;,&amp;nbsp;&lt;code&gt;.drop()&lt;/code&gt;, and more, directly on the iterator itself, lazily, so nothing gets computed until you actually need it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;readLogLines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INFO: server started&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ERROR: connection refused&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INFO: request received&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ERROR: timeout on request 442&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INFO: request completed&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="c1"&gt;// Lazy pipeline. Stops pulling from the generator the moment it has 3 matches.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstThreeErrors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;readLogLines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ERROR&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ERROR: &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="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firstThreeErrors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// ["connection refused", "timeout on request 442"]&lt;/span&gt;
&lt;span class="c1"&gt;// Real use case: pulling from a paginated or unbounded data source&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;fetchAllUserIds&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;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getUserIdsForPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// pretend API call&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;ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;first50ActiveUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetchAllUserIds&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;isUserActive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffptcv7378zaq2wfkmhln.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%2Ffptcv7378zaq2wfkmhln.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For anything dealing with large or unbounded data, streaming logs, paginated APIs, infinite sequences, this is the difference between pulling gigabytes into memory and processing only what you actually need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where Things Actually Stand Right&amp;nbsp;Now
&lt;/h3&gt;

&lt;p&gt;To be straightforward about it, since accuracy matters more than hype here:&lt;/p&gt;

&lt;p&gt;Promise.try, RegExp.escape, and iterator helpers shipped as part of ES2025, the 16th edition, and they’re already available in current versions of Chrome, Firefox, Safari, and Node.&lt;/p&gt;

&lt;p&gt;The Temporal API is officially part of ES2026, the 17th edition, approved on June 30, 2026. Firefox and Chromium-based browsers already support it natively, Safari has partial support in Technology Preview, and the official polyfill covers everything else in the meantime.&lt;/p&gt;

&lt;p&gt;None of this is speculative or “coming eventually.” Every snippet above works exactly as written in a current browser, or through the Temporal polyfill if you need broader coverage today.&lt;/p&gt;

&lt;p&gt;JavaScript isn’t getting louder with every release, it’s getting smarter, day by day. It’s quietly fixing the exact problems that made developers reach for a library before writing five lines of native code. If you’ve been putting off checking what’s new, this is genuinely worth your time. Please try these out in your own code, and let me know in the comments which one saves you the most headaches.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Did you learn something good today as a developer?&lt;br&gt;
Then show some love.&lt;br&gt;
© &lt;a href="https://www.linkedin.com/in/muhammad-usman-strategist/" rel="noopener noreferrer"&gt;Muhammad Usman&lt;/a&gt;&lt;br&gt;
WordPress Developer | Website Strategist | SEO Specialist&lt;br&gt;
Don’t forget to subscribe to &lt;a href="https://developersjourney.substack.com/" rel="noopener noreferrer"&gt;Developer’s Journey&lt;/a&gt; to show your support.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" alt="Developer's Journey"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>programming</category>
    </item>
    <item>
      <title>Copy These 29 Text Animations. The Code Is Already Done.</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Mon, 20 Jul 2026 10:37:15 +0000</pubDate>
      <link>https://dev.to/web_dev-usman/copy-these-29-text-animations-the-code-is-already-done-87d</link>
      <guid>https://dev.to/web_dev-usman/copy-these-29-text-animations-the-code-is-already-done-87d</guid>
      <description>&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%2F7hy2ba1ahgm50wkv2nkw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7hy2ba1ahgm50wkv2nkw.gif" alt=" " width="720" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most text animation on the web is the same three tricks wearing different clothes: fade something in, slide something up, maybe throw a blur on it. I wanted to know how far past those three tricks you could actually go without reaching for a heavy animation library, so I built twenty-nine of them, side by side, in plain CSS and JavaScript. Some are one property. Some are a canvas loop. All of them run without a single dependency.&lt;/p&gt;

&lt;p&gt;Here’s what I learned building all twenty-nine, organized by what they’re actually for: pulling a reader’s eye to new content, holding their attention on something static, responding to their cursor, or clearing the stage for what comes next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;As promised, here are all the examples.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/web-strategist/embed/dPNmvGo?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Reveal: getting text to arrive instead of just appearing
&lt;/h3&gt;

&lt;p&gt;The simplest possible text animation is &lt;code&gt;opacity: 0&lt;/code&gt; to &lt;code&gt;opacity: 1&lt;/code&gt;. It works. It's also invisible as a design choice, because every site does it. The interesting question is what happens between 0 and 1.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scramble
&lt;/h4&gt;

&lt;p&gt;This animation replaces letters with noise before resolving them, left to right, like a decoding sequence:&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;run&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;revealed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&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;frame&lt;/span&gt;&lt;span class="o"&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;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;target&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="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &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;out&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;revealed&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CHARS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;randInt&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;CHARS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&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="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;out&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;frame&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;revealed&lt;/span&gt;&lt;span class="o"&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;revealed&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;target&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="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2Fy3y46eu8xqyaj865qgua.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy3y46eu8xqyaj865qgua.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The trick is the &lt;code&gt;frame % 3&lt;/code&gt; check. Without it, a letter locks in on every single tick, and the whole word resolves in a blink. Slowing the reveal rate independently of the redraw rate is what makes it read as decoding rather than flickering.&lt;/p&gt;

&lt;h4&gt;
  
  
  Stagger Fade and Blur&amp;nbsp;Focus
&lt;/h4&gt;

&lt;p&gt;Both animations split text into individual character spans and animate each one on a delay proportional to its position:&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;splitToSpans&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="nx"&gt;textOverride&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;staggerMax&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;text&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;len&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;chars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&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;s&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;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;span&lt;/span&gt;&lt;span class="dl"&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;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;staggerMax&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;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;--d&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;i&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;staggerMax&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ms&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;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &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="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;u00A0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;frag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&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="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2Fbwfzcmfcz6fvjs16hry9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbwfzcmfcz6fvjs16hry9.gif" width="800" height="370"&gt;&lt;/a&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;.stage&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-anim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"blur"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.ch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&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;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;14px&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;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.06&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;opacity&lt;/span&gt; &lt;span class="m"&gt;0.6s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="m"&gt;0.6s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt; &lt;span class="m"&gt;0.6s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transition-delay&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;--d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0ms&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2F49wbc85de98m1ljzzhio.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F49wbc85de98m1ljzzhio.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice the delay is computed once, in JavaScript, then handed to CSS as a custom property. The animation itself is pure CSS transition; JavaScript’s only job is figuring out how long each letter should wait its turn. This split matters because it means the animation performance comes from the browser’s transition engine, not from a JavaScript timing loop trying to keep twenty things in sync.&lt;/p&gt;

&lt;h4&gt;
  
  
  3D Flip-In
&lt;/h4&gt;

&lt;p&gt;This one takes the same staggered-span approach and adds a hinge:&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;.stage&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-anim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"flip"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;perspective&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.stage&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-anim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"flip"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.ch&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;rotateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;90deg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transform-origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt; &lt;span class="m"&gt;0.5s&lt;/span&gt; &lt;span class="n"&gt;cubic-bezier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2Fbmr9ayvylys2bdp7j4pz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbmr9ayvylys2bdp7j4pz.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;perspective&lt;/code&gt; on the parent is what gives &lt;code&gt;rotateX&lt;/code&gt; something to rotate through. Skip it and the letters just squash flat instead of appearing to fold toward you.&lt;/p&gt;

&lt;h4&gt;
  
  
  Split-Flap
&lt;/h4&gt;

&lt;p&gt;This is the one that actually earns its comparison to an airport departures board, because each letter cycles through real random characters before landing, at a slightly different speed per letter:&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;spans&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&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;finalChar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&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;setInterval&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;count&lt;/span&gt;&lt;span class="o"&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;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;total&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;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;finalChar&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;clearInterval&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CHARS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;randInt&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;CHARS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;code&gt;45 + i * 4&lt;/code&gt; is doing quiet work here. Each letter's interval runs slightly slower than the one before it, so they don't all land on the same frame. That small stagger is the entire difference between "looks like a glitch" and "looks like a mechanism."&lt;/p&gt;

&lt;h4&gt;
  
  
  Curtain Wipe and Ink Signature
&lt;/h4&gt;

&lt;p&gt;Both fake a reveal without touching the text’s own opacity at all. The curtain is a solid bar sitting on top of the word that shrinks away:&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;.curtain-bar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transform-origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;left&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;scaleX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt; &lt;span class="m"&gt;0.9s&lt;/span&gt; &lt;span class="n"&gt;cubic-bezier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.6&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="m"&gt;0.15&lt;/span&gt;&lt;span class="p"&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="nc"&gt;.stage&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-anim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"curtain"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nc"&gt;.in&lt;/span&gt; &lt;span class="nc"&gt;.curtain-bar&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;scaleX&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The ink signature draws an SVG path underneath the word using the classic dash offset trick:&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;.ink-underline&lt;/span&gt; &lt;span class="nt"&gt;path&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;stroke-dasharray&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;340&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;stroke-dashoffset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;340&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;stroke-dashoffset&lt;/span&gt; &lt;span class="m"&gt;1s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.stage&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-anim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"ink"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nc"&gt;.in&lt;/span&gt; &lt;span class="nc"&gt;.ink-underline&lt;/span&gt; &lt;span class="nt"&gt;path&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;stroke-dashoffset&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Set the dash array and the offset to the same number, and the entire stroke starts invisible. Animate the offset to zero, and the line appears to draw itself. No JavaScript needed for the drawing itself, just the intersection observer that adds the&amp;nbsp;&lt;code&gt;.in&lt;/code&gt; class when the element scrolls into view.&lt;/p&gt;

&lt;h4&gt;
  
  
  Glitch Split
&lt;/h4&gt;

&lt;p&gt;This is the one specimen in this group that runs continuously instead of triggering once, using duplicated text layered in red and cyan with clipped, offset keyframes:&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;.glitch&lt;/span&gt;&lt;span class="nd"&gt;::before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data-text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ff3b6b&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;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-2px&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="py"&gt;mix-blend-mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;screen&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;glitchTop&lt;/span&gt; &lt;span class="m"&gt;2.6s&lt;/span&gt; &lt;span class="n"&gt;infinite&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;glitchTop&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="err"&gt;89&lt;/span&gt;&lt;span class="o"&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;clip-path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;inset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&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;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translate&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="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;90&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;clip-path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;inset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10%&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;60%&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;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-3px&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;-1px&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;&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%2Frrygg1belm3cb13squ7q.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frrygg1belm3cb13squ7q.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;0%, 89%, 100%&lt;/code&gt; selector is the key. Ninety percent of the animation cycle is a clean, un-glitched hold. The glitch itself lives in a narrow 10% window. That ratio is what keeps it readable as text with an occasional artifact, rather than an unreadable flicker.&lt;/p&gt;

&lt;h3&gt;
  
  
  Loop: text that keeps moving because it’s meant to be looked at, not&amp;nbsp;read
&lt;/h3&gt;

&lt;p&gt;Reveal animations run once and stop. Loop animations are for text that needs to hold attention indefinitely, a hero headline, a status indicator, a ticker.&lt;/p&gt;

&lt;h4&gt;
  
  
  Wave
&lt;/h4&gt;

&lt;p&gt;This staggers a vertical bounce per character using the same &lt;code&gt;--i&lt;/code&gt; index every span already carries:&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;.stage&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-anim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"wave"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nc"&gt;.in&lt;/span&gt; &lt;span class="nc"&gt;.ch&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;waveMove&lt;/span&gt; &lt;span class="m"&gt;1.8s&lt;/span&gt; &lt;span class="n"&gt;ease-in-out&lt;/span&gt; &lt;span class="n"&gt;infinite&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;animation-delay&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;--i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="m"&gt;60ms&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2Fmngqdu5gq81aiaaeyw2e.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmngqdu5gq81aiaaeyw2e.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;animation-delay&lt;/code&gt; runs off &lt;code&gt;calc()&lt;/code&gt; reading straight from the custom property, so there's no per-letter JavaScript at all beyond the initial split. That's worth noticing: three of the loop animations in this set reuse the exact same span-splitting utility that the reveal animations use. The difference between "letters fade in" and "letters bounce forever" is which CSS rule you attach to&amp;nbsp;&lt;code&gt;.ch&lt;/code&gt;, not how you built the letters.&lt;/p&gt;

&lt;h4&gt;
  
  
  Shimmer
&lt;/h4&gt;

&lt;p&gt;This fakes a light sweep using a gradient clipped to text:&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;.stage&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-anim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"shimmer"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.demo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;linear-gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="m"&gt;100deg&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;--paper-dim&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="m"&gt;30%&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;--brass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="m"&gt;45%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="m"&gt;#fff&lt;/span&gt; &lt;span class="m"&gt;50%&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;--brass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="m"&gt;55%&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;--paper-dim&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="m"&gt;70%&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;background-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;250%&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;-webkit-background-clip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-clip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;shimmerMove&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;200%&lt;/span&gt; &lt;span class="m"&gt;0&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="m"&gt;-100%&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&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%2F70r4gu8k1jq8tbky9d4o.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F70r4gu8k1jq8tbky9d4o.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The gradient is three times wider than the text (&lt;code&gt;250%&lt;/code&gt;), which is what lets the bright band slide across and off the edges cleanly instead of popping in and out abruptly.&lt;/p&gt;

&lt;h4&gt;
  
  
  Breathing Glow
&lt;/h4&gt;

&lt;p&gt;This is the smallest amount of code in the whole set for one of the more effective results, just an oscillating &lt;code&gt;text-shadow&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="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;glowPulse&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="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;text-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;227&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;169&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;74&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;50&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;text-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;26px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;227&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;169&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;74&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;6px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;227&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;169&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;74&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.55&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;&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%2F5fq5ed86pqe63jm3mhyi.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5fq5ed86pqe63jm3mhyi.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two shadow layers at the peak, one wide and soft, one tight and bright, is what sells the glow. A single shadow value just looks like the text got fuzzy.&lt;/p&gt;

&lt;h4&gt;
  
  
  Liquid Wobble
&lt;/h4&gt;

&lt;p&gt;This treats each letter like it’s suspended in something viscous, skewing and squashing on a cycle:&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%2Fwq9gwj56c30sr8gxld4p.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwq9gwj56c30sr8gxld4p.gif" width="800" height="370"&gt;&lt;/a&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="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;liquidWob&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="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;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;skewX&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="n"&gt;scaleY&lt;/span&gt;&lt;span class="p"&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="err"&gt;25&lt;/span&gt;&lt;span class="o"&gt;%&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;skewX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-6deg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;scaleY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.08&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;50&lt;/span&gt;&lt;span class="o"&gt;%&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;skewX&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="n"&gt;scaleY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.94&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;75&lt;/span&gt;&lt;span class="o"&gt;%&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;skewX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6deg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;scaleY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.05&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;h4&gt;
  
  
  Eased Marquee
&lt;/h4&gt;

&lt;p&gt;This replaces the classic linear scroll with a cubic-bezier that accelerates, holds, and decelerates:&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;marqueeMove&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;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;45&lt;/span&gt;&lt;span class="o"&gt;%&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;translateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-40%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;50&lt;/span&gt;&lt;span class="o"&gt;%&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;translateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-40%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;95&lt;/span&gt;&lt;span class="o"&gt;%&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;translateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6%&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;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6%&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;&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%2F0k08bo0uplo2lcjd0jqk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0k08bo0uplo2lcjd0jqk.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That flat stretch from 45% to 50% is a deliberate pause at the far end of the scroll, giving a reader’s eye a moment to land before the track reverses. Pure linear marquees never rest, which is exactly why they read as cheap.&lt;/p&gt;

&lt;h4&gt;
  
  
  Kinetic Rotator
&lt;/h4&gt;

&lt;p&gt;This is the one loop animation that’s mostly JavaScript, because it’s swapping entire words, not animating one fixed string:&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;show&lt;/span&gt;&lt;span class="p"&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="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&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="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;translateY(18px)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&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="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;translateY(0)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The &lt;code&gt;requestAnimationFrame&lt;/code&gt; wrapper matters more than it looks like it should. Set the transform and immediately flip opacity in the same tick, and the browser may collapse both style writes into one paint, skipping the transition entirely. Forcing a frame boundary between "set the start state" and "set the end state" is what guarantees the transition actually plays.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interactive: animations that need a cursor to mean&amp;nbsp;anything
&lt;/h3&gt;

&lt;p&gt;These five don’t animate on their own. They’re built to respond to the reader in real time, which means the JavaScript is doing continuous math on every &lt;code&gt;mousemove&lt;/code&gt; event instead of firing once and finishing.&lt;/p&gt;

&lt;h4&gt;
  
  
  Magnetic Pull
&lt;/h4&gt;

&lt;p&gt;This measures the distance from the cursor to each letter’s center and nudges the letter toward it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;stage&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;mousemove&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;span class="nx"&gt;spans&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&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;dx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mx&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;dy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;my&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cy&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;dist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&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;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dy&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;dy&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;pull&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;dist&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;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`translate(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;dx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;pull&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;
      &lt;span class="nx"&gt;dy&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;pull&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.35&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px)`&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;&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%2Fahc63b8xdn88bs80tc6m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fahc63b8xdn88bs80tc6m.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Math.max(30,&amp;nbsp;...)&lt;/code&gt; prevents a division that blows up as the cursor gets close to a letter's exact center. Without that floor, &lt;code&gt;90 / dist&lt;/code&gt; approaches infinity and the letter would jump wildly instead of easing toward the cursor.&lt;/p&gt;

&lt;h4&gt;
  
  
  Weight Morph
&lt;/h4&gt;

&lt;p&gt;This does something you can’t do with a JPEG: it changes the actual weight axis of a variable font in response to proximity.&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;dist&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;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mx&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cx&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;wght&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fontVariationSettings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`"wght" &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;wght&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;&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%2Fn2mwsam7qfggoas2ojtt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn2mwsam7qfggoas2ojtt.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This only works because the font file itself has weight defined as a continuous variable axis rather than a fixed set of files (400, 700, and so on). Static font formats can’t do this at all; there’s no in-between file to interpolate toward.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cursor Distort
&lt;/h4&gt;

&lt;p&gt;This applies a fisheye skew based on horizontal distance from the pointer, with the skew direction flipping depending on which side the cursor sits:&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;dist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mx&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;cx&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;proximity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&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;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;120&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;skew&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;proximity&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h4&gt;
  
  
  Scroll Scrub
&lt;/h4&gt;

&lt;p&gt;This ties a text fill directly to scroll position instead of the cursor, using a gradient clipped to text with a hard stop at a variable percentage:&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;update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoundingClientRect&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;progress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&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="nx"&gt;vh&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;stage&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;--p&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;progress&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.stage&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-anim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"scrub"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.demo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;linear-gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="m"&gt;90deg&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;--paper&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;--p&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="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--paper-dim&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;--p&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="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;-webkit-background-clip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-clip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2F0nxiqro18lkprtonnxsw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0nxiqro18lkprtonnxsw.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The gradient has a hard edge, not a soft one, because both color stops sit at the exact same position (&lt;code&gt;var(--p)&lt;/code&gt;). That's what turns a gradient into a fill meter instead of a blur.&lt;/p&gt;

&lt;h4&gt;
  
  
  Hover Scatter
&lt;/h4&gt;

&lt;p&gt;This is the simplest of the five: split the word into spans, then on &lt;code&gt;mouseenter&lt;/code&gt;, throw each one to a random offset and rotation, and let a CSS transition pull it back on &lt;code&gt;mouseleave&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="nx"&gt;stage&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;mouseenter&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;spans&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&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;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`translate(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;px, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;30&lt;/span&gt;
    &lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;px) rotate(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;deg)`&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;&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%2Fztpdqv9op82ey828n3i0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fztpdqv9op82ey828n3i0.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The animation is entirely the CSS &lt;code&gt;transition&lt;/code&gt; on&amp;nbsp;&lt;code&gt;.ch&lt;/code&gt;; JavaScript only ever sets a target, never runs the motion itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exit: clearing the stage, deliberately
&lt;/h3&gt;

&lt;p&gt;Exit animations get less attention than entrances, but they’re what makes a hover interaction feel complete instead of half finished.&lt;/p&gt;

&lt;h4&gt;
  
  
  Shatter
&lt;/h4&gt;

&lt;p&gt;This pre-computes a random trajectory per letter, storing it as CSS custom properties the moment the page loads, then triggers the actual motion purely through&amp;nbsp;&lt;code&gt;:hover&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="nx"&gt;spans&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&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;s&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;--tx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;px&lt;/span&gt;&lt;span class="dl"&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;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;--ty&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;px&lt;/span&gt;&lt;span class="dl"&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;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;--tr&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deg&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.stage&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-anim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"shatter"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="nc"&gt;.ch&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;translate&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;--tx&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="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--ty&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="n"&gt;rotate&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;--tr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0deg&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Precomputing the random values once and storing them as properties means every hover produces the same shatter pattern instead of a new random one each time. That consistency is what makes it feel designed rather than glitchy.&lt;/p&gt;

&lt;h4&gt;
  
  
  Dissolve and&amp;nbsp;Fold
&lt;/h4&gt;

&lt;p&gt;Both keep the whole word intact and animate it as one block instead of splitting into letters, which is a deliberate contrast to shatter:&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;.stage&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-anim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"dissolve"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="nc"&gt;.demo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&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;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.stage&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-anim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"fold"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="nc"&gt;.demo&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;rotateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;70deg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;scaleY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2Fhlw6f50as4gnnr86qzjy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhlw6f50as4gnnr86qzjy.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fold needs &lt;code&gt;perspective&lt;/code&gt; on its parent stage for the same reason flip-in does, without it, &lt;code&gt;rotateX&lt;/code&gt; just flattens the text vertically instead of appearing to tip away from the viewer.&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%2Fdcp4o3nmlose4x8q53zz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdcp4o3nmlose4x8q53zz.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Terminal Cycle
&lt;/h4&gt;

&lt;p&gt;This loops through typing and deleting several strings, character by character, in an endless cycle that never needs a hover trigger:&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;typeWord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cb&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;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&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;setInterval&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;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&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;i&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="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;word&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="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;clearInterval&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="nf"&gt;cb&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="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deleteWord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cb&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;text&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="nx"&gt;textContent&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;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&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="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&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;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;clearInterval&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="nf"&gt;cb&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="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2Fd6dvr6id36ln6frxw4tj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd6dvr6id36ln6frxw4tj.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deleting runs almost twice as fast as typing, 35ms per character against 60ms. That asymmetry is what makes it read as a terminal instead of just the typewriter effect in reverse.&lt;/p&gt;

&lt;h3&gt;
  
  
  Experimental: the ones that don’t fit a category because they’re doing something structurally different
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Variable Weight Breathing
&lt;/h4&gt;

&lt;p&gt;This animates a font’s weight axis on a loop instead of on cursor proximity:&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;wghtBreathe&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="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="py"&gt;font-variation-settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"wght"&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;"opsz"&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;50&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;font-variation-settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"wght"&lt;/span&gt; &lt;span class="m"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;"opsz"&lt;/span&gt; &lt;span class="m"&gt;100&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;&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%2Ffbejhf3260u93kiah856.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffbejhf3260u93kiah856.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note the &lt;code&gt;opsz&lt;/code&gt; (optical size) axis moving alongside weight. Fonts with a real optical size axis subtly reshape their letterforms at large sizes, not just thicken them, so animating both together looks like the letters are actually being redrawn rather than just gaining a bold filter.&lt;/p&gt;

&lt;h4&gt;
  
  
  Matrix Formation
&lt;/h4&gt;

&lt;p&gt;This is the one specimen built on canvas instead of DOM spans, because it needs to render a whole field of falling, changing characters behind a target word:&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;for &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;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;cols&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="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;locked&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;drops&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="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#C7A03D&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;char&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;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CHARS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;randInt&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;CHARS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ch&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;drops&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="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;drops&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="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&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%2Fk8b0oixou6dhx9xt4wkq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk8b0oixou6dhx9xt4wkq.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Only certain columns get a &lt;code&gt;locked&lt;/code&gt; target letter assigned; the rest just rain random characters forever. The word "forms" because those specific columns stop scrambling once their falling counter reaches the target row, while every other column keeps going. It's the only animation in the set where DOM manipulation would have been the wrong tool entirely, drawing and erasing dozens of characters sixty times a second is exactly what canvas is for.&lt;/p&gt;

&lt;h4&gt;
  
  
  Word Morph
&lt;/h4&gt;

&lt;p&gt;This cross-fades between two full words stacked in the same position:&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;.morph-wrap&lt;/span&gt; &lt;span class="nc"&gt;.demo.b&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;absolute&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;0&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;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&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;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.morph-wrap.swap&lt;/span&gt; &lt;span class="nc"&gt;.demo.a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&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;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.morph-wrap.swap&lt;/span&gt; &lt;span class="nc"&gt;.demo.b&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blur&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Both words occupy the same coordinates via &lt;code&gt;position: absolute&lt;/code&gt;, so the swap reads as one word transforming into another rather than two separate words taking turns.&lt;/p&gt;

&lt;h4&gt;
  
  
  Chromatic Scroll
&lt;/h4&gt;

&lt;p&gt;This ties a red/cyan channel split to how far a section sits from the vertical center of the viewport:&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;offset&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="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="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;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stageCenter&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;center&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="nx"&gt;vh&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mag&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;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;8&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="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textShadow&lt;/span&gt; &lt;span class="o"&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;offset&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;mag&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px 0 rgba(255,59,107,.7), &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;mag&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px 0 rgba(59,214,255,.7)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The two shadow offsets are exact negatives of each other, which is what keeps the split symmetric around the true letterforms instead of just shifting the whole word sideways.&lt;/p&gt;

&lt;h4&gt;
  
  
  Gravity Drop
&lt;/h4&gt;

&lt;p&gt;This reuses the same staggered-span helper from the reveal group, but with a keyframe animation that overshoots before settling:&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;gravityDrop&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;opacity&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;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-160px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;60&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&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;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="err"&gt;80&lt;/span&gt;&lt;span class="o"&gt;%&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;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-4px&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;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&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;translateY&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;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%2Fvnb0qqx0igx031rmpzhh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvnb0qqx0igx031rmpzhh.gif" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The overshoot at 60% and the small bounce back at 80% are what sell the idea of weight. A letter that falls and stops dead at 0 looks like it faded in from above. A letter that falls past zero and settles back looks like it actually landed.&lt;/p&gt;

&lt;h3&gt;
  
  
  What twenty-nine examples taught me about three or four techniques
&lt;/h3&gt;

&lt;p&gt;Strip away the surface variety, and this whole set really only rests on a handful of underlying mechanisms: splitting text into per-character spans and staggering a CSS transition across them, clipping a gradient to text for anything involving color movement, reading and writing custom properties as the bridge between JavaScript’s math and CSS’s rendering, and canvas for the one case where you’re not really animating text at all but drawing it fresh every frame.&lt;/p&gt;

&lt;p&gt;The variety comes from combining those four ideas differently, not from needing thirty different technical approaches. Scramble and split-flap both interval-scramble characters; the only real difference is that split-flap staggers its per-letter timing and scramble doesn’t. Wave and liquid wobble both loop a transform on the same span-index delay; one moves the letter, the other skews it. Once you see the shared mechanism underneath, twenty-nine animations stop looking like twenty-nine things to learn and start looking like four things to combine.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Did you learn something good today as a developer?&lt;br&gt;
Then show some love.&lt;br&gt;
© &lt;a href="https://www.linkedin.com/in/muhammad-usman-strategist/" rel="noopener noreferrer"&gt;Muhammad Usman&lt;/a&gt;&lt;br&gt;
WordPress Developer | Website Strategist | SEO Specialist&lt;br&gt;
Don’t forget to subscribe to &lt;a href="https://developersjourney.substack.com/" rel="noopener noreferrer"&gt;Developer’s Journey&lt;/a&gt; to show your support.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" alt="Developer's Journey" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>css</category>
    </item>
    <item>
      <title>Stop building marketing sites with React, Next.js, and Angular (you're overengineering them)</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Fri, 03 Jul 2026 10:41:35 +0000</pubDate>
      <link>https://dev.to/web_dev-usman/stop-building-marketing-sites-with-react-nextjs-and-angular-youre-overengineering-them-1jp6</link>
      <guid>https://dev.to/web_dev-usman/stop-building-marketing-sites-with-react-nextjs-and-angular-youre-overengineering-them-1jp6</guid>
      <description>&lt;p&gt;A client asks for a website. You open VS Code, run &lt;code&gt;create-next-app&lt;/code&gt;, wire up a component library, connect a CMS, and three weeks later ship a beautifully engineered site that loads 400KB of JS to render a hero section and a contact form.&lt;/p&gt;

&lt;p&gt;The client's happy for about a month. Then they ask why their bounce rate is 70% and their Lighthouse score sits in the 40s. You didn't do anything wrong technically. You just answered a question nobody asked.&lt;/p&gt;

&lt;p&gt;This happens constantly with marketing and business websites, the kind whose only job is to get someone to book a call, sign up, or buy something. Not dashboards. Not products with user accounts, permissions, real-time state. Static pages selling a service.&lt;/p&gt;

&lt;h2&gt;
  
  
  The default stack isn't always the right stack
&lt;/h2&gt;

&lt;p&gt;React, Next.js, and Angular solve real problems: client-side state management, complex interactivity, reusable components across a large app. A marketing site has none of those problems. It has five to ten pages, a form, maybe a blog, and one job: turn a visitor into a lead.&lt;/p&gt;

&lt;p&gt;Reach for a SPA framework by default and you inherit a hydration step, a JS runtime, a build pipeline, a bundle size, all to serve content that's mostly static text and images. Every one of those adds milliseconds to Time to Interactive. Google's own research shows bounce probability climbing sharply once load time passes 3 seconds.&lt;/p&gt;

&lt;p&gt;This isn't a knock on the frameworks. It's a mismatch between the tool and the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a marketing site actually needs
&lt;/h2&gt;

&lt;p&gt;Ask what the page has to do before deciding how to build it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load fast on a mid-range phone over a mediocre connection&lt;/li&gt;
&lt;li&gt;Rank in search, which means clean HTML and fast Core Web Vitals&lt;/li&gt;
&lt;li&gt;Let a marketer edit copy without opening a pull request&lt;/li&gt;
&lt;li&gt;Push a visitor toward one action per page, not compete with a dozen widgets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For that job, plain HTML/CSS/JS, WordPress, Webflow, or a static-first tool like Astro will usually beat a client-rendered framework on the metrics that matter to the business: load time, SEO, and how easily a non-technical person can update it after launch.&lt;/p&gt;

&lt;p&gt;Astro is worth calling out on its own. It ships zero JS by default and only hydrates the components that actually need interactivity. You get component-based development without paying the client-side framework tax.&lt;/p&gt;

&lt;h2&gt;
  
  
  When React, Next.js, and Angular are the right call
&lt;/h2&gt;

&lt;p&gt;This isn't "never use a framework." It's "match the tool to the job":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The site needs a logged-in dashboard, account area, complex state&lt;/li&gt;
&lt;li&gt;There's heavy client-side interactivity: filtering, real-time updates, drag-and-drop&lt;/li&gt;
&lt;li&gt;You're building a product, not a marketing page for one&lt;/li&gt;
&lt;li&gt;The team already has a design system built around the framework, and switching costs more than it saves&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of that's true, use the framework. Next.js with static generation still performs well for content-heavy sites too. The point isn't "React bad." It's "pick based on the job, not the resume line."&lt;/p&gt;

&lt;h2&gt;
  
  
  The part developers usually skip
&lt;/h2&gt;

&lt;p&gt;Here's what actually determines whether the site works: define what it needs to do before touching the stack.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What's the one action you want a visitor to take?&lt;/li&gt;
&lt;li&gt;How long should the page be to build trust without losing them?&lt;/li&gt;
&lt;li&gt;Where does the CTA go, and how many times does it repeat?&lt;/li&gt;
&lt;li&gt;What's the path from "never heard of this business" to "booked a call"?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't marketing fluff questions. They're requirements for the build, the same way "does this need real-time sync" is a requirement for a chat app. Skip them and you'll ship something structurally sound that generates zero leads, because nobody built it against an objective in the first place.&lt;/p&gt;

&lt;p&gt;A fast, well-coded site that doesn't route people toward a decision is an expensive digital brochure. The stack only matters once you know what the page is trying to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;Before you scaffold anything, ask what the site needs to accomplish, not what you're comfortable building. Most marketing sites need speed, clean markup, easy editing: HTML/CSS/JS, WordPress, Webflow, or Astro. Save React, Next.js, and Angular for sites that need what they're actually good at: complex state, heavy interactivity, logged-in experiences.&lt;/p&gt;

&lt;p&gt;Your job isn't proving you can build a SPA. It's shipping something that gets the business what it's paying for.&lt;/p&gt;

&lt;h2&gt;
  
  
  One more thing: hosting matters too
&lt;/h2&gt;

&lt;p&gt;All of this falls apart on slow hosting. A lean stack on a bad server still ships a bad Time to First Byte, and that's a metric no framework choice fixes after the fact.&lt;/p&gt;

&lt;p&gt;For client marketing sites I usually reach for &lt;a href="https://www.hostinger.com/pk?REFERRALCODE=USISTUDIOHE1" rel="noopener noreferrer"&gt;Hostinger&lt;/a&gt; (referral link, I get credit if you sign up). It's fast without any server tuning and handles WordPress or a static Astro build the same way. That link also knocks an extra 20% off.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>astro</category>
    </item>
    <item>
      <title>Everything a Junior Developer Needs to Know About Hosting Before Their First Client Project</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Mon, 29 Jun 2026 07:24:31 +0000</pubDate>
      <link>https://dev.to/web_dev-usman/everything-a-junior-developer-needs-to-know-about-hosting-before-their-first-client-project-1cbd</link>
      <guid>https://dev.to/web_dev-usman/everything-a-junior-developer-needs-to-know-about-hosting-before-their-first-client-project-1cbd</guid>
      <description>&lt;p&gt;Your first client project goes well. You build the site, they love it, and then they ask: "So how do we get this thing online?"&lt;/p&gt;

&lt;p&gt;And you realize you have no answer ready.&lt;/p&gt;

&lt;p&gt;Hosting doesn't come up much when you're learning to code. Tutorials assume you already know what it is, or they skip it entirely and deploy to Vercel with one click. But your client's local bakery isn't going on Vercel. They want an email that says @theirbakery.com and a URL they can put on a business card.&lt;/p&gt;

&lt;p&gt;Here's what you actually need to know before that conversation happens.&lt;/p&gt;




&lt;h2&gt;
  
  
  The three things every client site needs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg7o4uwdq2c5ghycwvoab.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%2Fg7o4uwdq2c5ghycwvoab.png" alt="The three things every client site needs" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Get clear on the difference between a domain, hosting, and SSL. Junior devs often mix these up, and clients always will.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;domain&lt;/strong&gt; is the address: theirbakery.com. You register it through a domain registrar (Namecheap, Porkbun, or through your hosting provider). A .com costs roughly $10–15/year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hosting&lt;/strong&gt; is where the website files live. When someone types the domain into a browser, their computer connects to the hosting server and loads the files. Shared hosting (where the client's site sits on a server alongside hundreds of other sites) costs $2–10/month and handles almost every small business site fine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SSL&lt;/strong&gt; is the padlock in the browser bar. It means the connection is encrypted. You need it. Google flags sites without it. Most hosting providers include it free via Let's Encrypt, so this is usually a checkbox during setup, not a separate purchase.&lt;/p&gt;

&lt;p&gt;Those three things are the floor. Everything else is optional until the client asks for it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who should own the hosting account
&lt;/h2&gt;

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

&lt;p&gt;This is where junior developers most often make a mistake. The answer is: the client.&lt;/p&gt;

&lt;p&gt;If the hosting account is in your name and the relationship ends badly, you're holding their website hostage. If they want to hire someone else later, they're stuck waiting on you. If you get hit by a bus, they lose access to their own site.&lt;/p&gt;

&lt;p&gt;Set the account up in the client's name using their email address and their payment method. You can be added as a collaborator or get the login credentials to manage it, but the account is theirs.&lt;/p&gt;

&lt;p&gt;Same rule for the domain. Register it in their name. Disputes over domain ownership are slow, expensive, and completely avoidable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Shared hosting is fine for most small clients
&lt;/h2&gt;

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

&lt;p&gt;A lot of junior devs assume clients need something powerful: a VPS, a cloud server, something that sounds serious. For a brochure site or a WordPress blog getting a few hundred visitors a day, they don't.&lt;/p&gt;

&lt;p&gt;Shared hosting means the client's site runs on a server shared with other sites, splitting the resources. For low-traffic sites this is almost indistinguishable from dedicated resources in practice. It's cheap because the cost is shared, not because it's bad.&lt;/p&gt;

&lt;p&gt;For most early client projects, the &lt;a href="https://www.hostinger.com/pk?REFERRALCODE=USISTUDIOHE1" rel="noopener noreferrer"&gt;Hostinger Premium or Business plan&lt;/a&gt; covers everything you need. The Premium plan is around $2.99/month and lets you host up to 100 websites, which matters once you have a few clients, because you're not paying for a separate account per project. One plan, multiple sites, free domain in the first year, SSL included.&lt;/p&gt;

&lt;p&gt;When does shared hosting stop being enough? When a site gets consistent traffic in the tens of thousands of monthly visitors, runs resource-heavy custom code, or processes a lot of simultaneous transactions. A WooCommerce store doing serious volume needs a VPS or a managed host. A florist's five-page website does not.&lt;/p&gt;




&lt;h2&gt;
  
  
  What cPanel actually is
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4e0hcbmdlw32g1ux4oj4.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%2F4e0hcbmdlw32g1ux4oj4.png" alt="cPanel" width="799" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most shared hosting accounts come with cPanel, a browser-based dashboard for managing the hosting. It's where you'll spend most of your time.&lt;/p&gt;

&lt;p&gt;From cPanel you can create email accounts, install WordPress in about 90 seconds, manage files through a built-in file manager, create MySQL databases, configure DNS records, set up subdomains, and check error logs.&lt;/p&gt;

&lt;p&gt;You don't need to memorize it before you start. The layout is consistent enough across providers that you'll figure it out as you go. The main thing is knowing it exists: it's your primary interface for managing a client site, not the command line, at least not for typical small projects.&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%2Fz2ahxg2scjg7wa4y9mj0.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%2Fz2ahxg2scjg7wa4y9mj0.png" alt="Hpanel Hostinger" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some hosts use a custom dashboard instead of cPanel. Hostinger uses one called hPanel. Same concept, different layout.&lt;/p&gt;




&lt;h2&gt;
  
  
  Clients always want email
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ukm58fv9sbw7bvs31j4.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%2F4ukm58fv9sbw7bvs31j4.png" alt="Web Mail" width="799" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don't ask about email before you build the site, your client will ask about it after launch.&lt;/p&gt;

&lt;p&gt;They want &lt;a href="mailto:hello@theirbusiness.com"&gt;hello@theirbusiness.com&lt;/a&gt;, not &lt;a href="mailto:hello@gmail.com"&gt;hello@gmail.com&lt;/a&gt;. Most hosting plans include email hosting. You create the accounts in cPanel and hand over the credentials. The client then connects that address to whatever app they use (Gmail, Outlook, Apple Mail) using IMAP settings the host provides.&lt;/p&gt;

&lt;p&gt;Walk them through the setup, or write them a short guide. "How do I check my business email in Gmail" is the most common post-launch question you'll get, almost without exception.&lt;/p&gt;

&lt;p&gt;One thing worth knowing: email on shared hosting is basic. It works fine for a small business that needs a contact address and maybe two or three accounts. If a client sends mass newsletters or runs a sales team with real email volume, they need a dedicated service like Google Workspace ($6/user/month) instead. Know which situation you're in before launch.&lt;/p&gt;




&lt;h2&gt;
  
  
  Backups: have this conversation before something breaks
&lt;/h2&gt;

&lt;p&gt;Most hosting providers run automated backups, but the frequency varies. Hostinger does weekly backups on the basic plans and daily backups on higher-tier ones. If the site gets hacked on a Wednesday and your backup schedule is weekly, you might be restoring a version that's six days old.&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%2F5b8ve3l8b65gjabzxzw5.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%2F5b8ve3l8b65gjabzxzw5.png" alt="Hostinger backup screenshot" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tell the client this. Ask if they want a more aggressive setup. A WordPress plugin like UpdraftPlus can run its own backups to Google Drive regardless of what the host does. It's worth installing on every WordPress project, full stop.&lt;/p&gt;

&lt;p&gt;The time not to be explaining backup schedules is while you're trying to recover a broken site at 11pm.&lt;/p&gt;




&lt;h2&gt;
  
  
  A checklist for your first handoff
&lt;/h2&gt;

&lt;p&gt;Before you hand anything over:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hosting account in the client's name with their payment info&lt;/li&gt;
&lt;li&gt;Domain registered in the client's name&lt;/li&gt;
&lt;li&gt;SSL active (confirm the padlock appears in the browser)&lt;/li&gt;
&lt;li&gt;Email accounts set up, client can log in&lt;/li&gt;
&lt;li&gt;Client has their cPanel or hPanel credentials&lt;/li&gt;
&lt;li&gt;Backups are running&lt;/li&gt;
&lt;li&gt;You've agreed in writing on whether you're doing ongoing maintenance or they're on their own&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one matters. If they expect free updates and you expect to be done at launch, someone is going to be annoyed in three months. Make it explicit before the project ends, not after.&lt;/p&gt;




&lt;p&gt;Hosting feels complicated before you've dealt with it. By your third client site it's close to routine. The first one takes longer because you're learning where the buttons are. That's normal.&lt;/p&gt;

&lt;p&gt;The part that trips people up isn't technical. It's the account ownership conversation and the email conversation. Have both of them early, and most of the rest is just clicking through a setup wizard.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're ready to get your first client site online, &lt;a href="https://www.hostinger.com/pk?REFERRALCODE=USISTUDIOHE1" rel="noopener noreferrer"&gt;Hostinger is where I'd start&lt;/a&gt; — 20% off with that link, free domain in the first year, and everything covered in this article works out of the box.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>hosting</category>
      <category>career</category>
    </item>
    <item>
      <title>The Real Reason Developers Give Up Side Projects (It Is Not Motivation)</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Tue, 23 Jun 2026 07:18:49 +0000</pubDate>
      <link>https://dev.to/web_dev-usman/the-real-reason-developers-give-up-side-projects-it-is-not-motivation-43cd</link>
      <guid>https://dev.to/web_dev-usman/the-real-reason-developers-give-up-side-projects-it-is-not-motivation-43cd</guid>
      <description>&lt;p&gt;Open your GitHub right now. Go to your repositories and count the unfinished ones. Three? Seven? More than you are comfortable admitting?&lt;/p&gt;

&lt;p&gt;I will wait.&lt;/p&gt;

&lt;p&gt;The first week of a side project feels like nothing else. You are thinking about it in the shower. You are sketching out features at midnight. You are telling yourself that this one is different, that this is the project you are actually going to ship. The commits come fast. The energy is real. Everything feels possible.&lt;/p&gt;

&lt;p&gt;Then something shifts. The commits slow down. A week passes, then two. You open the folder one evening, stare at the code for a few minutes, then close it and watch something on YouTube instead. One day you realize the last commit was six weeks ago and you are not even sure you remember what the project was supposed to do.&lt;/p&gt;

&lt;p&gt;Everyone says this is a motivation problem. You ran out of steam. Life got busy. You lost interest. The idea stopped exciting you.&lt;/p&gt;

&lt;p&gt;But what if motivation was never the real issue at all?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Story Developers Tell Themselves
&lt;/h2&gt;

&lt;p&gt;When a side project dies, there is a standard list of explanations developers reach for.&lt;/p&gt;

&lt;p&gt;Work got hectic. A new framework came out and the old project felt irrelevant. A better idea came along. You just needed a short break and somehow never came back. These explanations feel completely true when you say them. And they are not entirely wrong. But they are surface-level answers. They describe what happened on the outside. They do not explain what was already broken on the inside.&lt;/p&gt;

&lt;p&gt;The real problem existed from day one, before work got busy, before the new idea arrived, before motivation became an issue. It was planted the moment you started the project. And because it is invisible at first, most developers never see it until it is too late.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Actual Reason
&lt;/h2&gt;

&lt;p&gt;Here is the honest answer: developers abandon side projects because they never defined what finishing looks like.&lt;/p&gt;

&lt;p&gt;They know what they want to build. They have a clear picture of the features, the design, the feeling the project should give users. But they never write down what the first finished version actually is. There is no definition of done. And a project without a definition of done is not a project. It is an infinite loop.&lt;/p&gt;

&lt;p&gt;Think about what this looks like in practice. You build the core feature. It works. Then you notice the UI looks rough, so you spend a weekend redesigning it. The redesign looks better, but now the code underneath feels messy, so you refactor. While refactoring, you think of a feature that would make the whole thing more useful, so you start building that. Each step feels like progress. Each step technically is progress. But none of it gets you closer to finishing, because you never defined where the finish line is.&lt;/p&gt;

&lt;p&gt;The project does not die from a lack of motivation. It dies from a lack of closure. Every time you open that folder, the gap between where the project is and where you imagined it would be feels a little larger. That growing gap is what wears you down. Not a lack of caring. The caring is still there. That is actually what makes it hurt.&lt;/p&gt;

&lt;p&gt;I have lived this more than once. My personality assessment project sat unfinished for weeks because I kept expanding what "finished" meant. First it was just the quiz logic. Then it needed better UI. Then it needed shareable results. Then it needed a loading animation because the basic one looked lazy. I was always building, but I was never done. The finish line kept moving because I had never drawn it in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Perfectionism Disguises Itself as Productivity
&lt;/h2&gt;

&lt;p&gt;Here is the part that makes this problem so hard to catch in the moment.&lt;/p&gt;

&lt;p&gt;Developers are trained to care about quality. Clean code. Proper architecture. Good performance. These are genuine professional values and they are worth having. But inside a side project with no external deadline, those same values quietly become a trap.&lt;/p&gt;

&lt;p&gt;Every refactor feels responsible. Every redesign feels like you are raising the bar. Every "let me just clean this up before I move on" feels like diligence. But none of it is actually moving you toward shipping. It is moving you toward a version of the project that feels safe enough to show people.&lt;/p&gt;

&lt;p&gt;And that is the uncomfortable part. An unfinished project cannot be judged. It cannot fail publicly. It cannot disappoint anyone, including yourself. As long as it is in progress, it still holds all the potential you imagined on day one. Shipping it means finding out if the real version lives up to the version in your head.&lt;/p&gt;

&lt;p&gt;So the refactors keep coming. The redesigns keep happening. The project keeps getting better and closer to perfect. And it never ships.&lt;/p&gt;

&lt;p&gt;Perfectionism is almost never how it feels from the inside. From the inside, it feels like standards. Naming it honestly is the first step toward breaking the pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Comparison That Probably Stings a Little
&lt;/h2&gt;

&lt;p&gt;Think about how you work at your actual job. A feature is due on Friday. The code is not quite how you would write it if you had unlimited time. The UI has a few rough edges. But it is Friday, so you ship it. You write a note about what to improve later and you move on.&lt;/p&gt;

&lt;p&gt;That thing ships. It works. Users use it. Nobody knows about the rough edges except you.&lt;/p&gt;

&lt;p&gt;Now compare that to your side project. No deadline. No manager waiting. No team depending on you. So every rough edge becomes a blocker. Every imperfection gets fixed before moving forward. The project has all the time in the world, so you give it all the time in the world. And somehow it never gets done.&lt;/p&gt;

&lt;p&gt;The difference between work projects and side projects is not code quality. It is the presence of external pressure. At work, that pressure forces you to make the hardest decision in software: deciding that something is good enough to exist in the world right now.&lt;/p&gt;

&lt;p&gt;Side projects never force you to make that decision. So most developers never make it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Actually Do About It
&lt;/h2&gt;

&lt;p&gt;This is not a list of productivity hacks. These are three specific changes that address the actual problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Define done before you write a single line of code.&lt;/strong&gt; Sit down and write one paragraph. Not a vision statement. Not a list of features. One paragraph that describes what the first version looks like when a real person can use it. What does it do? What does it not do? Where does it start and where does it stop? That paragraph becomes your filter for every decision after it. If a new feature idea does not fit inside that paragraph, it does not go into version one. It goes on a list for later.&lt;/p&gt;

&lt;p&gt;This one step would have saved most of my abandoned projects. Not because the paragraph is magic, but because it forces you to make a decision you usually avoid making.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build in public from the start, even when the project is half-broken.&lt;/strong&gt; Post about what you are building. Share the messy version. Write about the problem you are trying to solve before you have solved it. What happens when you do this is that people start responding. They ask questions. They say they have the same problem. They tell you what feature they would actually use. That external pull creates accountability that motivation alone cannot manufacture. The project stops being just yours and starts having people waiting for it.&lt;/p&gt;

&lt;p&gt;Writing on dev.to while building is the most effective version of this I have found personally. It creates a rhythm. Readers become an audience and an audience creates a reason to keep going.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ship before you are ready.&lt;/strong&gt; Set a date. Not a goal, not a target, a real date. Write it down. When that date arrives, ship whatever exists. A rough project that is live is infinitely more valuable than a perfect project that no one ever sees. The feedback you get from one real user in one day of being live will teach you more than six months of building in private.&lt;/p&gt;

&lt;p&gt;The version you ship does not have to be impressive. It has to exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Harder Truth
&lt;/h2&gt;

&lt;p&gt;Some side projects are not meant to be finished. Some of them exist to teach you a new framework, explore an idea you were curious about, or scratch a creative itch that needed scratching. That is completely valid. There is nothing wrong with a project that teaches you something and then gets set aside.&lt;/p&gt;

&lt;p&gt;The mistake is calling it a side project when it is actually a learning experiment. If you named it that from the start, you would not feel like a failure when you moved on. You finished it. The goal was to learn, and you learned.&lt;/p&gt;

&lt;p&gt;The problem only shows up when you genuinely want to ship something and you are not being honest with yourself about why it is not moving. Blame the motivation. Blame the workload. Blame the new idea that came along. The real answer is usually simpler and less comfortable: you never drew the finish line.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Only Thing Worth Doing After Reading This
&lt;/h2&gt;

&lt;p&gt;If you have an unfinished project sitting in your repos right now, do not go looking for a new productivity system. Do not rewatch that video about staying consistent. Do not reorganize your Notion board.&lt;/p&gt;

&lt;p&gt;Open the project folder. Open a blank document next to it. Write one sentence that answers this question: what does this project do when it is done, in its simplest form?&lt;/p&gt;

&lt;p&gt;Build only toward that.&lt;/p&gt;

&lt;p&gt;The project does not need to be impressive. It does not need to be polished. It does not need to be ready for a Product Hunt launch. It needs to exist somewhere that is not just your local machine.&lt;/p&gt;

&lt;p&gt;How many unfinished projects are sitting in your repos right now? And if you think back honestly, do you know what actually stopped you? Drop your number in the comments. I have a feeling the answers are going to look familiar.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Did you learn something good today as a developer?&lt;br&gt;
Then show some love.&lt;br&gt;
© &lt;a href="https://www.linkedin.com/in/muhammad-usman-strategist/" rel="noopener noreferrer"&gt;Muhammad Usman&lt;/a&gt;&lt;br&gt;
WordPress Developer | Website Strategist | SEO Specialist&lt;br&gt;
Don’t forget to subscribe to &lt;a href="https://developersjourney.substack.com/" rel="noopener noreferrer"&gt;Developer’s Journey&lt;/a&gt; to show your support.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" alt="Developer's Journey" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Why You Should Learn Programming Through Books (Not Just Online Tutorials)</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Tue, 19 May 2026 11:56:45 +0000</pubDate>
      <link>https://dev.to/web_dev-usman/why-you-should-learn-programming-through-books-not-just-online-tutorials-35b6</link>
      <guid>https://dev.to/web_dev-usman/why-you-should-learn-programming-through-books-not-just-online-tutorials-35b6</guid>
      <description>&lt;p&gt;Books don’t just teach you to code — they teach you to think like a programmer.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;The man who does not read has no advantage over the man who cannot read.&lt;/p&gt;

&lt;p&gt;Learning programming using an online tutorial is like taking a picture.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You click, and that’s that. Learning to program with books, though — that’s like creating a painting. You layer and layer on it, and you keep working for weeks. You might still have the same image in the end, but there’s a depth to it that’s impossible to capture with a snapshot.&lt;/p&gt;

&lt;p&gt;I know we live in a world where everyone wants fast results. Watching online tutorials might seem like the easiest way to learn programming. But the quality of outcome you get with books cannot be matched.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can go much deeper with books than you can using any other method.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And here’s something people don’t talk about enough: when you start working, there won’t be any video tutorials to help you. You’ll have to read documentation and implement things by yourself.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Building a habit of reading and understanding technical material is a must if you want a solid career as a programmer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s why I’m giving you &lt;strong&gt;5 practical books&lt;/strong&gt; to get started with.&lt;/p&gt;

&lt;p&gt;Let’s do this.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Python Crash Course — Learn by Building Cool Projects
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2xpy6fzp48gakt39sv5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2xpy6fzp48gakt39sv5.jpeg" alt="Python Crash Course — Learn by Building Cool Projects" width="799" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to learn Python by building cool projects, check out this book called “Python Crash Course.” The first half of the book deals with the basics like variables, conditionals, loops, and functions. But the real magic happens in the second part of the book, where you actually build projects.&lt;/p&gt;

&lt;p&gt;You’ll use the pygame package to build an &lt;strong&gt;Alien Invasion&lt;/strong&gt; game. How does that sound as your first ever project? You’ll be able to shoot down the alien fleet and even have a scoreboard to list high scores.&lt;/p&gt;

&lt;p&gt;In the second project, you’ll learn how to work with APIs. You’ll download data from the GitHub API and visualize it using Matplotlib. And in the final project, you’ll build a &lt;strong&gt;web app using Django&lt;/strong&gt;, a very popular Python web framework. You’ll also learn how to style your app using bootstrap, a widely-used CSS framework. At the end, you’ll even deploy your website to the cloud, so the entire world can see it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After completing this book, you’ll feel confident enough to start building your own Python projects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Eloquent JavaScript — For Web Development Enthusiasts
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvrnp2rkaacpsuiqj34q7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvrnp2rkaacpsuiqj34q7.jpg" alt="Eloquent JavaScript — For Web Development Enthusiasts" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, I have a great recommendation for web development enthusiasts. If you want a deep understanding of JavaScript, try out the book “Eloquent JavaScript.”&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This book is available online completely for free. And the best part? You can try out all the exercises right on their website.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the first part of the book, you learn the basics — things like variables, functions, and objects. In the second part, you dive into how JavaScript interacts with the browser and the Document Object Model, or &lt;strong&gt;DOM&lt;/strong&gt;. Finally, in the last part, you’ll learn about &lt;strong&gt;Node.js&lt;/strong&gt;, which allows you to run JavaScript on the server instead of just in the browser.&lt;/p&gt;

&lt;p&gt;Every chapter gives you exercises to test your knowledge. You’ll also build some really cool projects. You’ll create a brand-new programming language called Egg. You’ll make a web app for editing pixel art. And in the final project, you’ll build a website that helps people organize meetings to share their skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The Pragmatic Programmer — Timeless Principles
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm20l6iecs6b0xu6wcii3.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm20l6iecs6b0xu6wcii3.jpeg" alt="The Pragmatic Programmer — Timeless Principles" width="700" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Next, we have a timeless classic: “The Pragmatic Programmer.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The principles in this book aren’t tied to specific technologies or programming languages. That makes them applicable even years after the book was first published in 1999.&lt;/p&gt;

&lt;p&gt;This book covers topics like &lt;strong&gt;debugging, testing, automation, and communication&lt;/strong&gt;, giving you a well-rounded perspective on what it takes to be an effective software developer. It focuses on &lt;strong&gt;fundamental principles and best practices&lt;/strong&gt; you can apply in any programming context.&lt;/p&gt;

&lt;p&gt;One of the best parts about this book is how it uses clever metaphors and analogies to explain complex technical concepts. For example, it introduces the idea of “&lt;strong&gt;Code Kata&lt;/strong&gt;.” In Japanese, the word Kata means “form” and is used to describe deliberate practice and repetition in martial arts. By doing Code Kata exercises, programmers can reinforce their knowledge of algorithms, data structures, and design patterns.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Whether you’re a beginner or an experienced developer, this book has something for everyone. It’s a must-read for anyone serious about honing their craft.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  4. Clean Code — Writing Maintainable Software
&lt;/h2&gt;

&lt;p&gt;So, you’ve learned a couple of programming languages and you’ve become a pragmatic programmer. Now, you need to know how to write &lt;strong&gt;clean, maintainable code&lt;/strong&gt;. For that, we have another classic: “Clean Code” by Uncle Bob.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;The primary goal of this book is to improve the readability and maintainability of your code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It teaches you to write code that’s easy for other developers to understand, modify, and extend.&lt;/p&gt;

&lt;p&gt;You’ll learn when — and when not — to use comments. The book encourages you to write &lt;strong&gt;self-explanatory code&lt;/strong&gt; instead of relying on tons of comments. It also covers how to properly name your variables, functions, and classes.&lt;/p&gt;

&lt;p&gt;The book uses real-world examples to drive the points home. Uncle Bob writes most code snippets in Java, but the concepts easily apply to other languages. It also introduces software design principles like the &lt;strong&gt;Single Responsibility Principle (SRP)&lt;/strong&gt; and &lt;strong&gt;Don’t Repeat Yourself (DRY)&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The book can get a bit too opinionated at times. So you don’t have to follow everything to a tee.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But it’s still a fantastic starting point to improve the quality of your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Designing Data-Intensive Applications (DDIA) — Think Like a Systems Architect
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2Aoz09Ph3E5Pxz6od5" 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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2Aoz09Ph3E5Pxz6od5" alt="Designing Data-Intensive Applications (DDIA) — Think Like a Systems Architect" width="1200" height="630"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to go from a junior developer to a senior developer, you have to start thinking beyond just code. You need to know how to architect your systems in a way that they can reliably handle thousands of simultaneous requests.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For that, you should read “Designing Data-Intensive Applications” (often called DDIA).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This book introduces you to the challenges of building systems that are &lt;strong&gt;reliable, scalable, and maintainable&lt;/strong&gt;. You’ll learn when to use relational databases vs. NoSQL databases. DDIA also helps you understand how databases efficiently &lt;strong&gt;store and retrieve data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It teaches you how to distribute data across multiple machines when your dataset becomes too large for a single server. And while it covers a lot of theory, it also provides practical advice you can use in the real world. You’ll read examples from big tech companies like &lt;strong&gt;Google and Amazon&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The book ends with a look at emerging trends in data systems, like new databases and storage technologies.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to learn how to make smart trade-offs while building large-scale applications, DDIA is a must-read.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;If you want to build a &lt;strong&gt;deeper understanding&lt;/strong&gt; of programming concepts, books are the best way to do it.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Did you learn something good today as a developer?&lt;br&gt;
Then show some love.&lt;br&gt;
© &lt;a href="https://www.linkedin.com/in/muhammad-usman-strategist/" rel="noopener noreferrer"&gt;Muhammad Usman&lt;/a&gt;&lt;br&gt;
WordPress Developer | Website Strategist | SEO Specialist&lt;br&gt;
Don’t forget to subscribe to &lt;a href="https://developersjourney.substack.com/" rel="noopener noreferrer"&gt;Developer’s Journey&lt;/a&gt; to show your support.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" alt="Developer's Journey" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programming</category>
      <category>learning</category>
      <category>coding</category>
      <category>productivity</category>
    </item>
    <item>
      <title>The $0 to $50/Month Tech Stack to Launch Your First SaaS</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Wed, 13 May 2026 10:20:19 +0000</pubDate>
      <link>https://dev.to/web_dev-usman/the-0-to-50month-tech-stack-to-launch-your-first-saas-12c9</link>
      <guid>https://dev.to/web_dev-usman/the-0-to-50month-tech-stack-to-launch-your-first-saas-12c9</guid>
      <description>&lt;p&gt;Most people never ship their SaaS idea.&lt;/p&gt;

&lt;p&gt;Not because the idea is bad. Not because they lack skills. Because they spend three weeks researching the "perfect" stack, get overwhelmed by AWS pricing pages, and quietly close the tab.&lt;/p&gt;

&lt;p&gt;This article is not that. This is the exact stack I would use today if I were starting from zero, a developer with an idea and an empty wallet, trying to get something in front of real users as fast as possible. Every tool listed here either has a free tier or costs a few dollars a month. The whole thing stays under $50/month even after you start getting traction.&lt;/p&gt;

&lt;p&gt;No enterprise nonsense. No over-engineering. Just tools that let you build, ship, and grow.&lt;/p&gt;




&lt;h2&gt;
  
  
  The philosophy first
&lt;/h2&gt;

&lt;p&gt;Before the tools: the biggest mistake first-time SaaS builders make is paying for infrastructure before they have a single paying customer.&lt;/p&gt;

&lt;p&gt;Your job in month one is not to build something scalable. Your job is to find out if anyone will pay for this thing. That means keeping costs at zero for as long as humanly possible, then introducing paid tiers only when free options genuinely become a bottleneck.&lt;/p&gt;

&lt;p&gt;Every tool below follows that rule.&lt;/p&gt;




&lt;h2&gt;
  
  
  The full stack at a glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Next.js&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend / API&lt;/td&gt;
&lt;td&gt;Next.js API routes or FastAPI&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Supabase&lt;/td&gt;
&lt;td&gt;Free (up to 500MB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;Supabase Auth&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting&lt;/td&gt;
&lt;td&gt;Hostinger Node.js Hosting&lt;/td&gt;
&lt;td&gt;$3.99/mo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain&lt;/td&gt;
&lt;td&gt;Hostinger&lt;/td&gt;
&lt;td&gt;~$10/yr&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payments&lt;/td&gt;
&lt;td&gt;Stripe&lt;/td&gt;
&lt;td&gt;Free (2.9% + 30c per transaction)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Email&lt;/td&gt;
&lt;td&gt;Resend&lt;/td&gt;
&lt;td&gt;Free (up to 3,000 emails/mo)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Analytics&lt;/td&gt;
&lt;td&gt;Plausible or Umami (self-hosted)&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error tracking&lt;/td&gt;
&lt;td&gt;Sentry&lt;/td&gt;
&lt;td&gt;Free (up to 5,000 errors/mo)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Total at launch: &lt;strong&gt;$3.99/month + domain.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 1: Frontend + Backend with Next.js
&lt;/h2&gt;

&lt;p&gt;Next.js is the right call for a solo founder or small team building a SaaS in 2026. It handles your frontend, your API routes, and your server-side rendering in one framework. You are not maintaining a separate Express server. You are not juggling two repos. One codebase, one deployment.&lt;/p&gt;

&lt;p&gt;Use the App Router. Use Server Components for anything that does not need interactivity. This keeps your JavaScript bundle small and your pages fast, which matters for SEO and for users on slower connections.&lt;/p&gt;

&lt;p&gt;If your SaaS is primarily an AI tool or data-heavy backend, swap Next.js API routes for FastAPI. Python's ecosystem for AI, data processing, and async tasks is unmatched, and FastAPI is genuinely fast to build with. You can still use Next.js for your frontend and point it at a FastAPI backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to build first:&lt;/strong&gt; The signup page, the core feature (one, not five), and a simple dashboard. That is it. Resist building anything else.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 2: Database and Auth with Supabase
&lt;/h2&gt;

&lt;p&gt;Supabase gives you a Postgres database, authentication, real-time subscriptions, and file storage, all on a generous free tier. For a new SaaS, this is an absurd amount of infrastructure for zero dollars.&lt;/p&gt;

&lt;p&gt;The free tier covers you up to 500MB of database storage and 50,000 monthly active users on auth. You will not hit those limits before you are making real money.&lt;/p&gt;

&lt;p&gt;A few things worth knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Row Level Security (RLS) from day one. It keeps your data access logic in the database, not scattered across your API.&lt;/li&gt;
&lt;li&gt;Supabase Auth handles OAuth (Google, GitHub) out of the box. No Passport.js setup, no JWT headaches.&lt;/li&gt;
&lt;li&gt;The Supabase JavaScript client works seamlessly inside Next.js Server Components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you outgrow the free tier, the Pro plan is $25/month and gives you 8GB of storage and daily backups. At that point, you should have paying customers covering it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 3: Hosting with Hostinger
&lt;/h2&gt;

&lt;p&gt;This is the one paid tool in the stack from day one, and it is worth it.&lt;/p&gt;

&lt;p&gt;The reason you do not want to rely on free hosting tiers for your main app: they sleep. Render's free tier spins down your server after 15 minutes of inactivity. Fly.io's free machines get paused. Your demo fails in front of the one person who might have become your first customer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hostinger.pk/?REFERRALCODE=USISTUDIOHE1" rel="noopener noreferrer"&gt;Hostinger's Node.js hosting&lt;/a&gt; runs your Next.js or Node.js app on a live server that stays on, at $3.99/month. You can also grab your domain there and connect it in a few clicks. Deployment is straightforward: connect your GitHub repo, push code, and it deploys automatically.&lt;/p&gt;

&lt;p&gt;If you are running a FastAPI backend, Hostinger's VPS plans start at the same price range and give you root access to install anything you need: Python, Gunicorn, Nginx, whatever your stack requires.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I use Hostinger for several projects. It is not trying to be AWS. It is trying to be the easiest, cheapest way to keep a Node.js or PHP app live. For a solo founder launching a first SaaS, that is exactly what you want. &lt;a href="https://hostinger.pk/?REFERRALCODE=USISTUDIOHE1" rel="noopener noreferrer"&gt;Get 20% extra discount here.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Layer 4: Payments with Stripe
&lt;/h2&gt;

&lt;p&gt;Stripe is the standard. Do not use anything else until you have a reason to.&lt;/p&gt;

&lt;p&gt;The free tier means you pay nothing until you process a transaction. Then it is 2.9% plus 30 cents per charge. On a $29/month subscription, that is about $1.14 per transaction. Reasonable.&lt;/p&gt;

&lt;p&gt;What most people do not realise: Stripe Checkout handles your entire payment UI. You do not need to build a checkout page. You redirect users to a Stripe-hosted page, and Stripe handles card collection, 3D Secure, tax calculation, and PCI compliance. Wire it to a webhook, update the user's subscription status in Supabase, done.&lt;/p&gt;

&lt;p&gt;For subscriptions specifically, use Stripe Billing. It handles trial periods, proration on plan changes, dunning (automatic retries on failed payments), and cancellations. Things that would take weeks to build yourself.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 5: Email with Resend
&lt;/h2&gt;

&lt;p&gt;Transactional email (welcome emails, password resets, upgrade receipts) is non-negotiable for a SaaS. Resend gives you 3,000 emails per month for free with a proper API that works beautifully from Next.js.&lt;/p&gt;

&lt;p&gt;The developer experience is significantly cleaner than SendGrid or Mailgun. You write your emails as React components using the &lt;code&gt;react-email&lt;/code&gt; library, which means type safety, reusable components, and no more wrestling with HTML tables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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;Html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Text&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="s1"&gt;@react-email/components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;WelcomeEmail&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hey &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;, welcome aboard.&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://yourapp.com/dashboard"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Go to your dashboard
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Html&lt;/span&gt;&lt;span class="p"&gt;&amp;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;When you hit the free limit, Resend's paid tier starts at $20/month for 50,000 emails. By that point, you will have the revenue to cover it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 6: Analytics and Error Tracking
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Analytics:&lt;/strong&gt; Do not use Google Analytics. It is bloated, it shares your users' data with Google, and it will scare privacy-conscious users in 2026. Use Plausible (lightweight, privacy-first, $9/month) or self-host Umami on your existing Hostinger VPS for free. Umami is a single Node.js app. Add it as a second service alongside your main app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error tracking:&lt;/strong&gt; Sentry's free tier captures 5,000 errors per month and shows you the exact stack trace, user session, and browser when something breaks in production. Integrate it in one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/layout.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Sentry&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;@sentry/nextjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;Sentry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;dsn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEXT_PUBLIC_SENTRY_DSN&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will find bugs you never would have found otherwise.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the cost curve actually looks like
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Month 1 (building, no users):&lt;/strong&gt; $3.99/month. Domain is a one-time $10/year cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Month 2 to 3 (early users, free tier everywhere):&lt;/strong&gt; Still $3.99/month. Supabase, Stripe, Resend, and Sentry are all free at small scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Month 4 to 6 (getting traction, 100+ users):&lt;/strong&gt; You might upgrade Supabase to Pro ($25/month) and add Plausible ($9/month) for better analytics. Stack is now around $38/month.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Month 6+ (revenue coming in):&lt;/strong&gt; Your hosting might need an upgrade depending on traffic. Hostinger's plans scale without requiring a migration to a different platform. Total stack stays under $50/month well into the thousands-of-users range.&lt;/p&gt;

&lt;p&gt;The point is: the costs scale with your success. You are not paying $200/month in infrastructure before you have a single dollar of revenue.&lt;/p&gt;




&lt;h2&gt;
  
  
  The one trap to avoid
&lt;/h2&gt;

&lt;p&gt;The trap is adding complexity before you have users.&lt;/p&gt;

&lt;p&gt;You do not need a separate Redis instance on day one. You do not need a message queue. You do not need microservices, Kubernetes, or a CDN with edge functions until your traffic makes those things genuinely necessary.&lt;/p&gt;

&lt;p&gt;Every layer of infrastructure you add is a layer you have to debug at 11pm when something breaks and your only user is waiting for a response.&lt;/p&gt;

&lt;p&gt;Start with this stack. Get to ten paying customers. Then look at what is actually breaking and fix only that.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick start checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Create Next.js app with &lt;code&gt;npx create-next-app@latest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Set up Supabase project, enable RLS on all tables&lt;/li&gt;
&lt;li&gt;[ ] Configure Supabase Auth with Google OAuth&lt;/li&gt;
&lt;li&gt;[ ] Get a domain and Node.js hosting on &lt;a href="https://hostinger.pk/?REFERRALCODE=USISTUDIOHE1" rel="noopener noreferrer"&gt;Hostinger&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Connect GitHub repo for automatic deploys&lt;/li&gt;
&lt;li&gt;[ ] Create Stripe account, set up one Product and one Price&lt;/li&gt;
&lt;li&gt;[ ] Add Stripe webhook to update Supabase on subscription events&lt;/li&gt;
&lt;li&gt;[ ] Set up Resend, write welcome email with react-email&lt;/li&gt;
&lt;li&gt;[ ] Add Sentry to catch production errors&lt;/li&gt;
&lt;li&gt;[ ] Self-host Umami on the same VPS for analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is your entire infrastructure. Everything else is product.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;The SaaS graveyard is full of products that were never shipped, not products that shipped on the wrong stack.&lt;/p&gt;

&lt;p&gt;Pick these tools. Build the thing. Ship it to five people this week.&lt;/p&gt;

&lt;p&gt;The stack can always be changed later. The feedback you get from real users this week cannot be replicated by anything else.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Did you learn something good today as a developer?&lt;br&gt;
Then show some love.&lt;br&gt;
© &lt;a href="https://www.linkedin.com/in/muhammad-usman-strategist/" rel="noopener noreferrer"&gt;Muhammad Usman&lt;/a&gt;&lt;br&gt;
WordPress Developer | Website Strategist | SEO Specialist&lt;br&gt;
Don’t forget to subscribe to &lt;a href="https://developersjourney.substack.com/" rel="noopener noreferrer"&gt;Developer’s Journey&lt;/a&gt; to show your support.&lt;br&gt;
&lt;a href="https://hostinger.pk/?REFERRALCODE=USISTUDIOHE1" rel="noopener noreferrer"&gt;Get 20% extra discount on Hostinger&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" alt="Developer's Journey" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Stop Writing Clean Code. Write Honest Code Instead.</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Sat, 09 May 2026 09:52:55 +0000</pubDate>
      <link>https://dev.to/web_dev-usman/stop-writing-clean-code-write-honest-code-instead-18ek</link>
      <guid>https://dev.to/web_dev-usman/stop-writing-clean-code-write-honest-code-instead-18ek</guid>
      <description>&lt;p&gt;There is a codebase out there with a simple "send an email" operation that goes through seven layers of abstraction.&lt;/p&gt;

&lt;p&gt;An EmailService that uses an EmailProvider that wraps an EmailClient that calls an EmailAdapter that uses a MessageSender that invokes a TransportLayer that finally, after all of that, calls the actual email API.&lt;/p&gt;

&lt;p&gt;Every layer has a reason. Logging here. Error handling there. Retries somewhere in the middle. It is, by almost every definition the industry has agreed on, clean code.&lt;/p&gt;

&lt;p&gt;It is also code that nobody on the team can fully understand anymore.&lt;/p&gt;

&lt;p&gt;That is the problem nobody talks about when they are quoting Uncle Bob at you in a code review.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Clean Code Stopped Being a Tool and Became a Standard
&lt;/h2&gt;

&lt;p&gt;Robert Martin's book came out in 2008. It gave developers a vocabulary and a set of rules. Short functions. Meaningful names. Single responsibility. No comments because the code should speak for itself.&lt;/p&gt;

&lt;p&gt;Good ideas. Genuinely. The problem is what happened next.&lt;/p&gt;

&lt;p&gt;Developers turned a set of practical guidelines for a specific context into a universal standard for all code everywhere. Clean code stopped being a tool and became an identity. Writing clean code meant you were a serious developer. Writing anything else meant you were cutting corners, being lazy, not caring about your craft.&lt;/p&gt;

&lt;p&gt;And once something becomes an identity, it stops being questioned.&lt;/p&gt;

&lt;p&gt;So developers started abstracting things that did not need abstracting. Creating interfaces for classes that would never have a second implementation. Splitting functions into sub-functions into sub-sub-functions until the original logic was spread across twelve files and finding out what the code actually does requires a forty minute archaeology expedition.&lt;/p&gt;

&lt;p&gt;All of it in the name of cleanliness. None of it in the name of actually solving the problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Performance Conversation Nobody Wanted to Have
&lt;/h2&gt;

&lt;p&gt;In 2023, a programmer named Casey Muratori published a video called "Clean Code, Horrible Performance." He took Uncle Bob's clean code examples and benchmarked them against straightforward implementations.&lt;/p&gt;

&lt;p&gt;The clean versions were up to 23 times slower.&lt;/p&gt;

&lt;p&gt;The reaction from the clean code community was, predictably, defensive. Performance does not matter for most applications. The bottleneck is usually the database anyway. You are optimizing prematurely.&lt;/p&gt;

&lt;p&gt;Some of that is true. Most modern software spends the majority of its time waiting for user input, not executing business logic. For a lot of applications, the performance gap is irrelevant.&lt;/p&gt;

&lt;p&gt;But that is not really the point Muratori was making. The point is that the clean code rules were presented as universally correct, context-free laws. And they are not. They are tradeoffs. Every abstraction you add is a layer someone has to understand. Every tiny function is a context switch in a reader's brain. Every interface is an indirection that obscures what is actually happening.&lt;/p&gt;

&lt;p&gt;Clean code moves the complexity. It does not eliminate it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What "Honest Code" Actually Means
&lt;/h2&gt;

&lt;p&gt;Honest code is not messy code. It is not an excuse to write whatever you want and call it a style choice.&lt;/p&gt;

&lt;p&gt;Honest code is code that does not pretend.&lt;/p&gt;

&lt;p&gt;It does not pretend that the business logic is simpler than it is. A lot of codebases have genuinely complicated rules because the domain is genuinely complicated. Forcing that into short, clean functions sometimes means the complexity goes underground, hiding in the gaps between functions, in the sequence of calls, in the assumptions baked into naming.&lt;/p&gt;

&lt;p&gt;It does not pretend that future requirements justify present architecture. One developer built a feature with a flexible configuration system, keyboard shortcuts, and multiple user pathways because he imagined power users doing complex workflows. Ninety percent of actual users just wanted to click one button. All the flexibility was just confusing them. The architecture was built for a future that never arrived.&lt;/p&gt;

&lt;p&gt;It does not pretend that all code is equally important. Your authentication logic that handles money needs rock-solid testing and careful review. Your internal admin dashboard that three people use to generate reports can be rough around the edges. Treating every line of code with the same level of ceremony is not discipline. It is a misallocation of attention.&lt;/p&gt;

&lt;p&gt;And honest code does not hide behind abstraction when a comment would do the job better and faster.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Comment Rule Nobody Should Follow Blindly
&lt;/h2&gt;

&lt;p&gt;Clean code says code should be self-documenting. Comments are a failure. If you need a comment to explain the code, the code is not clean enough.&lt;/p&gt;

&lt;p&gt;This is one of the most damaging ideas in mainstream software development.&lt;/p&gt;

&lt;p&gt;There is a category of code that is necessarily dense, complex, or counterintuitive, not because the developer wrote it badly, but because the problem it solves is genuinely hard. A performance-critical path that uses bitwise operations for speed. A workaround for a third-party library bug that will be removed when the library updates. A business rule that sounds insane but reflects a legal requirement that the developer spent two days understanding.&lt;/p&gt;

&lt;p&gt;Clean code says: make the code clearer.&lt;/p&gt;

&lt;p&gt;Honest code says: write the comment. Explain the why. Leave the breadcrumb for the next developer who will be just as confused as you were, because the confusion is correct. The thing is actually confusing.&lt;/p&gt;

&lt;p&gt;The developer who wrote the confusing thing and left no comment was not being disciplined. They were being unkind.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Biggest Technical Debt Nobody Tracks
&lt;/h2&gt;

&lt;p&gt;Technical debt gets measured in two ways: things that broke and things that slowed down feature development.&lt;/p&gt;

&lt;p&gt;Nobody tracks the hours spent by new developers trying to understand an abstraction layer that was added for cleanliness rather than necessity. Nobody counts the time spent tracing through seven layers of email infrastructure to find the one line that actually sends the email. Nobody measures the cognitive load of a codebase where everything is theoretically clean but nothing is immediately legible.&lt;/p&gt;

&lt;p&gt;That cost is real. It accumulates quietly. And it is often worse in codebases that followed the clean code rules most faithfully, because the complexity did not go away. It just got distributed more evenly across more files with better names.&lt;/p&gt;

&lt;p&gt;The biggest source of developer frustration, by a wide margin according to Stack Overflow's own data, is technical debt. Not messy code specifically. Debt. The gap between what the code is and what it needs to be.&lt;/p&gt;

&lt;p&gt;Clean code pursued as an end in itself creates its own kind of debt. The debt of over-abstraction. The debt of architecture that outpaced the actual requirements. The debt of code that is legible line by line but incomprehensible as a system.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to Do Instead
&lt;/h2&gt;

&lt;p&gt;Write code that works first. Code that you understand. Code that you can debug at 2am when it breaks in production and you are tired and the pressure is real.&lt;/p&gt;

&lt;p&gt;Then ask: who else needs to understand this? What do they need to know that the code cannot tell them? Write that down. In a comment, in a README, in a commit message. Somewhere.&lt;/p&gt;

&lt;p&gt;Ask: what parts of this are likely to change? Abstract those. The parts that are stable, that have been stable for years, that nobody has asked to modify since they were written, leave them alone. Do not add an interface to something that will never have a second implementation just because a rule says to.&lt;/p&gt;

&lt;p&gt;Ask: what does this code actually do? Not what it is supposed to do. What it actually does. If you cannot answer that in two sentences without referencing the three layers above and below it, that is not clean. That is hidden.&lt;/p&gt;

&lt;p&gt;Honest code is code that tells the truth about what it does, where it is fragile, why it makes the choices it makes, and what it is not designed to handle.&lt;/p&gt;

&lt;p&gt;Clean code wants to look good. Honest code wants to be understood.&lt;/p&gt;

&lt;p&gt;Those are not always the same thing. And in the gap between them is where most debugging happens.&lt;/p&gt;




&lt;p&gt;You have probably inherited a codebase at some point that was written by someone who cared deeply about cleanliness. Beautiful structure. Consistent naming. Short functions everywhere.&lt;/p&gt;

&lt;p&gt;And you still could not figure out what it did.&lt;/p&gt;

&lt;p&gt;That is not a coincidence. That is clean code working exactly as designed, optimizing for appearance at the expense of truth.&lt;/p&gt;

&lt;p&gt;Write the comment. Name the tradeoff. Leave the breadcrumb.&lt;/p&gt;

&lt;p&gt;The next developer will thank you. That developer is probably you, six months from now, tired, staring at something you wrote and wondering what you were thinking.&lt;/p&gt;

&lt;p&gt;Give that person the honest version.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Did you learn something good today as a developer?&lt;br&gt;
Then show some love.&lt;br&gt;
© &lt;a href="https://www.linkedin.com/in/muhammad-usman-strategist/" rel="noopener noreferrer"&gt;Muhammad Usman&lt;/a&gt;&lt;br&gt;
WordPress Developer | Website Strategist | SEO Specialist&lt;br&gt;
Don’t forget to subscribe to &lt;a href="https://developersjourney.substack.com/" rel="noopener noreferrer"&gt;Developer’s Journey&lt;/a&gt; to show your support.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" alt="Developer's Journey" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>coding</category>
    </item>
    <item>
      <title>What Developers Actually Feel About Their Jobs</title>
      <dc:creator>Muhammad Usman</dc:creator>
      <pubDate>Thu, 07 May 2026 12:09:48 +0000</pubDate>
      <link>https://dev.to/web_dev-usman/what-developers-actually-feel-about-their-jobs-2d87</link>
      <guid>https://dev.to/web_dev-usman/what-developers-actually-feel-about-their-jobs-2d87</guid>
      <description>&lt;p&gt;Three out of four developers are not happy at work right now.&lt;/p&gt;

&lt;p&gt;Not burned out. Not quitting. Just not happy. Showing up. Doing the tickets. Closing the laptop. Doing it again tomorrow.&lt;/p&gt;

&lt;p&gt;That number comes from Stack Overflow's 2025 Developer Survey, 49,000 developers across 177 countries. Only 24% said they were genuinely happy at work. The rest are somewhere on a scale between fine and actively hating it. One in three reportedly hate their job. Almost half are in what researchers call "survival mode."&lt;/p&gt;

&lt;p&gt;Survival mode. In a profession that is supposed to be one of the most in-demand, well-paid, intellectually stimulating careers available.&lt;/p&gt;

&lt;p&gt;So what is actually going on?&lt;/p&gt;




&lt;h2&gt;
  
  
  The Gap Between What We Told Ourselves and What It Actually Is
&lt;/h2&gt;

&lt;p&gt;Most developers got into this because of the craft. The feeling of building something from nothing. The puzzle of it. The moment a thing you imagined actually works.&lt;/p&gt;

&lt;p&gt;One developer described it plainly: when you get burned out, you start counting the minutes until 5pm. You go home and look for distractions. You stop caring whether the code is good. You just want it to be done.&lt;/p&gt;

&lt;p&gt;That is not a person who hates programming. That is a person who loved it and slowly had it taken from them by something they cannot quite name.&lt;/p&gt;

&lt;p&gt;The job sold itself one way. It turned out to be something else. And the gap between those two things is where a lot of developer unhappiness actually lives.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Developers Say Actually Makes Them Happy
&lt;/h2&gt;

&lt;p&gt;The survey data on this is worth sitting with for a moment because it is not what most companies are optimizing for.&lt;/p&gt;

&lt;p&gt;The top driver of developer job satisfaction is not salary. It is not tech stack, perks, or remote work. It is autonomy and trust.&lt;/p&gt;

&lt;p&gt;Developers want to be trusted to make decisions. They want to own their work. They want to not have someone looking over their shoulder second-guessing every architectural choice while simultaneously not understanding the codebase.&lt;/p&gt;

&lt;p&gt;After that comes competitive pay. Then solving real world problems that actually matter.&lt;/p&gt;

&lt;p&gt;Notice what is not on that list. The ping-pong table. The unlimited PTO that nobody actually takes. The AI tool the company rolled out company-wide without asking whether anyone wanted it. The reorg that moved everyone to a new team with a new manager for the third time in two years.&lt;/p&gt;

&lt;p&gt;The things that would genuinely help developers are not complicated. They are also, for many organizations, apparently very difficult to provide.&lt;/p&gt;




&lt;h2&gt;
  
  
  The AI Problem Nobody Wants to Admit
&lt;/h2&gt;

&lt;p&gt;There is a strange thing happening right now in developer culture around AI.&lt;/p&gt;

&lt;p&gt;84% of developers are using or planning to use AI tools in their work. Adoption is going up every year. But here is the part that does not make it into the press releases: 46% of developers distrust AI tool outputs, compared to only 33% who trust them. Positive sentiment toward AI tools has dropped from over 70% to 60% in just one year.&lt;/p&gt;

&lt;p&gt;Developers are using something they increasingly do not trust, because they feel like they have to.&lt;/p&gt;

&lt;p&gt;Two thirds report that AI answers are almost right but not quite. 45% say they lose significant time debugging AI-generated code. The thing that was supposed to make their jobs easier is, for nearly half of them, creating a new category of frustrating work: cleaning up confident mistakes.&lt;/p&gt;

&lt;p&gt;And there is a subtler cost underneath that. When you spend your day fixing something a tool generated rather than building something yourself, you lose the thing that makes the work feel meaningful. Problem-solving. Ownership. The satisfaction of understanding why something works.&lt;/p&gt;

&lt;p&gt;One survey respondent put it simply: the most satisfying part of the job is solving problems. That has not changed. What has changed is how much of the day is actually spent doing that versus managing the output of tools that solved the wrong problem fast.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Developer Nobody Is Building Tools For
&lt;/h2&gt;

&lt;p&gt;Here is a segment of the developer population that the industry largely ignores: the one working completely alone.&lt;/p&gt;

&lt;p&gt;The solo freelancer. The developer at a small company where they are the only technical person. The person building a side project for two years hoping someone notices. The junior engineer on a team where everyone else is too busy to explain things and asking questions starts to feel like a liability.&lt;/p&gt;

&lt;p&gt;These developers are not unhappy because of bad management or the wrong tech stack. They are unhappy because the work is genuinely isolating in a way that has no structural fix. Nobody is going to address it in a quarterly planning session. There is no metric for it.&lt;/p&gt;

&lt;p&gt;One developer spent years building an npm module, waiting for someone to find it meaningful, maybe even collaborate on it. The module sat there. The months passed. Even his colleagues could not understand what he had built. That specific kind of invisible effort, work that is technically real and personally significant but completely unwitnessed, is one of the most common and least-discussed experiences in the field.&lt;/p&gt;




&lt;h2&gt;
  
  
  Survival Mode Is Not a Phase. For Many, It Is the Default.
&lt;/h2&gt;

&lt;p&gt;The phrase "survival mode" sounds temporary. Like a rough patch before things improve.&lt;/p&gt;

&lt;p&gt;For a lot of developers, it is just Tuesday.&lt;/p&gt;

&lt;p&gt;They are not dramatically unhappy. They are not about to quit. They are doing the standup, the sprint planning, the code review, the deployment. They are technically fine. But the version of themselves that used to get excited about a hard problem, that used to stay late not because of a deadline but because they genuinely wanted to see if it worked, that version quietly left at some point and nobody noticed.&lt;/p&gt;

&lt;p&gt;One developer who lost his passion for code described it: without passion, work is just grinding. You go through the motions but do not enjoy the moment.&lt;/p&gt;

&lt;p&gt;Going through the motions. That is survival mode. And it is invisible to everyone except the person doing it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Number That Should Bother More People
&lt;/h2&gt;

&lt;p&gt;24% of developers are happy at work.&lt;/p&gt;

&lt;p&gt;That is the high point. That is after job satisfaction improved from last year.&lt;/p&gt;

&lt;p&gt;In any other industry, if three quarters of the workforce reported being unhappy, it would be a crisis. In tech, it is a data point in an annual survey that gets shared on LinkedIn for two days and then forgotten.&lt;/p&gt;

&lt;p&gt;The developers who are satisfied are mostly the ones with autonomy, decent pay, and work that feels like it matters. Those things are not rare because they are hard to provide. They are rare because they are not what most organizations are actually measuring or optimizing for.&lt;/p&gt;

&lt;p&gt;Retros capture what broke. Sprints capture what shipped. Stand-ups capture what is blocked. Nobody built a ritual for what you solved, or whether the person solving it still cares about their work.&lt;/p&gt;

&lt;p&gt;That gap, between what organizations track and what developers actually need, is where most of the unhappiness lives.&lt;/p&gt;




&lt;p&gt;You might be reading this and recognizing yourself somewhere in it. The survival mode. The AI frustration. The invisible work nobody witnesses. The counting of minutes.&lt;/p&gt;

&lt;p&gt;If you are, you are not an outlier. You are three quarters of the profession.&lt;/p&gt;

&lt;p&gt;That is worth knowing. Not because it fixes anything. But because the story you have been telling yourself, that everyone else is fine and something is wrong with you, is not true.&lt;/p&gt;

&lt;p&gt;Most people are not fine. They are just quiet about it.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Did you learn something good today as a developer?&lt;br&gt;
Then show some love.&lt;br&gt;
© &lt;a href="https://www.linkedin.com/in/muhammad-usman-strategist/" rel="noopener noreferrer"&gt;Muhammad Usman&lt;/a&gt;&lt;br&gt;
WordPress Developer | Website Strategist | SEO Specialist&lt;br&gt;
Don’t forget to subscribe to &lt;a href="https://developersjourney.substack.com/" rel="noopener noreferrer"&gt;Developer’s Journey&lt;/a&gt; to show your support.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh3jsza7m50ojhdd4yuuc.png" alt="Developer's Journey" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>career</category>
    </item>
  </channel>
</rss>
