<?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: Antonio </title>
    <description>The latest articles on DEV Community by Antonio  (@antonioprosperi2svg).</description>
    <link>https://dev.to/antonioprosperi2svg</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4092373%2F27c3ef5d-a3a1-442b-95b9-9e5f97c623dc.gif</url>
      <title>DEV Community: Antonio </title>
      <link>https://dev.to/antonioprosperi2svg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/antonioprosperi2svg"/>
    <language>en</language>
    <item>
      <title>bug.ai.dev: writing docs at night made me find 11 real bugs in my own library</title>
      <dc:creator>Antonio </dc:creator>
      <pubDate>Wed, 11 Nov 2026 21:38:06 +0000</pubDate>
      <link>https://dev.to/antonioprosperi2svg/bugaidev-writing-docs-at-night-made-me-find-11-real-bugs-in-my-own-library-3g3c</link>
      <guid>https://dev.to/antonioprosperi2svg/bugaidev-writing-docs-at-night-made-me-find-11-real-bugs-in-my-own-library-3g3c</guid>
      <description>&lt;p&gt;Hi everyone, I'm Antonio. I'm 53, I work as a factory worker during the day, and in the evening I keep building my own projects: modules, classes, a small 2D game engine and a debugging tool called &lt;strong&gt;BeeLadybug&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Last time I told you how I &lt;a href="https://dev.to/antonioprosperi2svg/i-wanted-a-floating-search-bar-the-fix-was-a-few-lines-of-css-after-hours-of-arguing-with-ai-272f"&gt;argued with AI for hours over a floating search bar&lt;/a&gt; that only needed a few lines of CSS.&lt;/p&gt;

&lt;p&gt;This time the story is different. This time the AIs were more bugged than my code. 😂&lt;/p&gt;

&lt;h2&gt;
  
  
  What BeeLadybug is
&lt;/h2&gt;

&lt;p&gt;BeeLadybug is an open-source inspection overlay that runs inside a Shadow DOM. You send it raw data, and adapters turn the page into something you can read:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'https://cdn.jsdelivr.net/npm/bee-ladybug/src/index.js'&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="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;BeeLadybugCore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;WebDOMAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;CSSAdapter&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="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;bee&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;BeeLadybugCore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebDOMAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;root&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="n"&gt;body&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;attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CSSAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attach&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste that in the console of any page (Chrome may ask you to type &lt;code&gt;allow pasting&lt;/code&gt; first), press &lt;strong&gt;F6&lt;/strong&gt; to start the CSS hunt, and &lt;strong&gt;F8&lt;/strong&gt; to export a full HTML report.&lt;/p&gt;

&lt;h2&gt;
  
  
  The plan: just write the docs
&lt;/h2&gt;

&lt;p&gt;I'm writing the documentation one adapter at a time. Canvas, WebDOM, and then &lt;strong&gt;CSSAdapter&lt;/strong&gt;, about 1,235 lines.&lt;/p&gt;

&lt;p&gt;To document it properly I asked an AI to read the module and explain it to me. Instead of an explanation, I got a list of bugs.&lt;/p&gt;

&lt;p&gt;Then I asked a second AI to check the same folder. It found a &lt;em&gt;different&lt;/em&gt; list. One said "10 functions" and then listed 11. Another said "5 points" and wrote 6.&lt;/p&gt;

&lt;p&gt;After a full day of work, reading 1,500 lines of code with two AIs arguing in my head... my brain got bugged too. 😂&lt;/p&gt;

&lt;h2&gt;
  
  
  How I got out of it: I checked with my own eyes
&lt;/h2&gt;

&lt;p&gt;I stopped trusting the numbers and opened the file myself. One of the claims was that the &lt;code&gt;S&lt;/code&gt; key scan didn't filter the same noise as the F8 report.&lt;/p&gt;

&lt;p&gt;Line 144, inside &lt;code&gt;scan()&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="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="n"&gt;el&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;isBeeChrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;isSkippedTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Line 216, inside &lt;code&gt;snapshot()&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="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="n"&gt;el&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;isBeeChrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;isSkippedTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;isReportNoise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;el&lt;/span&gt;&lt;span class="p"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There it was. The quick scan was missing &lt;code&gt;isReportNoise(el)&lt;/code&gt;, so on a WordPress site it reported fake problems on &lt;code&gt;#wpadminbar&lt;/code&gt; and on hidden elements, while the F8 report skipped them correctly.&lt;/p&gt;

&lt;p&gt;The bug was real. The counting was wrong, but the bugs were real.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 11 bugs (short version)
&lt;/h2&gt;

&lt;p&gt;Merging both reviews, these were the ones worth fixing now:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;With the CSS hunt on, &lt;strong&gt;Ctrl+S / Ctrl+P / Cmd+S were blocked&lt;/strong&gt;. &lt;code&gt;#handleKey&lt;/code&gt; didn't check modifier keys.&lt;/li&gt;
&lt;li&gt;With the overlay hidden (F2), the &lt;code&gt;P&lt;/code&gt; and &lt;code&gt;S&lt;/code&gt; keys and the hover/pin boxes &lt;strong&gt;were still active&lt;/strong&gt; on the page.&lt;/li&gt;
&lt;li&gt;A stylesheet change before the first mouse move inspected the element at &lt;strong&gt;(0,0)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scan()&lt;/code&gt; didn't filter &lt;code&gt;isReportNoise&lt;/code&gt;, as shown above.&lt;/li&gt;
&lt;li&gt;Modern colors like &lt;code&gt;oklch()&lt;/code&gt;, &lt;code&gt;lab()&lt;/code&gt;, &lt;code&gt;color()&lt;/code&gt; and &lt;code&gt;color-mix()&lt;/code&gt; produced a &lt;strong&gt;fake "invisible text"&lt;/strong&gt; warning.&lt;/li&gt;
&lt;li&gt;Stylesheets that were &lt;strong&gt;disabled&lt;/strong&gt; or had a non-matching &lt;code&gt;media&lt;/code&gt; (like &lt;code&gt;print&lt;/code&gt;) were counted as active.&lt;/li&gt;
&lt;li&gt;The snapshot cut to 80 rows &lt;strong&gt;before&lt;/strong&gt; sorting by severity, so a harmless &lt;code&gt;will-change&lt;/code&gt; could push out a real error.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;touchesSheet&lt;/code&gt; checked the whole subtree on every mutation, which invalidated the cache almost every frame.&lt;/li&gt;
&lt;li&gt;HUD states (&lt;code&gt;css.target&lt;/code&gt;, &lt;code&gt;css.hits&lt;/code&gt;, &lt;code&gt;css.pin&lt;/code&gt;) &lt;strong&gt;stayed stuck&lt;/strong&gt; after turning the hunt off.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cssPath&lt;/code&gt; didn't escape special characters, which breaks with Tailwind classes like &lt;code&gt;sm:w-1/2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The other adapters didn't recognize CSSAdapter's own boxes (&lt;code&gt;data-bee-ladybug-css&lt;/code&gt;), so they could count them as page nodes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One small fix, as an example. The keyboard shortcut problem was solved like this:&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="nf"&gt;handleKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&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="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctrlKey&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metaKey&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;altKey&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="kc"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;visible&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// ... S scans, P pins&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;npm test&lt;/code&gt;: &lt;strong&gt;70 tests, 70 passing&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm run lint&lt;/code&gt;: clean&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm run typecheck&lt;/code&gt;: clean&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The things that are design limits, not bugs (like overflow inside &lt;code&gt;overflow:hidden&lt;/code&gt; ancestors, or &lt;code&gt;@import&lt;/code&gt; sheets not being visible), will go in the docs as &lt;strong&gt;known limitations&lt;/strong&gt;. I think that's more honest than pretending they don't exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Writing docs is a code review.&lt;/strong&gt; When you have to explain a function, you notice when it doesn't do what you think.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two AIs disagreeing doesn't mean nobody is right.&lt;/strong&gt; It means you have to open the file and look.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't trust counts, trust lines.&lt;/strong&gt; "Line 144 vs line 216" is a fact; "10 or 11 bugs" is just noise.&lt;/li&gt;
&lt;li&gt;You don't need a degree to read code. You need patience, coffee, and the stubbornness to check one line at a time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;BeeLadybug is on npm as &lt;a href="https://www.npmjs.com/package/bee-ladybug" rel="noopener noreferrer"&gt;&lt;code&gt;bee-ladybug&lt;/code&gt;&lt;/a&gt;, and the docs (in Italian, for now) are on &lt;a href="https://beeenginejs.com/ladybug/inizia/" rel="noopener noreferrer"&gt;beeenginejs.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you're also building things at night after work: keep going. Your brain will get bugged, but your code will get better. 🐞&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>ai</category>
      <category>debugging</category>
    </item>
    <item>
      <title>I wanted a floating search bar. My AI assistants wanted a bigger project. 😅 A few CSS changes later: the behavior I wanted and a mobile PageSpeed score of 99. Ever had to convince AI to keep things simple?</title>
      <dc:creator>Antonio </dc:creator>
      <pubDate>Sat, 07 Nov 2026 21:51:19 +0000</pubDate>
      <link>https://dev.to/antonioprosperi2svg/i-wanted-a-floating-search-bar-my-ai-assistants-wanted-a-bigger-project-a-few-css-changes-2ppc</link>
      <guid>https://dev.to/antonioprosperi2svg/i-wanted-a-floating-search-bar-my-ai-assistants-wanted-a-bigger-project-a-few-css-changes-2ppc</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/antonioprosperi2svg/i-wanted-a-floating-search-bar-the-fix-was-a-few-lines-of-css-after-hours-of-arguing-with-ai-272f" class="crayons-story__hidden-navigation-link"&gt;I Wanted a Floating Search Bar. The Fix Was a Few Lines of CSS (After Hours of Arguing With AI)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/antonioprosperi2svg" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4092373%2F27c3ef5d-a3a1-442b-95b9-9e5f97c623dc.gif" alt="antonioprosperi2svg profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/antonioprosperi2svg" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Antonio 
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Antonio 
                
                
              
              &lt;div id="story-author-preview-content-4995822" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/antonioprosperi2svg" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4092373%2F27c3ef5d-a3a1-442b-95b9-9e5f97c623dc.gif" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Antonio &lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/antonioprosperi2svg/i-wanted-a-floating-search-bar-the-fix-was-a-few-lines-of-css-after-hours-of-arguing-with-ai-272f" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Nov 7&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/antonioprosperi2svg/i-wanted-a-floating-search-bar-the-fix-was-a-few-lines-of-css-after-hours-of-arguing-with-ai-272f" id="article-link-4995822"&gt;
          I Wanted a Floating Search Bar. The Fix Was a Few Lines of CSS (After Hours of Arguing With AI)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/css"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;css&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/performance"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;performance&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/antonioprosperi2svg/i-wanted-a-floating-search-bar-the-fix-was-a-few-lines-of-css-after-hours-of-arguing-with-ai-272f" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/antonioprosperi2svg/i-wanted-a-floating-search-bar-the-fix-was-a-few-lines-of-css-after-hours-of-arguing-with-ai-272f#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
          
          &lt;div class="only-sidebar-menu-item trusted-visible-block print-hidden align-center"&gt;
                
                    
                
          &lt;/div&gt;

        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>css</category>
      <category>frontend</category>
      <category>performance</category>
    </item>
    <item>
      <title>I Wanted a Floating Search Bar. The Fix Was a Few Lines of CSS (After Hours of Arguing With AI)</title>
      <dc:creator>Antonio </dc:creator>
      <pubDate>Sat, 07 Nov 2026 21:46:30 +0000</pubDate>
      <link>https://dev.to/antonioprosperi2svg/i-wanted-a-floating-search-bar-the-fix-was-a-few-lines-of-css-after-hours-of-arguing-with-ai-272f</link>
      <guid>https://dev.to/antonioprosperi2svg/i-wanted-a-floating-search-bar-the-fix-was-a-few-lines-of-css-after-hours-of-arguing-with-ai-272f</guid>
      <description>&lt;p&gt;I already had the solution on the screen. Twice, actually.&lt;/p&gt;

&lt;p&gt;Two small floating logo/search buttons on my site stayed visible all the way to the footer. Their &lt;code&gt;.blocco-nav-fluttuante&lt;/code&gt; used &lt;code&gt;position: fixed&lt;/code&gt;, with &lt;code&gt;top: 45px&lt;/code&gt; and &lt;code&gt;left: 20px&lt;/code&gt;. No JavaScript moving them around. They simply stayed there.&lt;/p&gt;

&lt;p&gt;So why couldn't my central search and categories bar work the same way?&lt;/p&gt;

&lt;p&gt;That was my point. Getting my AI assistants to stay focused on it took considerably longer than writing the CSS.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/antonioprosperi2svg/how-i-rebuilt-the-homepage-of-my-html5-games-portal-and-what-i-learned-about-caching-2kn"&gt;my previous article&lt;/a&gt;, I covered the homepage rebuild of &lt;a href="https://www.playcombo.it/" rel="noopener noreferrer"&gt;SPC – Super Play Combo&lt;/a&gt;, my WordPress games portal. This time, the important part isn't a new engine or a clever architecture. It's the simple solution I kept asking for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here is the fix—not three sections later
&lt;/h2&gt;

&lt;p&gt;I wanted a rounded bar, slightly detached from the top and sides, with games scrolling underneath it. Visible right down to the footer. I showed Poki as a visual reference for that behavior, not as a source of code.&lt;/p&gt;

&lt;p&gt;These are the two CSS rules that delivered it on the Arcade page:&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;.barra-fissa-spc&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;fixed&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;12px&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;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;540px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;22px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.contenitore-arcade-spc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;150px&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fixed positioning from the first paint, plus space already reserved underneath. That was the solution for the bar.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The bar stayed in its existing HTML location. Its controls, IDs, event handlers, URLs, and category logic stayed intact. No separate external file. No engine rewrite. No rebuilding the categories just to make a bar float.&lt;/p&gt;

&lt;p&gt;A few CSS declarations. A much longer conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the two little buttons had the right idea
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;sticky&lt;/code&gt; and &lt;code&gt;fixed&lt;/code&gt; aren't interchangeable. In my layout, a sticky bar was constrained by its containing block. It didn't stay visible through the footer the way I wanted.&lt;/p&gt;

&lt;p&gt;The little floating buttons already demonstrated the alternative: anchor to the viewport with &lt;code&gt;fixed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the central bar, &lt;code&gt;top: 12px&lt;/code&gt; creates the gap above it; the side offsets and maximum width keep it centered; the radius rounds all four corners. The games can scroll behind it, including through that small gap above.&lt;/p&gt;

&lt;p&gt;Because fixed elements don't occupy normal-flow space, the container needs room at the top. The final value here was &lt;strong&gt;150px&lt;/strong&gt;, not the earlier 135px trial. That keeps the title, description, and first games clear of the bar initially. It's a value for my layout, to check at different widths and with the WordPress admin bar—not a magic number for every site.&lt;/p&gt;

&lt;h2&gt;
  
  
  The JavaScript detour we didn't need
&lt;/h2&gt;

&lt;p&gt;The earlier &lt;code&gt;spostaBarra()&lt;/code&gt; function relocated the bar into the body on &lt;code&gt;DOMContentLoaded&lt;/code&gt;. Moving a visible element after rendering was an avoidable layout-shift risk. A Puzzle report showing the whole &lt;code&gt;#page&lt;/code&gt; displaced made that worth investigating.&lt;/p&gt;

&lt;p&gt;The answer wasn't another relocation strategy. It was to stop relocating 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="nf"&gt;avvia&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// spostaBarra();&lt;/span&gt;
  &lt;span class="nf"&gt;osservaGioco&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;osservaGioco()&lt;/code&gt; still handles visibility when opening a game. Removing the move didn't mean throwing away useful behavior.&lt;/p&gt;

&lt;p&gt;During troubleshooting of the optimized styles, we also added this as the first CSS rule:&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;.spc-css-guard&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;--spc&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was a debugging precaution, not a diagnosed universal LiteSpeed fix. The layout solution remained &lt;code&gt;fixed&lt;/code&gt; plus reserved space, with &lt;code&gt;!important&lt;/code&gt; on my container padding to keep it applied.&lt;/p&gt;

&lt;h2&gt;
  
  
  My AI assistants were helping. Enthusiastically. Elsewhere.
&lt;/h2&gt;

&lt;p&gt;The discussion kept wandering into animation, visual styling, layout shifts, and changes to the game engine. Meanwhile, I kept returning to those two little floating buttons.&lt;/p&gt;

&lt;p&gt;I knew the behavior I wanted. I was using AI to implement it, not asking it to replace the goal with something more complicated.&lt;/p&gt;

&lt;p&gt;I also did my part to prolong the adventure: undoing and reapplying changes whenever PageSpeed moved. Apparently, my afternoon needed a second source of stubbornness.&lt;/p&gt;

&lt;p&gt;Still, this was a satisfying little vindication. I didn't need to name every CSS property to recognize that the working example was already on my own page.&lt;/p&gt;

&lt;h2&gt;
  
  
  One separate issue, not a reason to rebuild the bar
&lt;/h2&gt;

&lt;p&gt;The game grid had its own loading problem. An intermediate Arcade report showed CLS &lt;strong&gt;0.120&lt;/strong&gt;: &lt;strong&gt;0.102&lt;/strong&gt; attributed to pagination and &lt;strong&gt;0.018&lt;/strong&gt; to the grid.&lt;/p&gt;

&lt;p&gt;The separate fix reserved responsive space for the first &lt;strong&gt;60 cards&lt;/strong&gt; while JavaScript populated the grid. Once filled, the waiting class was removed, allowing filtered results and shorter final pages to use their natural height.&lt;/p&gt;

&lt;p&gt;That mattered for stability. It wasn't part of making the search bar float, and it didn't require reinventing the bar.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result—and six categories still waiting
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://pagespeed.web.dev/analysis/https-www-playcombo-it-arcade/hv7eilt6r4?form_factor=mobile" rel="noopener noreferrer"&gt;later Arcade mobile lab report&lt;/a&gt; reached &lt;strong&gt;99 Performance&lt;/strong&gt;, with &lt;strong&gt;FCP and LCP at 1.4s&lt;/strong&gt;, &lt;strong&gt;30ms Total Blocking Time&lt;/strong&gt;, and &lt;strong&gt;CLS 0.017&lt;/strong&gt;. Accessibility, Best Practices, and SEO were &lt;strong&gt;100&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not a promise of zero CLS everywhere, and not a claim that the bar's CSS alone produced the whole score. But the intended behavior worked, and the layout was much steadier.&lt;/p&gt;

&lt;p&gt;Now I'm saving the stable version before carefully updating the &lt;strong&gt;six remaining categories&lt;/strong&gt;. First, this article. Even debugging deserves an intermission.&lt;/p&gt;

&lt;p&gt;Have your AI assistants ever confidently complicated something you already knew could be simple? And have you solved a floating-bar or layout-shift problem this way? Tell me in the comments.&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>ai</category>
      <category>performance</category>
    </item>
    <item>
      <title>"I don't talk much, so I wrote a dialogue plugin instead. 🐝 Feedback welcome!"</title>
      <dc:creator>Antonio </dc:creator>
      <pubDate>Sun, 01 Nov 2026 11:06:41 +0000</pubDate>
      <link>https://dev.to/antonioprosperi2svg/i-dont-talk-much-so-i-wrote-a-dialogue-plugin-instead-feedback-welcome-2ibb</link>
      <guid>https://dev.to/antonioprosperi2svg/i-dont-talk-much-so-i-wrote-a-dialogue-plugin-instead-feedback-welcome-2ibb</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/antonioprosperi2svg/how-nice-it-is-to-talk-beedialogue-lands-in-beeengine-2110-cad" class="crayons-story__hidden-navigation-link"&gt;How nice it is to talk — BeeDialogue lands in BeeEngine 2.11.0&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/antonioprosperi2svg" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4092373%2F27c3ef5d-a3a1-442b-95b9-9e5f97c623dc.gif" alt="antonioprosperi2svg profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/antonioprosperi2svg" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Antonio 
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Antonio 
                
                
              
              &lt;div id="story-author-preview-content-4957035" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/antonioprosperi2svg" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4092373%2F27c3ef5d-a3a1-442b-95b9-9e5f97c623dc.gif" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Antonio &lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/antonioprosperi2svg/how-nice-it-is-to-talk-beedialogue-lands-in-beeengine-2110-cad" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Nov 1&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/antonioprosperi2svg/how-nice-it-is-to-talk-beedialogue-lands-in-beeengine-2110-cad" id="article-link-4957035"&gt;
          How nice it is to talk — BeeDialogue lands in BeeEngine 2.11.0
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/gamedev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;gamedev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/antonioprosperi2svg/how-nice-it-is-to-talk-beedialogue-lands-in-beeengine-2110-cad" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/antonioprosperi2svg/how-nice-it-is-to-talk-beedialogue-lands-in-beeengine-2110-cad#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
          
          &lt;div class="only-sidebar-menu-item trusted-visible-block print-hidden align-center"&gt;
                
                    
                
          &lt;/div&gt;

        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>gamedev</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How nice it is to talk — BeeDialogue lands in BeeEngine 2.11.0</title>
      <dc:creator>Antonio </dc:creator>
      <pubDate>Sun, 01 Nov 2026 11:03:43 +0000</pubDate>
      <link>https://dev.to/antonioprosperi2svg/how-nice-it-is-to-talk-beedialogue-lands-in-beeengine-2110-cad</link>
      <guid>https://dev.to/antonioprosperi2svg/how-nice-it-is-to-talk-beedialogue-lands-in-beeengine-2110-cad</guid>
      <description>&lt;p&gt;Hi. I'm Antonio. I'm 53. I build things out of pure passion.&lt;/p&gt;

&lt;p&gt;I don't talk much. But when I do… &lt;strong&gt;BeeDialogue&lt;/strong&gt; comes out.&lt;/p&gt;




&lt;h2&gt;
  
  
  From “dialogue” to a dialogue plugin
&lt;/h2&gt;

&lt;p&gt;BeeEngine is a small 2D HTML5 Canvas engine I keep shaping in the open. Physics, scenes, sprites, tiles, audio buses, an inventory plugin, a locale plugin. Useful pieces. Quiet pieces.&lt;/p&gt;

&lt;p&gt;What was missing for story-shaped games was obvious: a place for NPCs to say something without me inventing a new &lt;code&gt;if&lt;/code&gt; tree every weekend.&lt;/p&gt;

&lt;p&gt;So &lt;strong&gt;v2.11.0&lt;/strong&gt; adds &lt;strong&gt;BeeDialogue&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not a chatbot. Not a voice synthesizer. A dialogue &lt;em&gt;tree&lt;/em&gt;: speakers, lines, branching choices, straight-line advances. The kind of thing you wire to a blue rectangle that pretends to be a guide on a bridge.&lt;/p&gt;




&lt;h2&gt;
  
  
  The engine stays blind (on purpose)
&lt;/h2&gt;

&lt;p&gt;BeeEngine has a plugin contract I take seriously. The core does not import plugins. A plugin attaches itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BeeEngine&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;beeengine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BeeDialogue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BeeLocale&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;beeengine/plugins&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;game&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;BeeEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;480&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;locale&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;BeeLocale&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="cm"&gt;/* strings… */&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;game&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;dialogue&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;BeeDialogue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;game&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;cancelKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Escape&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// attach() registers it as 'dialogue' — detach() unregisters&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No monkey-patch of &lt;code&gt;loop()&lt;/code&gt;. No hijacking of &lt;code&gt;update&lt;/code&gt; / &lt;code&gt;render&lt;/code&gt;. BeeDialogue has &lt;strong&gt;no tick of its own&lt;/strong&gt; and no DOM listeners. Your scene calls the verbs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;handleInput(input)&lt;/code&gt; from &lt;code&gt;scene.update&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;draw(ctx)&lt;/code&gt; from &lt;code&gt;scene.draw&lt;/code&gt; (screen space, after the camera)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The motor stays a motor. The plugin stays a plugin. I sleep better.&lt;/p&gt;




&lt;h2&gt;
  
  
  A tree you can read
&lt;/h2&gt;

&lt;p&gt;You &lt;code&gt;load&lt;/code&gt; a tree once. Nodes can be an array (easier to skim) or a map. Literal &lt;code&gt;text&lt;/code&gt; / &lt;code&gt;speaker&lt;/code&gt; work. Or &lt;code&gt;textKey&lt;/code&gt; / &lt;code&gt;speakerKey&lt;/code&gt; if you pass an optional &lt;strong&gt;BeeLocale&lt;/strong&gt; (constructor, &lt;code&gt;setLocale&lt;/code&gt;, or &lt;code&gt;engine.plugin('locale')&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;dialogue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;intro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;intro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;speakerKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;guide&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;textKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;textKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ask_map&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;map&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;map&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;textKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bye&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bye&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;map&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;speakerKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;guide&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;textKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;map&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tip&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;speakerKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;guide&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;textKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tip&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;Rules that saved me from myself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node &lt;strong&gt;without&lt;/strong&gt; &lt;code&gt;choices&lt;/code&gt; → &lt;code&gt;advance()&lt;/code&gt; follows &lt;code&gt;next&lt;/code&gt; (or ends).&lt;/li&gt;
&lt;li&gt;Node &lt;strong&gt;with&lt;/strong&gt; &lt;code&gt;choices&lt;/code&gt; → &lt;code&gt;choose(index)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The wrong verb returns &lt;code&gt;false&lt;/code&gt; and warns. Good. I need warnings more than cleverness.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;start()&lt;/code&gt; while already open does a clean restart (&lt;code&gt;end&lt;/code&gt; with reason &lt;code&gt;restart&lt;/code&gt;, then &lt;code&gt;start&lt;/code&gt; again).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Drawing choices (without becoming a second renderer)
&lt;/h2&gt;

&lt;p&gt;BeeDialogue is not &lt;code&gt;BeeText.drawHUD&lt;/code&gt;. It draws a simple panel when you ask.&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;scene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_dt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&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;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wasPressed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;KeyE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;dialogue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="nx"&gt;dialogue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;dialogue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Space / Enter advances or confirms; arrows move the highlight&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;dialogue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;80&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;code&gt;onChange&lt;/code&gt; reports &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;node&lt;/code&gt;, &lt;code&gt;choice&lt;/code&gt;, &lt;code&gt;advance&lt;/code&gt;, and &lt;code&gt;end&lt;/code&gt; (with a &lt;code&gt;reason&lt;/code&gt;: &lt;code&gt;finished&lt;/code&gt;, &lt;code&gt;cancel&lt;/code&gt;, &lt;code&gt;restart&lt;/code&gt;, &lt;code&gt;reload&lt;/code&gt;, &lt;code&gt;missing-node&lt;/code&gt;…). Enough to feed a future quest plugin without hard-wiring anything today.&lt;/p&gt;

&lt;p&gt;And yes — &lt;code&gt;toJSON&lt;/code&gt; / &lt;code&gt;fromJSON&lt;/code&gt; save the tree and where you stood, so you can tuck the DTO into &lt;code&gt;BeeSave&lt;/code&gt; next to inventory slots. Definitions stay yours; restore reopens on the saved node and emits &lt;code&gt;node&lt;/code&gt; (not a fake second &lt;code&gt;start&lt;/code&gt;).&lt;/p&gt;




&lt;h2&gt;
  
  
  About that demo label
&lt;/h2&gt;

&lt;p&gt;The demo is &lt;code&gt;examples/dialogue.html&lt;/code&gt;. Press &lt;strong&gt;E&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The English string does &lt;strong&gt;not&lt;/strong&gt; say “E to talk”.&lt;/p&gt;

&lt;p&gt;It says &lt;strong&gt;“E to interact”&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Because BeeDialogue does not talk. It does not clear its throat. It does not do regional accents. It advances nodes. The joke writes itself, and I left it in the locale table on purpose (&lt;code&gt;talk: 'E to interact'&lt;/code&gt;). Press &lt;strong&gt;L&lt;/strong&gt; if you want Italian. The guide still will not speak aloud. She will, however, mention a village east of a bridge, which is already more social than most of my week.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this shape
&lt;/h2&gt;

&lt;p&gt;I like small contracts:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Piece&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;BeeLocale&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;t(key)&lt;/code&gt; — pure read&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BeeInventory&lt;/td&gt;
&lt;td&gt;stacks, use, equip — no draw loop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BeeDialogue&lt;/td&gt;
&lt;td&gt;tree state — you draw and feed input&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Together they feel like a tiny RPG toolkit without pretending to be one. Next ideas on the shelf (one at a time): Quest, Post FX, scene Transition, action remapping… Lights, Spine, Net later. Those touch more surface area. Dialogue was the polite guest who hangs its coat on &lt;code&gt;attach&lt;/code&gt; and leaves with &lt;code&gt;detach&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/antonioprosperi2-svg/BeeEngine-V2.5.0" rel="noopener noreferrer"&gt;BeeEngine-V2.5.0&lt;/a&gt; (package &lt;code&gt;beeengine&lt;/code&gt; &lt;strong&gt;2.11.0&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Demo: &lt;code&gt;examples/dialogue.html&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Tests: &lt;code&gt;node scripts/test-beedialogue.mjs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Import: &lt;code&gt;import { BeeDialogue } from 'beeengine/plugins'&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you break it, tell me how. If you use it in a jam game with three lines of dialogue and a torch tip, tell me that too. Short messages welcome — I don't talk much.&lt;/p&gt;

&lt;p&gt;But when I do… you already know what comes out.&lt;/p&gt;

&lt;p&gt;— Antonio&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>gamedev</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How I Rebuilt the Homepage of My HTML5 Games Portal (and What I Learned About Caching)</title>
      <dc:creator>Antonio </dc:creator>
      <pubDate>Sat, 31 Oct 2026 19:03:01 +0000</pubDate>
      <link>https://dev.to/antonioprosperi2svg/how-i-rebuilt-the-homepage-of-my-html5-games-portal-and-what-i-learned-about-caching-2kn</link>
      <guid>https://dev.to/antonioprosperi2svg/how-i-rebuilt-the-homepage-of-my-html5-games-portal-and-what-i-learned-about-caching-2kn</guid>
      <description>&lt;p&gt;I run a free HTML5 games portal, &lt;strong&gt;&lt;a href="https://playcombo.it" rel="noopener noreferrer"&gt;SPC – Super Play Combo&lt;/a&gt;&lt;/strong&gt;. It's built on WordPress with the GeneratePress theme and has over 3,000 games from the GameMonetize and GamePix feeds. Over the last few weeks I rebuilt the homepage in a Poki-like style, with one horizontal row per category. It looked easy. It wasn't.&lt;/p&gt;

&lt;p&gt;Here are the real problems I ran into and how I fixed them.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Category rows with no duplicates
&lt;/h2&gt;

&lt;p&gt;Each category (Puzzle, Arcade, Match-3, Mahjong, Quiz, Sports, Racing…) has its own page with its own game list. The homepage shows one row per category, built by a script called &lt;code&gt;motore-playcombo.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The feeds use English category names, while my site uses Italian ones, so I made a map:&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;CATEGORIE_HOME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;puzzle&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;sparabolle&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;arcade&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;match-3&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;mahjong&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;trivia&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;gamesforgirls&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;sports&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;racing&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;card&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;adventure&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;platformer&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;2048&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;Golden rule: &lt;strong&gt;each game appears in exactly one row&lt;/strong&gt;. A &lt;code&gt;Set&lt;/code&gt; of already-used ids does the job:&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;alreadyShown&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;Set&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;removeDuplicates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;games&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;games&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;g&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;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&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;alreadyShown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;alreadyShown&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="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rows further down only load when they're about to scroll into view:&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;observer&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;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entries&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;entries&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;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isIntersecting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;loadRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unobserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rootMargin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;300px&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;h2&gt;
  
  
  2. "It works when I'm logged in, but not in incognito"
&lt;/h2&gt;

&lt;p&gt;The Quiz and Card rows were full when I was logged in as admin, but &lt;strong&gt;empty for visitors&lt;/strong&gt;. The culprit was LiteSpeed Cache. For visitors who aren't logged in, it optimizes the page and turns the game list inside the HTML into &lt;strong&gt;base64&lt;/strong&gt;. My script was looking for plain text and found nothing.&lt;/p&gt;

&lt;p&gt;The fix is to try decoding 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="nf"&gt;readList&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="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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&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="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;e&lt;/span&gt;&lt;span class="p"&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;atob&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="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;e&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;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt; always test in incognito. What you see as an admin is not what your users see.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The little &lt;code&gt;?v=&lt;/code&gt; number that saves your life
&lt;/h2&gt;

&lt;p&gt;The script is loaded like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/js/motore-playcombo.js?v=16"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;?v=16&lt;/code&gt; does nothing to the code. It only tells the browser (and the cache, and the PWA service worker) that the file is new. Every time I upload a new version, I:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;bump the number on &lt;strong&gt;every&lt;/strong&gt; page that loads the script;&lt;/li&gt;
&lt;li&gt;purge the LiteSpeed cache.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Forget this and you'll get 404 errors for files you already deleted, because the browser is still running the old version. Ask me how I know.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Thumbnails: from wsrv.nl to i0.wp.com
&lt;/h2&gt;

&lt;p&gt;To make thumbnails lighter, I was running them through an image proxy. Then I found out that the service's &lt;code&gt;robots.txt&lt;/code&gt; blocks Googlebot, so Google couldn't see my images. I switched to WordPress's free image CDN:&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;optimizeImg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gamepix&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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;return&lt;/span&gt; &lt;span class="nx"&gt;url&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;u&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;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`https://i0.wp.com/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?w=240&amp;amp;quality=75`&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;I also added a small safety net: if the optimized image fails to load, it falls back to the original.&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;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;original&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 result is a &lt;strong&gt;much&lt;/strong&gt; faster homepage.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. A bit of (lightweight) style
&lt;/h2&gt;

&lt;p&gt;One last touch: the background has game-themed icons (a joypad, a coin, a star, a heart) made with pure CSS and no shadows, so phones don't struggle. With &lt;code&gt;body.page-id-XXXX&lt;/code&gt; I can give each page its own look, like floating yellow stars only on the Girls page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Always&lt;/strong&gt; test in incognito and on a phone.&lt;/li&gt;
&lt;li&gt;The cache is your friend, until you forget about it.&lt;/li&gt;
&lt;li&gt;A wrong (or unchanged) &lt;code&gt;?v=&lt;/code&gt; can cost you hours.&lt;/li&gt;
&lt;li&gt;Check the &lt;code&gt;robots.txt&lt;/code&gt; of any third-party service you rely on.&lt;/li&gt;
&lt;li&gt;PWA errors often go away by themselves after a few minutes, so don't panic right away.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to see the result, the games are on &lt;strong&gt;&lt;a href="https://playcombo.it" rel="noopener noreferrer"&gt;playcombo.it&lt;/a&gt;&lt;/strong&gt;. Free, as always. 🎮&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>wordpress</category>
      <category>webperf</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Pressed F8 on a big games portal: 25 errors. On my own site: 4. Then the report found bugs in my debugger itself 😄</title>
      <dc:creator>Antonio </dc:creator>
      <pubDate>Mon, 26 Oct 2026 22:10:04 +0000</pubDate>
      <link>https://dev.to/antonioprosperi2svg/pressed-f8-on-a-big-games-portal-25-errors-on-my-own-site-4-then-the-report-found-bugs-in-my-1c01</link>
      <guid>https://dev.to/antonioprosperi2svg/pressed-f8-on-a-big-games-portal-25-errors-on-my-own-site-4-then-the-report-found-bugs-in-my-1c01</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/antonioprosperi2svg/i-got-tired-of-reading-css-bugs-in-a-tiny-overlay-so-i-made-my-debugger-print-a-report-48n9" class="crayons-story__hidden-navigation-link"&gt;I got tired of reading CSS bugs in a tiny overlay, so I made my debugger print a report&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/antonioprosperi2svg" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4092373%2F27c3ef5d-a3a1-442b-95b9-9e5f97c623dc.gif" alt="antonioprosperi2svg profile" class="crayons-avatar__image" width="512" height="512"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/antonioprosperi2svg" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Antonio 
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Antonio 
                
                
              
              &lt;div id="story-author-preview-content-4924354" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/antonioprosperi2svg" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4092373%2F27c3ef5d-a3a1-442b-95b9-9e5f97c623dc.gif" class="crayons-avatar__image" alt="" width="512" height="512"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Antonio &lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/antonioprosperi2svg/i-got-tired-of-reading-css-bugs-in-a-tiny-overlay-so-i-made-my-debugger-print-a-report-48n9" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Oct 26&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/antonioprosperi2svg/i-got-tired-of-reading-css-bugs-in-a-tiny-overlay-so-i-made-my-debugger-print-a-report-48n9" id="article-link-4924354"&gt;
          I got tired of reading CSS bugs in a tiny overlay, so I made my debugger print a report
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/debugging"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;debugging&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/antonioprosperi2svg/i-got-tired-of-reading-css-bugs-in-a-tiny-overlay-so-i-made-my-debugger-print-a-report-48n9" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/antonioprosperi2svg/i-got-tired-of-reading-css-bugs-in-a-tiny-overlay-so-i-made-my-debugger-print-a-report-48n9#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
          
          &lt;div class="only-sidebar-menu-item trusted-visible-block print-hidden align-center"&gt;
                
                    
                
          &lt;/div&gt;

        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>debugging</category>
      <category>softwaredevelopment</category>
      <category>tools</category>
    </item>
    <item>
      <title>I got tired of reading CSS bugs in a tiny overlay, so I made my debugger print a report</title>
      <dc:creator>Antonio </dc:creator>
      <pubDate>Mon, 26 Oct 2026 22:07:26 +0000</pubDate>
      <link>https://dev.to/antonioprosperi2svg/i-got-tired-of-reading-css-bugs-in-a-tiny-overlay-so-i-made-my-debugger-print-a-report-48n9</link>
      <guid>https://dev.to/antonioprosperi2svg/i-got-tired-of-reading-css-bugs-in-a-tiny-overlay-so-i-made-my-debugger-print-a-report-48n9</guid>
      <description>&lt;p&gt;BeeLadybug, my open-source debug overlay, has always shown what's happening in real time: FPS, logs, &lt;code&gt;!important&lt;/code&gt;, z-index traps, clicks being swallowed by the wrong element.&lt;/p&gt;

&lt;p&gt;The problem is the overlay. Make it big and it covers the game or the page you're debugging. Make it small, the way it is now, and you're squinting at a phone-sized box on the left of the screen while the rows scroll past.&lt;/p&gt;

&lt;p&gt;One evening I gave up and asked myself a simple question: why can't I just press a key and get &lt;strong&gt;everything&lt;/strong&gt; on one page, to read calmly?&lt;/p&gt;

&lt;h2&gt;
  
  
  One key, one file
&lt;/h2&gt;

&lt;p&gt;Version &lt;strong&gt;0.6.1&lt;/strong&gt; adds &lt;code&gt;exportReport()&lt;/code&gt;. Press &lt;strong&gt;F8&lt;/strong&gt;, or the EXPORT button, and you get &lt;code&gt;report-YYYYMMDD-HHMM.html&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a summary at the top: errors, warnings, ok&lt;/li&gt;
&lt;li&gt;the Core log with sim time and frame&lt;/li&gt;
&lt;li&gt;series: FPS min / avg / max, nodes, mutations&lt;/li&gt;
&lt;li&gt;one section per adapter: Canvas hitboxes and collisions, DOM box model and clipped nodes, CSS (&lt;code&gt;!important&lt;/code&gt;, stacking contexts, intercepted clicks, overflow), long tasks, slow resources, Python metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's plain HTML with a dark theme. Ctrl+P turns it into a PDF. You can also get &lt;code&gt;json&lt;/code&gt; (for CI or an AI agent) or &lt;code&gt;csv&lt;/code&gt; (for a spreadsheet).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BeeLadybugCore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;exportReport&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;bee-ladybug&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;bee&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;BeeLadybugCore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// ...attach adapters...&lt;/span&gt;
&lt;span class="nf"&gt;exportReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// downloads the file&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In headless mode (&lt;code&gt;ui: false&lt;/code&gt;) nothing is downloaded. The function just returns the data, so it works in Node and in bots too.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it fits a "blind" Core
&lt;/h2&gt;

&lt;p&gt;The Core still knows nothing about Canvas, the DOM or Python. Each adapter can now register an optional &lt;code&gt;snapshot()&lt;/code&gt; hook that returns rows like &lt;code&gt;{ severity, selector, rule, value, source }&lt;/code&gt;. The exporter asks every registered adapter for its snapshot, and if one throws, it becomes a single &lt;code&gt;warn&lt;/code&gt; row while the rest of the report still renders. A new adapter only has to implement &lt;code&gt;snapshot()&lt;/code&gt; to show up in the report.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then I pointed it at real sites
&lt;/h2&gt;

&lt;p&gt;First, my own games portal. It found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;my &lt;code&gt;.entry-content&lt;/code&gt; creating a stacking context that &lt;strong&gt;traps the z-index&lt;/strong&gt; of the game grid&lt;/li&gt;
&lt;li&gt;a container &lt;strong&gt;blocking clicks&lt;/strong&gt; on three elements&lt;/li&gt;
&lt;li&gt;an average of &lt;strong&gt;33 FPS&lt;/strong&gt;, which explains a lot&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, for fun, a big professional games portal. &lt;strong&gt;25 errors, 51 warnings&lt;/strong&gt; 😄 To be fair, most of them are intentional tricks: negative margins so a carousel can bleed to the edges, and content clipped on purpose inside cards. Their site works great. It still averaged ~52 FPS with 3× my DOM nodes, which taught me more than the error count did.&lt;/p&gt;

&lt;h2&gt;
  
  
  …and it found bugs in itself
&lt;/h2&gt;

&lt;p&gt;The best part of testing on real pages: the report exposed its own weak spots.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an icon from the WordPress admin bar slipped through the filter&lt;/li&gt;
&lt;li&gt;the same row repeated dozens of times instead of being grouped as &lt;code&gt;×N&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the summary said "0 errors" while the log had four of them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three are being fixed. A debugger that finds bugs in itself on its first real run felt like a good sign.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Install it in your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i bee-ladybug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or try it right now without installing: open any page, press F12 and paste this in the console, then press F8 for the report.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://cdn.jsdelivr.net/npm/bee-ladybug@0.6.1/src/index.js&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;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;BeeLadybugCore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WebDOMAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CSSAdapter&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;bee&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;BeeLadybugCore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebDOMAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CSSAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bee&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bee&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;Feedback welcome, especially from people debugging Canvas games and DOM-heavy pages.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>debugging</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Chrome DevTools tells you z-index is 9999. It doesn't tell you which parent is trapping it. Now my debugger does.</title>
      <dc:creator>Antonio </dc:creator>
      <pubDate>Sat, 24 Oct 2026 22:22:46 +0000</pubDate>
      <link>https://dev.to/antonioprosperi2svg/chrome-devtools-tells-you-z-index-is-9999-it-doesnt-tell-you-which-parent-is-trapping-it-now-30hi</link>
      <guid>https://dev.to/antonioprosperi2svg/chrome-devtools-tells-you-z-index-is-9999-it-doesnt-tell-you-which-parent-is-trapping-it-now-30hi</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/antonioprosperi2svg/why-your-z-index-doesnt-work-my-debugger-now-points-to-the-exact-line-30f3" class="crayons-story__hidden-navigation-link"&gt;Why your z-index doesn't work: my debugger now points to the exact line&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/antonioprosperi2svg" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4092373%2F27c3ef5d-a3a1-442b-95b9-9e5f97c623dc.gif" alt="antonioprosperi2svg profile" class="crayons-avatar__image" width="512" height="512"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/antonioprosperi2svg" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Antonio 
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Antonio 
                
                
              
              &lt;div id="story-author-preview-content-4899738" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/antonioprosperi2svg" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4092373%2F27c3ef5d-a3a1-442b-95b9-9e5f97c623dc.gif" class="crayons-avatar__image" alt="" width="512" height="512"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Antonio &lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/antonioprosperi2svg/why-your-z-index-doesnt-work-my-debugger-now-points-to-the-exact-line-30f3" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Oct 22&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/antonioprosperi2svg/why-your-z-index-doesnt-work-my-debugger-now-points-to-the-exact-line-30f3" id="article-link-4899738"&gt;
          Why your z-index doesn't work: my debugger now points to the exact line
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/css"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;css&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/debugging"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;debugging&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/antonioprosperi2svg/why-your-z-index-doesnt-work-my-debugger-now-points-to-the-exact-line-30f3" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/antonioprosperi2svg/why-your-z-index-doesnt-work-my-debugger-now-points-to-the-exact-line-30f3#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              2&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            2 min read
          &lt;/small&gt;
          
          &lt;div class="only-sidebar-menu-item trusted-visible-block print-hidden align-center"&gt;
                
                    
                
          &lt;/div&gt;

        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>css</category>
      <category>debugging</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Two docs sites, one WordPress install, zero plugins fighting each other. Here's how I kept BeeEngine and BeeLadybug apart.</title>
      <dc:creator>Antonio </dc:creator>
      <pubDate>Sat, 24 Oct 2026 22:17:29 +0000</pubDate>
      <link>https://dev.to/antonioprosperi2svg/two-docs-sites-one-wordpress-install-zero-plugins-fighting-each-other-heres-how-i-kept-39gh</link>
      <guid>https://dev.to/antonioprosperi2svg/two-docs-sites-one-wordpress-install-zero-plugins-fighting-each-other-heres-how-i-kept-39gh</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/antonioprosperi2svg/how-i-kept-two-docs-sites-apart-in-one-wordpress-install-and-almost-gave-up-md7" class="crayons-story__hidden-navigation-link"&gt;How I kept two docs sites apart in one WordPress install (and almost gave up)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/antonioprosperi2svg" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4092373%2F27c3ef5d-a3a1-442b-95b9-9e5f97c623dc.gif" alt="antonioprosperi2svg profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/antonioprosperi2svg" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Antonio 
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Antonio 
                
                
              
              &lt;div id="story-author-preview-content-4912512" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/antonioprosperi2svg" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4092373%2F27c3ef5d-a3a1-442b-95b9-9e5f97c623dc.gif" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Antonio &lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/antonioprosperi2svg/how-i-kept-two-docs-sites-apart-in-one-wordpress-install-and-almost-gave-up-md7" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Oct 24&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/antonioprosperi2svg/how-i-kept-two-docs-sites-apart-in-one-wordpress-install-and-almost-gave-up-md7" id="article-link-4912512"&gt;
          How I kept two docs sites apart in one WordPress install (and almost gave up)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/wordpress"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;wordpress&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/documentation"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;documentation&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/antonioprosperi2svg/how-i-kept-two-docs-sites-apart-in-one-wordpress-install-and-almost-gave-up-md7" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/antonioprosperi2svg/how-i-kept-two-docs-sites-apart-in-one-wordpress-install-and-almost-gave-up-md7#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              1&lt;span class="hidden s:inline"&gt;&amp;nbsp;comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            2 min read
          &lt;/small&gt;
          
          &lt;div class="only-sidebar-menu-item trusted-visible-block print-hidden align-center"&gt;
                
                    
                
          &lt;/div&gt;

        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>php</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>wordpress</category>
    </item>
    <item>
      <title>How I kept two docs sites apart in one WordPress install (and almost gave up)</title>
      <dc:creator>Antonio </dc:creator>
      <pubDate>Sat, 24 Oct 2026 22:07:28 +0000</pubDate>
      <link>https://dev.to/antonioprosperi2svg/how-i-kept-two-docs-sites-apart-in-one-wordpress-install-and-almost-gave-up-md7</link>
      <guid>https://dev.to/antonioprosperi2svg/how-i-kept-two-docs-sites-apart-in-one-wordpress-install-and-almost-gave-up-md7</guid>
      <description>&lt;p&gt;I already had the BeeEngine docs on beeenginejs.com as static WordPress pages. When BeeLadybug grew big enough to need its own docs, about 33 pages, I hit a wall. Everything I made ended up mixed in with the BeeEngine pages: the same page list, the same hierarchy, the same mess. Using posts wasn't an option either, because docs aren't blog articles.&lt;/p&gt;

&lt;p&gt;I'll be honest: I was close to dropping it. I'm not a WordPress plugin expert, and every solution I found was either too complicated or broke something else.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: a custom post type
&lt;/h2&gt;

&lt;p&gt;The answer turned out to be simple. I gave BeeLadybug its own content type:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I installed &lt;strong&gt;Custom Post Type UI&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;I created a post type with the slug &lt;code&gt;ladybug&lt;/code&gt;, set &lt;strong&gt;Hierarchical&lt;/strong&gt; to true and &lt;strong&gt;Has archive&lt;/strong&gt; to false.&lt;/li&gt;
&lt;li&gt;I went to &lt;strong&gt;Settings → Permalinks&lt;/strong&gt; and clicked &lt;strong&gt;Save&lt;/strong&gt;. Skip this step and you'll get 404s.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now every BeeLadybug page lives under &lt;code&gt;/ladybug/...&lt;/code&gt; with its own URL, and it's completely separate from the BeeEngine pages in the admin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping the style separate too
&lt;/h2&gt;

&lt;p&gt;Each page is a Custom HTML block, and all the CSS is scoped under a &lt;code&gt;.bld-docs&lt;/code&gt; wrapper, so it never leaks into the theme or the BeeEngine docs. Links to pages I haven't written yet point to &lt;code&gt;#&lt;/code&gt; and get dimmed:&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;.bld-docs&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"#"&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;.4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;pointer-events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;The problem was never WordPress, it was not knowing which tool to use. If you're stuck on something similar, keep going. The fix might be one plugin and one checkbox away.🫈🫈🫈&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://beeenginejs.com/ladybug/inizia/" rel="noopener noreferrer"&gt;BeeLadybug docs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>documentation</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Why your z-index doesn't work: my debugger now points to the exact line</title>
      <dc:creator>Antonio </dc:creator>
      <pubDate>Thu, 22 Oct 2026 19:48:29 +0000</pubDate>
      <link>https://dev.to/antonioprosperi2svg/why-your-z-index-doesnt-work-my-debugger-now-points-to-the-exact-line-30f3</link>
      <guid>https://dev.to/antonioprosperi2svg/why-your-z-index-doesnt-work-my-debugger-now-points-to-the-exact-line-30f3</guid>
      <description>&lt;p&gt;The same evening I shipped this, Chrome opened "New in DevTools" and proudly announced DevTools for agents: AI that reads your CSS rules. Thanks Google, I'll take it as a sign I'm on the right track. Their version is for AI agents. Mine is for a 53-year-old guy pressing F6😂😂😂😂😂😂.&lt;/p&gt;

&lt;p&gt;We've all done it. A popup stays behind the header, so you write &lt;code&gt;z-index: 999&lt;/code&gt;. Then &lt;code&gt;9999&lt;/code&gt;. Then &lt;code&gt;99999&lt;/code&gt;. Nothing changes.&lt;/p&gt;

&lt;p&gt;The problem is almost never the element you're fixing. It's one of its &lt;strong&gt;ancestors&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The invisible box
&lt;/h2&gt;

&lt;p&gt;When an element has a &lt;code&gt;transform&lt;/code&gt;, an &lt;code&gt;opacity&lt;/code&gt; below 1, a &lt;code&gt;filter&lt;/code&gt;, or a &lt;code&gt;position&lt;/code&gt; with a &lt;code&gt;z-index&lt;/code&gt;, it creates a &lt;strong&gt;stacking context&lt;/strong&gt;. Think of it as a closed box: its children can only stack &lt;em&gt;inside&lt;/em&gt; the box. A child with &lt;code&gt;z-index: 99999&lt;/code&gt; is still only as high as the box itself.&lt;/p&gt;

&lt;p&gt;DevTools won't tell you which ancestor is the box. You have to climb the tree by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea came from a comment
&lt;/h2&gt;

&lt;p&gt;After my last post about &lt;a href="https://www.npmjs.com/package/bee-ladybug" rel="noopener noreferrer"&gt;BeeLadybug's CSS hunt&lt;/a&gt;, a reader suggested in the comments: scan the ancestors with &lt;code&gt;getComputedStyle&lt;/code&gt;, flag whatever creates a stacking context, then group it by cause, like the click-blocker lines. He also warned that &lt;code&gt;will-change&lt;/code&gt; is often set on purpose for animations, so it should be a hint, not a verdict.&lt;/p&gt;

&lt;p&gt;So that's exactly what 0.5.4 does.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it looks like
&lt;/h2&gt;

&lt;p&gt;On the demo page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;div.hero creates stacking context (transform) - z-index of 3 children is trapped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click the line and it lists &lt;code&gt;span.b1&lt;/code&gt;, &lt;code&gt;span.b2&lt;/code&gt;, &lt;code&gt;span.b3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;will-change&lt;/code&gt; stays a grey info line, with the z-index note on the same line:&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;div&lt;/span&gt;&lt;span class="nc"&gt;.layer-hint&lt;/span&gt; &lt;span class="nt"&gt;will-change&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;opacity&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="nt"&gt;z-index&lt;/span&gt; &lt;span class="nt"&gt;of&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt; &lt;span class="nt"&gt;child&lt;/span&gt; &lt;span class="nt"&gt;stays&lt;/span&gt; &lt;span class="nt"&gt;in&lt;/span&gt; &lt;span class="nt"&gt;this&lt;/span&gt; &lt;span class="nt"&gt;layer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Then I ran it on my own site
&lt;/h2&gt;

&lt;p&gt;I tested it on my live HTML5 games portal. Logged in, it flagged the WordPress admin bar blocking clicks (only I see that). In incognito, only this was left:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;div.entry-content creates stacking context (z-index) - z-index of 1 child is trapped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the INSPECT section went one step further. It showed the rule responsible, inside my LiteSpeed-minified CSS:&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;.site-header&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.main-navigation&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.entry-content&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.griglia-giochi-spc&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="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One &lt;code&gt;!important&lt;/code&gt; rule from my own custom CSS, creating four boxes at once. It's not a bug today, since each box has a single child. But the day I add a dropdown that must cover the header, I already know where to look.&lt;/p&gt;

&lt;p&gt;That's the point: not "something is wrong", but &lt;strong&gt;"this line caused it"&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it (F12, paste in the console)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://cdn.jsdelivr.net/npm/bee-ladybug@0.5.4/src/index.js&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;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;BeeLadybugCore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WebDOMAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CSSAdapter&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;bee&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;BeeLadybugCore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebDOMAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bee&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CSSAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bee&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;attach&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;Press &lt;strong&gt;F6&lt;/strong&gt; for the CSS hunt, &lt;strong&gt;S&lt;/strong&gt; to scan the page. Zero dependencies, no extension.&lt;/p&gt;

&lt;p&gt;Next time your z-index "doesn't work", let the ladybug find the box. 🐞&lt;/p&gt;

</description>
      <category>css</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>debugging</category>
    </item>
  </channel>
</rss>
