<?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: arielbk</title>
    <description>The latest articles on DEV Community by arielbk (@arielbk).</description>
    <link>https://dev.to/arielbk</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%2F118701%2F0deea333-1733-443c-acea-c1e1e66e7abe.jpeg</url>
      <title>DEV Community: arielbk</title>
      <link>https://dev.to/arielbk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arielbk"/>
    <language>en</language>
    <item>
      <title>How to make an adaptive emoji card (TS React and Chakra UI)</title>
      <dc:creator>arielbk</dc:creator>
      <pubDate>Sat, 28 Oct 2023 15:22:28 +0000</pubDate>
      <link>https://dev.to/arielbk/how-to-make-an-adaptive-emoji-card-ts-react-and-chakra-ui-54kf</link>
      <guid>https://dev.to/arielbk/how-to-make-an-adaptive-emoji-card-ts-react-and-chakra-ui-54kf</guid>
      <description>&lt;p&gt;I was experimenting with gradient borders and stumbled across an interesting technique — cards that adapt to the content inside them. You can see a demo of the effect in action &lt;a href="https://tuckshop-ui.vercel.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's what we'll be building today:&lt;/p&gt;

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

&lt;p&gt;This card will magically adapt it's colours to the emoji passed to it, but a similar approach could be used for any kind of content.&lt;/p&gt;

&lt;p&gt;Let's run through the steps from scratch and break it down!&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Initialise the Project&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We'll be building from the ground up without abstracting anything. The tech stack we'll be using is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vite&lt;/strong&gt; with &lt;strong&gt;React&lt;/strong&gt; and &lt;strong&gt;TypeScript&lt;/strong&gt;: To quickly set up our project environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chakra UI&lt;/strong&gt;: It's not necessary for the effect, but Chakra's style props make styling easier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framer Motion&lt;/strong&gt;: This is a peer dependency of Chakra UI and will come in handy if we decide to animate the card.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Set up the project with Vite&lt;/strong&gt;: Start by running the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create vite@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose React with TypeScript when prompted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install Chakra UI and Framer Motion&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create a Chakra theme&lt;/strong&gt;: Save the following in &lt;code&gt;theme.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ThemeConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;extendTheme&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@chakra-ui/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ThemeConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;initialColorMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;useSystemColorMode&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;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extendTheme&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;global&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#121212&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This sets the Chakra colour scheme to dark mode and applies a dark grey background.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integrate the Chakra Provider&lt;/strong&gt;: Modify &lt;code&gt;src/main.tsx&lt;/code&gt; to include the Chakra provider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ChakraProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@chakra-ui/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./theme&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StrictMode&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ChakraProvider&lt;/span&gt; &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ChakraProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;React&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="na"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Styling Adjustments&lt;/strong&gt;: Ensure your page takes up the entire screen by setting &lt;code&gt;min-height: 100vh;&lt;/code&gt; on the &lt;code&gt;#root&lt;/code&gt; element within &lt;code&gt;App.css&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Build the Basic Card&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let's lay the foundation by first creating a basic card component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create the Component&lt;/strong&gt;: Create a &lt;code&gt;src/components/EmojiCard.tsx&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BoxProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@chakra-ui/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;emoji&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;EmojiCard&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;emoji&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="cm"&gt;/* main container */&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"relative"&lt;/span&gt; &lt;span class="na"&gt;maxW&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;bg&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"#181818"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      /* content wrapper */
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt;
        &lt;span class="na"&gt;px&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;py&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;base&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;sm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex"&lt;/span&gt;
        &lt;span class="na"&gt;alignItems&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;
        &lt;span class="na"&gt;flexDirection&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;column&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;row&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        /* emoji container */
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt;
          &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex"&lt;/span&gt;
          &lt;span class="na"&gt;alignItems&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;
          &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;
          &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"80px"&lt;/span&gt;
          &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"200px"&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;emoji&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        /* text content container */
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Box&lt;/code&gt; is a component from Chakra UI that allows us to pass in style props directly.&lt;/p&gt;

&lt;p&gt;In this basic setup we have a surrounding main container with a constrained width and a background. We also have a content wrapper on the inside with a place for our emoji and for the text content.&lt;/p&gt;

&lt;p&gt;This code serves as a base structure for our card.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Render the Component&lt;/strong&gt;: Update &lt;code&gt;App.tsx&lt;/code&gt; to render our new component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;EmojiCard&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/EmojiCard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;EmojiCard&lt;/span&gt; &lt;span class="nx"&gt;emoji&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🍬&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;Lorem&lt;/span&gt; &lt;span class="nx"&gt;ipsum&lt;/span&gt; &lt;span class="nx"&gt;dolor&lt;/span&gt; &lt;span class="nx"&gt;sit&lt;/span&gt; &lt;span class="nx"&gt;amet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;consectetur&lt;/span&gt; &lt;span class="nx"&gt;adipisicing&lt;/span&gt; &lt;span class="nx"&gt;elit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Commodi&lt;/span&gt; &lt;span class="nx"&gt;explicabo&lt;/span&gt; &lt;span class="nx"&gt;doloremque&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;accusantium&lt;/span&gt; &lt;span class="nx"&gt;repellat&lt;/span&gt; &lt;span class="nx"&gt;dolorem&lt;/span&gt; &lt;span class="nx"&gt;natus&lt;/span&gt; &lt;span class="nx"&gt;soluta&lt;/span&gt; &lt;span class="nx"&gt;quos&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;EmojiCard&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Now we have something to work with!&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;The Effect&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;With the initial setup done, let's get into the fun part — creating the effect!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Background Emoji&lt;/strong&gt;: Add the emoji as a background within the main container but before the content wrapper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt;
  &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"absolute"&lt;/span&gt;
  &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;top&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt;
  &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;alignItems&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex"&lt;/span&gt;
  &lt;span class="na"&gt;_before&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;emoji&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;This places a duplicate emoji in the middle of the card. Notice how it goes over the content even though the background component is before our content in the code.&lt;/p&gt;

&lt;p&gt;Because the background element has an &lt;code&gt;absolute&lt;/code&gt; position, and our content has a default &lt;code&gt;static&lt;/code&gt; position, CSS's &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context" rel="noopener noreferrer"&gt;&lt;em&gt;stacking context&lt;/em&gt;&lt;/a&gt; puts the background over the content. To fix this, set the content wrapper box to &lt;code&gt;position="relative"&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Styling Tweaks&lt;/strong&gt;: Increase the emoji size by adjusting the font size up to 1100, and add a filter to the emoji background element: &lt;code&gt;filter={"blur(80px)"}&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;This is an interesting gradient effect, but we want to confine it to our card. Add an &lt;code&gt;overflow="hidden"&lt;/code&gt; to the main container.&lt;/p&gt;

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

&lt;p&gt;Now let's add the following to the content wrapper to cut out a space for content in the middle, and get a subtle border with these gradient colours:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;backgroundColor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#151515&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;border&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2px solid transparent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;backgroundClip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;padding-box&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interesting part here is the &lt;code&gt;backgroundClip&lt;/code&gt; property. It determines how far the background extends within an element.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;padding-box&lt;/code&gt; means the &lt;code&gt;backgroundColor&lt;/code&gt; we set will extend to the outer edge of the padding, but won't go under the border.&lt;/p&gt;

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

&lt;p&gt;This card should now respond to any emoji you pass into it and use it to fill the background gradient:&lt;/p&gt;

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




&lt;h2&gt;
  
  
  &lt;strong&gt;Add Polish&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let's enhance this effect further!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gradient Background&lt;/strong&gt;: Replace the &lt;code&gt;backgroundColor&lt;/code&gt; property we've set with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;backgroundImage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;linear-gradient(rgb(20 20 20 / 0.8), rgb(20 20 20))&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will replace the solid background with a light gradient, slightly transparent at the top, so that some of the colour from the background can shine through:&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Animate the Background&lt;/strong&gt;: We can make the card a little more dynamic and eye-catching by animating the emoji background using Framer Motion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useTransform&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;framer-motion&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;AnimatedBox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;span class="c1"&gt;// inside our component&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTime&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;rotate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTransform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16000&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// every 16 seconds...&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;360&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// ...rotate 360deg&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;clamp&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="c1"&gt;// repeat the animation&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;span class="c1"&gt;// convert our emoji background to a framer motion component&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AnimatedBox&lt;/span&gt;
  &lt;span class="c1"&gt;// pass in our special framer motion value&lt;/span&gt;
  &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;rotate&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;We convert the &lt;code&gt;Box&lt;/code&gt; component for the emoji background into an &lt;code&gt;AnimatedBox&lt;/code&gt; using Framer Motion's &lt;code&gt;motion&lt;/code&gt; utility. This allows the component to accept special values that Framer Motion animates for us outside of React's standard rendering cycle.&lt;/p&gt;

&lt;p&gt;We use the &lt;code&gt;useTime&lt;/code&gt; and &lt;code&gt;useTransform&lt;/code&gt; hooks from Framer Motion to calculate how much the emoji should rotate. Then we pass the &lt;code&gt;rotate&lt;/code&gt; value as a style prop to our Framer Motion component to handle the animation.&lt;/p&gt;

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

&lt;p&gt;This is the final result in action.&lt;/p&gt;

&lt;p&gt;Well done for making it this far! You can check out the final code for this on the &lt;a href="https://codesandbox.io/p/github/arielbk/emoji-card-demo/main" rel="noopener noreferrer"&gt;CodeSandbox here&lt;/a&gt;, and the &lt;a href="https://tuckshop-ui.vercel.app/" rel="noopener noreferrer"&gt;original experimentation demo&lt;/a&gt; shows it in action with some different emojis.&lt;/p&gt;




&lt;p&gt;It's exciting to stumble across techniques like this. We've just scratched the surface,  and there are lots of different directions you could take.&lt;/p&gt;

&lt;p&gt;Imagine this effect with different light modes, or as an icon button that self-styles based on the provided icon.&lt;/p&gt;

&lt;p&gt;You're not restricted to emojis; throw in any image, pattern, or coloured text. Experiment with different borders. Play around with the filter blur — remove it, or use another.&lt;/p&gt;

&lt;p&gt;Let us know in the comments how you went!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>webdev</category>
      <category>react</category>
      <category>css</category>
    </item>
    <item>
      <title>How to make a 3D shiny card animation (React TS and Framer Motion)</title>
      <dc:creator>arielbk</dc:creator>
      <pubDate>Thu, 17 Nov 2022 07:15:00 +0000</pubDate>
      <link>https://dev.to/arielbk/how-to-make-a-3d-shiny-card-animation-react-ts-and-framer-motion-ijf</link>
      <guid>https://dev.to/arielbk/how-to-make-a-3d-shiny-card-animation-react-ts-and-framer-motion-ijf</guid>
      <description>&lt;p&gt;I noticed a 3D card animation on the Astro website that responds to mouse position, and it stuck in my mind.&lt;/p&gt;

&lt;p&gt;I'd been meaning to update my portfolio website, and wanted something simple with social links and some novel effect.&lt;/p&gt;

&lt;p&gt;I thought it would be a great opportunity to try out some animation techniques. You can see what I ended up with &lt;a href="https://arielbk.com" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The background grid uses a technique outlined in my &lt;a href="https://dev.to/arielbk/how-to-make-an-advanced-pointer-animation-ts-react-and-framer-motion-2p39"&gt;last tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this tutorial we'll focus on a 3D animation that responds to mouse movement, creating a piece of glass that animates on a dotted grid background. &lt;/p&gt;

&lt;p&gt;Check out the demo of what we'll be building &lt;a href="https://shiny3dcard.netlify.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The tech we'll be using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React&lt;/li&gt;
&lt;li&gt;Vite&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Emotion for CSS-in-JS&lt;/li&gt;
&lt;li&gt;Framer Motion&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;First off, we'll scaffold our project with Vite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# npm&lt;/span&gt;
npm create vite@latest 3d-card-animation &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--template&lt;/span&gt; react-ts

&lt;span class="c"&gt;# yarn&lt;/span&gt;
yarn create vite 3d-card-animation &lt;span class="nt"&gt;--template&lt;/span&gt; react-ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And install the dependencies we'll need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @emotion/react @emotion/styled framer-motion

&lt;span class="c"&gt;# yarn&lt;/span&gt;
yarn add @emotion/react @emotion/styled framer-motion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll use the default Vite styling for this tutorial, but we'll remove the light mode variant. Open up the &lt;code&gt;index.css&lt;/code&gt; file and remove the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prefers&lt;/span&gt;&lt;span class="o"&gt;-&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;scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;light&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;root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;213547&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;background&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;ffffff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nl"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;747&lt;/span&gt;&lt;span class="nx"&gt;bff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;background&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;f9f9f9&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;h3&gt;
  
  
  Dotted grid
&lt;/h3&gt;

&lt;p&gt;Inside of &lt;code&gt;src&lt;/code&gt;, create a new &lt;code&gt;components&lt;/code&gt; folder, and a &lt;code&gt;DotGrid.tsx&lt;/code&gt; file inside of it. Add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@emotion/styled&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;SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&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;DotGrid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="s2"&gt;`
  position: absolute;
  width: 100%;
  height: 100%;
  background-size: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;SIZE&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px;
  background-image: radial-gradient(
    circle at 1px 1px,
    white 2px,
    transparent 0
  );
  background-position: center;
  transform: translateZ(-500px);
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;DotGrid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will serve as the backdrop for our 3D card. The &lt;code&gt;background-&lt;/code&gt; CSS properties are used to render our grid using the magic of a radial gradient. &lt;code&gt;translateZ&lt;/code&gt; sends the element back on the z-axis, pushing the grid 'back' into the page.&lt;/p&gt;

&lt;p&gt;We'll empty out our &lt;code&gt;App.tsx&lt;/code&gt; file and replace it with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@emotion/styled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;DotGrid&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/DotGrid&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;Container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="s2"&gt;`
  position: relative;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  perspective: 1000px;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DotGrid&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're setting the width and height to the viewport, and setting &lt;code&gt;overflow&lt;/code&gt; to hidden so that when our animation goes off the page we don't end up with any scroll bars.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Card
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;Card.tsx&lt;/code&gt; file inside of &lt;code&gt;components&lt;/code&gt; with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@emotion/styled&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;Container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="s2"&gt;`
  width: 300px;
  height: 400px;
  border-radius: 20px;
  padding: 1rem 2rem;
  border: 1px solid rgba(200 200 200 / 0.2);
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
  color: #eee;
  text-shadow: 0 1px 0 #999;
`&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;Card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;3D card effect with react and framer motion&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we're going to render this &lt;code&gt;Card&lt;/code&gt; component and wrap our application. We'll be animating it with Framer Motion soon, so we'll make the wrapper a &lt;code&gt;motion.div&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/Card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;motion&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;framer-motion&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;RotationWrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;`
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  transform-style: preserve-3d;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RotationWrapper&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DotGrid&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RotationWrapper&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our card should now be rendered in the middle of our dotted grid, but it's completely transparent. We want to give it a &lt;em&gt;glass look&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The glass look
&lt;/h3&gt;

&lt;p&gt;Usually we could apply a &lt;code&gt;backgroundFilter&lt;/code&gt; style directly to our &lt;code&gt;Card&lt;/code&gt; component, but that won't work here because of the &lt;code&gt;transform-style&lt;/code&gt; property on our &lt;code&gt;RotationWrapper&lt;/code&gt;. This property is necessary for the &lt;code&gt;translateZ&lt;/code&gt; on our &lt;code&gt;DotGrid&lt;/code&gt;. You can read more about it &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-style" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To work around this, all we need to do is add a wrapper around  &lt;code&gt;Card&lt;/code&gt; and style that. We'll make it a &lt;code&gt;motion.div&lt;/code&gt; so we can pass motion values to it later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CardWrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;`
  border-radius: 20px;
  backdrop-filter: blur(3px) brightness(120%);
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CardWrapper&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;CardWrapper&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Our elements are all set up — let's start animating them!&lt;/p&gt;

&lt;h2&gt;
  
  
  3D Rotate
&lt;/h2&gt;

&lt;p&gt;We'll be continuing the rest of the tutorial directly inside the &lt;code&gt;App.tsx&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Track mouse movement
&lt;/h3&gt;

&lt;p&gt;First, lets track mouse movement in relation to our card. Add the following to the &lt;code&gt;App&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useMotionValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;framer-motion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ... &lt;/span&gt;

&lt;span class="c1"&gt;// mouse position&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mouseX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMotionValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerWidth&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="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;mouseY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMotionValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHeight&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="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// handle mouse move on document&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&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;handleMouseMove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MouseEvent&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;// animate mouse x and y&lt;/span&gt;
        &lt;span class="nf"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientX&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientY&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// recalculate grid on resize&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mousemove&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleMouseMove&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// cleanup&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mousemove&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleMouseMove&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;This adds an event listener when the component is mounted that will update motion values for the x and y position of the mouse.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rotate elements
&lt;/h3&gt;

&lt;p&gt;Now we need to translate our mouse coordinates into values to rotate our elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useMotionValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useTransform&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;framer-motion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cardRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLDivElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dampen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rotateX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useTransform&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&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;mouseY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newMouseY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cardRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&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;rect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cardRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoundingClientRect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newRotateX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newMouseY&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;newRotateX&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;dampen&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;rotateY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTransform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newMouseX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cardRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&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;rect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cardRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoundingClientRect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newRotateY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newMouseX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&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;newRotateY&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;dampen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RotationWrapper&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rotateX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rotateY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DotGrid&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CardWrapper&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cardRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;CardWrapper&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RotationWrapper&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We pass a reference (&lt;code&gt;cardRef&lt;/code&gt;) to the &lt;code&gt;CardWrapper&lt;/code&gt; so that we can access its DOM element and determine our mouse position in relation to it.&lt;/p&gt;

&lt;p&gt;Then, we use the Framer Motion &lt;code&gt;useTransform&lt;/code&gt; hook to take our mouse position and translate it into values that represent the number of degrees to rotate on the x and y axis.&lt;/p&gt;

&lt;p&gt;Adjusting the &lt;code&gt;dampen&lt;/code&gt; variable will make this rotation more or less extreme.&lt;/p&gt;

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

&lt;p&gt;Our card should now be rotating along with the background.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Polish
&lt;/h2&gt;

&lt;p&gt;Let's add a sleek finishing touch to our 3D glass. We're going to do that by applying a light gradient over the card, and animating the position of that gradient.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gradient sheen
&lt;/h3&gt;

&lt;p&gt;Add the following to the &lt;code&gt;App.tsx&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useMotionTemplate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useMotionValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useTransform&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;framer-motion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diagonalMovement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useTransform&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rotateX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;newRotateX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newRotateY&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="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newRotateX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;newRotateY&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;position&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sheenPosition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTransform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;diagonalMovement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&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;sheenGradient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMotionTemplate&lt;/span&gt;&lt;span class="s2"&gt;`linear-gradient(55deg, transparent, rgba(255 255 255 / 1) &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sheenPosition&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%, transparent)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CardWrapper&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cardRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;backgroundImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;sheenGradient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we use a transform hook to take our existing &lt;code&gt;rotateX&lt;/code&gt; and &lt;code&gt;rotateY&lt;/code&gt; values, combine them, and return a single value called &lt;code&gt;diagonalMovement&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We take a range from &lt;code&gt;diagonalMovement&lt;/code&gt; of &lt;code&gt;-5&lt;/code&gt; and &lt;code&gt;5&lt;/code&gt; and transform it into a new range. &lt;code&gt;50%&lt;/code&gt; should be our centre (our gradient would be through the middle of the card) with &lt;code&gt;150&lt;/code&gt; above and below that.&lt;/p&gt;

&lt;p&gt;We use the motion template hook to construct a template literal string that we can pass to our motion div as a background image property.&lt;/p&gt;

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

&lt;p&gt;We have a pure white gradient running over our card. We'll need to lower the opacity, but notice how the gradient runs over the top right edge — it stops at the bottom right edge. The gradient position cannot go under &lt;code&gt;0%&lt;/code&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  Sheen opacity
&lt;/h3&gt;

&lt;p&gt;We'll make a couple of tweaks to fix our gradient issue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sheenOpacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTransform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;sheenPosition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="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="mf"&gt;0.05&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sheenGradient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMotionTemplate&lt;/span&gt;&lt;span class="s2"&gt;`linear-gradient(
    55deg,
    transparent,
    rgba(255 255 255 / &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sheenOpacity&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;sheenPosition&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%,
    transparent)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We add another motion value, this time transforming the &lt;code&gt;sheenPosition&lt;/code&gt;. We want the opacity to be &lt;code&gt;0&lt;/code&gt; when the sheen is to the left or the right, and a maximum of &lt;code&gt;0.05&lt;/code&gt; when it's in the centre. We  pass this into the &lt;em&gt;alpha&lt;/em&gt; portion of our gradient's RGBA value to control the opacity.&lt;/p&gt;

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




&lt;p&gt;Well done — you've got a nice shiny 3D card you can fill with whatever content you want!&lt;/p&gt;

&lt;p&gt;There's lots more you could do with this if you wanted to experiment.&lt;/p&gt;

&lt;p&gt;Tweak some of the values and see what happens. To get a feel for the 3D side of things, I would suggest adjusting the &lt;code&gt;perspective&lt;/code&gt; property on the &lt;code&gt;Container&lt;/code&gt; element, &lt;code&gt;translateZ&lt;/code&gt; on the &lt;code&gt;DotGrid&lt;/code&gt; component, and the &lt;code&gt;dampen&lt;/code&gt; variable that gets passed to our &lt;code&gt;rotateX&lt;/code&gt; and &lt;code&gt;rotateY&lt;/code&gt; motion values.&lt;/p&gt;

&lt;p&gt;You can see the final code for this on the &lt;a href="https://github.com/arielbk/shiny-3d-card" rel="noopener noreferrer"&gt;repo&lt;/a&gt;, which is built and deployed on the &lt;a href="https://shiny3dcard.netlify.app/" rel="noopener noreferrer"&gt;demo page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Did you have any issues along the way? Maybe you took this effect in a whole new direction?&lt;/p&gt;

&lt;p&gt;Let us know in the comments!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>webdev</category>
      <category>react</category>
      <category>css</category>
    </item>
    <item>
      <title>How to make an advanced pointer animation (TS React and Framer Motion)</title>
      <dc:creator>arielbk</dc:creator>
      <pubDate>Thu, 08 Sep 2022 08:05:44 +0000</pubDate>
      <link>https://dev.to/arielbk/how-to-make-an-advanced-pointer-animation-ts-react-and-framer-motion-2p39</link>
      <guid>https://dev.to/arielbk/how-to-make-an-advanced-pointer-animation-ts-react-and-framer-motion-2p39</guid>
      <description>&lt;p&gt;I found the &lt;a href="https://blog.pointer.gg/" rel="noopener noreferrer"&gt;Pointer blog&lt;/a&gt; through Product Hunt, and I was really impressed with the background animation there. It's intricate, but because it only appears when the mouse is moved it's still low key and minimal.&lt;/p&gt;

&lt;p&gt;I wanted to see how it was made, so I experimented and tried to reverse engineer it. This is what we'll be building today: &lt;a href="https://pointer-animation.netlify.app/" rel="noopener noreferrer"&gt;demo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I learnt a lot about Framer Motion along the way, and finally got a chance to try out Vite. It's fast.&lt;/p&gt;

&lt;p&gt;I figured this is a great opportunity to pass on the knowledge. Here are some of the things you'll learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React&lt;/li&gt;
&lt;li&gt;Vite&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Emotion for CSS-in-JS&lt;/li&gt;
&lt;li&gt;Advanced animation with Framer Motion&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;We'll start by scaffolding our project with Vite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# npm&lt;/span&gt;
npm create vite@latest pointer-animation &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--template&lt;/span&gt; react-ts

&lt;span class="c"&gt;# yarn&lt;/span&gt;
yarn create vite pointer-animation &lt;span class="nt"&gt;--template&lt;/span&gt; react-ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the commands at the the end to install dependencies and run the project in development mode, then install some further dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# npm&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @emotion/react @emotion/styled framer-motion

&lt;span class="c"&gt;# yarn&lt;/span&gt;
yarn add @emotion/react @emotion/styled framer-motion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The grid
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;components&lt;/code&gt; folder inside of &lt;code&gt;src&lt;/code&gt; where we can start to build our components, and inside that create a &lt;code&gt;Cell.tsx&lt;/code&gt; component with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@emotion/styled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CELL_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&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;Container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="s2"&gt;`
  width: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;CELL_SIZE&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px;
  height: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;CELL_SIZE&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px;
  border: 1px dashed #555;
  color: #777;
  display: flex;
  justify-content: center;
  align-items: center;
  user-select: none;
`&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;Cell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;→&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Cell&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 our grid cell with some basic styling. Notice that there is a text &lt;code&gt;→&lt;/code&gt; that we will animate later. The &lt;code&gt;CELL_SIZE&lt;/code&gt; is a constant at the top of the file so we can easily adjust it.&lt;/p&gt;

&lt;p&gt;Next up, let's create a &lt;code&gt;Grid.tsx&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@emotion/styled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;motion&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;framer-motion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Cell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CELL_SIZE&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Cell&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;Container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;`
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  display: grid;
  grid-template-columns: repeat(&lt;/span&gt;&lt;span class="p"&gt;${(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, 1fr);
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Grid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setColumns&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setRows&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// determine rows and columns&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&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;calculateGrid&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;columnCount&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;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerWidth&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;CELL_SIZE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setColumns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;columnCount&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;rowCount&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;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHeight&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;CELL_SIZE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setRows&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rowCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="c1"&gt;// calculate the grid on load&lt;/span&gt;
    &lt;span class="nf"&gt;calculateGrid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// recalculate grid on resize&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;calculateGrid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// cleanup&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;calculateGrid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt; &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&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="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;columns&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;rows&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Cell&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Let's break this down.&lt;/p&gt;

&lt;p&gt;We style our &lt;code&gt;Container&lt;/code&gt; element so that it covers the entire viewport (&lt;code&gt;100vw&lt;/code&gt; and &lt;code&gt;100vw&lt;/code&gt;) and is absolutely positioned to the top left.&lt;/p&gt;

&lt;p&gt;We use CSS grid here, and determine the number of columns based on a prop from the main &lt;code&gt;Grid&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Grid&lt;/code&gt; component holds the number of columns and rows in state. That's calculated inside the &lt;code&gt;useEffect&lt;/code&gt; which runs when the component mounts.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;calculateGrid&lt;/code&gt; function determines the number of columns and rows we'll need to cover the entire screen with &lt;code&gt;Cell&lt;/code&gt;s. We call this once (so it runs when the component mounts) and add it to an event listener. If the user resizes the screen, the number of rows and columns will be recalculated.&lt;/p&gt;

&lt;p&gt;Finally, we render &lt;code&gt;Cell&lt;/code&gt; components based on the number of columns and rows with a little trick using &lt;code&gt;Array.from&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's remove some boilerplate and render the &lt;code&gt;Grid&lt;/code&gt; component inside of &lt;code&gt;App.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Grid&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/Grid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Grid&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We should now have a grid that responds to the user's browser width!&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Pointers
&lt;/h2&gt;

&lt;p&gt;We have our static grid and arrows, and now we want them to point towards the mouse cursor. &lt;/p&gt;

&lt;p&gt;Add the following to the &lt;code&gt;Grid&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useMotionValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;framer-motion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="c1"&gt;// mouse position&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mouseX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMotionValue&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;mouseY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMotionValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// handle mouse move on document&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&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;handleMouseMove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MouseEvent&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;// animate mouse x and y&lt;/span&gt;
        &lt;span class="nf"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientX&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="c1"&gt;// recalculate grid on resize&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mousemove&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleMouseMove&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// cleanup&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mousemove&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleMouseMove&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Cell&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;mouseX&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;mouseX&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;mouseY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;mouseY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have new state here that will store the coordinates of the mouse cursor as &lt;em&gt;motion&lt;/em&gt; values. This means we can pass the values to Framer Motion to handle animation.&lt;/p&gt;

&lt;p&gt;We've added an event listener to the window object that updates the motion value using an &lt;code&gt;animate&lt;/code&gt; function whenever the mouse moves. We pass that value down to every cell as a prop.&lt;/p&gt;

&lt;p&gt;Now, on to the &lt;code&gt;Cell&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MotionValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useTransform&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;framer-motion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;CellProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;mouseX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MotionValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;mouseY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MotionValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Cell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CellProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;mouseX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mouseY&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPosition&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLDivElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;→&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are receiving the mouse coordinate props here and typing them as motion values that hold a number.&lt;/p&gt;

&lt;p&gt;We want to determine the &lt;em&gt;position&lt;/em&gt; of each cell. To do that, we've added state to hold coordinates, and a React &lt;code&gt;ref&lt;/code&gt; we can use to reference the DOM element of the cell.&lt;/p&gt;

&lt;p&gt;Let's add a &lt;code&gt;useEffect&lt;/code&gt; that will set the centre position of the cell to state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoundingClientRect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// center x coordinate&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;CELL_SIZE&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="c1"&gt;// center y coordinate&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;CELL_SIZE&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="nf"&gt;setPosition&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&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;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every cell now knows it's own coordinates, and is being passed the coordinates of the mouse cursor.&lt;/p&gt;

&lt;p&gt;We need to determine the angle of the line from the current cell to the mouse cursor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;direction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useTransform&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mouseX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mouseY&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;newX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newY&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;diffY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newY&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;diffX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;position&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;angleRadians&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;atan2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;diffY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;diffX&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;angleDegrees&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;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;angleRadians&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;180&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;angleDegrees&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;direction&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;→&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We do this with the &lt;code&gt;useTransform&lt;/code&gt; hook from Framer Motion. This takes in motion values, transforms them, and gives back a new motion value.&lt;/p&gt;

&lt;p&gt;The crucial part here is the &lt;code&gt;Math.atan2&lt;/code&gt; method that we use to find the angle between the centre of the cell and the mouse cursor. We convert that from radians to degrees so we can pass it directly to our arrow.&lt;/p&gt;

&lt;p&gt;The arrow is wrapped in a &lt;code&gt;motion.div&lt;/code&gt; and we pass it our new motion value to animate.&lt;/p&gt;

&lt;p&gt;The arrows should now be following the mouse cursor!&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Spotlight
&lt;/h2&gt;

&lt;p&gt;We already have a pretty cool effect, but the next touches will really make it impressive.&lt;/p&gt;

&lt;p&gt;First off, we'll add the following styles to our &lt;code&gt;Grid&lt;/code&gt;'s  styled &lt;code&gt;Container&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;mask-image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;radial-gradient&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="err"&gt;300&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;300&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="nt"&gt;transparent&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;mask-repeat&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;no-repeat&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should now see that the middle of our arrow grid is &lt;em&gt;lit up&lt;/em&gt; and the outside is darkened. We want this centre mask to follow our mouse.&lt;/p&gt;

&lt;p&gt;Add the following underneath our mouse coordinate motion values in the &lt;code&gt;Grid&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useMotionTemplate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useMotionValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useTransform&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;framer-motion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;centerMouseX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useTransform&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&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;mouseX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newX&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;newX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerWidth&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;centerMouseY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useTransform&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&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;mouseY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newY&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;newY&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHeight&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;WebkitMaskPosition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useMotionTemplate&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;centerMouseX&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;centerMouseY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, our mask will be at the centre of the screen and its placement will be anchored from there. We transform the current mouse position so that the coordinates are from the centre of the screen.&lt;/p&gt;

&lt;p&gt;We then create a motion template value with a hook from Framer Motion, and we can add that to our &lt;code&gt;Grid&lt;/code&gt;'s &lt;code&gt;Container&lt;/code&gt; component like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt; &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WebkitMaskPosition&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We should now have a spotlight that follows our mouse cursor!&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Velocity Fade
&lt;/h2&gt;

&lt;p&gt;For this final touch we'll need to do some gymnastics to make it smooth, so be warned.&lt;/p&gt;

&lt;p&gt;Under our previous mouse motion values in the &lt;code&gt;Grid&lt;/code&gt; component, add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useMotionTemplate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useMotionValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useTransform&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useVelocity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;framer-motion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="c1"&gt;// eased mouse position&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mouseXEased&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMotionValue&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;mouseYEased&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMotionValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// mouse velocity&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mouseXVelocity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useVelocity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseXEased&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;mouseYVelocity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useVelocity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseYEased&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;mouseVelocity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useTransform&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mouseXVelocity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mouseYVelocity&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;latestX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;latestY&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;latestX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;latestY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// map mouse velocity to an opacity value&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;opacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTransform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseVelocity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create a motion value that again holds the mouse coordinates, except this time they are going to be eased. This is what will give us the fading out effect in the end.&lt;/p&gt;

&lt;p&gt;We determine the velocity of the mouse cursor by combining the velocity of our x and y coordinates with Framer Motion's &lt;code&gt;useVelocity&lt;/code&gt; hook.&lt;/p&gt;

&lt;p&gt;From there, we map the mouse velocity (I found a range of &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;1000&lt;/code&gt; worked well) to an opacity value between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We're almost there. We just need to animate the eased mouse coordinates when the mouse moves. Our &lt;code&gt;handleMouseMove&lt;/code&gt; function inside of &lt;code&gt;Grid&lt;/code&gt; should look like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;AnimationOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useMotionTemplate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useMotionValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useTransform&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useVelocity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;framer-motion&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleMouseMove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MouseEvent&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;// animate mouse x and y&lt;/span&gt;
    &lt;span class="nf"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientX&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// animate eased mouse x and y&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AnimationOptions&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;easeOut&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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;animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseXEased&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseYEased&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we pass the opacity value to the &lt;code&gt;style&lt;/code&gt; prop of our &lt;code&gt;Grid&lt;/code&gt;'s &lt;code&gt;Container&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Container&lt;/span&gt;
    &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;WebkitMaskPosition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The grid should now fade in and out based on the user's mouse velocity. This part really brings the animation together.&lt;/p&gt;

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




&lt;p&gt;Well done for making it this far!&lt;/p&gt;

&lt;p&gt;There are techniques here that you can get creative with. It was a learning experience for me, and I'm looking forward to diving deeper.&lt;/p&gt;

&lt;p&gt;You can check out the &lt;a href="https://github.com/arielbk/pointer-animation" rel="noopener noreferrer"&gt;final project repo&lt;/a&gt; to see the final code, and again here's a link to the &lt;a href="https://pointer-animation.netlify.app/" rel="noopener noreferrer"&gt;demo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Did you have any problems along the way? Are there parts you think could be improved? Did you manage to use the techniques to create something else?&lt;/p&gt;

&lt;p&gt;I'd love to hear about it in the comments!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>webdev</category>
      <category>react</category>
      <category>css</category>
    </item>
    <item>
      <title>12 handpicked resources for newbie developers</title>
      <dc:creator>arielbk</dc:creator>
      <pubDate>Wed, 31 Aug 2022 15:20:19 +0000</pubDate>
      <link>https://dev.to/arielbk/12-handpicked-resources-for-newbie-developers-45pc</link>
      <guid>https://dev.to/arielbk/12-handpicked-resources-for-newbie-developers-45pc</guid>
      <description>&lt;p&gt;Learning to code is hard. It's great that there are so many resources to choose from, but that also makes it difficult. &lt;/p&gt;

&lt;p&gt;These are the best resources that really helped me while starting out, or that I found out about later.&lt;/p&gt;

&lt;p&gt;I'm not a fan of listicles with resources that anyone could have found with a quick Google search. These are handpicked! 👌&lt;/p&gt;




&lt;h2&gt;
  
  
  Identify
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Get an idea of what coding is and what a developer actually does. Find out what you're in for. &lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  &lt;a href="https://eloquentjavascript.net/00_intro.html"&gt;Eloquent JavaScript intro chapter&lt;/a&gt; - Reading
&lt;/h3&gt;

&lt;p&gt;This book introduction is a great definition of programming and explains what a developer does in simple and practical terms. The whole book is a fantastic intro to JavaScript.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://norvig.com/21-days.html"&gt;Teach Yourself Programming in Ten Years&lt;/a&gt; - Reading
&lt;/h3&gt;

&lt;p&gt;This pushes against the trend of short-term thinking while learning. It helps to put things in perspective, and provides great advice for a longer time frame.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.edx.org/course/how-to-learn-math-for-students-2"&gt;How to Learn Math for Students&lt;/a&gt; - Course
&lt;/h3&gt;

&lt;p&gt;Coding involves some amount of maths, depending on what you do with it, and many people have insecurities around that. This course teaches how to approach and think about maths.&lt;/p&gt;




&lt;h2&gt;
  
  
  Podcasts
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Listen to podcasts. They are a great way to maximise your time, and keep you inspired and connected.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  &lt;a href="https://www.codenewbie.org/podcast"&gt;CodeNewbie Podcast&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Listen to people's stories and how they use code at their jobs. This can inspire you and expand your ideas about what you could do with code.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://syntax.fm/"&gt;Syntax&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Syntax is a light and informal podcast. The show hosts are two web developers who have been teaching for a long time, but still keep up with the latest trends in the space.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.frontendhappyhour.com/"&gt;Front End Happy Hour&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Front End Happy Hour features experienced developers, many from Netflix. The vibe is light like after work drinks, and you'll gain insights from senior developers at large companies.&lt;/p&gt;




&lt;h2&gt;
  
  
  Learning paths
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Spend time exploring, see what's out there and what you enjoy, and then focus in. Create a plan for your own learning. It can change, but only after deliberate consideration.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  &lt;a href="https://github.com/P1xt/p1xt-guides"&gt;P1xt Guides&lt;/a&gt; - Guide
&lt;/h3&gt;

&lt;p&gt;This helped tremendously when I started plotting a path of what to learn. Although it was created a few years ago now, many of the resources are still very relevant today.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.edx.org/course/introduction-computer-science-harvardx-cs50x"&gt;CS50: Introduction to Computer Science&lt;/a&gt; - Course
&lt;/h3&gt;

&lt;p&gt;This is the first online computer science course I took. It is difficult but very well structured. It make the major topics approachable and lays a strong foundation for CS.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://microsoft.github.io/Web-Dev-For-Beginners/#/"&gt;Web Dev for Beginners&lt;/a&gt; - Course
&lt;/h3&gt;

&lt;p&gt;Microsoft's 12-week web dev course is a great way to learn and practice the basics of web development. This is the course I wished I'd had when I started learning.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://roadmap.sh"&gt;roadmap.sh&lt;/a&gt; - Guide
&lt;/h3&gt;

&lt;p&gt;Roadmaps are great for providing context before diving deeper into your next topic. Pick a dev role you're interested in and see what kind of technologies you would need to know for that role.&lt;/p&gt;




&lt;h2&gt;
  
  
  HTML, CSS, JavaScript
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Treat tutorials as a starting point, and then decide if you want to explore things yourself or build out the tutorial project more.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  &lt;a href="https://geddski.teachable.com/p/flexbox-zombies"&gt;Flexbox Zombies&lt;/a&gt; - Game
&lt;/h3&gt;

&lt;p&gt;Flexbox is a crucial part of CSS to understand. The syntax for it is unintuitive and can be difficult to remember. This game teaches you, and provides a way to practice it, in a fun format.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://javascript30.com"&gt;JavaScript 30&lt;/a&gt; - Course
&lt;/h3&gt;

&lt;p&gt;Build 30 JavaScript projects over 30 days without any additional libraries. Once you're past learning the basic syntax of JavaScript, you'll want to build actual projects. These are some creative and fun ones to get you inspired.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Building projects is where the real learning happens. You will come across roadblocks, but this is how you learn to problem solve.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;I'm a frontend developer, and some of these resources lean towards that, but all of these should be applicable to whatever kind of coding you want to get into.&lt;/p&gt;

&lt;p&gt;I've purposely tried to keep this list short. Once you've studied the foundations, get out there and build!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>codenewbie</category>
      <category>100daysofcode</category>
      <category>learning</category>
    </item>
    <item>
      <title>How to become a developer</title>
      <dc:creator>arielbk</dc:creator>
      <pubDate>Fri, 19 Aug 2022 14:12:44 +0000</pubDate>
      <link>https://dev.to/arielbk/how-to-become-a-developer-58da</link>
      <guid>https://dev.to/arielbk/how-to-become-a-developer-58da</guid>
      <description>&lt;p&gt;I landed my first dev job after about a year of self-directed study.&lt;/p&gt;

&lt;p&gt;I can still relate to it, but over the past three years I've also had time to reflect on the experience.&lt;/p&gt;

&lt;p&gt;It was a rocky road, and I did a lot of things well, but there were also things I could have done better.&lt;/p&gt;

&lt;p&gt;These are the lessons I learned.&lt;br&gt;
 &lt;/p&gt;

&lt;h1&gt;
  
  
  Identify
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;I was afraid to commit, even though I wanted to get into coding for a long time. I imagined a job where I robotically wrote code all day and thought I may get stuck doing it forever.&lt;/p&gt;

&lt;p&gt;I wasn't even sure what coding was, and doubted whether I could do it. After all, I wasn't a maths genius.&lt;/p&gt;

&lt;p&gt;When I faced these thoughts, I realised I was holding myself back. This did not have to be a lifelong commitment.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Take the time to figure out what coding is and what a developer does. Find out what you're in for.&lt;/p&gt;

&lt;p&gt;There are many ways that code can be used, but the foundations are mostly the same. Take the time to explore, and keep an open mind.&lt;/p&gt;

&lt;p&gt;Coding can be like a puzzle game solved by fitting pieces together and reframing the problem in different ways. It can be frustrating sometimes, but the satisfaction of solving the puzzle is worth it.&lt;/p&gt;

&lt;p&gt;Learn what code looks like. Watch YouTube videos, or look at source code. It can be overwhelming, but a mass of code is just a lot of smaller pieces.&lt;/p&gt;




&lt;p&gt;Immerse yourself. If you're surrounded by experts you will naturally soak up some of their knowledge&lt;/p&gt;

&lt;p&gt;Go to dev meetups in your area and embrace the vibrant online developer community.&lt;/p&gt;

&lt;p&gt;Listen to podcasts. They are a great way to maximise your time, and keep you inspired and connected.&lt;br&gt;
 &lt;/p&gt;

&lt;h1&gt;
  
  
  Learn
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;I'd have dozens of tabs open at any time, all relating to web development. I read countless articles and tutorials.&lt;/p&gt;

&lt;p&gt;The first course I took, a free online introductory course to computer science, was fantastic for building foundational knowledge.&lt;/p&gt;

&lt;p&gt;Although challenging, it was well structured. I decided I would give the course a chance and then decide if I wanted to continue learning.&lt;/p&gt;


&lt;/blockquote&gt;

&lt;p&gt;It's important to research and explore, but eventually you'll want a concrete plan to anchor and guide you. Your learning will be less efficient if you constantly shift focus.&lt;/p&gt;

&lt;p&gt;Spend time exploring, see what's out there and what you enjoy, and then focus in. Create a plan for your own learning. It can change, but only after deliberate consideration.&lt;/p&gt;

&lt;p&gt;A danger on the other side is not allowing yourself to progress until you've mastered &lt;em&gt;every topic&lt;/em&gt; you come across. Learn enough to be proficient and then move on. You can return to something later to understand it deeply.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tutorials
&lt;/h3&gt;

&lt;p&gt;Using a whole tech stack can be overwhelming in the beginning, and tutorials are great for guiding you through that.&lt;/p&gt;

&lt;p&gt;But be careful: it's easy to get stuck in 'tutorial purgatory' — doing tutorials without applying what you learn.&lt;/p&gt;

&lt;p&gt;Treat tutorials as a starting point, and then decide if you want to explore things yourself or build out the tutorial project more.&lt;br&gt;
 &lt;/p&gt;

&lt;h1&gt;
  
  
  Build
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;It was hard to step away from tutorials where everything was neatly laid out, so I decided to block off the morning time for intensive work on my own projects.&lt;/p&gt;

&lt;p&gt;At the end of the day, when I didn't need to be quite as focused, I followed along with tutorials and looked out for lessons that I could apply.&lt;/p&gt;


&lt;/blockquote&gt;

&lt;p&gt;Building projects is where the real learning happens. You will come across roadblocks, but this is how you learn to problem solve.&lt;/p&gt;

&lt;p&gt;Projects teach you to manage yourself. Start out with something small and gradually expand your goals.&lt;/p&gt;

&lt;h3&gt;
  
  
  What to build
&lt;/h3&gt;

&lt;p&gt;Choose a project that challenges you, but not so much that it's overwhelming. The sweet spot is when you're about 80% comfortable with the whole tech stack.&lt;/p&gt;

&lt;p&gt;There's no need to think of a completely original idea to start building. Cloning an existing project is great practice. Reverse engineer it and add your own spin.&lt;br&gt;
 &lt;/p&gt;

&lt;h1&gt;
  
  
  Apply
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;After about 9 months of online courses and tutorials, I started to apply for jobs. I crafted a CV bio and cover letter describing how keen I was to learn.&lt;/p&gt;

&lt;p&gt;I got 0 interviews, and many simply didn't reply. I didn't have experience to list so companies weren't interested in finding out more.&lt;/p&gt;

&lt;p&gt;I didn't let this discourage me. I shifted focus to showcasing my work. Over the next months I created a portfolio with 5 side projects that were live and open source.&lt;/p&gt;


&lt;/blockquote&gt;

&lt;p&gt;Once you land your first job you'll get to learn while working on real projects, but landing that first job can be difficult without real experience.&lt;/p&gt;

&lt;p&gt;Picture yourself working where you want and plot a path to get there. Find a job listing you would like to apply for, see what the requirements are, and work on meeting them.&lt;/p&gt;

&lt;p&gt;Do what you would do on the job before you have it, and put it out there for the world to see.&lt;/p&gt;

&lt;p&gt;You don't necessarily need a computer science degree to land a dev job. Show off your code and let your projects be your qualification.&lt;/p&gt;

&lt;p&gt;Open source your code on a platform like GitHub as soon as you can. Push code often and keep your projects up to date.&lt;/p&gt;

&lt;p&gt;Your code is there to show what you're capable of. It should showcase how you think an app or website should be built. Keep this in mind and be deliberate in the patterns you use.&lt;/p&gt;

&lt;p&gt;Demo your websites. It's much easier for someone to check out a demo of what you've built, get excited and curious, and &lt;em&gt;then&lt;/em&gt; dig into the code.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;This time things were different. I had projects to show, and companies were actually getting back to me.&lt;/p&gt;

&lt;p&gt;I interviewed with a handful of them, and received multiple offers. I was able to negotiate and take my pick.&lt;/p&gt;

&lt;p&gt;I decided to work for a startup in the IoT space, and was excited to start my next chapter.&lt;/p&gt;


&lt;/blockquote&gt;

&lt;p&gt;Being a beginner is difficult, but your rate of learning is through the roof. Basically anything you do will be a learning opportunity.&lt;/p&gt;

&lt;p&gt;Let's recap the main points for breaking into a dev career:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identify&lt;/strong&gt; – &lt;em&gt;find out what you're in for&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn&lt;/strong&gt; - &lt;em&gt;plan a path and treat tutorials as a starting point&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build&lt;/strong&gt; - &lt;em&gt;build real projects and put them out there&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply&lt;/strong&gt; - &lt;em&gt;do what you would do at your dream job before you have it&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you land your first job, your hard work will have paid off. I'm still amazed at how fortunate I am to have a job that's fun and that I look forward to doing.&lt;/p&gt;

&lt;p&gt;Everybody is in a unique situation and people learn differently. This is my experience, but I hope these lessons can translate to other learners on their journey.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>codenewbie</category>
      <category>100daysofcode</category>
      <category>learning</category>
    </item>
    <item>
      <title>How to mentor a junior dev</title>
      <dc:creator>arielbk</dc:creator>
      <pubDate>Fri, 03 Jun 2022 15:04:05 +0000</pubDate>
      <link>https://dev.to/arielbk/how-to-mentor-a-junior-dev-21dd</link>
      <guid>https://dev.to/arielbk/how-to-mentor-a-junior-dev-21dd</guid>
      <description>&lt;p&gt;Passing on your knowledge has the potential to provide more value than actually writing code. Smart companies know this and reward it.&lt;/p&gt;

&lt;p&gt;Mentoring can have a huge impact on the world. It creates a ripple effect, where you influence someone's mental models and approaches to code in the years to come.&lt;/p&gt;

&lt;p&gt;You become a better developer, and your understanding deepens as you learn to articulate topics well.&lt;/p&gt;

&lt;p&gt;Mentoring is about empathy and clarity. A mentor acts as a guide and provides support so the junior can focus and learn.&lt;/p&gt;




&lt;h2&gt;
  
  
  Roles
&lt;/h2&gt;

&lt;p&gt;The terms &lt;em&gt;junior&lt;/em&gt; and &lt;em&gt;senior&lt;/em&gt; are thrown around a lot these days, but they continue to be fuzzy.&lt;/p&gt;

&lt;p&gt;We're going to assume for this article that the mentor is a senior developer and the one being mentored is a junior. Let's explore what the differences are between them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Junior
&lt;/h3&gt;

&lt;p&gt;At this stage a developer learns about the pieces so they can form a bigger picture over time.&lt;/p&gt;

&lt;p&gt;It's impossible to take it all in at once, so it's important for a junior developer to have focus. There's a danger of jumping from one thing to the next without understanding how that thing connects to the whole.&lt;/p&gt;

&lt;h3&gt;
  
  
  Senior
&lt;/h3&gt;

&lt;p&gt;The senior role implies technical knowledge, but this is not the defining characteristic. &lt;/p&gt;

&lt;p&gt;Seniors have experience to draw analogies from. A senior developer understands how a decision today can affect a project or the entire company in the future.&lt;/p&gt;

&lt;p&gt;A defining trait for a senior developer is security in their lack of knowledge. They are willing to ask questions, and experience gives them realistic confidence in their ability to figure something out.&lt;/p&gt;

&lt;p&gt;They have picked up meta skills along the way that make them adaptable. They know how to get themselves unstuck. They can impart this wisdom because they have walked the path themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Onboarding
&lt;/h2&gt;

&lt;p&gt;Starting out in a new codebase or company can be exciting and scary. Understand how overwhelming it can be for a junior in the beginning.&lt;/p&gt;

&lt;p&gt;Start with the broadest information and slowly work your way down. Make it clear there's no need to understand every little thing in the beginning.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is the tech stack we work with, these are some of our repositories, this is our folder structure...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is a lot that the junior has to absorb, so documentation should be easily referenced and accessible. Project &lt;code&gt;README&lt;/code&gt; files are a great place for project-specific information.&lt;/p&gt;

&lt;p&gt;Many open source projects will use the &lt;code&gt;good first issue&lt;/code&gt; tag on GitHub for first-time contributors. These are tasks that are not too complex and ideal to familiarise oneself with the codebase.&lt;/p&gt;

&lt;p&gt;Start with these kinds of small tasks and celebrate small wins. Ease the junior into reading and writing code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teach
&lt;/h2&gt;

&lt;p&gt;The priority for a junior is focus. If you find a potential 'teachable moment', pause and question whether it's beneficial for them to learn this right now.&lt;/p&gt;

&lt;p&gt;It's okay to gloss over something and come back to it later when it's relevant. Practice just-in-time teaching, and the junior will be able to apply the knowledge.&lt;/p&gt;

&lt;p&gt;Check in with the junior to see how confident they feel about a particular topic.&lt;/p&gt;

&lt;p&gt;Don't overwhelm them with unnecessary implementation details, but don't exclude crucial pieces that are necessary to understand. There's a balance in finding the right level of abstraction.&lt;/p&gt;

&lt;p&gt;Everyone is different and not everyone learns the same way. Gather feedback on what's working and what isn't. Many people struggle to understand a theoretical concept until it is applied, so provide ways for the junior to practice what they've learnt.&lt;/p&gt;

&lt;p&gt;Peer code and work through tasks together. Small habits that you may not think to point out explicitly are shown — things like keyboard shortcuts, git commands and editor extensions.&lt;/p&gt;

&lt;p&gt;Explain your reasoning as you go and don't be afraid to look things up and debug. This is a part of the job and immensely valuable for a junior to see.&lt;/p&gt;

&lt;p&gt;A junior should ask for help and describe what they've tried once they've spent time on the problem themselves. A little bit of struggle is a part of learning, but not so much that they feel helpless.&lt;/p&gt;

&lt;p&gt;Small wins and guard rails are great in the beginning, but step back and provide more independence as the junior starts to get the hang of things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review
&lt;/h2&gt;

&lt;p&gt;Reviews put things in perspective. They are a chance to reflect on what's been learnt, and refine processes going forward.&lt;/p&gt;

&lt;p&gt;Plan one-on-one meetings sometimes. Ask the junior how they think you could improve, or if there is anything you can do to help them.&lt;/p&gt;

&lt;p&gt;Code reviews encourage communication. Cultivate a healthy feedback cycle as part of your flow. Have your code reviewed by the junior if it's within their grasp and relevant to their current focus. Be prepared to explain why you did something a certain way.&lt;/p&gt;

&lt;p&gt;Consider how you manage your time. Batch it so that you can get your own work done, along with focused sessions with the junior.&lt;/p&gt;

&lt;p&gt;They can prepare things to go through together at your next meeting. This gives the junior time to get themselves unstuck, and to articulate the problem well if they do need help.&lt;/p&gt;




&lt;p&gt;You don't have to wait for permission to mentor others. Leave breadcrumbs to help other motivated people walk the path.&lt;/p&gt;

&lt;p&gt;If you have struggled with something, others will too. Leave a comment on a GitHub issue, or write a blog post about it.&lt;/p&gt;

&lt;p&gt;A powerful way to learn is to lend a helping hand to those who are just behind you on their journey.&lt;/p&gt;

&lt;p&gt;Passing on knowledge brings value not only to juniors, seniors, and companies, but ultimately — to the entire community&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>productivity</category>
      <category>career</category>
      <category>management</category>
    </item>
    <item>
      <title>How to improve your project estimates</title>
      <dc:creator>arielbk</dc:creator>
      <pubDate>Wed, 13 Apr 2022 16:51:13 +0000</pubDate>
      <link>https://dev.to/arielbk/how-to-improve-your-project-estimates-35a2</link>
      <guid>https://dev.to/arielbk/how-to-improve-your-project-estimates-35a2</guid>
      <description>&lt;p&gt;As creators we imagine things and then we try to make them real. Charting a path between the two is the heart of project planning, and as developers we provide time estimates for that path.&lt;/p&gt;

&lt;p&gt;Estimates are notoriously difficult.&lt;/p&gt;

&lt;p&gt;Learning to estimate well gives you freedom. It can provide breathing room to add polish and make something you're proud of.&lt;/p&gt;

&lt;p&gt;It's easy to get stung and set unrealistic expectations that lead to burnout. The following is a broad approach to estimating, and a path to improve.&lt;/p&gt;

&lt;p&gt;There are five steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Understand&lt;/li&gt;
&lt;li&gt;Formulate the project&lt;/li&gt;
&lt;li&gt;Define the parts&lt;/li&gt;
&lt;li&gt;Execute and record&lt;/li&gt;
&lt;li&gt;Reflect&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt; &lt;br&gt;
🍞 &lt;strong&gt;Making toast&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We'll be using the example of making toast along the way to illustrate these ideas&lt;br&gt;
 &lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  1. Understand
&lt;/h2&gt;

&lt;p&gt;People are terrible at estimating how long something will take, and almost everyone thinks they are better at it than they really are.&lt;/p&gt;

&lt;p&gt;By avoiding common pitfalls you'll dramatically improve your estimates.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Planning Fallacy
&lt;/h3&gt;

&lt;p&gt;The Planning Fallacy is a concept formalised by Daniel Kahneman and Amos Tversky, and is described in Kahneman's classic book, &lt;em&gt;Thinking, Fast and Slow&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;People think things will take far less time than they do.&lt;/p&gt;

&lt;p&gt;There are two biases here: the &lt;em&gt;Inside View&lt;/em&gt; and the &lt;em&gt;Optimism Bias&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Inside View&lt;/em&gt; means we can look at similar projects from the past, but believe that we will accomplish them in less time.&lt;/p&gt;

&lt;p&gt;    "For us it will be different."&lt;/p&gt;

&lt;p&gt;    "This time it will be different."&lt;/p&gt;

&lt;p&gt;Everybody believes they are the exception to the rule. We view the situation from the &lt;em&gt;inside&lt;/em&gt; rather than stepping back and viewing things objectively.&lt;/p&gt;

&lt;p&gt;An &lt;em&gt;Optimism Bias&lt;/em&gt; has inspired people to chart unknown territory, start businesses and become parents, but this works against us when we fail to account for things going wrong.&lt;/p&gt;

&lt;p&gt;The fascinating thing about biases is that even if we become aware of them, they usually continue to influence our judgment just as before.&lt;/p&gt;

&lt;p&gt;We must therefore approach our estimates rationally through &lt;em&gt;systems&lt;/em&gt;.&lt;br&gt;
 &lt;/p&gt;
&lt;h2&gt;
  
  
  2. Formulate the project
&lt;/h2&gt;

&lt;p&gt;To start with, we need to know roughly where we're going. Question assumptions about the project from the beginning, and then move forward with confidence.&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;What is the problem we wish to solve?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;What is it we're trying to achieve?&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt; &lt;br&gt;
🍞 &lt;strong&gt;Making toast&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The problem that we want to solve is that we're hungry and need food for energy.&lt;/p&gt;

&lt;p&gt;Toast is not the only solution to the problem, we could eat something else, but it is one of the simplest and fastest ways to achieve our goal.&lt;br&gt;
 &lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Take an Outside View
&lt;/h3&gt;

&lt;p&gt;Use similar projects completed in the past as the baseline for an estimate, and adjust from there based on specifics.&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;How experienced are the team members?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;Have we completed a project like this in the past?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Consider alternative ways of thinking about the project. We are much better at giving estimates for others than ourselves:&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;What if we were to hire a team to do this project?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;What would we expect from them?&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt; &lt;br&gt;
🍞 &lt;strong&gt;Making toast&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We have already made toast thousands of times before. We are going to make it in our home, so that means we'll be able to find things quickly.&lt;/p&gt;

&lt;p&gt;If we asked somebody else with similar experience to make the toast for us we would expect it ready within twenty five minutes, and for them to clean up afterwards. We would want a toast that is crispy, but not burnt.&lt;br&gt;
 &lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Define the MVP
&lt;/h3&gt;

&lt;p&gt;Thought experiments help to separate parts of the projects that are critical from those that are just &lt;em&gt;nice to have&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;What if we had to finish the project in half the time?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;How about in a quarter of the time?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With this informing your thinking you can define the MVP — &lt;em&gt;Minimum Viable Product&lt;/em&gt;. This is the most stripped-down version of the project that could be shipped.&lt;/p&gt;

&lt;p&gt;By developing an MVP first you get an experience of the whole project. Critical parts are explored before embarking on the next phase.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt; &lt;br&gt;
🍞 &lt;strong&gt;Making toast&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We still haven't considered exactly what kind of toast we'll be making. We're going to aim for an MVP to start with.&lt;/p&gt;

&lt;p&gt;Let's use a loaf that is already sliced to save us some cutting.&lt;/p&gt;

&lt;p&gt;There are spreads to consider, but for the first phase let's just plan one layer of butter. We can add other spreads in the next phase.&lt;/p&gt;

&lt;p&gt;How many pieces of toast do we want? Well, we are hungry, but a couple of pieces will do for now.&lt;br&gt;
 &lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Communicate
&lt;/h3&gt;

&lt;p&gt;Expectations for the project should be communicated as soon as possible. It should be clear what the project involves.&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;Have we communicated the project clearly with everyone involved?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;Is there a shared understanding of what is expected?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Projects have a tendency to pick up requirements along the way. &lt;em&gt;Scope Creep&lt;/em&gt; can be avoided by formulating the project early and clearly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt; &lt;br&gt;
🍞 &lt;strong&gt;Making toast&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We realise that perhaps our flatmate may also want toast since we're making it.&lt;/p&gt;

&lt;p&gt;We go to ask them, and find out they've already eaten. We confirm this, and proceed with confidence.&lt;br&gt;
 &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;
  
  
  3. Define the Pieces
&lt;/h2&gt;

&lt;p&gt;It is easy to underestimate the intricacies of the project before you break it down and think it through.&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;What exactly would we do if we had to make a start right this minute?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Walk through the steps and imagine doing them. Your brain prepares for action and unearths things that you may not have thought of.&lt;/p&gt;

&lt;p&gt;Tasks should be actionable. Help your future self so that when it comes time to execute you are prepared.&lt;/p&gt;

&lt;p&gt;Tasks should have clear boundaries. The first and the final step should be distinct. The process in between becomes clearer when you surround it with something concrete.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt; &lt;br&gt;
🍞 &lt;strong&gt;Making toast&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Toast... where do we start?&lt;/p&gt;

&lt;p&gt;First, we'll want to prepare everything. We'll need to get out the bread, the butter, and a plate. We'll also need a butter knife.&lt;/p&gt;

&lt;p&gt;After we've buttered the toast, assuming we don't want any more, we'll need to put these things away again. We'll also need to wash the dishes in the end.&lt;/p&gt;

&lt;p&gt;It's easy to forget about preparation and clean up after a project, so it's good we account for these things now.&lt;br&gt;
 &lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Buffer time
&lt;/h3&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/8xRqXYsksFg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Things will go wrong, and often it is just out of our control. Adding a buffer to our estimates helps account for this.&lt;/p&gt;

&lt;p&gt;Create separate estimates: the actual time you think the task will take, along with an adjusted estimate that applies some buffer.&lt;/p&gt;

&lt;p&gt;The blogger Steve Pavlina describes the concept of a &lt;a href="https://stevepavlina.com/blog/2008/05/how-to-make-accurate-time-estimates/" rel="noopener noreferrer"&gt;fudge ratio&lt;/a&gt;. This is a number that you apply to your estimates to give them a buffer.&lt;/p&gt;

&lt;p&gt;Start with a fudge factor that seems reasonable to you, and over time you can adjust it based on historical data.&lt;/p&gt;

&lt;p&gt;Multiply your original estimate by this ratio to get your new adjusted estimate.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt; &lt;br&gt;
🍞 &lt;strong&gt;Making toast&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We don't have historical data to base our estimates on, but after running through the steps we estimate it will take us 10 minutes to get to our buttered toast MVP plus cleanup.&lt;/p&gt;

&lt;p&gt;Let's start out with a fudge ratio of &lt;code&gt;1.3&lt;/code&gt;. We don't expect too many unknowns since we've made toast before.&lt;/p&gt;

&lt;p&gt;Our adjusted estimate for the whole project is now &lt;code&gt;10 minutes * 1.3 = 13 minutes&lt;/code&gt;.&lt;br&gt;
 &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  4. Execute and Record
&lt;/h2&gt;

&lt;p&gt;You have your project and tasks defined. It's time to dive in, but it's important to come up for air sometimes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timeboxing
&lt;/h3&gt;

&lt;p&gt;Tasks can be worked on endlessly. Timeboxing is an effective way to counteract perfectionism.&lt;/p&gt;

&lt;p&gt;First work towards &lt;em&gt;good enough&lt;/em&gt;. Work on the task in the time allotted, then move on.&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;What is the purpose of this task?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;What needs to be achieved here?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We can always come back to optimise and add polish later on, but for now you are serving the whole project by moving on.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt; &lt;br&gt;
🍞 &lt;strong&gt;Making toast&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We may get caught trying to spread the butter evenly over one slice, while the other cools down. This is no good.&lt;/p&gt;

&lt;p&gt;Let's set a time limit on this task. We won't spend more than 1 minute spreading one slice.&lt;br&gt;
 &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Getting unstuck
&lt;/h3&gt;

&lt;p&gt;Pushing yourself to a deadline on a task can be counterproductive. You may know the stressful feeling of hacking away at something that just doesn't want to work.&lt;/p&gt;

&lt;p&gt;Get away from it. Take a walk. Come back and look at it with fresh eyes.&lt;/p&gt;

&lt;p&gt;Walk through the problem and consider splitting it up further if needed.&lt;/p&gt;

&lt;p&gt;Talk through the problem with someone. They don't necessarily need to be technical, and they can help provide a fresh perspective.&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;Who can we talk with to help see the problem from a different perspective?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;    &lt;em&gt;What is the minimum we must complete for this task in order to move on?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There's no need to over-optimise in the beginning. First, try to develop any solution that fulfills the purpose.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt; &lt;br&gt;
🍞 &lt;strong&gt;Making toast&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We open the fridge to retrieve the butter, but realise that the expiration date has passed. This was not part of the plan.&lt;/p&gt;

&lt;p&gt;Take a breath. We go to our flatmate to ask for advice, and realise that they were about to go to the store. They can pick us up some butter while they're there 👌&lt;br&gt;
 &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Record your estimates
&lt;/h3&gt;

&lt;p&gt;Keep a record of your estimates and actual time spent on tasks. Gather data to optimise your process over time. Gather data, and from there you can begin to analyse it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt; &lt;br&gt;
🍞 &lt;strong&gt;Making toast&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Set a stopwatch as you make the toast, and record how long each step take you.&lt;br&gt;
 &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  5. Analyse
&lt;/h2&gt;

&lt;p&gt;This is where the magic happens. By analysing your past estimates you can reflect and set a trajectory for the future.&lt;/p&gt;

&lt;p&gt;You'll build a history of completed tasks that you can refer to for future estimate baselines.&lt;/p&gt;

&lt;p&gt;Keep a record of your fudge ratio. When it comes time to reflect on past estimates, you can adjust it based on the solid data you've collected.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt; &lt;br&gt;
🍞 &lt;strong&gt;Making toast&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We now have a record of how long our buttered toast MVP generally takes us, and we can make more informed estimates in the future.&lt;/p&gt;

&lt;p&gt;Since we have past estimates for each task, we can now take on even bigger projects in the future.&lt;/p&gt;

&lt;p&gt;We can better judge any steps we have done before, and we know how inaccurate our estimates for unknown steps usually are.&lt;/p&gt;

&lt;p&gt;In the next phase we could kick things up a notch and make ourselves a toasted sandwich with different spreads and fillings.&lt;br&gt;
 &lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Estimating projects well is an indicator of wisdom and experience. Most developers will only learn this after many years, but you can start to cultivate this skill early.&lt;/p&gt;

&lt;p&gt;Tracking and analysing your progress over time puts you on a path of improvement. The key to this approach is in making estimation conscious through concrete systems. &lt;/p&gt;

&lt;p&gt;Project planning charts the path between what we imagine and what we create. By enhancing your estimation skills you will broaden your perspective and expand the possibilities of what you can build.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>productivity</category>
      <category>management</category>
      <category>career</category>
    </item>
    <item>
      <title>How to communicate remotely</title>
      <dc:creator>arielbk</dc:creator>
      <pubDate>Fri, 25 Mar 2022 10:29:18 +0000</pubDate>
      <link>https://dev.to/arielbk/how-to-communicate-remotely-a20</link>
      <guid>https://dev.to/arielbk/how-to-communicate-remotely-a20</guid>
      <description>&lt;p&gt;You've just made your morning coffee, eager to get into this new feature you've been planning. Your editor is open. Hands on the keyboard. Here we go.&lt;/p&gt;

&lt;p&gt;A notification flashes across the screen. A workmate has a question about something they're working on. Might as well tab over and check it before we dive into things, right?&lt;/p&gt;

&lt;p&gt;You stare at the cryptic message for a moment. The feature they've been assigned isn't defined well, so you suggest they ask the manager for some clarity.&lt;/p&gt;

&lt;p&gt;You tab back over to your editor, but notifications swallow your screen. The manager is panicking, and wants everyone on a call.&lt;/p&gt;

&lt;p&gt;People talk about bits and pieces of the project. Didn't we cover this last week? There's still confusion. The meeting goes on.&lt;/p&gt;

&lt;p&gt;A couple of people are talking in jargon about some project specifics. Why are we in this meeting? Nothing really seems clearer. The meeting goes on.&lt;/p&gt;




&lt;p&gt;Developers know the feeling of days squandered on ineffective calls and meetings, but it doesn't have to be like this.&lt;/p&gt;

&lt;p&gt;Coding is an incredible superpower, and so is communication. Learning to code and learning to communicate are skills that don't just add to each other — they multiply. If you can learn to be a great communicator as well as a great coder you will be unstoppable.&lt;/p&gt;

&lt;p&gt;This is my framework for remote communication, formulated while working remotely over the past two years. There are four main areas: empathize, prepare, clarify, and choose the right medium.&lt;br&gt;
 &lt;/p&gt;

&lt;h2&gt;
  
  
  Empathize
&lt;/h2&gt;

&lt;p&gt;After some days of working hard on a new feature you send it to a coworker, hoping for some feedback. You receive a reply:&lt;/p&gt;

&lt;p&gt;"It's not working."&lt;/p&gt;

&lt;p&gt;You wait for something more, but it looks like that's it.&lt;/p&gt;

&lt;p&gt;How does this make you feel? You've spent so much effort on something, only to have it boiled down to three words.&lt;/p&gt;

&lt;p&gt;Of course you want feedback. The response communicates a lack of empathy. They should have sent you details to reproduce and fix any issue they came across.&lt;/p&gt;

&lt;p&gt;At the same time, you don't know what's going on on their side. They may have been on a call and felt pressure to send &lt;em&gt;something&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Empathy is the foundation of communication. It's easy to judge people for how they make us feel. The real learning happens when we consider how our message is received by others.&lt;br&gt;
 &lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare
&lt;/h2&gt;

&lt;p&gt;Our coworker showed a lack of communication, but let's consider what we may have asked them. Preparing relevant information for an interaction means people can easily jump into a topic.&lt;/p&gt;

&lt;p&gt;Perhaps we sent them a link to the homepage, and told them the feature we worked on was &lt;em&gt;a new payment method on the accounts page&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Perhaps they were too busy to switch contexts and navigate around the website. You've been working on this for days, but for them it's new and takes energy to figure out.&lt;/p&gt;

&lt;p&gt;Provide material that will be helpful for them to quickly switch contexts. Sometimes it's best to show something with a screenshot to illustrate your meaning quickly.&lt;br&gt;
 &lt;/p&gt;

&lt;h2&gt;
  
  
  Clarify
&lt;/h2&gt;

&lt;p&gt;You don't want to drown people in information. Too much information puts the burden of finding what's relevant on the other person. Spend time refining your communication.&lt;/p&gt;

&lt;p&gt;Point out the parts that will be most relevant if you're sending long-form material.&lt;/p&gt;

&lt;p&gt;Spend a stretch of time planning and checking assumptions. This takes time up front, but it prevents needlessly wasting time later by proceeding with incorrect assumptions.&lt;/p&gt;

&lt;p&gt;Clarify how urgent a message is. Do you need someone to get back to you immediately, or just when they find the time? Start out with something like, "when you get a chance..." or "as soon as you can...".&lt;/p&gt;

&lt;p&gt;Urgency is relative — if everything is urgent, then nothing is urgent.&lt;br&gt;
 &lt;/p&gt;

&lt;h2&gt;
  
  
  Choose the right medium
&lt;/h2&gt;

&lt;p&gt;How we choose to communicate carries its own message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Instant messaging
&lt;/h3&gt;

&lt;p&gt;Instant messaging makes things easy, but has also created a pressure to always be 'on', ready to respond at any moment. It should be viewed as a shorter form of asynchronous communication. People should not be expected to respond instantly.&lt;/p&gt;

&lt;p&gt;If you're working on something deeply you can reply to messages in small batches. I work in &lt;em&gt;pomodoros&lt;/em&gt;, and reply to messages after I've completed my 25 minute deep work period.&lt;/p&gt;

&lt;p&gt;Remember that messages are always at least somewhat distracting. Do not start a conversation with a single 'hey'. Send your message once you have it prepared, or give the other person a clue for what you're going to follow up with so they can prepare for it: 'Hey, I have a question regarding x'.&lt;/p&gt;

&lt;p&gt;Keep your messages brief, and if they do become longer consider putting them in an email.&lt;/p&gt;

&lt;h3&gt;
  
  
  Email
&lt;/h3&gt;

&lt;p&gt;Emails are generally for longer content and have a longer reply window. It is useful for any material that can be easily referenced in the future, or when you want something to be given more time and deeper thought.&lt;/p&gt;

&lt;p&gt;Email is ideal to process in batches. Go through emails when you have the time and mental bandwidth for them. I usually go through emails twice during a work day.&lt;/p&gt;

&lt;p&gt;Since emails are a longer form of content it can be an ideal place to put things for people to prepare for a meeting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Calls and meetings
&lt;/h3&gt;

&lt;p&gt;Calls and meetings are the most disruptive form of communication and should be treated with care. There should always be a clear purpose for the meeting, and a clear next step after the meeting.&lt;/p&gt;

&lt;p&gt;Because meetings are disruptive, it pays to be careful when initiating them. Ask whether the same outcome could be achieved asynchronously through another medium.&lt;/p&gt;

&lt;p&gt;Calls can be lazy communication. It takes energy to articulate something through writing, and for some people it's much easier to just 'have a call'. This is a bad habit.&lt;/p&gt;

&lt;p&gt;Our brain is tricked into feeling as though the problem is solved just by scheduling the call. Writing pushes us to refine our thoughts.&lt;/p&gt;

&lt;p&gt;Schedule calls in advance and ensure people have the time and material to prepare. Putting people on the spot without preparation will usually lead to more confusion and ambiguity.&lt;/p&gt;

&lt;p&gt;Meetings work better when you have a visual aid. Take meeting notes, with the purpose of the meeting clearly stated at the beginning.&lt;/p&gt;

&lt;p&gt;While the meeting is in progress, keep watch for whether the conversation is serving the purpose. Bring it back, and if necessary deal with other topics afterwards.&lt;/p&gt;

&lt;p&gt;Add a visual anchor if you are describing something. Share your screen to show something rather than describe it with words. Often this will include more data points that you may not have thought to mention otherwise.&lt;/p&gt;




&lt;p&gt;Communication is a piece of a developer's skillset that potentiates everything else. It is a super power, and every interaction we have is a chance to build it.&lt;/p&gt;

&lt;p&gt;We communicate through our code by taking time and care in naming variables and functions, writing commit messages, and asking for help when we run into problems.&lt;/p&gt;

&lt;p&gt;Over time it goes from a &lt;em&gt;skill&lt;/em&gt; with concrete rules like those I've listed to an &lt;em&gt;art&lt;/em&gt; that you adapt fluidly to the situation.&lt;/p&gt;

&lt;p&gt;Like coding, communication becomes stronger as you make a habit of consciously improving it. It is a collection of many small things done right. Together they create something powerful.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>productivity</category>
      <category>career</category>
      <category>management</category>
    </item>
  </channel>
</rss>
