<?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: Meursyphus</title>
    <description>The latest articles on DEV Community by Meursyphus (@moondaeseung).</description>
    <link>https://dev.to/moondaeseung</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F940053%2F24594816-6c84-4d23-9434-913b51507e55.jpeg</url>
      <title>DEV Community: Meursyphus</title>
      <link>https://dev.to/moondaeseung</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/moondaeseung"/>
    <language>en</language>
    <item>
      <title>I made awesome react apps with transition aniamtion</title>
      <dc:creator>Meursyphus</dc:creator>
      <pubDate>Mon, 04 Aug 2025 03:08:08 +0000</pubDate>
      <link>https://dev.to/moondaeseung/i-made-awesome-react-apps-with-transition-aniamtion-286a</link>
      <guid>https://dev.to/moondaeseung/i-made-awesome-react-apps-with-transition-aniamtion-286a</guid>
      <description>&lt;p&gt;&lt;a href="https://ssgoi.dev/demo" rel="noopener noreferrer"&gt;https://ssgoi.dev/demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;you can see it on mobile phone. It makes animation when navigating other pages&lt;/p&gt;

</description>
      <category>react</category>
    </item>
    <item>
      <title>🚨 Still Manually Handling Complex Web Graphics?</title>
      <dc:creator>Meursyphus</dc:creator>
      <pubDate>Sat, 21 Jun 2025 16:27:06 +0000</pubDate>
      <link>https://dev.to/moondaeseung/still-manually-handling-complex-web-graphics-1gno</link>
      <guid>https://dev.to/moondaeseung/still-manually-handling-complex-web-graphics-1gno</guid>
      <description>&lt;p&gt;Are you still wrestling with manual calculations, text wrapping, drag-and-drop events, and endless revisions when handling complex web graphics? Are hundreds of lines of code driving you crazy every time there's a small change?&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;Flitter&lt;/strong&gt;(&lt;a href="https://flitter.dev" rel="noopener noreferrer"&gt;https://flitter.dev&lt;/a&gt;), your game-changing solution!&lt;/p&gt;




&lt;h2&gt;
  
  
  😫 Everyday Developer Struggles, Familiar?
&lt;/h2&gt;

&lt;p&gt;Imagine the frequent scenario at a startup meeting:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"We need a workflow editor, something like Figma—nodes you can drag and connect."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Developers panic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Using D3.js, that's easily three weeks of work..."&lt;/li&gt;
&lt;li&gt;"SVG? Canvas? How will we handle automatic text wrapping?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Say goodbye to these headaches with Flitter!&lt;/p&gt;




&lt;h2&gt;
  
  
  🥳 Flitter Magic: Just a Few Lines of Code
&lt;/h2&gt;

&lt;p&gt;Long text wrapping and centering seamlessly:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fflitter.dev%2Fauto-wrap.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fflitter.dev%2Fauto-wrap.gif" alt="Auto Wrap Demo" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the only code you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Container&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="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Long text automatically wraps and centers&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;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TextAlign&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;center&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;ul&gt;
&lt;li&gt;Declarative code—clear and intuitive&lt;/li&gt;
&lt;li&gt;Automatic cursor handling and drag interactions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No more coordinate calculations!&lt;/p&gt;




&lt;h2&gt;
  
  
  🔥 Unique Advantages of Flitter
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🚀 Dual Rendering System (SVG + Canvas)
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SVG&lt;/strong&gt;: SEO-friendly, selectable text&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Canvas&lt;/strong&gt;: High performance, smooth interactions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  💡 Server-side Rendering + Canvas Hydration
&lt;/h3&gt;

&lt;p&gt;Rapid initial load with smooth interactions right from the start.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Widget&lt;/span&gt;
  &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;canvas&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;ssr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="nx"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{...}&lt;/span&gt;
&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ❌ Still Using Other Libraries?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Issues&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;D3.js&lt;/td&gt;
&lt;td&gt;Manual calculations (coordinates, dimensions…)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Konva.js&lt;/td&gt;
&lt;td&gt;Difficult complex layouts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fabric.js&lt;/td&gt;
&lt;td&gt;Limited UI capabilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paper.js&lt;/td&gt;
&lt;td&gt;Only suitable for vector graphics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Three.js&lt;/td&gt;
&lt;td&gt;Overkill for 2D UI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  🎯 Flitter Simplifies Everything!
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Title&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;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;headerStyle&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EdgeInsets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;decoration&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;BoxDecoration&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#F3F4F6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BorderRadius&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;circular&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;mainAxisAlignment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spaceBetween&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="cm"&gt;/* Easily implemented layouts */&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  👨‍💻 Flutter Developers, You're Already Experts!
&lt;/h2&gt;

&lt;p&gt;Flitter shares nearly identical syntax with Flutter—instant onboarding!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Flutter code&lt;/span&gt;
&lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;padding:&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello Flutter"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Flitter code&lt;/span&gt;
&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EdgeInsets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello Flitter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🎖️ Proven in Real-world Projects
&lt;/h2&gt;

&lt;h3&gt;
  
  
  📌 EasyRD – ERD Diagram Editor
&lt;/h3&gt;

&lt;p&gt;Seamlessly handle over 100 nodes.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/meursyphus/easy-rd" rel="noopener noreferrer"&gt;Visit on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📌 Headless Chart – Customizable Charts
&lt;/h3&gt;

&lt;p&gt;Easier than D3.js, more flexible than Chart.js.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/meursyphus/headless-chart" rel="noopener noreferrer"&gt;Visit on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://headless-chart.pages.dev/" rel="noopener noreferrer"&gt;Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚩 Who Should Use Flitter?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;SaaS teams regularly developing complex UIs&lt;/li&gt;
&lt;li&gt;Teams frequently building node editors and workflows&lt;/li&gt;
&lt;li&gt;Data visualization teams needing custom charts&lt;/li&gt;
&lt;li&gt;Teams tired of complexity in existing graphic libraries&lt;/li&gt;
&lt;li&gt;Teams with Flutter developers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Get Started Right Now!
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @meursyphus/flitter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just one command to start!&lt;/p&gt;

&lt;p&gt;Check out the next page for detailed usage and examples.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>"Performance Has Improved!" Can You Really Prove It?</title>
      <dc:creator>Meursyphus</dc:creator>
      <pubDate>Tue, 10 Dec 2024 12:25:31 +0000</pubDate>
      <link>https://dev.to/moondaeseung/performance-has-improved-can-you-really-prove-it-10mn</link>
      <guid>https://dev.to/moondaeseung/performance-has-improved-can-you-really-prove-it-10mn</guid>
      <description>&lt;p&gt;Every frontend developer has experienced this situation:&lt;br&gt;
"I optimized this part, and it definitely feels faster!"&lt;br&gt;
"Hmm... I don't really notice much difference in my environment."&lt;/p&gt;

&lt;p&gt;When you open Chrome DevTools and try to measure performance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The hassle of opening the tools and clicking Record every time&lt;/li&gt;
&lt;li&gt;Measurement environments vary with browser cache, CPU state, network conditions&lt;/li&gt;
&lt;li&gt;Sharing performance improvement results with colleagues through screenshots&lt;/li&gt;
&lt;li&gt;Difficulty tracking whether performance degrades over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result, we end up saying performance has improved based on "feeling."&lt;br&gt;
However, true performance optimization should be provable with objective metrics.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore automated performance measurement methods to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Collect objective performance data in a consistent environment&lt;/li&gt;
&lt;li&gt;Track performance changes over time&lt;/li&gt;
&lt;li&gt;Establish performance metrics that the entire team can share&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Pro Tip&lt;/strong&gt;: While Chrome DevTools' Performance panel is a powerful tool, it has limitations with manual measurement. Through automation, we can overcome these limitations while still utilizing DevTools' analysis capabilities.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Scientific Experimentation: Reliable Performance Measurement Methods
&lt;/h1&gt;

&lt;p&gt;Did you know you can control Chrome DevTools' Performance panel programmatically?&lt;br&gt;
Using Playwright, you can automate performance measurements through browser automation.&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting Started with Automated Performance Measurement Using Playwright
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Capture performance traces&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;browser&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="c1"&gt;// Start Chrome trace recording&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startTracing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`./traces/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;formatDate&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;Date&lt;/span&gt;&lt;span class="p"&gt;())}&lt;/span&gt;&lt;span class="s2"&gt;.json`&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Load page and perform actions&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:4173/performance-test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button#start&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Record performance measurement points&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Perf:Started&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Perf:Ended&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;overall&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;Perf:Started&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;Perf:Ended&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// End measurement and save results&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopTracing&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;However, measuring just once isn't enough.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;A Habit from Physics Lab Days&lt;/strong&gt;&lt;br&gt;
"Remember, everyone! One measurement is no measurement!"&lt;/p&gt;

&lt;p&gt;This is a habit ingrained from writing physics lab reports. 😄&lt;br&gt;
I still vividly remember that measurement error is inversely proportional&lt;br&gt;
to the square root of the number of repeated measurements.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Scientific Approach to Performance Measurement
&lt;/h2&gt;

&lt;p&gt;Applying principles learned from physics experiments to web performance measurement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Importance of Repeated Measurements&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standard error decreases by 1/√n as the number of measurements (n) increases&lt;/li&gt;
&lt;li&gt;With 50 repetitions, error rate reduces to about 1/7 compared to a single measurement&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Strict Control of Variables&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Just like controlling temperature and humidity in a lab&lt;/li&gt;
&lt;li&gt;Essential to control browser cache, memory state, CPU load&lt;/li&gt;
&lt;li&gt;Must consider V8 engine's JIT compiler optimizations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Complete Code for Reliable Measurements
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Scientifically measure performance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&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;REPEAT_COUNT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// Sufficient repetitions for reliability&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;REPEAT_COUNT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Control variables: fresh browser environment each time&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&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;--no-sandbox&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;--disable-dev-shm-usage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startTracing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`./traces/trace_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.json`&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="c1"&gt;// Performance measurement&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;measurePerformance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopTracing&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Reset browser state&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Statistical analysis of results&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculateStats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
        Average: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ms
        Standard Deviation: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdDev&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ms
        95% Confidence Interval: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;confidenceInterval&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ms
    `&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;
  
  
  The Pitfall of JIT Compiler: Code Gets Faster with Execution
&lt;/h2&gt;

&lt;p&gt;Here's an interesting case I encountered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Incorrect measurement method: repeated measurements without browser restart&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Without browser restart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;runPerformanceTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Execution time changes:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;results&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 results showed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First 10 runs average: 450ms&lt;/li&gt;
&lt;li&gt;Middle 10 runs average: 380ms&lt;/li&gt;
&lt;li&gt;Last 10 runs average: 320ms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why does this happen?&lt;/strong&gt;&lt;br&gt;
It's because the V8 engine's JIT compiler learns execution patterns and optimizes the code. In other words, the same code gets faster with repeated execution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ Correct measurement method: restart browser each time&lt;/span&gt;
&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;With browser restart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&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;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&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;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;runPerformanceTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Execution time changes:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;results&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 results showed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First 10 runs average: 445ms&lt;/li&gt;
&lt;li&gt;Middle 10 runs average: 442ms&lt;/li&gt;
&lt;li&gt;Last 10 runs average: 448ms&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Pro Tip&lt;/strong&gt;:&lt;br&gt;
JIT compiler optimizations do occur in production environments.&lt;br&gt;
However, the goal of performance measurement is to obtain a baseline value,&lt;br&gt;
so we should measure in an environment without these optimizations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A physics major turned frontend developer applying experimental methodology...&lt;br&gt;
Who would have thought? 😄 Now, let's dive deeper into analyzing Chrome Trace Reports.&lt;/p&gt;
&lt;h1&gt;
  
  
  Analyzing Chrome Trace Reports
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;The Challenge: Flitter's Performance Optimization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I was developing the Flitter visualization framework and felt the need for performance optimization. Flitter uses SVG and Canvas to visualize dynamic data, providing various animations and interactions. While these features enrich data representation, they also cause performance overhead.&lt;/p&gt;

&lt;p&gt;For example, when data changes, &lt;code&gt;requestFrameAnimation&lt;/code&gt; is repeatedly called to redraw SVG elements. Although we optimized the callback function to trigger only once, we didn't realize that calling &lt;code&gt;requestFrameAnimation&lt;/code&gt; itself has a cost. This wasn't noticeable in normal cases but caused performance degradation when rendering complex UI repeatedly (e.g., mouse dragging).&lt;/p&gt;

&lt;p&gt;To solve this issue, we initially tried to track the execution time of specific functions and optimize animation routines. However, we couldn't confidently prove the effectiveness of performance improvements based on subjective feelings.&lt;/p&gt;

&lt;p&gt;"We need a systematic way to record JavaScript execution time and scientifically verify optimization results!"&lt;/p&gt;

&lt;p&gt;This conclusion led us to adopt automated performance measurement using Chrome Trace and Playwright.&lt;/p&gt;
&lt;h2&gt;
  
  
  Collecting Performance Data with Chrome Trace Reports
&lt;/h2&gt;

&lt;p&gt;Chrome Trace Reports record all major events that occur while the browser executes JavaScript code, allowing us to see how much CPU and memory each event consumes. This is particularly useful for analyzing JavaScript function calls and execution times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Use Chrome Trace Reports?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The biggest advantage of Chrome Trace Reports is being able to see the entire function call stack and execution time of each function at a glance. This allows quick identification of specific functions or repetitive code that burden performance. Especially in visualization frameworks like Flitter that interact with multiple elements, finding specific routines that cause performance load is crucial, and Chrome Trace is very helpful in solving these issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automating Chrome Trace with Playwright&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Playwright is a useful tool for automating performance measurements in browser environments and can collect performance data in conjunction with Chrome Trace Reports. With Playwright, you can easily save Trace Reports that track events occurring in the browser. The example code below shows how to record performance data from a specific point and save it as a JSON file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Capture performance traces and save JSON file when diagram is rendered&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;browser&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="c1"&gt;// Start Chrome trace recording&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startTracing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`./performance-history/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;formatDate&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;Date&lt;/span&gt;&lt;span class="p"&gt;())}&lt;/span&gt;&lt;span class="s2"&gt;.json`&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Navigate to the page to measure performance&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:4173/performance/diagram&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Mark the start of performance measurement&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Perf:Started&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Perf:Ended&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;overall&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;Perf:Started&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;Perf:Ended&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// End measurement and save results&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopTracing&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;
  
  
  Analyzing CpuProfile Events
&lt;/h2&gt;

&lt;p&gt;Although we can generate a JSON-formatted Trace Report using Playwright and Chrome Trace, analyzing this file directly is challenging. The report contains all events that occurred during execution, but it's difficult to intuitively understand each function's execution time or call count. We need to preprocess the data to extract meaningful information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CpuProfile Events and Preprocessing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CpuProfile&lt;/code&gt; events are recorded in the &lt;code&gt;disabled-by-default-v8.cpu_profiler&lt;/code&gt; category and track JavaScript function CPU usage. Each event is recorded with a time interval and includes &lt;code&gt;samples&lt;/code&gt; and &lt;code&gt;timeDeltas&lt;/code&gt; fields, which can be used to infer each function's execution time.&lt;/p&gt;

&lt;p&gt;To calculate each function's total execution time, we need to preprocess the data by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Iterating through &lt;code&gt;samples&lt;/code&gt; and &lt;code&gt;timeDeltas&lt;/code&gt; to calculate each node's total execution time&lt;/li&gt;
&lt;li&gt;Constructing a node hierarchy based on parent-child relationships and aggregating child node execution times to their parents&lt;/li&gt;
&lt;li&gt;Extracting function-level execution times and visualizing or identifying optimization points&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This preprocessing step provides a clear understanding of each function's resource usage and helps identify performance bottlenecks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing the ChromeTraceAnalyzer Class
&lt;/h2&gt;

&lt;p&gt;To automate the analysis of Trace Reports, we'll implement the &lt;code&gt;ChromeTraceAnalyzer&lt;/code&gt; class. This class will take Trace data as input, calculate each function's execution time, and provide performance metrics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ChromeTraceAnalyzer Class&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChromeTraceAnalyzer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Return the execution time of a specific function (in ms)&lt;/span&gt;
    &lt;span class="nf"&gt;getDurationMs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nodes is not initialized&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;functionName&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;name&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;result&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Convert to milliseconds&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Set up Trace data and calculate function execution times&lt;/span&gt;
    &lt;span class="nf"&gt;setConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;traceEvents&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Filter 'ProfileChunk' events&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;profileChunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;traceEvents&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;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ProfileChunk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Extract CpuProfile nodes and sample data&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;profileChunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cpuProfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;flat&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;sampleTimes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

        &lt;span class="c1"&gt;// Aggregate sample execution times&lt;/span&gt;
        &lt;span class="nx"&gt;profileChunks&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;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;cpuProfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;samples&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;timeDeltas&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="nx"&gt;samples&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;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;timeDeltas&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
                &lt;span class="nx"&gt;sampleTimes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sampleTimes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;delta&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="c1"&gt;// Construct node hierarchy and aggregate child node execution times&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;node&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callFrame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
            &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sampleTimes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="p"&gt;}));&lt;/span&gt;

        &lt;span class="c1"&gt;// Establish parent-child relationships and aggregate execution times&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nodesMap&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;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&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;node&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;nodesMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&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;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parentNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nodesMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&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;parentNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;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;h2&gt;
  
  
  Repeated Measurements for Reliability
&lt;/h2&gt;

&lt;p&gt;Although we can analyze Trace data using &lt;code&gt;ChromeTraceAnalyzer&lt;/code&gt;, a single measurement is not enough to evaluate performance. JavaScript execution performance can vary due to environmental changes, so we need to repeat measurements multiple times to obtain reliable data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repeated Measurement Code Example&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Capture analyzed trace when diagram is rendered with multiple runs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;COUNT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&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;duration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:4173/performance/diagram&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Start tracing&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startTracing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Perf:Started&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;svg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Perf:Ended&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;overall&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;Perf:Started&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;Perf:Ended&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="c1"&gt;// Extract Trace data and analyze&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trace&lt;/span&gt; &lt;span class="o"&gt;=&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stopTracing&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&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;analyzer&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;ChromeTraceAnalyzer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runApp&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDurationMs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;runApp&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;COUNT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mount&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDurationMs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mount&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;COUNT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;draw&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDurationMs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;draw&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;COUNT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDurationMs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;layout&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;COUNT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paint&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDurationMs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;paint&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;COUNT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**** Average Execution Time ****&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`runApp: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ms`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`mount: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ms`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`draw: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ms`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`layout: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ms`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`paint: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ms`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Visualizing Performance Data
&lt;/h2&gt;

&lt;p&gt;By repeating measurements and analyzing Trace data, we can obtain reliable performance metrics. To better understand performance changes over time, we can visualize the data using Flitter.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Flitter-Based Stacked Bar Chart&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We created a stacked bar chart using Flitter to display the average execution time of each function over multiple runs. This chart helps us identify performance bottlenecks and track changes in execution time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chart Configuration&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;X-axis: Measurement dates (track performance changes over time)&lt;/li&gt;
&lt;li&gt;Y-axis: Average execution time (ms)&lt;/li&gt;
&lt;li&gt;Stacked bars: Each function's execution time (color-coded)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Performance Changes Over Time&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By analyzing the chart, we can see how performance changes over time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Date-based performance changes&lt;/strong&gt;: We can track how performance changes on each measurement date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Function-level execution time&lt;/strong&gt;: We can identify which functions consume the most resources and optimize them accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The current Flitter library can be used as an efficient visualization solution in situations where performance optimization is important. You can check the related code on GitHub, and if you found this helpful, please give it a Star and thumbs up on GitHub! If you show interest in this project, we plan to continue developing and sharing performance improvements and various features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/meursyphus/flitter/blob/latest/packages/test/tests/tracking-performance.test.ts" rel="noopener noreferrer"&gt;https://github.com/meursyphus/flitter/blob/latest/packages/test/tests/tracking-performance.test.ts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docs&lt;/strong&gt;: &lt;a href="https://flitter.dev" rel="noopener noreferrer"&gt;Flitter Docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Portfolio of a 4-Year Frontend Developer</title>
      <dc:creator>Meursyphus</dc:creator>
      <pubDate>Tue, 10 Dec 2024 12:19:07 +0000</pubDate>
      <link>https://dev.to/moondaeseung/portfolio-of-a-4-year-frontend-developer-5g01</link>
      <guid>https://dev.to/moondaeseung/portfolio-of-a-4-year-frontend-developer-5g01</guid>
      <description>&lt;p&gt;Hello! In this post, I'd like to introduce the frontend projects I've been working on. Instead of just showing my work, I'll focus on the thought process behind the interactions and UX choices, and how I solved the challenges I faced.&lt;/p&gt;

&lt;p&gt;Ultimately, I'll be sharing the choices I made to improve the user experience and the insights I've gained from real-world practice. If you've been curious about my work, I think you'll find this interesting. So, shall we get started?&lt;/p&gt;

&lt;h2&gt;
  
  
  Project 1: Improving Search UX – Smooth Page Transitions and Slide Interactions
&lt;/h2&gt;

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

&lt;p&gt;If page transitions in a search interface aren't smooth, users can easily get confused. Especially when browsing through multiple pages of search results, abrupt page changes can make it difficult to understand where they are or what they’ll see next. To address this, I implemented slide interactions for the search results pages.&lt;/p&gt;

&lt;p&gt;When moving to the next page, the content slides to the left, and when returning to the previous page, it slides to the right. Maintaining a consistent transition speed was key. For instance, moving directly from page 1 to page 3 required a longer slide duration since the distance covered was greater. This helped create smooth, natural transitions between pages.&lt;/p&gt;

&lt;p&gt;Another crucial aspect of UX is maintaining context. Rather than simply refreshing the page, showing the transition visually allows users to better understand where they are and what they'll see next. I also ensured a smooth flow between pages by connecting the last row of the previous page with the first row of the next page.&lt;/p&gt;

&lt;p&gt;Technically, managing the DOM was a significant challenge. Preloading all the content during page transitions would overload both the browser and server, so I handled this by removing unnecessary DOM elements as the animation ended. Additionally, I added a fade-out effect for the disappearing page's content to make the transition feel even more seamless. This effect was a designer's request, and though it was challenging to implement, the visual satisfaction was worth it.&lt;/p&gt;

&lt;p&gt;As a result, page transitions became smooth and natural, allowing users to explore search results without losing context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project 2: Improving Search UX – Analyzing and Applying Naver's Search Interface
&lt;/h2&gt;

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

&lt;p&gt;Next, I want to talk about search UX. The search bar is one of the key interfaces that provide a search experience, and its usability greatly depends on how quickly and intuitively it delivers search results. So, I analyzed Naver's search UX and applied it to my own search component.&lt;/p&gt;

&lt;p&gt;Naver's search bar shows search results in real time as users type and highlights matching terms with color. This structure helps users quickly find what they're looking for by providing rapid visual feedback while typing. This makes the search results clearer and more intuitive.&lt;/p&gt;

&lt;p&gt;I also paid attention to the triggers for showing and hiding the search results panel. Naver's search bar opens the results panel when the user starts typing or presses the arrow key, and closes it when they clear the input or click outside. These subtle interactions make the user experience smoother. UX that responds to multiple triggers like this helps users stay immersed in the search task.&lt;/p&gt;

&lt;h3&gt;
  
  
  Applied Interactions and UX Improvements
&lt;/h3&gt;

&lt;p&gt;Based on this analysis, I incorporated similar UX elements into my search component. I designed it to display search results in real time while typing, highlighting the parts that match the search term to provide feedback to the user. Additionally, users could navigate the results using keyboard arrow keys, which improves usability by enabling navigation without the mouse.&lt;/p&gt;

&lt;p&gt;I also handled the triggers for automatically opening and closing the search results panel more meticulously. When the user starts typing, the results panel opens automatically, and when the input is cleared, the panel closes. While the search bar is open, users can also use various keyboard actions (e.g., arrow keys, enter key) to select results, allowing them to check the results more quickly and intuitively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project 3: Scroll Animation – Code Typing Effect on Page Scroll
&lt;/h2&gt;

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

&lt;p&gt;Next, I’d like to discuss scroll animation. Scroll animations are a key element in enhancing the user experience by adding visual effects to a webpage, making the experience more engaging. In particular, I wanted to provide a more lively experience for users of the Flitter.dev project through scroll animations.&lt;/p&gt;

&lt;p&gt;Adding scroll animations helps draw users' attention and increases the time they spend on the page. From the user's perspective, it can feel like the page comes alive as they scroll. The scroll animation I applied to Flitter.dev makes it look like code is being typed in real time, giving the impression that the code is actually being written on the screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation Method
&lt;/h3&gt;

&lt;p&gt;To implement this animation, I used Lottie animations. The process was as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write the complete code and then undo it line by line: After completing the entire code, I used the undo function to erase lines one by one, making it look like typing.&lt;/li&gt;
&lt;li&gt;Screen recording: I saved this process as a screen recording and converted it to MP4 format.&lt;/li&gt;
&lt;li&gt;Lottie conversion: I then converted the MP4 video to a Lottie file, allowing the typing animation to progress as the user scrolls.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thanks to this approach, I was able to implement a smooth, natural animation without affecting the page loading speed.&lt;/p&gt;

&lt;h3&gt;
  
  
  UX Impact
&lt;/h3&gt;

&lt;p&gt;The biggest advantage of this scroll animation is that it provides intuitive feedback to users. The real-time typing animation keeps users engaged with the content and draws their attention as they scroll through the page.&lt;/p&gt;

&lt;p&gt;Visit &lt;a href="https://flitter.dev" rel="noopener noreferrer"&gt;https://flitter.dev&lt;/a&gt; to check out the animation for yourself! 🌟&lt;/p&gt;

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

&lt;p&gt;I've introduced a few of the projects I've worked on so far. Though they're not perfect, I believe I’m growing step by step through these experiences. I'm constantly realizing how important user experience (UX) is, and I'll keep striving to create better interactions and UI in the future.&lt;/p&gt;

&lt;p&gt;Thank you for reading, and I hope these projects might serve as a small reference for your own work. 😄&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Can't Ask GPT Properly? Congratulations! You're Growing as a Developer</title>
      <dc:creator>Meursyphus</dc:creator>
      <pubDate>Tue, 10 Dec 2024 12:16:13 +0000</pubDate>
      <link>https://dev.to/moondaeseung/cant-ask-gpt-properly-congratulations-youre-growing-as-a-developer-4h7e</link>
      <guid>https://dev.to/moondaeseung/cant-ask-gpt-properly-congratulations-youre-growing-as-a-developer-4h7e</guid>
      <description>&lt;p&gt;"I asked GPT but the answer was weird..."&lt;/p&gt;

&lt;p&gt;This is a common message in developer chat rooms. Usually followed by a lengthy error log dump, without context or any explanation of what they tried to do.&lt;/p&gt;

&lt;p&gt;"Sorry, but how do I fix this?"&lt;br&gt;&lt;br&gt;
"This isn't working, and GPT doesn't understand what I'm saying 😢"&lt;/p&gt;

&lt;p&gt;Even senior developers from prestigious companies like Toss, Musinsa, and Naver can't understand these questions. But this isn't their fault. The questions are simply too vague.&lt;/p&gt;

&lt;h2&gt;
  
  
  GPT Doesn't Understand You? Congratulations!
&lt;/h2&gt;

&lt;p&gt;Sound strange? But I mean it. If GPT can't understand your questions, it's evidence that you're experiencing growing pains.&lt;/p&gt;

&lt;p&gt;Think about it. How can AI understand questions that even senior developers can't comprehend? While GPT is certainly a powerful tool, it's not a magic wand. Without clear context and accurate information, even the world's smartest AI can't provide a proper answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Difficulty with GPT Usage is a Sign of Growth
&lt;/h2&gt;

&lt;p&gt;Junior developer A had this concern:&lt;br&gt;
"Infinite scroll isn't working in React. I asked GPT but the answer was weird."&lt;/p&gt;

&lt;p&gt;Six months later, A asks like this:&lt;br&gt;
"I'm implementing infinite scroll with React Query, using Intersection Observer. I want to store the scroll position in sessionStorage to restore it on back navigation, but I'm seeing unnecessary re-renders. Should I apply memoization?"&lt;/p&gt;

&lt;p&gt;See the difference?&lt;/p&gt;

&lt;p&gt;Paradoxically, finding it difficult to use GPT is a signal that you're growing. As you understand technology more deeply, your questions become more specific and clear. And that's when GPT truly becomes your pair programmer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites for Clear Questions
&lt;/h2&gt;

&lt;p&gt;Here's what you need to properly utilize GPT:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Accurate understanding of the problem situation&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What you're trying to achieve&lt;/li&gt;
&lt;li&gt;Current state&lt;/li&gt;
&lt;li&gt;What errors are occurring&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Basic knowledge of your technology stack&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Role of each library or framework&lt;/li&gt;
&lt;li&gt;Core concepts and how they work&lt;/li&gt;
&lt;li&gt;Common problem-solving patterns&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Solutions you've attempted&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What approaches you've tried&lt;/li&gt;
&lt;li&gt;Results from each attempt&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With these preparations, GPT can provide much more useful answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Growing Developers Use GPT
&lt;/h2&gt;

&lt;p&gt;Stop asking GPT questions. Instead, give it commands.&lt;/p&gt;

&lt;p&gt;Not "What should I do about this error?"&lt;br&gt;&lt;br&gt;
But "Here's what I tried. Looking at the logs, the problem seems to be here. Suggest how I should modify this part."&lt;/p&gt;

&lt;p&gt;Not "How do I build this feature?"&lt;br&gt;&lt;br&gt;
But "Here are the requirements, and this is my tech stack. Analyze the best implementation approach considering performance and maintainability."&lt;/p&gt;

&lt;p&gt;This approach leads to remarkable changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deeper understanding of problems&lt;/li&gt;
&lt;li&gt;Better control over solutions&lt;/li&gt;
&lt;li&gt;Improved technical specification writing skills&lt;/li&gt;
&lt;li&gt;Enhanced communication with colleagues&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  This is Just the Beginning
&lt;/h2&gt;

&lt;p&gt;Still finding it difficult to ask GPT questions? Don't worry. That's evidence you're growing.&lt;/p&gt;

&lt;p&gt;As questions become more challenging, you learn more, and as you learn more, questions become clearer. And through this process, you'll find yourself growing from a junior to a mid-level developer.&lt;/p&gt;

&lt;p&gt;Start today. Stop asking GPT questions, and start giving it commands. Your real growth begins now.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Think 'use client' Means CSR? Master This Next.js Interview Question</title>
      <dc:creator>Meursyphus</dc:creator>
      <pubDate>Tue, 10 Dec 2024 12:15:45 +0000</pubDate>
      <link>https://dev.to/moondaeseung/think-use-client-means-csr-master-this-nextjs-interview-question-297n</link>
      <guid>https://dev.to/moondaeseung/think-use-client-means-csr-master-this-nextjs-interview-question-297n</guid>
      <description>&lt;p&gt;If you're a junior developer who has worked with Next.js, you've probably encountered this question in technical interviews:&lt;br&gt;&lt;br&gt;
"Is &lt;code&gt;use client&lt;/code&gt; exclusively for Client-Side Rendering (CSR)?"&lt;br&gt;&lt;br&gt;
If you can confidently answer "No, components with &lt;code&gt;use client&lt;/code&gt; can also utilize SSR (Server-Side Rendering)!", you'll leave a strong impression on your interviewer.&lt;/p&gt;

&lt;p&gt;In this article, we'll focus on SSR and Server Components to clearly understand what &lt;code&gt;use client&lt;/code&gt; really means and what the Hydration process entails. We'll also explore how all React components were client components before Server Components came along, and examine the performance benefits of Server Components to help you prepare thoroughly for Next.js interviews.&lt;/p&gt;


&lt;h2&gt;
  
  
  Understanding SSR, CSR, and Hydration
&lt;/h2&gt;

&lt;p&gt;Traditionally, React applications often operated with CSR (Client-Side Rendering). The browser receives basic HTML and JS bundles from the server, but the initial screen only contains an empty &lt;code&gt;&amp;lt;div id="root"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;, leaving users staring at a blank screen until JS loads and rendering completes. This delays initial loading times and negatively impacts SEO.&lt;/p&gt;

&lt;p&gt;One solution to this problem is SSR (Server-Side Rendering). With SSR, React components are rendered to HTML on the server before being sent to the client, allowing users to see actual content instead of a blank screen during initial load. However, this HTML is still in a "dry (Markup-only)" state without interactivity, and only becomes fully interactive after the browser loads JavaScript and React completes its hydration process by registering event handlers.&lt;/p&gt;
&lt;h3&gt;
  
  
  What is Hydration?
&lt;/h3&gt;

&lt;p&gt;Hydration is the process where static HTML rendered on the server is matched with React's virtual DOM on the client side, and event handlers are attached to create an interactive UI. In other words, after receiving "structure-only" HTML through SSR, once JavaScript loads and hydrate() executes, event and state management logic becomes active on top of this HTML structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Server: SSR] --(HTML)--&amp;gt; [Browser: Initial Display] 
                                      | 
                                      v 
                          (JS Load, hydrate()) 
                                      |
                                      v
                    [Browser: Event Handlers Attached, VDOM Sync]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now users can see content immediately upon page load, with interactivity becoming available as soon as JS is ready.&lt;/p&gt;




&lt;h2&gt;
  
  
  Distinguishing Server Components from Client Components
&lt;/h2&gt;

&lt;p&gt;Server Components, introduced after React 18, presented a new paradigm of "components that only run on the server." In Next.js, all components are Server Components by default, and only components that need to run on the client explicitly declare &lt;code&gt;use client&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Server Components are delivered to the client as HTML snippets and are excluded from hydration. This means the HTML returned by Server Components is simply inserted into the browser "as is," without event handlers or state being injected on the client side. As a result, Server Components consume minimal JavaScript bundle size, significantly helping with performance optimization.&lt;/p&gt;

&lt;p&gt;On the other hand, components declaring &lt;code&gt;use client&lt;/code&gt; behave like traditional React components. They generate initial HTML through SSR, then go through the hydration process to activate interactivity. Therefore, &lt;code&gt;use client&lt;/code&gt; components can utilize SSR and support the hydration process that combines SSR + CSR.&lt;/p&gt;




&lt;h2&gt;
  
  
  Before Server Components: All Components Were Client Components
&lt;/h2&gt;

&lt;p&gt;Before Server Components existed, all React components had to go through hydration on the client side. Even with SSR, all components ultimately needed to have their logic re-injected with JavaScript on the client. This led to large bundle sizes and longer initial loading times in large applications.&lt;/p&gt;

&lt;p&gt;After the introduction of Server Components, we can now handle "static parts that only need to be displayed" as Server Components without any declaration, while parts requiring interactivity can be marked with &lt;code&gt;use client&lt;/code&gt;. This clear separation enables more efficient bundle optimization and better performance.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Server Components Work: Slot Insertion and HTML Combination
&lt;/h2&gt;

&lt;p&gt;Server Components render HTML snippets on the server and provide them to the client, while React's render tree leaves a "hole" for these snippets. The final HTML is created by inserting these snippets into the corresponding holes. Here's a simple ASCII diagram illustrating this process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Server: RSC(Render)] --&amp;gt; [HTML snippet] 
                                | 
                                v 
                [React Render Tree]: "hole" creation
                                | 
                                v 
                    Combined HTML --&amp;gt; Client transmission 
                    (Server Components excluded from hydration)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this process, Server Components do not include JavaScript bundles. As a result, they cannot register event handlers or state, but this is actually beneficial for parts that only require static HTML. The reduced JavaScript bundle size leads to faster initial screen display.&lt;/p&gt;




&lt;h2&gt;
  
  
  Acing Your Interview: Confidently Answering "Is 'use client' Only for CSR?"
&lt;/h2&gt;

&lt;p&gt;For example, you might encounter this question in an interview:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; "Do components with &lt;code&gt;use client&lt;/code&gt; only support CSR?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model Answer:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
"No, in Next.js, all components are Server Components by default, and only components that need to run on the client explicitly declare &lt;code&gt;use client&lt;/code&gt;. These client components generate initial HTML through SSR and then go through the hydration process to activate interactivity on the client side. Therefore, &lt;code&gt;use client&lt;/code&gt; components can also utilize SSR. On the other hand, Server Components are excluded from hydration and only provide static HTML, reducing JavaScript bundle size and improving performance."&lt;/p&gt;

&lt;p&gt;If you can clearly explain this, the interviewer will recognize that you have a solid grasp of Server Components, SSR, and hydration concepts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Server-Side Rendering and Server Components Are Not Mutually Exclusive
&lt;/h2&gt;

&lt;p&gt;Finally, it's essential to note that Server Components do not replace SSR. SSR focuses on displaying content to users immediately during initial load, while Server Components provide an additional layer for optimizing bundle size and data fetching. These two technologies complement each other, and using them together enables you to create a better user experience and improve performance.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bonus: What Is 'use server'?
&lt;/h2&gt;

&lt;p&gt;'use server' is a different concept from Server Components, used to define Server Actions. Server Actions allow clients to directly call server functions, making them useful for handling server-side tasks like form submissions or data updates.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;All Next.js components are Server Components by default&lt;/li&gt;
&lt;li&gt;Client components require explicit &lt;code&gt;use client&lt;/code&gt; declaration&lt;/li&gt;
&lt;li&gt;Client components can utilize SSR: server-side HTML rendering followed by hydration&lt;/li&gt;
&lt;li&gt;Server Components provide static HTML without hydration, reducing JavaScript bundle size and improving performance&lt;/li&gt;
&lt;li&gt;'use server' is a separate feature for defining Server Actions&lt;/li&gt;
&lt;li&gt;Server Components complement SSR, not replace it: together, they provide optimal user experience and performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Armed with this knowledge, confidently answer interview questions. Emphasize that "use client components also support SSR" and explain how Server Components lead to bundle optimization and performance improvements. Highlighting that all components are Server Components by default and only client components need the 'use client' directive will demonstrate your deep understanding of Next.js architecture.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>If you're a front-end developer, you should at least know how to handle page transitions, right? Can't do it? 😱</title>
      <dc:creator>Meursyphus</dc:creator>
      <pubDate>Wed, 09 Oct 2024 07:53:51 +0000</pubDate>
      <link>https://dev.to/moondaeseung/if-youre-a-front-end-developer-you-should-at-least-know-how-to-handle-page-transitions-right-cant-do-it-51h4</link>
      <guid>https://dev.to/moondaeseung/if-youre-a-front-end-developer-you-should-at-least-know-how-to-handle-page-transitions-right-cant-do-it-51h4</guid>
      <description>&lt;p&gt;When we use smartphone apps, smooth screen transitions are an expected part of the experience. But on the web, it’s a different story. If developers don’t pay attention to page transitions, websites can feel jarring, with sudden screen changes every time you click, leaving users confused or, worse, making them leave the site.&lt;/p&gt;

&lt;p&gt;An experience where the screen suddenly switches, like “teleportation,” places a significant cognitive load on users. Ultimately, good UX should minimize this burden and create a natural flow. So, why are so many websites still overlooking this crucial aspect?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now, mastering this will give you a competitive edge!&lt;/strong&gt; By learning page transition techniques, you’ll not only enhance your web development skills but also gain an edge in app development. Thanks to technologies like &lt;strong&gt;WebView&lt;/strong&gt;, web front-end developers can easily start developing apps. If you can handle page transitions on the web, you can pretty much call yourself an app developer, right? 😎&lt;/p&gt;

&lt;h2&gt;
  
  
  Is your website still outdated?
&lt;/h2&gt;

&lt;p&gt;As a web developer, I’ve always been dissatisfied with how page transitions are handled on websites. Especially when transitioning between pages, the abrupt change of screen often makes users lose track of where they are or what they just clicked. I’ve always thought that such sudden shifts severely degrade the user experience. While smooth transitions are standard in apps, the web often still feels like “teleportation” when changing pages.&lt;/p&gt;

&lt;p&gt;To solve this, I initially tried simple CSS tricks to add smoother transitions. However, I quickly realized their limitations. While the transitions themselves became smoother, the issue of completely new screens appearing with every page load remained. I thought that to reduce users’ cognitive fatigue on the web, we needed transitions that not only flowed smoothly but also preserved the overall context.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, I present to you, SSGOI!!
&lt;/h2&gt;

&lt;p&gt;As I became more frustrated with page transitions, I naturally began thinking about solutions. Abrupt transitions are too common on the web. When the screen changes suddenly, users often find it hard to orient themselves, leading to a loss of focus. This experience made me realize the need for smoother, more intuitive transitions on the web as well.&lt;/p&gt;

&lt;p&gt;That’s when I decided to create &lt;strong&gt;SSGOI&lt;/strong&gt;, a library designed to provide seamless, app-like page transitions for the web. &lt;strong&gt;SSGOI&lt;/strong&gt; offers various animation effects and ensures users can clearly understand where they’re navigating.&lt;/p&gt;

&lt;p&gt;The biggest advantages of this library are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Various transition effects&lt;/strong&gt;: With several built-in animation options, developers can easily implement smooth page transitions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customizable transitions&lt;/strong&gt;: Dynamic transitions based on runtime conditions allow for a tailored user experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser compatibility&lt;/strong&gt;: Designed to work consistently across different browsers, SSGOI leverages the latest browser APIs while still supporting smooth transitions in browsers with limitations.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  Want to know the secret to smooth transitions like Pinterest?
&lt;/h2&gt;

&lt;p&gt;Implementing Pinterest-like transitions with &lt;strong&gt;SSGOI&lt;/strong&gt; wasn’t just about visual delight; it was about offering a more intuitive user experience. In image-centric layouts like Pinterest, it’s crucial that when a user clicks on an image, the context is maintained while the screen transitions smoothly.&lt;/p&gt;

&lt;p&gt;My goal was to have the clicked image smoothly &lt;strong&gt;enlarge&lt;/strong&gt; to the center of the screen, while the rest of the elements naturally fade away. This ensures that users stay focused on their selected content, and the page transitions without the common “disconnect” often felt on the web. It was also vital to ensure that during the image’s resizing, &lt;strong&gt;context is maintained&lt;/strong&gt;, so users clearly understand where they’re navigating.&lt;/p&gt;

&lt;p&gt;However, implementing this transition was no easy task. I had to carefully calculate how the image’s size and position would change across various screen sizes during the transition. Especially when the URL actually changes between pages, there was a lot of mathematical work involved in maintaining a smooth transition.&lt;/p&gt;

&lt;p&gt;In the end, I was able to overcome the complex calculations and deliver a seamless experience, as if using an app right on the web.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  My vision for the future.
&lt;/h2&gt;

&lt;p&gt;There are clear limitations in today’s web UX, especially with &lt;strong&gt;browser API restrictions&lt;/strong&gt; and &lt;strong&gt;cross-browser compatibility&lt;/strong&gt;. While smooth, intuitive page transitions are expected in apps, on the web, we still experience sudden screen changes and loss of context. This is because web browsers don’t yet provide all the necessary APIs to handle transitions smoothly. This makes it difficult for developers to easily implement a variety of page transition effects, and cross-browser compatibility adds to the challenge.&lt;/p&gt;

&lt;p&gt;This is where libraries like &lt;strong&gt;SSGOI&lt;/strong&gt; come in. &lt;strong&gt;SSGOI&lt;/strong&gt; bridges the gap, helping to provide an app-like, smooth user experience even on the web. By maintaining &lt;strong&gt;context&lt;/strong&gt; and handling transitions smoothly, it reduces the &lt;strong&gt;cognitive load&lt;/strong&gt; on users during page navigation. This allows developers to offer a better user experience without writing complex code.&lt;/p&gt;

&lt;p&gt;The future of web UX will only improve. With new &lt;strong&gt;browser APIs&lt;/strong&gt; and standards emerging, implementing page transitions will become much easier. Furthermore, as technologies like &lt;strong&gt;AI&lt;/strong&gt; become more integrated into the development process, complex tasks will be handled by AI, allowing developers to focus more on the creative aspects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to implement smooth transitions on the web? Check out SSGOI!
&lt;/h2&gt;

&lt;p&gt;Creating smooth, app-like transitions on the web is now a crucial task. Since user experience has a significant impact on the success of a website, it’s important not to overlook even small details like page transitions.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;SSGOI&lt;/strong&gt; library was designed to address these issues. With this library, you can implement smooth and natural page transitions without writing complex code. Built with cross-browser compatibility in mind, it ensures a consistent user experience across various environments.&lt;/p&gt;

&lt;p&gt;If you’re interested, visit the &lt;a href="https://github.com/meursyphus/ssgoi" rel="noopener noreferrer"&gt;SSGOI GitHub repository&lt;/a&gt;! 😄 If you find it useful, don’t forget to leave a &lt;strong&gt;Star&lt;/strong&gt;! ⭐ Your feedback and participation will help improve web UX for everyone.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>12 Best ER Diagram Tools to Use in 2024</title>
      <dc:creator>Meursyphus</dc:creator>
      <pubDate>Wed, 17 Jul 2024 15:05:37 +0000</pubDate>
      <link>https://dev.to/moondaeseung/12-best-er-diagram-tools-to-use-in-2024-8pl</link>
      <guid>https://dev.to/moondaeseung/12-best-er-diagram-tools-to-use-in-2024-8pl</guid>
      <description>&lt;p&gt;ER (Entity-Relationship) diagrams are essential tools for database design. In this article, we'll introduce the best ER diagram tools available in 2024.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;a href="https://www.lucidchart.com/pages/" rel="noopener noreferrer"&gt;Lucidchart&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2F9a215862-d5cc-4f7f-aa6a-2e87f78c3ca0.png%3Fw%3D1200%26format%3Dwebp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2F9a215862-d5cc-4f7f-aa6a-2e87f78c3ca0.png%3Fw%3D1200%26format%3Dwebp" alt="Lucidchart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lucidchart allows you to create various types of diagrams, including ER diagrams. It can be integrated with MS Office and G Suite.&lt;/p&gt;

&lt;p&gt;Key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time collaboration&lt;/li&gt;
&lt;li&gt;Automated diagramming&lt;/li&gt;
&lt;li&gt;Enhanced security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: Starting from $7.95/month for a single user account&lt;/p&gt;

&lt;h2&gt;
  
  
  2. &lt;a href="https://www.datanamic.com/" rel="noopener noreferrer"&gt;DeZign for Databases&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2F2b3562ac-4527-4324-b3e7-e7c33b7b8055.png%3Fw%3D1200%26format%3Dwebp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2F2b3562ac-4527-4324-b3e7-e7c33b7b8055.png%3Fw%3D1200%26format%3Dwebp" alt="DeZign for Databases"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DeZign for Databases is a tool that helps visualize database structures. It can create new databases as well as reverse engineer existing ones.&lt;/p&gt;

&lt;p&gt;Key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag and drop interface&lt;/li&gt;
&lt;li&gt;Various display modes&lt;/li&gt;
&lt;li&gt;Industry-standard design notation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: €19/month for Standard Edition, €59/month for Professional Version&lt;/p&gt;

&lt;h2&gt;
  
  
  3. &lt;a href="https://www.gleek.io/" rel="noopener noreferrer"&gt;Gleek.io&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2Fa79aa89e-4fc0-4524-b464-c2306be1b242.png%3Fw%3D1200%26format%3Dwebp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2Fa79aa89e-4fc0-4524-b464-c2306be1b242.png%3Fw%3D1200%26format%3Dwebp" alt="Gleek.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gleek.io is a fast diagramming and flowchart application that works through keyboard commands and code.&lt;/p&gt;

&lt;p&gt;Key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keyboard-based user interface&lt;/li&gt;
&lt;li&gt;Fast diagramming&lt;/li&gt;
&lt;li&gt;Version control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: Basic app is free, Premium version is €9.95/month&lt;/p&gt;

&lt;h2&gt;
  
  
  4. &lt;a href="https://easyrd.dev" rel="noopener noreferrer"&gt;EasyRd&lt;/a&gt;
&lt;/h2&gt;

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

&lt;p&gt;EasyRd is a recently emerged innovative ER diagram tool. It operates based on code and utilizes DBML (Database Markup Language), a well-known open-source syntax.&lt;/p&gt;

&lt;p&gt;Key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy generation through GPT with DBML syntax support&lt;/li&gt;
&lt;li&gt;Code-based diagram creation&lt;/li&gt;
&lt;li&gt;Completely free to use&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The biggest advantage of EasyRd is that it can easily generate ER diagrams through AI tools like GPT using DBML syntax. It provides a code-based interface familiar to developers while enabling intuitive visualization. Additionally, it's completely free to use, removing any cost burden.&lt;/p&gt;

&lt;p&gt;This tool will be particularly attractive to developers interested in rapid prototyping or AI-based database design.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;a href="https://www.dbdesigner.net/" rel="noopener noreferrer"&gt;DbDesigner&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2Fd72c83c1-b505-42bf-951a-f393f5326652.png%3Fw%3D1200%26format%3Dwebp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2Fd72c83c1-b505-42bf-951a-f393f5326652.png%3Fw%3D1200%26format%3Dwebp" alt="DbDesigner"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DbDesigner is suitable for teams that need to create different user classes for projects.&lt;/p&gt;

&lt;p&gt;Key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Advanced export options&lt;/li&gt;
&lt;li&gt;Project and team management&lt;/li&gt;
&lt;li&gt;Export and import to SQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: $6/month for basic package, $15/month for unlimited package&lt;/p&gt;

&lt;h2&gt;
  
  
  6. &lt;a href="https://www.smartdraw.com/" rel="noopener noreferrer"&gt;SmartDraw&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2F66ecfeb4-f004-40e6-b84d-6a583d6d63be.png%3Fw%3D1200%26format%3Dwebp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2F66ecfeb4-f004-40e6-b84d-6a583d6d63be.png%3Fw%3D1200%26format%3Dwebp" alt="SmartDraw"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SmartDraw is a web-based tool for diagramming and schema creation.&lt;/p&gt;

&lt;p&gt;Key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Intelligent formatting&lt;/li&gt;
&lt;li&gt;Professional results&lt;/li&gt;
&lt;li&gt;Visio import and export&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: Starting from $9.95/month for a single user account&lt;/p&gt;

&lt;h2&gt;
  
  
  7. &lt;a href="https://www.visual-paradigm.com/" rel="noopener noreferrer"&gt;Visual Paradigm&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2F6e7ce826-9eff-4315-a9a3-e180852bad0e.png%3Fw%3D1200%26format%3Dwebp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2F6e7ce826-9eff-4315-a9a3-e180852bad0e.png%3Fw%3D1200%26format%3Dwebp" alt="Visual Paradigm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Visual Paradigm comes with several ERD templates and can create various types of diagrams.&lt;/p&gt;

&lt;p&gt;Key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UML diagrams&lt;/li&gt;
&lt;li&gt;ER diagrams&lt;/li&gt;
&lt;li&gt;BPMN diagrams&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: Starting from $6/month, perpetual licenses start at $99 for a single user&lt;/p&gt;

&lt;h2&gt;
  
  
  8. &lt;a href="https://dbdiagram.io/home" rel="noopener noreferrer"&gt;dbdiagram.io&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2F86f8831c-59ee-42b2-8ef4-6571a1bbe4a3.png%3Fw%3D1200%26format%3Dwebp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2F86f8831c-59ee-42b2-8ef4-6571a1bbe4a3.png%3Fw%3D1200%26format%3Dwebp" alt="dbdiagram.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;dbdiagram.io allows power users to easily create ER diagrams.&lt;/p&gt;

&lt;p&gt;Key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQL statement generation&lt;/li&gt;
&lt;li&gt;Export to image and PDF&lt;/li&gt;
&lt;li&gt;One-click sharing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: Basic plan is free, Pro version is $9/month&lt;/p&gt;

&lt;h2&gt;
  
  
  9. &lt;a href="https://www.devart.com/dbforge/sql/studio/" rel="noopener noreferrer"&gt;dBForge Studio for SQL Server&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2F962b2ed9-a1b3-4d60-a962-750e73093ba2.png%3Fw%3D1200%26format%3Dwebp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2F962b2ed9-a1b3-4d60-a962-750e73093ba2.png%3Fw%3D1200%26format%3Dwebp" alt="dBForge Studio for SQL Server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;dBForge Studio for SQL Server is an SQL management tool that can also create ER diagrams.&lt;/p&gt;

&lt;p&gt;Key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQL coding support&lt;/li&gt;
&lt;li&gt;Index manager&lt;/li&gt;
&lt;li&gt;Schema comparison&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: Starting from $249.95&lt;/p&gt;

&lt;h2&gt;
  
  
  10. &lt;a href="https://www.navicat.com/en/products/navicat-data-modeler" rel="noopener noreferrer"&gt;Navicat Data Modeler&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2Fb493843e-24e2-4b98-abcd-cc6fa2b6cbf9.png%3Fw%3D1200%26format%3Dwebp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2Fb493843e-24e2-4b98-abcd-cc6fa2b6cbf9.png%3Fw%3D1200%26format%3Dwebp" alt="Navicat Data Modeler"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navicat Data Modeler creates diagrams for MySQL, Oracle, MariaDB, PostgreSQL, and SQLite.&lt;/p&gt;

&lt;p&gt;Key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database objects&lt;/li&gt;
&lt;li&gt;Reverse engineering&lt;/li&gt;
&lt;li&gt;SQL code generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: Enterprise version $22.99/month or $229.99/year (per user)&lt;/p&gt;

&lt;h2&gt;
  
  
  11. &lt;a href="https://creately.com/" rel="noopener noreferrer"&gt;Creately&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2Fa14be8eb-ab61-4557-b7ed-e6becc3cbac2.png%3Fw%3D1200%26format%3Dwebp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2Fa14be8eb-ab61-4557-b7ed-e6becc3cbac2.png%3Fw%3D1200%26format%3Dwebp" alt="Creately"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Creately claims to be "your visual workspace" and enables remote collaboration.&lt;/p&gt;

&lt;p&gt;Key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smart shapes&lt;/li&gt;
&lt;li&gt;Easy drawing shortcuts&lt;/li&gt;
&lt;li&gt;Real-time collaboration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: Team version $6/month (per user)&lt;/p&gt;

&lt;h2&gt;
  
  
  12. &lt;a href="https://www.gliffy.com/" rel="noopener noreferrer"&gt;Gliffy&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2F589b267b-3d40-4c96-86bb-b3b3792f0110.png%3Fw%3D1200%26format%3Dwebp" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.doclify.net%2Fgleek-web%2Fd%2F589b267b-3d40-4c96-86bb-b3b3792f0110.png%3Fw%3D1200%26format%3Dwebp" alt="Gliffy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gliffy is a diagramming tool that can be easily used by non-developers as well.&lt;/p&gt;

&lt;p&gt;Key features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Process flowcharts&lt;/li&gt;
&lt;li&gt;Workflow diagrams&lt;/li&gt;
&lt;li&gt;Data flow charts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Price: Pro version $7.99/month (per user)&lt;/p&gt;

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

&lt;p&gt;In 2024, there are various ER diagram tools available, allowing you to choose the one that best fits your project requirements. New tools like EasyRd are making the database design process even more efficient through integration with AI. Given that it's provided for free, why not consider EasyRd for your next project?&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Flitter vs D3.js: Revolutionizing Data Visualization for the Web</title>
      <dc:creator>Meursyphus</dc:creator>
      <pubDate>Sun, 14 Jul 2024 07:33:46 +0000</pubDate>
      <link>https://dev.to/moondaeseung/flitter-vs-d3js-revolutionizing-data-visualization-for-the-web-2f7h</link>
      <guid>https://dev.to/moondaeseung/flitter-vs-d3js-revolutionizing-data-visualization-for-the-web-2f7h</guid>
      <description>&lt;p&gt;In the world of web-based data visualization, D3.js has long been the go-to library for developers. However, Flitter is changing the game, offering a fresh approach that addresses many of the challenges developers face with D3. Let's explore why Flitter is becoming the preferred choice for modern data visualization projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Ease of Use: Simplifying the Complex
&lt;/h2&gt;

&lt;h3&gt;
  
  
  D3.js Approach:
&lt;/h3&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;svg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;d3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;svg&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;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;height&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;circle&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;data&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;112&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enter&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;circle&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;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;r&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Flitter Approach:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CustomPaint&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@meursyphus/flitter&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;BubbleChart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Container&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="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CustomPaint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;painter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;paint&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;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;data&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;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginPath&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="nf"&gt;arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&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="nf"&gt;fill&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="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;Flitter Advantage:&lt;/strong&gt; Flitter's declarative approach and widget-based architecture make it significantly easier to create and understand visualizations, especially for developers already familiar with modern UI frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Performance: Handling Large Datasets with Ease
&lt;/h2&gt;

&lt;p&gt;While D3.js can struggle with large datasets due to its direct DOM manipulation, Flitter's efficient rendering pipeline shines with big data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flitter's Optimized Rendering:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&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;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@meursyphus/flitter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Widget&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;@meursyphus/flitter-react&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;App&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="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Widget&lt;/span&gt;
      &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100vw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100vh&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="c1"&gt;// your widget here&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="cm"&gt;/**
       * you can choose between "canvas" and "svg". 
       * canvas is faster, while svg is useful for server side rendering
       */&lt;/span&gt;
      &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;canvas&lt;/span&gt;&lt;span class="dl"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Flitter Advantage:&lt;/strong&gt; Flitter's rendering approach allows for smooth handling of thousands of data points, maintaining high frame rates even with dynamic updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Integration with UI: Seamless Component Integration
&lt;/h2&gt;

&lt;p&gt;D3.js often requires additional work to integrate with modern UI frameworks. Flitter, on the other hand, is designed for seamless integration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flitter's Unified Approach:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@meursyphus/flitter&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;BarChart&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@meursyphus/flitter-chart&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Widget&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;@meursyphus/flitter-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Dashboard&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Widget&lt;/span&gt;
      &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100vw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100vh&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sales Dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nc"&gt;BarChart&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="cm"&gt;/* chart properties */&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
            &lt;span class="c1"&gt;// Other UI components&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="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Flitter Advantage:&lt;/strong&gt; Create entire applications with a consistent architecture, mixing visualizations and UI components effortlessly.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Responsive Design: Adapt to Any Screen
&lt;/h2&gt;

&lt;p&gt;While D3.js requires manual work for responsiveness, Flitter makes it straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Container&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@meursyphus/flitter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Widget&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;@meursyphus/flitter-react&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;YourWidget&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// your widget implementation here&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;App&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Widget&lt;/span&gt;
      &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;YourWidget&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// your widget will be centered whenever the screen size changes&lt;/span&gt;
      &lt;span class="p"&gt;})}&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Flitter Advantage:&lt;/strong&gt; Built-in responsiveness features make it easy to create visualizations that look great on any device.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Learning Curve: Familiarity for Modern Developers
&lt;/h2&gt;

&lt;p&gt;D3.js has a steep learning curve, especially for developers used to modern framework paradigms. Flitter leverages familiar concepts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InteractiveChart&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InteractiveChartState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InteractiveChartState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;InteractiveChart&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;private&lt;/span&gt; &lt;span class="nx"&gt;selectedData&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="nf"&gt;onDataPointSelected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&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;build&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="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nc"&gt;Chart&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;onDataPointClick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onDataPointSelected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Selected: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectedData&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="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;&lt;strong&gt;Flitter Advantage:&lt;/strong&gt; Developers familiar with modern UI frameworks can quickly become productive with Flitter, leveraging concepts they already know.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


**Flitter Advantage:** Create smooth, performant animations with a simpler, more intuitive API.

## Conclusion: Why Choose Flitter Over D3.js?

1. **Easier Learning Curve:** Familiar concepts for modern developers.
2. **Better Performance:** Efficient handling of large datasets.
3. **Seamless UI Integration:** Build entire applications with a consistent architecture.
4. **Built-in Responsiveness:** Easily create adaptive visualizations.
5. **Simplified Animations:** Create complex animations with less code.

While D3.js remains a powerful tool, Flitter represents the future of web-based data visualization. It combines the flexibility and power needed for complex visualizations with the ease of use and integration capabilities that modern developers expect.

Ready to take your data visualization projects to the next level? Choose Flitter and experience the future of web development today.

Visit here: [Flitter](https://flitter.dev) to get started.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
    </item>
    <item>
      <title>The Complete Guide to CSS object-fit Property</title>
      <dc:creator>Meursyphus</dc:creator>
      <pubDate>Sun, 14 Jul 2024 00:05:53 +0000</pubDate>
      <link>https://dev.to/moondaeseung/the-complete-guide-to-css-object-fit-property-3apa</link>
      <guid>https://dev.to/moondaeseung/the-complete-guide-to-css-object-fit-property-3apa</guid>
      <description>&lt;h1&gt;
  
  
  The Complete Guide to CSS object-fit: Key to Handling Images on the Web
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction: Why You Need to Know object-fit
&lt;/h2&gt;

&lt;p&gt;Dealing with images in web development has always been a challenging task. How can we consistently display images of various sizes and ratios? This is where the CSS &lt;code&gt;object-fit&lt;/code&gt; property plays a crucial role.&lt;/p&gt;

&lt;p&gt;Understanding &lt;code&gt;object-fit&lt;/code&gt; means more than just displaying images correctly. Recently, many cloud services that automatically adjust the size of user-uploaded images have been offering &lt;code&gt;object-fit&lt;/code&gt; as an option. Therefore, if you don't understand the exact behavior of &lt;code&gt;object-fit&lt;/code&gt;, you might unintentionally provide a negative user experience during the image optimization process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Concepts of object-fit
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;object-fit&lt;/code&gt; property determines how an image will be cropped or scaled to fit within the specified size (container size) of an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; tag, in relation to the original image size.&lt;/p&gt;

&lt;p&gt;An important point to note is that when only &lt;code&gt;width&lt;/code&gt; or &lt;code&gt;height&lt;/code&gt; is specified, the other dimension is automatically determined based on the original image ratio. In this case, for all &lt;code&gt;object-fit&lt;/code&gt; values except &lt;code&gt;scale-down&lt;/code&gt; and &lt;code&gt;none&lt;/code&gt;, the image will fill the container size while maintaining its aspect ratio. However, with &lt;code&gt;scale-down&lt;/code&gt; and &lt;code&gt;none&lt;/code&gt;, if the container size is larger than the image size, the image will maintain its original size without stretching.&lt;/p&gt;

&lt;h2&gt;
  
  
  object-fit Values and Their Effects
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. contain
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      Container
+--------------------+
|        Image       |
|:------------------:|
|:                  :|
|:                  :|
|:                  :|
|:                  :|
|:------------------:|
|                    |
+--------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Adjusts the image to be fully visible&lt;/li&gt;
&lt;li&gt;Maintains image aspect ratio&lt;/li&gt;
&lt;li&gt;May result in empty space within the container&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. cover
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;         Image
:######################:
:#                    #:
:#     Container      #:
:#  +------------+    #:
:#  |            |    #:
:#  |            |    #:
:#  |            |    #:
:#  +------------+    #:
:#                    #:
:######################:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Completely fills the container&lt;/li&gt;
&lt;li&gt;Maintains image aspect ratio&lt;/li&gt;
&lt;li&gt;May crop parts of the image&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. fill
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Completely fills the container&lt;/li&gt;
&lt;li&gt;Ignores image aspect ratio (may distort the image)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. none
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Maintains original image size&lt;/li&gt;
&lt;li&gt;Ignores container size (image may be clipped)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. scale-down
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Displays the image at the smaller size between &lt;code&gt;none&lt;/code&gt; and &lt;code&gt;contain&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Prevents the image from stretching&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Image Widget in Flitter
&lt;/h2&gt;

&lt;p&gt;The Flitter library also provides an Image widget that implements the behavior of &lt;code&gt;object-fit&lt;/code&gt;. Flitter's Image widget is designed to behave as similarly as possible to the native HTML &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag and supports various &lt;code&gt;object-fit&lt;/code&gt; options.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nc"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://flitter.dev/examples/object-fit/profile.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;750&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;objectFit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&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;If you want to see various examples of &lt;code&gt;object-fit&lt;/code&gt;, visit the following URL: &lt;a href="https://flitter.dev/examples/object-fit" rel="noopener noreferrer"&gt;https://flitter.dev/examples/object-fit&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;The &lt;code&gt;object-fit&lt;/code&gt; property is a powerful tool for handling images on the web. By properly understanding and using it, developers can effectively manage images of various sizes and ratios, providing users with a consistent visual experience. Understanding &lt;code&gt;object-fit&lt;/code&gt; becomes even more important when using image optimization services. We hope this guide helps you handle images more effectively in your web projects.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>You must know about principle of z-index</title>
      <dc:creator>Meursyphus</dc:creator>
      <pubDate>Wed, 10 Jul 2024 16:46:23 +0000</pubDate>
      <link>https://dev.to/moondaeseung/you-must-know-about-principle-of-z-index-4akj</link>
      <guid>https://dev.to/moondaeseung/you-must-know-about-principle-of-z-index-4akj</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Hi, I'm (flitter)[&lt;a href="https://flitter.dev" rel="noopener noreferrer"&gt;https://flitter.dev&lt;/a&gt;] maintainer and recently I provide z-index widget. &lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fru1rp878soehm61vnhoh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fru1rp878soehm61vnhoh.png" alt="Image description" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article explores the workings of the z-index property and how to implement it within SVGs.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Intended Audience&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Those struggling with z-index not applying as expected.&lt;/li&gt;
&lt;li&gt;Anyone unfamiliar with the concept of stacking context.&lt;/li&gt;
&lt;li&gt;Individuals looking to implement z-index directly in SVG.&lt;/li&gt;
&lt;li&gt;People interested in adding z-index behavior to charts or diagrams.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Keywords&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/z-index" rel="noopener noreferrer"&gt;z-index&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z_index/The_stacking_context" rel="noopener noreferrer"&gt;stacking context&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  &lt;strong&gt;What is Z-Index?&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;The z-index is a CSS property that adjusts the vertical stacking order of elements. Its default value is &lt;strong&gt;&lt;code&gt;auto&lt;/code&gt;&lt;/strong&gt;, equivalent to &lt;strong&gt;&lt;code&gt;z-index: 0&lt;/code&gt;&lt;/strong&gt;. However, &lt;strong&gt;&lt;code&gt;z-index: 0&lt;/code&gt;&lt;/strong&gt; creates a new stacking context, altering the precedence for child elements differently from &lt;strong&gt;&lt;code&gt;z-index: auto&lt;/code&gt;&lt;/strong&gt;. A stacking context will be explained further below.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Typical Z Order&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In the absence of a specified z-index, the vertical order of stack elements matches the order in which DOM nodes are rendered. This ordering is consistent with a Depth-First Search (DFS), where elements rendered later take precedence over those rendered earlier. For example, a pink box drawn over an orange box is higher in the stack..&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmt5a46d9omist0unkbc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmt5a46d9omist0unkbc6.png" alt="image-1" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Adding Z Elements&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Assigning a z-index of 9999 to a purple circle places it at the top, as shown in the illustration. Despite the pink box being the last reach in a depth-first search, the z-index rearrangement prioritizes the purple circle to be drawn last.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flr6pin0fximwkryvs2k6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flr6pin0fximwkryvs2k6.png" alt="example-2" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  &lt;strong&gt;What is a Stacking Context?&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Stacking context, along with an element's z-index, determines its vertical stack priority. Simply put, think of a stacking context as an array of a parent's z-index values. Even if a child element has a high z-index, it can still be placed lower in priority due to its stacking context.&lt;/p&gt;

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

&lt;p&gt;As shown in the illustration above, despite the purple circle having a z-index of 9999, it is obscured by the pink box below because it belongs to a new stacking context created by its parent's z-index of 0.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Situations Creating Stacking Context&lt;/p&gt;

&lt;p&gt;Stacking context can form not only when a parent element's z-index is specified but also under the following conditions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Root element of the document (&lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Element with a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/position" rel="noopener noreferrer"&gt;&lt;code&gt;position&lt;/code&gt;&lt;/a&gt; value &lt;code&gt;absolute&lt;/code&gt; or &lt;code&gt;relative&lt;/code&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/z-index" rel="noopener noreferrer"&gt;&lt;code&gt;z-index&lt;/code&gt;&lt;/a&gt; value other than &lt;code&gt;auto&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Element with a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/position" rel="noopener noreferrer"&gt;&lt;code&gt;position&lt;/code&gt;&lt;/a&gt; value &lt;code&gt;fixed&lt;/code&gt; or &lt;code&gt;sticky&lt;/code&gt; (sticky for all mobile browsers, but not older desktop browsers).&lt;/li&gt;
&lt;li&gt;Element with a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/container-type" rel="noopener noreferrer"&gt;&lt;code&gt;container-type&lt;/code&gt;&lt;/a&gt; value &lt;code&gt;size&lt;/code&gt; or &lt;code&gt;inline-size&lt;/code&gt; set, intended for &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_container_queries" rel="noopener noreferrer"&gt;container queries&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Element that is a child of a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexible_box_layout/Basic_concepts_of_flexbox" rel="noopener noreferrer"&gt;flex&lt;/a&gt; container, with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/z-index" rel="noopener noreferrer"&gt;&lt;code&gt;z-index&lt;/code&gt;&lt;/a&gt; value other than &lt;code&gt;auto&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Element that is a child of a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/grid" rel="noopener noreferrer"&gt;&lt;code&gt;grid&lt;/code&gt;&lt;/a&gt; container, with &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/z-index" rel="noopener noreferrer"&gt;&lt;code&gt;z-index&lt;/code&gt;&lt;/a&gt; value other than &lt;code&gt;auto&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Element with an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/opacity" rel="noopener noreferrer"&gt;&lt;code&gt;opacity&lt;/code&gt;&lt;/a&gt; value less than &lt;code&gt;1&lt;/code&gt; (See &lt;a href="https://www.w3.org/TR/css-color-3/#transparency" rel="noopener noreferrer"&gt;the specification for opacity&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Element with a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode" rel="noopener noreferrer"&gt;&lt;code&gt;mix-blend-mode&lt;/code&gt;&lt;/a&gt; value other than &lt;code&gt;normal&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Element with any of the following properties with value other than &lt;code&gt;none&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform" rel="noopener noreferrer"&gt;&lt;code&gt;transform&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter" rel="noopener noreferrer"&gt;&lt;code&gt;filter&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter" rel="noopener noreferrer"&gt;&lt;code&gt;backdrop-filter&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/perspective" rel="noopener noreferrer"&gt;&lt;code&gt;perspective&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path" rel="noopener noreferrer"&gt;&lt;code&gt;clip-path&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/mask" rel="noopener noreferrer"&gt;&lt;code&gt;mask&lt;/code&gt;&lt;/a&gt; / &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/mask-image" rel="noopener noreferrer"&gt;&lt;code&gt;mask-image&lt;/code&gt;&lt;/a&gt; / &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/mask-border" rel="noopener noreferrer"&gt;&lt;code&gt;mask-border&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Element with an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/isolation" rel="noopener noreferrer"&gt;&lt;code&gt;isolation&lt;/code&gt;&lt;/a&gt; value &lt;code&gt;isolate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Element with a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/will-change" rel="noopener noreferrer"&gt;&lt;code&gt;will-change&lt;/code&gt;&lt;/a&gt; value specifying any property that would create a stacking context on non-initial value (see &lt;a href="https://dev.opera.com/articles/css-will-change-property/" rel="noopener noreferrer"&gt;this post&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Element with a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/contain" rel="noopener noreferrer"&gt;&lt;code&gt;contain&lt;/code&gt;&lt;/a&gt; value of &lt;code&gt;layout&lt;/code&gt;, or &lt;code&gt;paint&lt;/code&gt;, or a composite value that includes either of them (i.e. &lt;code&gt;contain: strict&lt;/code&gt;, &lt;code&gt;contain: content&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Element placed into the &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Top_layer" rel="noopener noreferrer"&gt;top layer&lt;/a&gt; and its corresponding &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::backdrop" rel="noopener noreferrer"&gt;&lt;code&gt;::backdrop&lt;/code&gt;&lt;/a&gt;. Examples include &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API" rel="noopener noreferrer"&gt;fullscreen&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Popover_API" rel="noopener noreferrer"&gt;popover&lt;/a&gt; elements.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Stacking Context Operational Rules&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let's delve into how stacking contexts are formed and influence the order in which nodes are drawn, explained step by step. For those interested in directly jumping to the implementation logic of z-index, please proceed to the next section titled "Z-Index Implementation Logic."&lt;/p&gt;

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

&lt;p&gt;The illustration above represents a schematic of the DOM structure. The numbers on each node denote the order they are visited in a preorder traversal. Nodes 2 and 4 possess distinct stacking contexts. Node 3 inherits the &lt;strong&gt;stacking context&lt;/strong&gt; from node 2.&lt;/p&gt;

&lt;p&gt;Comparing nodes 2 and 4, even though node 4 has the same z-index, its higher node number grants it priority in the stacking order. Since node 3 inherits the &lt;strong&gt;stacking context&lt;/strong&gt; from node 2, no matter how high its z-index, it will be ranked lower in the stacking order compared to node 4.&lt;/p&gt;
&lt;h3&gt;
  
  
  Example: Complicated Stacking Context
&lt;/h3&gt;

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

&lt;p&gt;In the illustration, nodes 3 and 4 are situated below node 2, and node 7 is located beneath node 6. Notably, there exists a stacking context with a z-index of -1, as seen with node 6, and there are nodes, like node 5, that do not belong to any stacking context. Nodes without a separate stacking context are considered to have a z-index of 0.&lt;/p&gt;

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

&lt;p&gt;The nodes can be divided according to the drawing order as shown above. Node 1 takes precedence over nodes 6 and 7 in the vertical layer, and node 5 is superior to nodes 2, 3, and 4 in the vertical layer. Since nodes 3 and 4 are both below node 2, node 3 with the higher z-index takes precedence over node 4 in the vertical layer.&lt;br&gt;
Therefore, the drawing order is as follows:ㅋ&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrhd0m7l10ls8tzpk7le.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrhd0m7l10ls8tzpk7le.png" alt="image-6" width="800" height="206"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  &lt;strong&gt;Z-Index Implementation Logic&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Implementing z-index equates to creating a logic for arranging DOM drawing order, considering the stacking contexts. A stacking context can be identified through a pre-order traversal of the DOM tree. First, let's define a Stacking Context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;StackingContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;zIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="c1"&gt;//stacking context를 형성한 dom의 z-index&lt;/span&gt;
  &lt;span class="na"&gt;domOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="c1"&gt;//stacking context를 형성한 dom의 전위순회 순서&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CollectedDom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StackingContext&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="c1"&gt;//dom이 물려받은 stacking context&lt;/span&gt;
   &lt;span class="na"&gt;domOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="c1"&gt;//dom의 전위순회 순서&lt;/span&gt;
   &lt;span class="na"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HTMLELEMENT&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A StackingContext is formed by a DOM element that has a z-index. It collects the zIndex and domOrder of the formed DOM into the stacking context. A child inherits the StackingContext from its parent. If the child has a new z-index, it adds a new context to the Stacking context inherited from the parent. Then, the CollectedDom information corresponding to node 7 would be as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="na"&gt;zIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;domOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="c1"&gt;//6번 노드로부터 물려받음&lt;/span&gt;
  &lt;span class="na"&gt;domOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;
  &lt;span class="na"&gt;dom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;div태그&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have collected &lt;code&gt;const collectedDoms: CollectedDom[]&lt;/code&gt; while traversing the DOM, you can sort them in the correct order by considering the stacking context. There are three points to note:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If they are in the same stacking context, the order is determined by the DOM order.&lt;/li&gt;
&lt;li&gt;If there is no stacking context, the z-index is considered to be 0.&lt;/li&gt;
&lt;li&gt;In a stacking context, the parent element is drawn first regardless of the z-index of the child elements. (In vertical layer priority, it gives way to its children).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  정렬로직
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CollectedDom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CollectedDom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="cm"&gt;/*
     stacking context를 순회하며 비교합니다.
   */&lt;/span&gt;
     &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
         &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

     &lt;span class="cm"&gt;/*
      * stacking context가 서로 다른 경우의 노드는 context의 
            * zIndex를 먼저 비교하고, 그 다음의 dom 순서를 비교합니다.
     */&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;aContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;zIndex&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;bContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;zIndex&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;aContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;zIndex&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;bContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;zIndex&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;bContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&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;aContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;bContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;



     &lt;span class="cm"&gt;/* 
    * 이 아래부터는 a,b는 동일한 stacking context 있음을 의미한다.
    * a와 b의 관계는 아래 둘 중 하나이다. 
    *   1. 부모 - 자식
    *   2. 형제
   */&lt;/span&gt;

   &lt;span class="c1"&gt;// 1. 부모-자식인 경우&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;limit&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// 값이 같기 때문에 a,b 둘 중 어느것이여도 상관없다.&lt;/span&gt;
     &lt;span class="c1"&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;lastContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;lastContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&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;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="c1"&gt;// 2. 형제인 경우 &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;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;zIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;domOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&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;bContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contexts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;zIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;domOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

     &lt;span class="cm"&gt;/*
      * stacking context가 서로 다른 경우의 노드는 context의 
            * zIndex를 먼저 비교하고, 그 다음의 dom 순서를 비교합니다.
     */&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;aContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;zIndex&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;bContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;zIndex&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;aContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;zIndex&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;bContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;zIndex&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;bContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&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;aContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;bContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="c1"&gt;// 그 외는 돔 순서로 결정한다.&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;domOrder&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code expresses the logic for sorting by z-index. First, it checks if the stacking contexts are different. If they are different, it prioritizes comparing the zIndex, followed by comparing the DOM order. The length of the stacking contexts can be different. It compares them sequentially based on the shortest context. If the compared stacking contexts are all the same, it proceeds to the next step.&lt;/p&gt;

&lt;p&gt;If the compared stacking contexts have the same value, it checks if the two DOMs have a &lt;code&gt;parent-child relationship&lt;/code&gt;. If they are in the same stacking context, regardless of the child's z-index value, the child takes precedence over the parent in the vertical layer.&lt;/p&gt;

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

&lt;p&gt;In the diagram, despite the red circle having a lower z-index value of -1 than its parent, it's clear that it has a higher priority in the vertical layering. If the parent's &lt;strong&gt;&lt;code&gt;z-index: 0&lt;/code&gt;&lt;/strong&gt; were to be removed, then the red circle would be positioned under the blue box.&lt;/p&gt;

&lt;p&gt;The stacking context for the blue box is &lt;strong&gt;&lt;code&gt;[{zIndex: 0, domOrder: 2}]&lt;/code&gt;&lt;/strong&gt;, and for the red circle, it is &lt;strong&gt;&lt;code&gt;[{zIndex: 0, domOrder: 2}, {zIndex: -1, domOrder: 3}]&lt;/code&gt;&lt;/strong&gt;. Let's consider adding a purple circle as a child of the blue box.&lt;/p&gt;

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

&lt;p&gt;The stacking context for the purple circle, similar to the blue box, is &lt;strong&gt;&lt;code&gt;[{zIndex: 0, domOrder: 2}]&lt;/code&gt;&lt;/strong&gt;. However, because its own domOrder is 3, it does not create a stacking context. As can be seen in the diagram above, the purple circle has a higher priority in the vertical layering than the red circle. Since an unspecified z-index is considered as 0, the red circle with a &lt;strong&gt;&lt;code&gt;z-index of -1&lt;/code&gt;&lt;/strong&gt; is consequently lower in priority.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Implementing in SVG&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;SVG does not support the z-index property. Instead, elements positioned later in the DOM are given higher priority in the vertical stack. To apply z-index in SVG, one must manually manipulate the order of DOM elements. This is similar in canvas.&lt;/p&gt;

&lt;p&gt;Using the &lt;strong&gt;flutterjs&lt;/strong&gt; library, which creates an SVG tree analogous to the DOM tree, I leveraged the Visitor pattern and Stacking Contexts to implement z-index.&lt;/p&gt;

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

&lt;h1&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;This article has provided insights into the z-index property and its practical application within SVG. Writing this piece also allowed me to correct misunderstandings about the stacking context's operational rules and improve drag behavior in an ERD diagram I'm developing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvwmzf5ndd0mq72ykq1sj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvwmzf5ndd0mq72ykq1sj.gif" alt="drag" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;References&lt;/strong&gt;
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://flitter.dev/" rel="noopener noreferrer"&gt;https://flitter.dev/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/z-index" rel="noopener noreferrer"&gt;MDN on z-index&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>The Hidden Power of the Box Model: What Every Frontend Dev Must Know</title>
      <dc:creator>Meursyphus</dc:creator>
      <pubDate>Tue, 09 Jul 2024 14:51:34 +0000</pubDate>
      <link>https://dev.to/moondaeseung/the-hidden-power-of-the-box-model-what-every-frontend-dev-must-know-4ba2</link>
      <guid>https://dev.to/moondaeseung/the-hidden-power-of-the-box-model-what-every-frontend-dev-must-know-4ba2</guid>
      <description>&lt;p&gt;As the developer of &lt;a href="//flitter.dev"&gt;flitter.dev&lt;/a&gt;, a rendering engine framework, I often find myself explaining the intricacies of how browsers and rendering engines work. This article aims to provide a comprehensive overview of the box model, its implementation in browsers, and how similar concepts are used in other frameworks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrjsi8vh88r5drxhkzqf.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhrjsi8vh88r5drxhkzqf.jpeg" alt="box model tree" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Box Model and Browser Rendering
&lt;/h2&gt;

&lt;p&gt;Browser rendering engines use the Box Model as the foundation for constructing web page layouts. When we write HTML tags, the browser parses them to create a Render Tree. Examining the class inheritance relationships of the instances that make up this tree, we find that the superclass is named RenderBox. Most HTML elements are parsed into instances of classes that inherit from RenderBox.&lt;/p&gt;

&lt;p&gt;Key characteristics of the Box Model include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Area Distinction&lt;/strong&gt;: Elements are separated into box units.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spacing Control&lt;/strong&gt;: Margins and padding allow for adjustment of space between content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layout Alignment&lt;/strong&gt;: Elements are aligned either horizontally or vertically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tree Structure&lt;/strong&gt;: Boxes can contain other boxes, resulting in an overall tree structure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Box Model is particularly useful for displaying content. Books, magazines, newspapers, and websites primarily arrange content horizontally or vertically, and parent-child paragraph structures are easily represented. However, games and 2D/3D graphic images are challenging to resolve with the Box Model. These elements are difficult to divide into box shapes, requiring separate definitions for interaction units.&lt;/p&gt;

&lt;p&gt;Browsers leverage the Box Model to help position elements as desired using only HTML and CSS. Consider the scenario of creating a desktop application without a browser engine. You would need to construct the Render Tree yourself, calculate coordinates for element layouts based on the hierarchical structure, determine which element was triggered by an event at (x, y) coordinates, and implement a hitTest() method for each Render Tree element to decide whether to activate event handlers.&lt;/p&gt;

&lt;p&gt;For mobile apps that don't use browsers, frameworks perform these tasks. For instance, Google's cross-platform framework Flutter generates RenderObject instances (which inherit from RenderBox) for each widget. When the root object calls for layout, it calculates the positions of its children and passes coordinate information to the graphics engine for painting on the screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Visualization and the Box Model
&lt;/h2&gt;

&lt;p&gt;Data visualization content like charts and diagrams often contains many elements that can be represented by the Box Model. Bar graphs, in particular, can be fully expressed using just the Box Model. However, certain graphic elements (e.g., curved or bent lines) are challenging to represent in HTML. Consequently, chart and diagram libraries typically use SVG or Canvas instead of HTML. This means that these libraries must perform the role of the browser, which is why creating charts and diagrams can be complex.&lt;/p&gt;

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

&lt;p&gt;Understanding the Box Model and how rendering engines work is crucial for web developers and those working on rendering frameworks. While the Box Model is powerful and widely applicable, it's important to recognize its limitations and know when alternative approaches are necessary. As we continue to develop flitter.dev and other rendering solutions, these foundational concepts remain at the core of our work.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
