<?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: Zygimantas Sniurevicius</title>
    <description>The latest articles on DEV Community by Zygimantas Sniurevicius (@zygiss22).</description>
    <link>https://dev.to/zygiss22</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%2F459550%2F1aba388d-7979-4b3c-a5af-2bcffd7d0a20.jpeg</url>
      <title>DEV Community: Zygimantas Sniurevicius</title>
      <link>https://dev.to/zygiss22</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zygiss22"/>
    <language>en</language>
    <item>
      <title>Extracting a color palette from an image with javascript</title>
      <dc:creator>Zygimantas Sniurevicius</dc:creator>
      <pubDate>Wed, 23 Mar 2022 14:56:06 +0000</pubDate>
      <link>https://dev.to/producthackers/creating-a-color-palette-with-javascript-44ip</link>
      <guid>https://dev.to/producthackers/creating-a-color-palette-with-javascript-44ip</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Today I am bring you something really interesting that I think is worth sharing. Let me begin by showcasing the end result.&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%2Fcxkd5xcgzafzjihr5n5g.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcxkd5xcgzafzjihr5n5g.JPG" alt="Project Image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you can’t wait and want to test it yourself, here are the links to the app demo and the repository.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://zygiss22.github.io/color-palette-extraction/" rel="noopener noreferrer"&gt;Demo app&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/zygisS22/color-palette-extraction" rel="noopener noreferrer"&gt;Repository&lt;/a&gt; (the entire codebase is &lt;strong&gt;commented&lt;/strong&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Explanation
&lt;/h4&gt;

&lt;p&gt;We can load any image and extract a color palette and every color is accompanied by its opposed color (complementary).&lt;/p&gt;

&lt;p&gt;Example of a similar technique can be found in &lt;strong&gt;Spotify&lt;/strong&gt;, when you navigate to a song/playlist or album you get a custom color gradient on top that represents the dominant color of the picture, this gradient adds a unique feel to each page and it's actually the reason why I am doing this post.&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%2Fomys9isjhkt3carj43ja.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomys9isjhkt3carj43ja.JPG" alt="Spotify example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are several websites that provide this service such as &lt;a href="https://coolors.co/image-picker" rel="noopener noreferrer"&gt;coolors.co&lt;/a&gt; or &lt;a href="https://www.canva.com/colors/color-palette-generator/" rel="noopener noreferrer"&gt;canva.com&lt;/a&gt;, if you ever wondered how does it work you are in the correct place, let's find out.&lt;/p&gt;

&lt;h3&gt;
  
  
  📝 Steps
&lt;/h3&gt;

&lt;p&gt;Now that we know what we are dealing here, let’s start by explaining the process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load an image into a canvas.&lt;/li&gt;
&lt;li&gt;Extract image information.&lt;/li&gt;
&lt;li&gt;Build an array of RGB colors.&lt;/li&gt;
&lt;li&gt;Apply Color quantization.&lt;/li&gt;
&lt;/ol&gt;

&lt;h6&gt;
  
  
  BONUS TRACK
&lt;/h6&gt;

&lt;ul&gt;
&lt;li&gt;Order colors by luminance.&lt;/li&gt;
&lt;li&gt;Create a complementary version of each color. &lt;/li&gt;
&lt;li&gt;Build the HTML to display the color palette.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🖼️ Load an image into a canvas
&lt;/h3&gt;

&lt;p&gt;First we create the basic HTML of our page, we need a form input of type file to upload the image and a canvas element because that’s how we gain access to the image’s data.&lt;/p&gt;

&lt;p&gt;index.html&lt;/p&gt;

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

&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"imgfile"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"btnLoad"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Load"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"main();"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;canvas&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"canvas"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"palette"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"complementary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  🚜 Extract image information
&lt;/h3&gt;

&lt;p&gt;We load the image into the canvas using the event handler &lt;code&gt;.onload&lt;/code&gt;, this allow us to access the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData" rel="noopener noreferrer"&gt;getImageData()&lt;/a&gt; method from the canvas API.&lt;/p&gt;

&lt;p&gt;index.js&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imgFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;imgfile&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;image&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;Image&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;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;imgFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileReader&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;FileReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;fileReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;canvas&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&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;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&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;ctx&lt;/span&gt; &lt;span class="o"&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;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drawImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;image&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;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getImageData&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;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="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;height&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;The information returned from &lt;code&gt;getImageData()&lt;/code&gt; represents all the pixels that compose the image, meaning that we have an &lt;strong&gt;humongous&lt;/strong&gt; array of values in the following format:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;133&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;133&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;colorSpace:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"srgb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;height:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;420&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;width:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;320&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


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

&lt;/div&gt;

&lt;p&gt;Each value inside data represents a channel of a pixel R (red), G (Green), B (Blue) and A (Alpha), Every four elements of the data array form the &lt;a href="https://en.wikipedia.org/wiki/RGBA_color_model" rel="noopener noreferrer"&gt;RGBA&lt;/a&gt; color model.&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%2Fd5r4wa4dfi767qu2kc8l.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%2Fd5r4wa4dfi767qu2kc8l.png" alt="data example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🏗️ Build an array of RGB colors
&lt;/h3&gt;

&lt;p&gt;Immediately after obtaining the image data we have to parse it to something more readable, this will make our live easier in the future.&lt;/p&gt;

&lt;p&gt;We loop through the image data every four elements and return an array of color objects in &lt;a href="https://en.wikipedia.org/wiki/RGB_color_model" rel="noopener noreferrer"&gt;RGB&lt;/a&gt; mode instead of RGBA.&lt;/p&gt;

&lt;p&gt;index.js&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buildRgb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;imageData&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;rgbValues&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="nx"&gt;imageData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;4&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;rgb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;imageData&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="na"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;imageData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;imageData&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;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;rgbValues&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;rgb&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;rgbValues&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;h3&gt;
  
  
  🎨 Color quantization
&lt;/h3&gt;

&lt;p&gt;After building the rgb colors array we need to somehow know which colors are the most representative of the image, to obtain this we use &lt;a href="https://en.wikipedia.org/wiki/Color_quantization" rel="noopener noreferrer"&gt;color quantization&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Wikipedia describes color quantization as&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A process that reduces the number of distinct colors used in an image, usually with the intention that the new image should be as visually similar as possible to the original image.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  Median cut algorthm
&lt;/h4&gt;

&lt;p&gt;To achieve color quantization we are gonna use an algorithm called &lt;a href="https://en.wikipedia.org/wiki/Median_cut" rel="noopener noreferrer"&gt;median-cut&lt;/a&gt;, the process is the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find the color channel ( red, green or blue) in the image with the biggest range.
&lt;/li&gt;
&lt;li&gt;Sort pixels by that channel.&lt;/li&gt;
&lt;li&gt;Divide the list in half.&lt;/li&gt;
&lt;li&gt;Repeat the process for each half until you have the desired number of colors.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It sounds easy but it is a little bit complex, so I am gonna try my best to explain the code below.&lt;/p&gt;

&lt;p&gt;Let's begin by creating a function that finds the &lt;a href="https://en.wikipedia.org/wiki/Channel_(digital_image)" rel="noopener noreferrer"&gt;color channel&lt;/a&gt; with the biggest range.&lt;/p&gt;

&lt;p&gt;Initialize the min rgb values to the maximum number and the max rgb values to the minimum, this way we can determine what is the lowest and highest accurately.&lt;/p&gt;

&lt;p&gt;Then, loop through every pixel and compare it with our current values using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min" rel="noopener noreferrer"&gt;Math.min&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max" rel="noopener noreferrer"&gt;Math.max&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Subsequently, we check the difference between every channels min and max results and return the letter of the channel with the biggest range.&lt;/p&gt;

&lt;p&gt;index.js&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;findBiggestColorRange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rgbValues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;rMin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MAX_VALUE&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;gMin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MAX_VALUE&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;bMin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MAX_VALUE&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;rMax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MIN_VALUE&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;gMax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MIN_VALUE&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;bMax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MIN_VALUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;rgbValues&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;pixel&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;rMin&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;rMin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pixel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;gMin&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;gMin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pixel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;bMin&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;bMin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pixel&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;rMax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rMax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pixel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;gMax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gMax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pixel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;bMax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bMax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pixel&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="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rRange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rMax&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;rMin&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;gRange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gMax&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;gMin&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;bRange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bMax&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;bMin&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;biggestRange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rRange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gRange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bRange&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;biggestRange&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;rRange&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="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="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;biggestRange&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;gRange&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;g&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  Recursion time
&lt;/h4&gt;

&lt;p&gt;Now that we have the component with the biggest range of colors in it (R, G or B), sort it and then split it by half, using the two halves we repeat the same process and call the function again, each time adding a value to depth.&lt;/p&gt;

&lt;p&gt;index.js&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;quantization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rgbValues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;depth&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;// base code goes here&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;componentToSortBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;findBiggestColorRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rgbValues&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;rgbValues&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;p1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;p2&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="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;componentToSortBy&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;componentToSortBy&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;mid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rgbValues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;quantization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rgbValues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;depth&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;quantization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rgbValues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;depth&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;As for the base case, we enter it when our depth is equal to the MAX_DEPTH, in our case 4, then add up all the values and divide by half to get the average.&lt;/p&gt;

&lt;h6&gt;
  
  
  Note: Depth in this case means how many colors we want by power of 2.
&lt;/h6&gt;

&lt;p&gt;index.js&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;quantization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rgbValues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;depth&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;MAX_DEPTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;depth&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;MAX_DEPTH&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;rgbValues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rgbValues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;curr&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;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;curr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;curr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;curr&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;r&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;g&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;b&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="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;rgbValues&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;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;rgbValues&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;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&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;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;rgbValues&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// recursion code goes below&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This is it, we are done with median-cut and the palette extraction.&lt;/p&gt;

&lt;h3&gt;
  
  
  📑 Extra steps
&lt;/h3&gt;

&lt;p&gt;There are a lot of things that we could do here but i don't want to abuse of your precious time, if you are interested in expanding a little bit the scope of the project, check the repository, it contains all the extra code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Order colors by luminance.
There are different ways of doing this, depending of your needs, here we use the &lt;a href="https://en.wikipedia.org/wiki/Relative_luminance" rel="noopener noreferrer"&gt;relative luminance&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create &lt;a href="https://en.wikipedia.org/wiki/Complementary_colors" rel="noopener noreferrer"&gt;complementary&lt;/a&gt; version of each color.&lt;/li&gt;
&lt;li&gt;Build the HTML to display the color palette.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🗃️ Resources
&lt;/h3&gt;

&lt;p&gt;If you want to go further into the topic I suggest trying different algorithms to create the color palette, find the dominant dolor, understand how color spaces work or add different color schemes, here are some examples to help you out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;a href="https://en.wikipedia.org/wiki/K-means_clustering" rel="noopener noreferrer"&gt;K-means algorithm&lt;/a&gt; to create the color palette.&lt;/li&gt;
&lt;li&gt;Use &lt;a href="https://en.wikipedia.org/wiki/Octree" rel="noopener noreferrer"&gt;Octree algorithm&lt;/a&gt; to implement the color palette.&lt;/li&gt;
&lt;li&gt;Watch this talk about color &lt;a href="https://www.youtube.com/watch?v=AS1OHMW873s" rel="noopener noreferrer"&gt;"RGB to XYZ: The Science and History of Color" by John Austin&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Add different color combinations like &lt;a href="https://en.wikipedia.org/wiki/Monochromatic_color" rel="noopener noreferrer"&gt;Monochromatic&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/Color_scheme#Triadic" rel="noopener noreferrer"&gt;Triadic&lt;/a&gt;, check this &lt;a href="https://www.canva.com/colors/color-wheel/" rel="noopener noreferrer"&gt;page&lt;/a&gt; for more examples.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  👋 Final remarks
&lt;/h3&gt;

&lt;p&gt;Thank you for your time, I hope you enjoyed this article and have learned something along the way, have a nice day :)&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%2Fhlqptjm4k7kwph6on11n.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%2Fhlqptjm4k7kwph6on11n.gif" alt="Bob Ross goodbye"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  (Cover photo by Zhang Xinxin on Unsplash)
&lt;/h6&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>MediaStream API in Javascript</title>
      <dc:creator>Zygimantas Sniurevicius</dc:creator>
      <pubDate>Fri, 15 Oct 2021 10:34:03 +0000</pubDate>
      <link>https://dev.to/producthackers/mediastream-api-in-javascript-16h2</link>
      <guid>https://dev.to/producthackers/mediastream-api-in-javascript-16h2</guid>
      <description>&lt;p&gt;Hello fellow dev’s today we are gonna see how easy it is to record your voice or screen in the browser using Mediastream Recording API, with just a few lines we can have something working immediately, first  let’s see how MDN defines &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder" rel="noopener noreferrer"&gt;Mediastream Recording API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;“The MediaStream Recording API is comprised of a single major interface, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder" rel="noopener noreferrer"&gt;MediaRecorder&lt;/a&gt;, which does all the work of taking the data from a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaStream" rel="noopener noreferrer"&gt;MediaStream&lt;/a&gt; and delivering it to you for processing. The data is delivered by a series of dataavailable events, already in the format you specify when creating the &lt;code&gt;MediaRecorder&lt;/code&gt;”&lt;/p&gt;

&lt;p&gt;There are a lot of technical words in that explanation but in a extremely simplified way mediaStream provides us the tools to control audio and videos using streams of data to deliver information with events like &lt;strong&gt;dataavailable&lt;/strong&gt; or &lt;strong&gt;onstop&lt;/strong&gt;, after that we manipulate this information however we see fit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial setup
&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%2Fibo0ru8aqeojtob3bdm1.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fibo0ru8aqeojtob3bdm1.JPG" alt="repository header"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;all the code you see in this article is available in the following &lt;a href="https://github.com/zygisS22/MediaStreamAPI" rel="noopener noreferrer"&gt;REPOSITORY&lt;/a&gt;&lt;br&gt;
and if you wanna test the code directly you can do it &lt;a href="https://zygiss22.github.io/MediaStreamAPI/" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This project uses only javascript vanilla, we don’t need anything eccentric like react.js or vue.js, but of course if you want to try it using some framework go ahead because it’s basically the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTML
&lt;/h2&gt;

&lt;p&gt;The HTML file is a simple template, with links to our css and js files, other than that we some buttons and a gallery, this is where we gonna display all our audios/videos.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS
&lt;/h2&gt;

&lt;p&gt;As for the styling I added some basic flex styles just for centering and a fancy button gradient just for presentation purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Javascript
&lt;/h2&gt;

&lt;p&gt;Now, here we have the main dish, let’s go through  almost line by line.&lt;/p&gt;

&lt;p&gt;We start by declaring all the HTML selectors we'll end up using for future events, mediaRecorder is gonna be the main object that dictates if we recording audio or our screen and the chunks variable is where we gonna store our recording data before converting it into an HTML element.&lt;/p&gt;

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

const buttons = document.querySelectorAll(".button");
const startAudioButton = document.querySelector("#startAudio");
const startScreenButton = document.querySelector("#startScreen");
const stopButton = document.querySelector("#stopAudio");
const audioList = document.querySelector("#audio-list");
const videoList = document.querySelector("#video-list");

let mediaRecorder = null;
let chunks = [];



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

&lt;/div&gt;

&lt;p&gt;Here we add click events to our three beautiful buttons so each one calls the function associate with the HTML element when we want to start or stop recording.&lt;/p&gt;

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

startAudioButton .addEventListener("click", recordAudio);
stopButton.addEventListener("click", stopRecording);
startScreenButton.addEventListener("click", recordSCreen);


function recordAudio() {
    // ...code
}

function  stopRecording() {
    // ...code
}

function  recordSCreen() {
    // ...code
}



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

&lt;/div&gt;

&lt;p&gt;The first “big” function we have is for recording audio, here we have a promise that calls the method &lt;strong&gt;.getUserMedia()&lt;/strong&gt; with a json object to specify that we need only audio, this pops up a window asking for our &lt;strong&gt;permission&lt;/strong&gt; to use the microphone inside the browser, after that we get a stream.&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%2Fqhok6ep8e573xf6yv46b.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhok6ep8e573xf6yv46b.JPG" alt="microphone permission"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This stream can be obtained from audio or video, but in our case we want to capture our microphones stream, so we use it to initialize a new MediaRecorder object.&lt;/p&gt;

&lt;p&gt;During the recording we will get a continues flow of data from the event &lt;strong&gt;ondataavailable&lt;/strong&gt;, this data has the following structure:&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%2Fjhtcfmi8p7ffvsm0tzlp.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhtcfmi8p7ffvsm0tzlp.JPG" alt="console.log data"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the definition of a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob" rel="noopener noreferrer"&gt;Blob&lt;/a&gt; for those that dont know what it means.&lt;/p&gt;

&lt;p&gt;“The Blob object represents a blob, which is a file-like object of immutable, raw data; they can be read as text or binary data, or converted into a ReadableStream “&lt;/p&gt;

&lt;p&gt;we store all this information inside the array chunks as we are gonna need it later to create the audio element with it.&lt;/p&gt;

&lt;p&gt;Then whenever we stop recording we call another function that creates the  HTML audio element using the chunks array (Blobs).&lt;/p&gt;

&lt;p&gt;Lastly we start the recording with...you guessed it &lt;strong&gt;mediaRecorder.start(x)&lt;/strong&gt; by default it saves the entire file into a single Blob, but if we specify a duration then it creates a Blob every X milliseconds.&lt;/p&gt;

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

function recordAudio() {
  navigator.mediaDevices
    .getUserMedia({ audio: true})
    .then((stream) =&amp;gt; {
      mediaRecorder = new MediaRecorder(stream);
      mediaRecorder.ondataavailable = (e) =&amp;gt; {
        chunks.push(e.data);
      };
      mediaRecorder.onstop = (e) =&amp;gt; {
        createMediaElement("audio", "audio/mp3", audioList);
      };
      mediaRecorder.onerror = (e) =&amp;gt; {};
      mediaRecorder.start(1000);
    })
}


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

&lt;/div&gt;

&lt;p&gt;We stop the recording by simply calling mediaRecorder.stop()&lt;/p&gt;

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

function stopRecording() {
  mediaRecorder.stop();
}


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

&lt;/div&gt;

&lt;p&gt;When we stop a recording we automatically create a &lt;strong&gt;mediaRecorder.onstop&lt;/strong&gt; event , this then calls the function &lt;strong&gt;createMediaElement(...)&lt;/strong&gt; with the mediaType (audio or video), fileType and the placeToAdd (where to insert the element we just created).&lt;/p&gt;

&lt;p&gt;Now we use all the stored information in the chunks array to create one Blob and make it into a url.&lt;/p&gt;

&lt;p&gt;Then we create the HTML element passing the url as src and we reset the let variables.&lt;/p&gt;

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

function createMediaElement(mediaType, fileType, placeToAdd) {
  const blob = new Blob(chunks, {
    type: fileType,
  });
  const mediaURL = window.URL.createObjectURL(blob);
  const element = document.createElement(mediaType);
  element.setAttribute("controls", "");
  element.src = mediaURL;
  placeToAdd.insertBefore(element, placeToAdd.firstElementChild);
  mediaRecorder = null;
  chunks = [];
}


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

&lt;/div&gt;

&lt;p&gt;Screen recording is more or less the same thing, the only big differences is that we call &lt;strong&gt;getDisplayMedia&lt;/strong&gt; instead of &lt;strong&gt;getUserMedia&lt;/strong&gt; and when we create the media element we pass the chunks type as fileType.&lt;/p&gt;

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

function recordSCreen() {
  navigator.mediaDevices
    .getDisplayMedia({ mediaSource: "screen"})
    .then((stream) =&amp;gt; {
      mediaRecorder = new MediaRecorder(stream);
      mediaRecorder.ondataavailable = (e) =&amp;gt; {
        chunks.push(e.data);
      };
      mediaRecorder.onstop = (e) =&amp;gt; {
        createMediaElement("video", chunks[0].type, videoList);
      };
      mediaRecorder.start();
    })
}


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

&lt;/div&gt;

&lt;p&gt;With this we have basically covered the entire thing, as you can see there is not much to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;As always thanks for reading and I hope you learnt something new today, stay safe and healthy!&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%2Fabi41zpbiej9ql2roslh.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%2Fabi41zpbiej9ql2roslh.gif" alt="Goodbye gif"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Explaining SSR &amp; CSR in Javascript</title>
      <dc:creator>Zygimantas Sniurevicius</dc:creator>
      <pubDate>Fri, 01 Oct 2021 10:35:04 +0000</pubDate>
      <link>https://dev.to/producthackers/explaining-ssr-csr-in-javascript-3iig</link>
      <guid>https://dev.to/producthackers/explaining-ssr-csr-in-javascript-3iig</guid>
      <description>&lt;p&gt;Recently at my job we decided to ditch &lt;strong&gt;React.js&lt;/strong&gt; and go with Javascript vanilla for better perfomance since our website is a &lt;strong&gt;newspaper&lt;/strong&gt; we found it to be difficult justify having React.js for something so uneventful, in the process we talked a lot about CSR, SSR and even a Hybrid approach, I found it hard to understand how these rendering techniques work, after investigating it myself, I decided to create this post with my findings.&lt;/p&gt;

&lt;p&gt;Before going too deep let's first see all the diferent kind of rendering we can expect in Javascript:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Client side rendering also known as &lt;strong&gt;CSR&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Server side rendering usually referenced as &lt;strong&gt;SSR&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid&lt;/strong&gt; rendering a combination of both &lt;strong&gt;CSR&lt;/strong&gt; and &lt;strong&gt;SSR&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  The critical path
&lt;/h1&gt;

&lt;p&gt;Let's begin by understanding how the browser paints information on our screen when we visit a website.&lt;/p&gt;

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

&lt;p&gt;There is a &lt;strong&gt;sequence of events&lt;/strong&gt; that every browser must go through before rendering the initial view of a web page, we won't go into much detail but if you want more information about this topic check these links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Critical_rendering_path" rel="noopener noreferrer"&gt;Mozilla MDN Critical rendering path&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=SmE4OwHztCc" rel="noopener noreferrer"&gt;Ryan Seddon: So how does the browser actually render a website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/web/updates/2019/02/rendering-on-the-web" rel="noopener noreferrer"&gt;Rendering on the Web&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, we start with an HTML request, after the server returns the HTML, the browser begins parsing the HTML converting the received bytes to the DOM tree, then initiates requests every time it finds links to external &lt;strong&gt;resources&lt;/strong&gt; (stylesheets, scripts, or embedded image references) until it gets to the end of the file that's when&lt;br&gt;
it builds the CSS object model.&lt;/p&gt;

&lt;p&gt;With the &lt;strong&gt;DOM&lt;/strong&gt; and &lt;strong&gt;CSSOM&lt;/strong&gt; complete, the browser builds the render tree, computing the styles for all the &lt;strong&gt;visible content&lt;/strong&gt;. After the render tree is complete, layout occurs, defining the location and size of all the render tree elements. Once complete, the page is rendered on the screen.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is Client-side rendering ?
&lt;/h1&gt;

&lt;p&gt;Instead of receiving all the data from the HTML document we use a &lt;strong&gt;barebones version&lt;/strong&gt; with basic information and a link to a Javascript file wich then renders the rest of our web page using the browser.&lt;/p&gt;

&lt;p&gt;This is the default for many frameworks in javascript such as React.js, Angular.js, Vue.js...etc&lt;/p&gt;

&lt;h4&gt;
  
  
  How it works
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;User requests access to our webpage&lt;/li&gt;
&lt;li&gt;Server sends a response to our browser&lt;/li&gt;
&lt;li&gt;Browser downloads the javascript file&lt;/li&gt;
&lt;li&gt;Executes the files content&lt;/li&gt;
&lt;li&gt;Content is visible and you can navigate and interact with the web page&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  What is Server-side rendering ?
&lt;/h1&gt;

&lt;p&gt;Rather than having a small HTML document wich then calls the assets needed, we move the process of rendering our initial page to the server, there we process the javascript of the website and render it to a &lt;strong&gt;static HTML&lt;/strong&gt; so the clients browser doens't have to.&lt;/p&gt;

&lt;h4&gt;
  
  
  How it works
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;User requests access to our webpage&lt;/li&gt;
&lt;li&gt;Server sends ready to go HTML files&lt;/li&gt;
&lt;li&gt;Browser renders the page but its not interactive&lt;/li&gt;
&lt;li&gt;Browser downloads the Javascript&lt;/li&gt;
&lt;li&gt;Execute the Javascript&lt;/li&gt;
&lt;li&gt;Content is interactive&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Difference in rendering between CSR vs SSR
&lt;/h4&gt;

&lt;p&gt;As you can see the main difference in terms of steps is that with SSR the content is visible sooner but it isn't interactive, meanwhile with CSR the page takes longer to load but its interactive and visible at the same time.&lt;/p&gt;

&lt;h1&gt;
  
  
  Advantages of SSR
&lt;/h1&gt;

&lt;h4&gt;
  
  
  SEO
&lt;/h4&gt;

&lt;p&gt;The complete page's HTML is rendered, this assures the page metadata and content is always visible and accurate for the web crawlers to scan.&lt;/p&gt;

&lt;h4&gt;
  
  
  Faster load
&lt;/h4&gt;

&lt;p&gt;Pages have a much faster load time and a quicker first contentful paint because the content is available in the browser sooner.&lt;/p&gt;

&lt;h4&gt;
  
  
  Social media
&lt;/h4&gt;

&lt;p&gt;When someone shares your page on Facebook or Twitter, it includes a preview of the page because we have all the metadata and content pre rendered on our server already.&lt;/p&gt;

&lt;h4&gt;
  
  
  Discoverability
&lt;/h4&gt;

&lt;p&gt;not long ago google announced that it would give preferential search rankings to the sites with the fastest page load speed (&lt;a href="https://web.dev/vitals/" rel="noopener noreferrer"&gt;See Core Web Vitals&lt;/a&gt;). Meaning that sites with a better user experience will have better search rankings.&lt;/p&gt;

&lt;h1&gt;
  
  
  Final words
&lt;/h1&gt;

&lt;p&gt;I hope this article helped you to understand these concepts a little bit better, if you want to dig deeper remember to check the links I left for you, see you on the next article and have a nice day :D&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%2Fm7resgn2rejbbi8ypiky.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%2Fm7resgn2rejbbi8ypiky.gif" alt="Goodbye"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>performance</category>
    </item>
    <item>
      <title>My reasons to never finish some projects</title>
      <dc:creator>Zygimantas Sniurevicius</dc:creator>
      <pubDate>Wed, 30 Jun 2021 13:38:59 +0000</pubDate>
      <link>https://dev.to/producthackers/my-reasons-to-never-finish-some-projects-17j6</link>
      <guid>https://dev.to/producthackers/my-reasons-to-never-finish-some-projects-17j6</guid>
      <description>&lt;p&gt;Hello, today I wanted to speak about a topic I have been dealing with my whole life, "why the hell I keep leaving things half done?" I imagine that just from reading the title of the article your mind already gently reminded you about X or Y that you never finished but pretend that you will come back to it once the "timing" is right, after speaking with colleagues and friends about it I have realized that the struggle is universally the same for developers around the globe.&lt;/p&gt;

&lt;h3&gt;
  
  
  INTRODUCTION
&lt;/h3&gt;

&lt;p&gt;This is all coming from a developer's perspective that has been programming professionally for around 3 years, so after some deliberation, I came to a small list of 8 moments or signs of when a project is going to be abandoned, let's dig in.&lt;/p&gt;

&lt;h3&gt;
  
  
  EVERYTHING IS HALF DONE
&lt;/h3&gt;

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

&lt;p&gt;Let's start with a big one, this one happens when I already have something working and instead of continuing polishing and finishing one thing I keep jumping from one thing to another, after some days have passed, I come to the realization that every single part of my application is half done, this is where I almost always stop working on a project.&lt;/p&gt;

&lt;h3&gt;
  
  
  NEW TOY
&lt;/h3&gt;

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

&lt;p&gt;This one is self explanatory, it happens when one of the following things appears:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I become obsessed with a new and "better" idea&lt;/li&gt;
&lt;li&gt;New videogame release's&lt;/li&gt;
&lt;li&gt;Some kind of new technology that I want to test&lt;/li&gt;
&lt;li&gt;Any other type entertainment (tv shows, books, movies)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;for me personally, it's always the new games :D, I get sucked into it and when am done with it I can't even remember what was I doing before.&lt;/p&gt;

&lt;h3&gt;
  
  
  TAKES TOO LONG TO FINISH
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwtyr0ucjjd2je2kg7ruu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwtyr0ucjjd2je2kg7ruu.jpg" alt="Skeleton waiting"&gt;&lt;/a&gt;&lt;br&gt;
Ideally, this should never happen, but once or twice I let my imagination run wild and on a blink of an eye I seem to be working on a gigantic app that in no way I can finish, after some days I realize that this will probably take me multiple months to finish, that's when the despair settles in and I loath the idea of continuing working on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  WHY BOTHER, THERE ARE SIMILAR APPS
&lt;/h3&gt;

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

&lt;p&gt;Occasionally there are projects that I really enjoy and am having fun building it, but once I stop for a quick check up on "similar ideas" it hits me like a truck, I suddenly lose all motivation, why waste my time with this when there are hundred projects that are the same or better than mine?&lt;/p&gt;

&lt;h3&gt;
  
  
  MISSING PIECE
&lt;/h3&gt;

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

&lt;p&gt;Sometimes I really get interest in an idea and I start making a mental map of things needed to accomplish it, I try to rationalize every small feature and understand how it should work, after exploring this map there are always tiny details that escape my knowledge and I deem them impossible or too hard to execute because I can't find anything on the internet.&lt;/p&gt;

&lt;h3&gt;
  
  
  REFACTOR LOOP
&lt;/h3&gt;

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

&lt;p&gt;This happens when I make lazy design choices all around the project and I promise myself that I will fix them once I get it working, what follows is an eternal loop of refactors that lead me nowhere near the finish line, refactor on refactor on refactor...&lt;br&gt;
The only thing left for me to do is to rush the project no matter the state it is and dump it as soon as I can.&lt;/p&gt;

&lt;h3&gt;
  
  
  Already code full-time
&lt;/h3&gt;

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

&lt;p&gt;Last but not least, sometimes I have this train of thoughts of why should I waste time on personal projects when I already work full time as a developer, I see people around me doing all kinds of stuff and I get the feeling that I should be doing the same and stop wasting my time, projects born from this fear are usually short of passion and never last long enough.&lt;/p&gt;

&lt;h3&gt;
  
  
  CONCLUSION
&lt;/h3&gt;

&lt;p&gt;Let me finish by telling you that these reasons are personal for me, everyone works differently, it would be amazing if you could share your reasons to abandon a project in the comments below, I'm really interested in seeing the others point of view on the subject.&lt;/p&gt;

&lt;p&gt;Thanks for reading me and sorry if you see a typo, I leave you with some tips for anyone wanting to get better at finishing projects.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Small arcievable objectives&lt;/li&gt;
&lt;li&gt;Always start and focus on a minimal viable product&lt;/li&gt;
&lt;li&gt;Try to start projects that makes your life easier &lt;/li&gt;
&lt;li&gt;Make yourself accountable by telling other's about it.&lt;/li&gt;
&lt;li&gt;Don't just do something for the sake of doing it&lt;/li&gt;
&lt;li&gt;Set deadlines to push yourself&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%2Felhwquha6hvsqjmlivds.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%2Felhwquha6hvsqjmlivds.gif" alt="Goodbye"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>portfolio</category>
      <category>discuss</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Intersection Observer using React</title>
      <dc:creator>Zygimantas Sniurevicius</dc:creator>
      <pubDate>Mon, 15 Feb 2021 07:57:50 +0000</pubDate>
      <link>https://dev.to/producthackers/intersection-observer-using-react-49ko</link>
      <guid>https://dev.to/producthackers/intersection-observer-using-react-49ko</guid>
      <description>&lt;p&gt;Today we are gonna explore how to use the intersection observer API in React and see some useful examples, you can find the code in the following &lt;a href="https://github.com/zygisS22/intersectionObserverApi" rel="noopener noreferrer"&gt;repository&lt;/a&gt;, let's begin.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API" rel="noopener noreferrer"&gt;Mozilla web documentation&lt;/a&gt; describes the intersection observer API as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;lets code register a callback function that is executed whenever an element they wish to monitor enters or exits another element (or the viewport), or when the amount by which the two intersect changes by a requested amount. This way, sites no longer need to do anything on the main thread to watch for this kind of element intersection, and the browser is free to optimize the management of intersections as it sees fit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In plain english, it allows us to detect when certain elements are visible in our &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Viewport_concepts" rel="noopener noreferrer"&gt;viewport&lt;/a&gt;, this only happens when the element meets your desired intersection ratio.&lt;/p&gt;

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

&lt;p&gt;As you can see, if we scroll down the page the intersection ratio will be going up until it meets the designed threshold and that's when the callback function is executed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Initialization
&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%2Fi%2Fdcwkrxkxqvl258qdtllf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdcwkrxkxqvl258qdtllf.png" alt="Constructor" width="800" height="131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The intersection observer object constructor requires two arguments:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Callback function&lt;/li&gt;
&lt;li&gt;Options&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Just like that we are ready to see some action but first we need to know what each option means, the options argument is an object with the following values:&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;root&lt;/strong&gt;: The element that is used as the viewport for checking visibility of the target. Must be the ancestor of the target. Defaults to the browser viewport if not specified or if null.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;rootMargin&lt;/strong&gt;: This set of values serves to grow or shrink each side of the root element's bounding box before computing intersections, the options are similar to those of margin in CSS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;threshold&lt;/strong&gt;: Either a single number or an array of numbers which indicate at what percentage of the target's visibility the observer's callback should be executed, ranges from 0 to 1.0, where 1.0 means every pixel is visible in the viewport.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Using React.js
&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%2Fi%2Fyd1l1b6hldo8xxwz9y0o.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyd1l1b6hldo8xxwz9y0o.gif" alt="viewport implementation gif" width="668" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's see an implementation of the intersection observer API using react.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Start with a reference to the element we want to observe, use the react hook &lt;strong&gt;useRef&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Create a state variable &lt;code&gt;isVisible&lt;/code&gt;, we are gonna use it to display a message whenever our box is in the viewport.&lt;/li&gt;
&lt;li&gt;Declare a &lt;strong&gt;callback&lt;/strong&gt; function that receives an array of  IntersectionObserverEntries as a parameter, inside this function we take the first and only entry and check if is intersecting with the viewport and if it is then we call &lt;code&gt;setIsVisible&lt;/code&gt; with the value of &lt;code&gt;entry.isIntersecting&lt;/code&gt; (true/false).&lt;/li&gt;
&lt;li&gt;Create the options object with the same values as the image.&lt;/li&gt;
&lt;li&gt;Add the react hook &lt;strong&gt;useEffect&lt;/strong&gt; and create an observer contructor using the callback function and the options we just created before, it's &lt;strong&gt;optional&lt;/strong&gt; in our case but you can return a cleanup function to unobserve our target when the component &lt;strong&gt;unmounts&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;useRef&lt;/strong&gt; variable on the element we want to observe.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzgcplfssai6w3h9026qa.png" alt="useRef element" width="800" height="110"&gt;
&lt;/li&gt;
&lt;li&gt;Let's add a background and some properties to our HTML elements
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7am7ap8chudxva0vhzy3.png" alt="css styles" width="728" height="1650"&gt;
&lt;/li&gt;
&lt;li&gt;It's done, simple and easy!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;remember this is just a basic implementation and there are many different ways of doing it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Hooking it up
&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%2Fi%2Fx25932zltsj5j8ech36y.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fx25932zltsj5j8ech36y.gif" alt="in viewport gif 2" width="341" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's now implement the same code we just did before but separating all the logic into a new hook called &lt;code&gt;useElementOnScreen&lt;/code&gt;.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Create a new function called &lt;code&gt;useElementOnScreen&lt;/code&gt; with the parameter &lt;strong&gt;options&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Move &lt;strong&gt;useRef&lt;/strong&gt;, &lt;strong&gt;useState&lt;/strong&gt; and the entire &lt;strong&gt;useEffect&lt;/strong&gt; inside our new shiny hook.&lt;/li&gt;
&lt;li&gt;Now the only thing missing in our hook is the return statement, we pass &lt;code&gt;isVisible&lt;/code&gt; and &lt;code&gt;containerRef&lt;/code&gt; as an array.&lt;/li&gt;
&lt;li&gt;okay, we are almost there, we just need to call it in our component and see if it works!&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;Import the recently created hook file into our component.&lt;/li&gt;
&lt;li&gt;Initialize it with the options object.&lt;/li&gt;
&lt;li&gt;Just like that we are done.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Congratulations we have successfully used the intersection observer API and we even made a hook for it!&lt;/p&gt;




&lt;h2&gt;
  
  
  Final words
&lt;/h2&gt;

&lt;p&gt;Thanks for reading this, Hopefully it helped someone getting started with the IO API using react, stay safe ❤️!&lt;/p&gt;

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

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>html</category>
    </item>
    <item>
      <title>Using Puppeteer to scrape answers in Stackoverflow</title>
      <dc:creator>Zygimantas Sniurevicius</dc:creator>
      <pubDate>Mon, 15 Feb 2021 07:57:11 +0000</pubDate>
      <link>https://dev.to/producthackers/using-puppeteer-to-scrape-answers-in-stackoverflow-4608</link>
      <guid>https://dev.to/producthackers/using-puppeteer-to-scrape-answers-in-stackoverflow-4608</guid>
      <description>&lt;h2&gt;
  
  
  What is Puppeteer
&lt;/h2&gt;

&lt;p&gt;Puppeteer is a node library that lets us control a chrome browser via commands, its one of the most used tools for web scraping because it grants us the ability to automate actions easily.&lt;/p&gt;




&lt;h2&gt;
  
  
  What are we doing
&lt;/h2&gt;

&lt;p&gt;Today we'll learn how to setup Puppeteer to scrape google top results when searching for a problem in stackoverflow, let's see how it will work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First we run the script with the question
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;how to exit vim&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Now we google the top results from stackoverflow&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhlak2lx5u6qfrlgyrdcu.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhlak2lx5u6qfrlgyrdcu.PNG" alt="vim question"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Collect all the links that match half or more words of our question.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;keywordMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&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://stackoverflow.com/questions/31595411/how-to-clear-the-screen-after-exit-vim/51330580&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;ul&gt;
&lt;li&gt;&lt;p&gt;Create a folder for the question asked.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Visit each URL and look for the answer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make a screenshot of the answer if there is one.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6h2bo4kwpapugjqul3tq.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6h2bo4kwpapugjqul3tq.PNG" alt="stackoverflow answer"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Save it in our folder previously created.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmfe3bmyeio2w00811jdf.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmfe3bmyeio2w00811jdf.PNG" alt="folder"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;p&gt;Im not going to cover all the code details in this blog post, things like how to create folders with node.js, how to loop through the array of urls and how to allow arguments in the script are all in my github repository.&lt;/p&gt;

&lt;p&gt;You can find the full code &lt;a href="https://github.com/zygisS22/stackoverflowAnswer" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Explaining the code
&lt;/h2&gt;

&lt;p&gt;After seeing the steps we need to do in the previous section its time to build it ourselves.&lt;/p&gt;

&lt;p&gt;Let's begin by initializing puppeteer inside an async function.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A headless browser is a web browser without a user interface.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Its recommended to use a try catch block because its difficult to control errors that happen while the browser is running.&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="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="k"&gt;try&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;puppeteer&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;false&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="s2"&gt;Error &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;error&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="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;To get all the result's from a specific website we need to construct the URL with &lt;code&gt;+site:stackoverflow.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pptr.dev/#?product=Puppeteer&amp;amp;version=v7.1.0&amp;amp;show=api-pagegotourl-options" rel="noopener noreferrer"&gt;page.goto&lt;/a&gt; accepts two parameters a string for the url and an object for the options, in our case we specify to wait to be completly loaded before moving on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;googleUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://www.google.com/search?q=how%20to%20exit%20vim+site%3Astackoverflow.com`&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="nx"&gt;googleUrl&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="s2"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;domcontentloaded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;networkidle0&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;h4&gt;
  
  
  Getting the url's
&lt;/h4&gt;

&lt;p&gt;After navigating to the google search page, its time to collect all the href links that belong to the section &lt;code&gt;https://stackoverflow.com/questions&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Inside the &lt;a href="https://pptr.dev/#?product=Puppeteer&amp;amp;version=v7.1.0&amp;amp;show=api-pageevaluatepagefunction-args" rel="noopener noreferrer"&gt;page.evaluate&lt;/a&gt; method we are allowed to access the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction" rel="noopener noreferrer"&gt;DOM&lt;/a&gt; with the document object, this means we can use selectors to find the information we need easily using &lt;code&gt;document.querySelector&lt;/code&gt; or &lt;code&gt;document.querySelectorAll&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;remember that document.querySelectorAll doesn't return an Array, instead, its a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/NodeList" rel="noopener noreferrer"&gt;NodeList&lt;/a&gt;, that's why we transform it to Array before filtering.&lt;/p&gt;

&lt;p&gt;Then, we map throught all the elements and return the url's.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;how%20to%20exit%20vim&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validUrls&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;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="nx"&gt;queryUrl&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;hrefElementsList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="s2"&gt;`div[data-async-context='query:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;queryUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%20site%3Astackoverflow.com'] a[href]`&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;filterElementsList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hrefElementsList&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;elem&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;elem&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;href&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;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://stackoverflow.com/questions&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;stackOverflowLinks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filterElementsList&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;elem&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;elem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;href&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;stackOverflowLinks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;queryUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Matching the url
&lt;/h4&gt;

&lt;p&gt;With our verified urls in a variable called &lt;code&gt;validUrls&lt;/code&gt; its time to check if some of them roughtly match what are we looking for.&lt;/p&gt;

&lt;p&gt;we split the question into an Array and loop each word, if the word its inside the stackoverflow url we add it to our variable &lt;code&gt;wordCounter&lt;/code&gt;, after we are done with this process we check if half of the words match the url.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryWordArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;how&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;to&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;exit&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;vim&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;keywordLikeability&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="nx"&gt;validUrls&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;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;wordCounter&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;queryWordArray&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;word&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="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;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="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;wordCounter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;wordCounter&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="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;queryWordArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;wordCounter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;keywordLikeability&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;keywordMatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;wordCounter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Capturing the answer
&lt;/h4&gt;

&lt;p&gt;Finally, we need a function that visits the stackoverflow website and checks if there is an answer, in case there is proceed to make a screenshot of the element and save it.&lt;/p&gt;

&lt;p&gt;we start by going to the stackoverflow url, and closing the popup because otherwise its gonna appear in our screenshot and we dont want that.&lt;/p&gt;

&lt;p&gt;To find the popup close button we use a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/XPath" rel="noopener noreferrer"&gt;xpath&lt;/a&gt; selector, its like a weird cousin of our beloved CSS selector but for xml/html.&lt;/p&gt;

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

&lt;p&gt;With the pop up gone it's time to see if we even have an answer, if we do, we make a &lt;a href="https://pptr.dev/#?product=Puppeteer&amp;amp;version=v7.1.0&amp;amp;show=api-elementhandlescreenshotoptions" rel="noopener noreferrer"&gt;screenshot&lt;/a&gt; and save it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;acceptedAnswer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;screenshot&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;`.howtoexitvim.png`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;clip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&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;1024&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;800&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;take care when using the screenshot method because its not consistent, to make it a smoother experience try to get the DOM element's size and location as shown in the picture above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getAnswerFromQuestion&lt;/span&gt; &lt;span class="o"&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;website&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="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="s2"&gt;Website&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;website&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="nx"&gt;website&lt;/span&gt;&lt;span class="p"&gt;,[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;domcontentloaded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;networkidle0&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;popUp&lt;/span&gt; &lt;span class="o"&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;$x&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;//button[@title='Dismiss']&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;popUp&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;popUp&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;acceptedAnswer&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.accepted-answer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;acceptedAnswer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;acceptedAnswer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;screenshot&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;`./howtoexitvim.png`&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;Call the function created in the previous section with the parameters and we are done!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAnswerFromQuestion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;keywordLikeability&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;url&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the final result, we can finally exit VIM!&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxjgrwclx1aj8iiudid4x.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxjgrwclx1aj8iiudid4x.PNG" alt="stackoverflow answer"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Final remarks
&lt;/h2&gt;

&lt;p&gt;I hope you learned something today and please check up the repository i set up it has all the code, thanks for reading me and stay awesome ❤️&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>webscraping</category>
    </item>
  </channel>
</rss>
