<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Sveta Slepner Blog RSS Feed]]></title><description><![CDATA[Sveta Slepner Blog RSS Feed]]></description><link>https://svetaslepner.com</link><generator>GatsbyJS</generator><lastBuildDate>Mon, 06 Jan 2025 21:02:03 GMT</lastBuildDate><item><title><![CDATA[7 Ways I'm Utilizing the Power of AI as a Front-end Developer]]></title><description><![CDATA[chemex It's hard to believe Chat GPT was introduced to our lives merely two years ago. I'm old enough to remember how Google revolutionized…]]></description><link>https://svetaslepner.com/2025-01-06-7-ways-im-utilizing-the-power-of-ai-as-a-front-end-developer/</link><guid isPermaLink="false">https://svetaslepner.com/2025-01-06-7-ways-im-utilizing-the-power-of-ai-as-a-front-end-developer/</guid><pubDate>Mon, 06 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/w_900,h_600,q_auto,c_thumb/v1736193263/blog/banner_article_ai.webp&quot; alt=&quot;chemex&quot;&gt;&lt;/p&gt;
&lt;p&gt;It&apos;s hard to believe Chat GPT was introduced to our lives merely two years ago. I&apos;m old enough to remember how Google revolutionized my Internet use, but no other technology has disrupted the industry to such an extent since then. As a front-end developer, I’ve embraced tools like ChatGPT and its competitors (looking at you, Claude) to make my day-to-day work more efficient. So now, I would like to share some ways I’ve been using it with you.&lt;/p&gt;
&lt;p&gt;But before we dive in, a warning — AI isn’t a magic wand that replaces the need for understanding code. If you’re a junior developer, take this as a friendly heads-up: AI&apos;s answers can range from spot-on to complete nonsense. Sometimes, it’s just close enough to be misleading. So, while AI is an incredible tool, it’s only as effective as your ability to evaluate and tweak what it gives you. Think of it as a coding assistant, not a replacement for your skills.&lt;/p&gt;
&lt;p&gt;Also, don’t forget to be polite—you never know when AI might develop a conscience. ;)&lt;/p&gt;
&lt;h2&gt;1. Generate Layout Code From an Image&lt;/h2&gt;
&lt;p&gt;A recent addition to ChatGPT (new as of the end of 2024) allows you to provide it an image of an interface design, and ask it to convert it to actual code. You can even be specific with what libraries you want it to write the code with:
&quot;Convert this image to React with styled-components&quot;.
This is a pretty amazing and time-saving feature, but it&apos;s not 100% perfect, so be careful!&lt;/p&gt;
&lt;p&gt;Here&apos;s the result of my asking ChatGPT to convert this screenshot from Figma to React.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The image:&lt;/strong&gt;&lt;br/&gt;&lt;br/&gt;
&lt;img src=&quot;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7z0xxaqgbb6tu7fmkgwj.png&quot; alt=&quot;Image description&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The result:&lt;/strong&gt;&lt;br/&gt;&lt;br/&gt;&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/vlcmxx?view=preview+%2B+editor&amp;module=%2Fsrc%2FApp.js&quot;
style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
title=&quot;basic-three-js&quot;
allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
&gt;&lt;/iframe&gt;
&lt;p&gt;As you can see, the styles aren&apos;t 100% correct, but the most tedious part, the layout, was done correctly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example prompt:&lt;/strong&gt;&lt;br/&gt;
&quot;Based on the attached image, please generate react code with styled-components&quot;
&quot;Based on the attached image, please generate vue code with Tailwind CSS&quot;&lt;/p&gt;
&lt;h2&gt;2. Generate CSS Animations&lt;/h2&gt;
&lt;p&gt;I&apos;ve been a front-end developer for over 15 years, and yet, CSS animations remain a mystery to me. While I&apos;m pretty good with CSS, animations feel like an entirely different beast. I can never seem to make them look smooth. Whenever I need one, I usually end up searching for a good example on CodeSandbox.io.
However, now with the power of AI, I can ask it to generate it for me, and even give it instructions on how exactly I envision it (but can&apos;t execute it myself).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example prompt:&lt;/strong&gt;&lt;br/&gt;
&quot;Create a CSS animation of a waiving div&quot;&lt;br/&gt;
&quot;Create a CSS animation of a bouncing div. The animation should last 1s and repeat 3 times&quot;
You can also ask for improvements:
&quot;It should feel more &apos;bouncy&apos;&quot;&lt;/p&gt;
&lt;h2&gt;3. Fixing TypeScript Errors&lt;/h2&gt;
&lt;p&gt;We’ve all been there: TypeScript is yelling at you, and you have no idea why. This is especially annoying when dealing with third-party libraries, where you&apos;re not in control. Instead of hunting through docs or Stack Overflow, you can simply paste the error into an AI chat and get tailored advice almost instantly.
You can even paste the code itself and ask it to fix the issue for you.
And, if you have some JS code you would like to convert to TS, it can do that for you as well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example prompts:&lt;/strong&gt;&lt;br/&gt;
&quot;Please explain the following TS error [ERROR]&quot;&lt;br/&gt;
&quot;Please fix the following TS code [YOUR CODE]&quot;&lt;br/&gt;
&quot;Please convert the following code from JS to TS [YOUR CODE]&quot;&lt;/p&gt;
&lt;h2&gt;4. Converting One Code to Another&lt;/h2&gt;
&lt;p&gt;Need to convert a vanilla JS script into a React component? Or maybe some old &lt;code&gt;jQuery&lt;/code&gt; code to something more modern? AI handles these transformations with ease. It’s not always perfect, but it’s usually a solid 90% there, which is a great jumping-off point.
I recently tried to convert some &lt;code&gt;Hammer.js&lt;/code&gt; code to vanilla JS events and was pretty amazed at how accurately Claude did it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example prompts:&lt;/strong&gt;&lt;br/&gt;
&quot;Please convert the following code to [YOUR CHOICE HERE]&quot;&lt;/p&gt;
&lt;h2&gt;5. Writing Tests&lt;/h2&gt;
&lt;p&gt;TDD or not, writing some test coverage for your code is important to making our codebase more reliable and less prone to future issues.
However, writing tests is not necessarily fun and can sometimes be time-consuming.&lt;/p&gt;
&lt;p&gt;From my experience, it&apos;s pretty good at covering multiple use cases, including edge cases, and it even creates test titles based on my requirements (For example, Given-When-Then).&lt;/p&gt;
&lt;p&gt;Of course, the reality is not that simple, and in larger code bases testing is far more complex, but AI can still help you with at least determining what cases you might want to test for and do some of the heavy lifting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example prompt:&lt;/strong&gt;&lt;br/&gt;
&quot;Please write unit tests for the code I&apos;ll give you. Use GIVEN WHEN THEN format for the test title. [YOUR CODE HERE]&quot;&lt;br/&gt;
&quot;Please write react testing library tests for this component&quot;&lt;/p&gt;
&lt;h2&gt;6. Generate Mock Data&lt;/h2&gt;
&lt;p&gt;You are waiting for your fellow Backend developer to finish the API you need for the new UI you&apos;re working on. In the meantime, you need some data to work with. Creating mock data is a tedious process manually, especially if the data structure is complex, or requires multiple API calls.
Using AI it takes two seconds to generate any kinda mock data you need, and if your company works with Open API Schema, it&apos;s even simpler, since you can simply provide the AI with the schema, and not even give it examples.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example prompts:&lt;/strong&gt;&lt;br/&gt;
&quot;Based on the attached API schema, create a mock data for the [API] API [YOUR SCHEMA]&quot;&lt;br/&gt;
&quot;Based on the following example, please create a mock data&quot;&lt;br/&gt;&lt;/p&gt;
&lt;h2&gt;7. Accessibility&lt;/h2&gt;
&lt;p&gt;Web accessibility is an important aspect of building inclusive applications, ensuring they can be used by everyone, including people with disabilities. I believe it also makes the experience better for everyone since it simplifies the UX.
Sadly, it is often overlooked, or shoved under the rug until legal knocks on the door. Also, it&apos;s not so straightforward, and there are tons of rules and special attributes you need to learn about to make your app more accessible.
AI can help you with some of that, and give you suggestions for improving accessibility, such as adding proper ARIA roles, fixing contrast issues, or ensuring keyboard navigation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example prompts:&lt;/strong&gt;&lt;br/&gt;
&quot;Please suggest how I can make the following component accessible&quot;
&lt;br/&gt;&lt;/p&gt;
&lt;h3&gt;✨ Bonus round! Here are some more ways I&apos;m using AI, but which are not specific to Front-end ✨:&lt;/h3&gt;
&lt;h2&gt;Simplifying Code&lt;/h2&gt;
&lt;p&gt;My code writing style involves throwing everything on my mind into the IDE. Once the code works, I start a cleanup. I consolidate code, rename variables, and move functions around.
Also, I believe in KISS (keep it stupid simple), so that &quot;future me/colleague&quot; can read my code and understand it without too much hassle (and too many comments).
Using AI allows me to make some shortcuts in that process, provide it with complex code, and ask it to simplify it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example prompts:&lt;/strong&gt;&lt;br/&gt;
&quot;[YOUR CODE] please simplify this code&quot;&lt;/p&gt;
&lt;h2&gt;Boiler plating&lt;/h2&gt;
&lt;p&gt;Starting a new project or feature can be intimidating when you’re staring at a blank screen. And it&apos;s especially true if you&apos;re trying some new programming language or library.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example prompts:&lt;/strong&gt;&lt;br/&gt;
&quot;Generate a Tanstack Query hook to fetch paginated data from an API.&quot;&lt;br/&gt;
&quot;Generate a boilerplate &quot;to-do list&quot; react app with Tanstack Router and Tanstack Query&quot;&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 10px&quot;&gt;-- Special thanks to Eitan Peer for reviewing this article --&lt;/span&gt;&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[GitHub Actions - A Beginner's Guide to Automating Your Development Process]]></title><description><![CDATA[chemex As a front-end developer, I was never really drawn to the "DevOps" side of my day-to-day work. The major reason is that up until now…]]></description><link>https://svetaslepner.com/2023-02-06-github-actions-a-beginners-guide-to-automating-your-development-process/</link><guid isPermaLink="false">https://svetaslepner.com/2023-02-06-github-actions-a-beginners-guide-to-automating-your-development-process/</guid><pubDate>Mon, 06 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/w_900,q_auto/v1675634450/blog/github-actions-2.jpg&quot; alt=&quot;chemex&quot;&gt;&lt;/p&gt;
&lt;p&gt;As a front-end developer, I was never really drawn to the &quot;DevOps&quot; side of my day-to-day work. The major reason is that up until now, in all of the places I have worked in, we&apos;ve been using Jenkins. And while it&apos;s a powerful tool no doubt, it sure is unwelcoming and hard to get started with. &lt;/p&gt;
&lt;p&gt;But in recent years GitHub has stepped into the game and in 2018 released &quot;GitHub Actions&quot;, a platform for creating custom, automated development workflows directly within the GitHub ecosystem.&lt;/p&gt;
&lt;p&gt;Whether you want to create a CI/CD pipeline or automate GitHub-related flows like opening a PR, adding automated comments, or sending a Slack notification each time someone merges a commit to master, GitHub Actions can help you create these processes and save you time and effort. And the best part is &lt;strong&gt;how straightforward it is&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;In this guide, we&apos;ll cover the basics of GitHub Actions and show you how to get started with them. We&apos;ll go through the process of setting up a simple workflow and explain some of the key concepts you need to know. By the end, you&apos;ll be able to use GitHub Actions to automate your own workflow and take your productivity to the next level!&lt;/p&gt;
&lt;h2&gt;First, some GitHub Actions terminology&lt;/h2&gt;
&lt;p&gt;Well, the name might be GitHub Actions, but let&apos;s put that aside for one second. What we&apos;re actually running are workflows. A workflow is a collection of jobs that are triggered by an event.&lt;/p&gt;
&lt;p&gt;Here&apos;s an example of a simple workflow&apos;s structure:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/v1675634607/blog/github-workflow.jpg&quot; alt=&quot;A github actions workflow&quot;&gt;&lt;/p&gt;
&lt;p&gt;As you can see, this workflow is running two jobs. A &lt;strong&gt;job&lt;/strong&gt; is a set of steps that are executed in sequence. Each step of a job can be an action. An &lt;strong&gt;action&lt;/strong&gt; is an individual step within a job that can perform a variety of tasks such as running a script, building an application, deploying code, or running tests.&lt;/p&gt;
&lt;h2&gt;Setting up a workflow&lt;/h2&gt;
&lt;p&gt;GitHub actions and workflows are written in YAML, a language that is a superset of JSON and is considered easier on the eye. You&apos;ll notice that indentations are used instead of curly brackets.&lt;/p&gt;
&lt;p&gt;For GitHub to recognize your &lt;code&gt;.yml&lt;/code&gt; files as workflows you have to store them inside the following folder of your repository: &lt;code&gt;.github/workflows/[workflow-name].yml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You can add a workflow manually by pushing your own files, or going to the &quot;Actions&quot; tab in your repo and either clicking on &quot;set up a workflow yourself&quot; or selecting one of the available templates GitHub suggests.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/v1675634738/blog/getting-started-ga.png&quot; alt=&quot;getting started with github actions&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once you have at least one workflow, you&apos;ll be able to manage them from the same page, as well as dispatch, re-run failed jobs, and view the status of previous runs.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/v1675634797/blog/ga-manage-page.png&quot; alt=&quot;github actions manage page&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Understanding the workflow&apos;s structure&lt;/h2&gt;
&lt;p&gt;Let&apos;s examine this basic workflow that says hi to the person who initiated the run and then runs some tests, and understand the different parts that it&apos;s constructed from.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;CI&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;pull_request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;unit-tests&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Install&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;npm install&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Run unit tests&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;npm test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;e2e-tests&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Install&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;npm install&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Run unit tests&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;npm e2e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, we need to define the workflow&apos;s settings. We can see that this workflow has three properties: &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;on&lt;/code&gt;, and &lt;code&gt;jobs&lt;/code&gt;.
&lt;br/&gt;&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/v1675635292/blog/worflow-basics.png&quot; alt=&quot;workflow basics&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;name&lt;/code&gt; is simply the workflow&apos;s name. It&apos;s not mandatory, however, I still recommend adding one, so it&apos;ll be easier to manage your workflows in the &quot;Actions&quot; tab.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;on&lt;/code&gt; defines the trigger of the workflow. You can set one or more. For instance, in the example shown above, the workflow will run whenever a pull request is opened or a push to any branch occurs.&lt;/p&gt;
&lt;p&gt;If you want to make your trigger more specific, you can provide extra parameters. Each trigger event is different, so let&apos;s have a look at some examples.&lt;/p&gt;
&lt;p&gt;1. &lt;strong&gt;A push to specific branches&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;master&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this one, we want the workflow to run on a push event, but only when the branch name equals the ones we provide using the &lt;code&gt;branches&lt;/code&gt; property. In this case, it&apos;s &quot;master&quot; or &quot;test&quot;. If we push something to a branch named &quot;test2&quot;, nothing will happen.&lt;/p&gt;
&lt;p&gt;By the way, in YAML arrays can be defined with square brackets or like so:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;master&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the exact same thing! You might see both styles in use, and it&apos;s up to your preference.&lt;/p&gt;
&lt;p&gt;Anyway, we can be even more specific, for instance, mention only branches that start with &lt;code&gt;tests/&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;tests/**&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or do the opposite and accept &lt;strong&gt;all&lt;/strong&gt; branches but ignore everything that starts with &lt;code&gt;tests/&lt;/code&gt; by using &lt;code&gt;branches-ignore&lt;/code&gt; instead of &lt;code&gt;branches&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;branches-ignore&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;tests/**&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;Scheduled workflow&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;schedule&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;cron&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;0 6 * * *&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can make our workflow run automatically on a scheduled basis, using the &lt;code&gt;schedule&lt;/code&gt; trigger. In this example, the workflow will run every day at 6:00 AM. You can see that schedule receives an array, so you can add multiple &lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule&quot;&gt;cron settings&lt;/a&gt; if you wish.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;strong&gt;Manual workflow dispatch&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Another common trigger is &lt;code&gt;workflow_dispatch&lt;/code&gt; which allows us to manually trigger the workflow directly from the GitHub Actions UI. It can even be configured to require parameters that can be later accessed by our actions.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;workflow_dispatch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Sveta&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;A name passed from the caller workflow&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Print the name&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo &amp;quot;Hi there, ${{ inputs.name }}&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is what it looks like inside the GitHub UI:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/v1675635759/blog/github-ui.png&quot; alt=&quot;github ui&quot;&gt;&lt;/p&gt;
&lt;p&gt;There are many more possible triggers and configurations, so going to the &lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on&quot;&gt;documentation&lt;/a&gt; is the best place to learn more.&lt;/p&gt;
&lt;p&gt;ℹ️ Note&lt;br&gt;
When you see an expression wrapped with &lt;code&gt;${{}}&lt;/code&gt; know that it&apos;s a way to access a variable&apos;s value, as seen in the example above. This is the way to get &lt;a href=&quot;https://docs.github.com/en/actions/learn-github-actions/contexts#github-context&quot;&gt;context&lt;/a&gt; information (like which branch we&apos;re on), &lt;a href=&quot;https://docs.github.com/en/actions/learn-github-actions/contexts#secrets-context&quot;&gt;secrets&lt;/a&gt;, our workflow&apos;s input values, and more.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo &amp;quot;Hi there, ${{ inputs.name }}&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Let&apos;s get things running: the &quot;jobs&quot; property&lt;/h2&gt;
&lt;p&gt;So up until now, we set up a trigger to our workflow, but now let&apos;s get into what the workflows are actually doing - running jobs that trigger our actions!&lt;/p&gt;
&lt;p&gt;When creating a workflow you can set it to run one or more jobs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unless configured otherwise, jobs run in parallel and don&apos;t depend on previous jobs to finish first.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/v1675636309/blog/jobs.png&quot; alt=&quot;jobs&quot;&gt;&lt;/p&gt;
&lt;p&gt;In the scenario above, our workflow runs two jobs: &quot;unit-tests&quot; and &quot;e2e-tests&quot;, and while the workflow is activated, the jobs will run simultaneously. We will see later how we can create dependencies between jobs.&lt;/p&gt;
&lt;p&gt;To define a job, we first give it an id (can be anything we like), and then we need to provide it with some configuration. &lt;/p&gt;
&lt;p&gt;There are 2 mandatory parameters:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;runs-on&lt;/code&gt; : This configures the job&apos;s runner. Runners are virtual machines (VMs) used to run the tasks defined in our jobs. GitHub provides hosted runners for each operating system (Linux, macOS, and Windows). You can see the full list of available runners here, as well as their specifications. If you require more granular control over your VM, you can self-host your own runners. One use case for using self-hosted runners is resource utilization. If you need to run your actions on stronger machines, &lt;a href=&quot;https://docs.github.com/en/actions/hosting-your-own-runners&quot;&gt;explore this option&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;steps&lt;/code&gt; - Here we list the array of actions the job will execute. The steps are executed one by one. We will go over actions in the next section.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Some notable optional parameters:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt; - Just like with workflows, it is not mandatory to provide a name for your job, but it&apos;s useful for visualization of your flow. &lt;/li&gt;
&lt;li&gt;&lt;code&gt;needs&lt;/code&gt; - Remember that we said that jobs don&apos;t depend on each other, and run in parallel? But we can create this dependency by using the &quot;needs&quot; param. Let&apos;s see the example below:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;unit-tests&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Install&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;npm install&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Run unit tests&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;npm test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;e2e-tests&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Install&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;npm install&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Run unit tests&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;npm e2e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;send-slack-notification&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;needs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;unit-tests&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;e2e-tests&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Send notification&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;rtCamp/action-slack-notify@v2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;SLACK_WEBHOOK&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ secrets.SLACK_WEBHOOK }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;SLACK_CHANNEL&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;team-ci&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;SLACK_TITLE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Finished running tests&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;SLACK_MESSAGE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Hooray :rocket:&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see that the last job, &lt;code&gt;send-slack-notification&lt;/code&gt; requires &lt;code&gt;unit-test&lt;/code&gt; and &lt;code&gt;e2e-tests&lt;/code&gt; to finish, since we want to send that slack notification only when both of these jobs are done executing.&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;code&gt;if&lt;/code&gt; - We can add a condition to our job that will allow us to set it to run only if some condition/s are met. For instance, let&apos;s say that our workflow can be triggered by both push and pull_request events, but we want to run a specific job in this flow that will only run if the trigger was specifically a &quot;push&quot; event.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;pull_request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;print-something-on-push&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;github.event_name == &amp;#39;push&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Print&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo &amp;quot;This job runs on push only&amp;quot;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;print-always&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Print&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo &amp;quot;This job always runs&amp;quot;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;code&gt;outputs&lt;/code&gt; - A job can produce an output that can later be accessed by other jobs (combined with &lt;code&gt;needs&lt;/code&gt; of course, as we have to wait for that job to resolve first). The output is an object, so you can pass any number of parameters that you want.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;10&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Job outputs test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;workflow_dispatch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Version&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;prepare-version-id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;version_w_hyphens&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ steps.replace-string.outputs.replaced }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;frabert/replace-string-action@v2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;replace-string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;\.&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ inputs.version }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;replace-with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;print&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo ${{ steps.replace-string.outputs.replaced }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;print-stuff&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;needs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;prepare-version-id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;print version id from another job&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo ${{needs.prepare-version-id.outputs.version_w_hyphens}}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, we have a workflow that expects a string input called &lt;code&gt;version&lt;/code&gt; on dispatch. &lt;/p&gt;
&lt;p&gt;Then, let&apos;s imagine that we need this version for multiple usages, and some of them require us to replace the dots in the string with hyphens.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;11&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;prepare-version-id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;       &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;version_w_hyphens&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ steps.replace-string.outputs.replaced }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see that &lt;code&gt;prepare-version-id&lt;/code&gt; defines the &lt;code&gt;outputs&lt;/code&gt; object, with one item - &lt;code&gt;version_w_hyphens&lt;/code&gt; which returns the value of the step that was responsible for replacing the dots with hyphens. Actions can return output as well, but more on that later. 
Then inside the other job called &lt;code&gt;print-stuff&lt;/code&gt; we can access this value by calling &lt;code&gt;needs.[job-id].outputs.[outpus-key]&lt;/code&gt; and in our case &lt;code&gt;needs.prepare-version-id.outputs.version_w_hyphens&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Now to the star of the show: Actions&lt;/h2&gt;
&lt;p&gt;As we stated before, jobs run an array of steps, where each step executes an action, where an action is a set of commands or tasks. There are 3 kinds of actions you can work with.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Using open-sourced actions&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the most part, there&apos;s a high probability that someone already has created a solution for at least some of the tasks you wish to accomplish. For instance, if you need to send a slack notification, publish to GitHub pages, upload an artifact, and so on, the community has got you covered.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;12&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Checkout&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;actions/checkout@v3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is an example of one of the most useful public actions there are, that allows you to checkout to the branch that&apos;s in the workflow&apos;s context (or to another one if you wish). 
All you have to do in order to use such an action is to create a step with the &lt;code&gt;uses&lt;/code&gt; property and provide the action&apos;s location, ie &lt;code&gt;[github-user]/[repo]@[version]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can specify a specific version, for example &lt;code&gt;@v3&lt;/code&gt; in that case, or simply refer to the latest possible version by using &lt;code&gt;@master&lt;/code&gt; (though then you&apos;re opening yourself to be affected by bugs or breaking changes).&lt;/p&gt;
&lt;p&gt;That&apos;s it. You don&apos;t have to actually install or configure anything.&lt;/p&gt;
&lt;p&gt;Some actions might expect some input parameters (or have some optional ones). In that case, all you have to do is to add thewith: property to the step and pass the required values.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;13&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;frabert/replace-string-action@v2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Replace string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;replace-string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;\.&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ inputs.version }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;replace-with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some actions might also return some sort of output. For instance, in this example, we use this action to run some regex expression on a string, so naturally, we need the result.
To do that we will need to provide an &lt;code&gt;id&lt;/code&gt; to the step, so we can access it later by calling &lt;code&gt;steps.[step-id].outputs.[key]&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;14&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;frabert/replace-string-action@v2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;replace-string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;\.&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ inputs.version }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;replace-with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;print replaced value from previous step&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo ${{ steps.replace-string.outputs.replaced }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⚠️ You should use caution with 3rd party actions as they may contain malicious code or vulnerabilities that can compromise the security of your project and lead to a data breach or other negative consequences. Make sure to check if the action is properly maintained and has a community base.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;Running shell commands&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can also run our own code, by running shell commands. The default depends on the kind of runner you&apos;re using. For instance, for Linux (ubuntu) it would use bash. You can change the shell type by providing an explicit one. See all the possible shells &lt;a href=&quot;https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;15&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Run install&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;npm install&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;bash&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;#an optional setting&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To run a multiline script, we can use a pipeline, like so:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;16&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Run install and test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;        npm install    &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;        npm test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In case we want our action to provide an output that can be accessed by other actions, we have to run the following command:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;17&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Set output&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo &amp;quot;{name}={value}&amp;quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can set as many as we want. Accessing the values from other steps follows the same convention as mentioned in the previous section.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;18&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;example&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;      echo &amp;quot;animal=&amp;#39;Dog&amp;#39;&amp;quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT  &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;      echo &amp;quot;name=&amp;#39;Fluffy&amp;#39;&amp;quot; &amp;gt;&amp;gt; $GITHUB_OUTPUT&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Print&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;      echo &amp;quot;Animal type: ${{steps.example.outputs.animal}}&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;      echo &amp;quot;Animal name: ${{steps.example.outputs.name}}&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;strong&gt;Running an action from a file&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&apos;s say we have a custom-made action that we use in multiple workflows and we don&apos;t want to repeat writing. In that case, we can create an action.yml file and store it inside our repo inside the following path: &lt;code&gt;.github/actions/[action-id]/action.yml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&apos;s an example action that&apos;s using the composite action method where you can create an action with the regular YML syntax and run one or more steps:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;19&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;My Action&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;An example of a custom action&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;A message to print&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;runs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;composite&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo Hello ${{ inputs.message }}.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;bash&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we can refer to it by calling it like this:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;20&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;My Workflow&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;push&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;print-message&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Print message&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;./.github/actions/my-action&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Hello, world!&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are other methods to create actions, where you create the action.yml file just to set up the input and output params and the script itself is written in other languages of your choice (JS, python, shell, and more).
You can read about it &lt;a href=&quot;https://docs.github.com/en/actions/creating-actions&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Some other action settings&lt;/h2&gt;
&lt;p&gt;Actions have some other parameters that are worth mentioning. 
Of course, the &lt;code&gt;name&lt;/code&gt; parameter, which again will make it easier to follow in the log, but the most useful one is &lt;code&gt;if&lt;/code&gt;. We already discussed it as a possible parameter for jobs, but actions can also be limited to running only on condition.&lt;/p&gt;
&lt;p&gt;One of the useful conditions we can check for is the job&apos;s status. For instance, send a failure message to Slack, but only when the job has failed. See the full list of status checks &lt;a href=&quot;https://docs.github.com/en/actions/learn-github-actions/expressions#status-check-functions&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;21&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;The job has succeeded&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ success() }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# do something if all the previous steps have finished successfuly&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;The job has failed&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ failure() }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# do something if the job has filed&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another useful action property is &lt;code&gt;continue-on-error&lt;/code&gt;. By default, if one step of a job failed, it will cause the entire job to end with the &quot;failure&quot; status. However, sometimes we might want to not count this failure as part of the whole job&apos;s status. In that case, we can pass this property to make the run ignore this step&apos;s status.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;22&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Ignore my failure&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;continue-on-error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Testing our workflow&lt;/h2&gt;
&lt;p&gt;So now that we have a workflow, how do we actually test it?
Well, it&apos;s simple and tricky at the same time. To be able to run a workflow its file must either exist on the master/main branch or use a trigger that occurs when pushing to the branch we&apos;re writing our action on.&lt;/p&gt;
&lt;p&gt;If the workflow happens to have a &lt;code&gt;worflow_dispatch&lt;/code&gt; trigger and we want to try some changes, we can apply them to a branch, add initiate the workflow from our branch.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/v1675699560/blog/worflow-dispatch.png&quot; alt=&quot;workflow dispatch&quot;&gt;&lt;/p&gt;
&lt;p&gt;There is also another way that allows you to run actions locally on your machine, but it&apos;s a little trickier to set up. You can read about it &lt;a href=&quot;https://github.com/nektos/act&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And that&apos;s it! These were the basics of what you need to know to get started with GitHub actions. Hope you will find it useful!&lt;/strong&gt;&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .default-dark .mtk4 { color: #569CD6; }
  .default-dark .mtk1 { color: #D4D4D4; }
  .default-dark .mtk8 { color: #CE9178; }
  .default-dark .mtk3 { color: #6A9955; }
  .default-dark .mtk15 { color: #C586C0; }
  .default-dark .mtk7 { color: #B5CEA8; }
  .default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Getting Started With Three.js]]></title><description><![CDATA[chemex The ability to render 3D objects in the browser opens up many exciting possibilities for creating interactive experiences. Whether…]]></description><link>https://svetaslepner.com/2022-03-15-getting-started-with-threejs/</link><guid isPermaLink="false">https://svetaslepner.com/2022-03-15-getting-started-with-threejs/</guid><pubDate>Tue, 15 Mar 2022 15:00:10 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/w_900,q_auto/v1675612385/blog/1_gpGc28Fet1z9ikx5ULB28Q.jpg&quot; alt=&quot;chemex&quot;&gt;&lt;/p&gt;
&lt;p&gt;The ability to render 3D objects in the browser opens up many exciting possibilities for creating interactive experiences. Whether you’re looking for a new way to showcase products on your e-commerce site, creating stunning landing pages, or maybe even developing a game.&lt;/p&gt;
&lt;p&gt;Since handling WebGL directly (JavaScript API for rendering interactive 2D and 3D graphics within any compatible web browser) can be complex, libraries, such as three.js, provide a simplified way to deal with rendering, animating, and interacting with 3D objects, while doing all the heavy lifting behind the scenes.&lt;/p&gt;
&lt;p&gt;With that being said, three.js itself can still be a little overwhelming for developers who have never dealt with 3D before. Hopefully, this article will get you up to speed and present the necessary basis, that may assist you even if you’ll require more advanced features later on.&lt;/p&gt;
&lt;p&gt;What does it take to render a simple cube?
The reason why working with 3D for a web developer might be confusing at first, is that even a simple task such as rendering a cube requires some knowledge in 3D jargon.&lt;/p&gt;
&lt;p&gt;If for instance, someone tells you, the web developer, to render a red box, I bet what you have in mind is “ok, I’ll create a div, use some CSS to size, place, and color it”. Pretty straightforward.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/q_auto/v1675620900/blog/oeay6m95y897qsfyxtya.jpg&quot; alt=&quot;A simple red box created with css&quot;&gt;&lt;/p&gt;
&lt;p&gt;However, to do the same in 3D will require you to:
A. Create something called a “scene”
B. Define a cube geometry
C. Create a material and attach it to the cube (to make it red)
D. Create a camera
E. Add lighting
F. Tell three.js to render all that&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/basic-three-js-3z9rr?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;basic-three-js&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;h2&gt;The scene&lt;/h2&gt;
&lt;p&gt;In three.js, a scene is like a container that holds all the objects used to render our 3D image. Think about a theatre stage, where we place the actors, the set, and the lighting.
In the same manner, we assign 3D objects and lighting to a scene.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Creating a scene&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;scene&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Scene&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;geometry&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BoxGeometry&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;material&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MeshStandardMaterial&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;({ &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;color:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0xff0000&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cube&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Mesh&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;geometry&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;material&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Assigning a 3D object to our scene&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;scene&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;geometry&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;directionalLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DirectionalLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0xffffff&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;directionalLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Adding a light source to our scene&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;scene&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;directionalLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And just like we might have multiple stage sets in our theatre, each showing a different play, we can create multiple scenes and switch between them, or render them simultaneously.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/q_auto/v1675620953/blog/pw4y7z0n129w1r0u2rbf.png&quot; alt=&quot;Origin: https://threejs.org/examples/?q=camera#webgl_camera&quot;&gt;&lt;br&gt;
Source: &lt;a href=&quot;https://threejs.org/examples/?q=camera#webgl_camera&quot;&gt;https://threejs.org/examples/?q=camera#webgl_camera&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;3D geometry&lt;/h2&gt;
&lt;p&gt;A 3D geometry is basically a set of instructions for “how to create a 3D shape”. It consists of faces, edges, and vertices.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/q_auto/v1675620993/blog/aotqw33lcr8ny85jeaap.jpg&quot; alt=&quot;Source: https://en.wikipedia.org/wiki/Polygon_mesh&quot;&gt;&lt;br&gt;
Source: &lt;a href=&quot;https://en.wikipedia.org/wiki/Polygon_mesh&quot;&gt;https://en.wikipedia.org/wiki/Polygon_mesh&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Luckily, three.js provides us with some built-in geometry classes, such as BoxGeometry, SphereGeometry, CylinderGeometry, and so on.&lt;/p&gt;
&lt;p&gt;For example, to create a simple box, all we need to do is to provide the width, height, and depth. We don’t need to delve into the complexities of defining all the faces ourselves.&lt;/p&gt;
&lt;p&gt;The size unit used in three.js represents meters, so 1 unit = 1 meter.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;geometry&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BoxGeometry&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/q_auto/v1675621050/blog/u60eiyzo4iutp3412tt0.jpg&quot; alt=&quot;3D Shapes&quot;&gt;&lt;br&gt;
Source: &lt;a href=&quot;https://en.wikipedia.org/wiki/Shape&quot;&gt;https://en.wikipedia.org/wiki/Shape&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In case you’re not happy with the existing geometries or need to create your own geometry classes, it is very possible. You can see some examples provided by three.js &lt;a href=&quot;https://github.com/mrdoob/three.js/tree/dev/examples/jsm/geometries&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Materials&lt;/h2&gt;
&lt;p&gt;Imagine holding two cubes in your hands, one made from glass, and the other from concrete. Both maybe have the same shape, but they look different and have distinct physical attributes such as reflectiveness, surface, and opacity.&lt;/p&gt;
&lt;p&gt;In the 3D world, we use materials to define such attributes for our 3D objects.&lt;/p&gt;
&lt;p&gt;With three.js we can either create our own materials with the built-in Material classes (such as MeshMatcapMaterial or MeshLambertMaterial), each has its own attributes, or load materials externally using MaterialLoader.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// A basic material, just coloring our cube red&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;material&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MeshStandardMaterial&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;({ &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;color:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0xff0000&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Texture maps are also worth mentioning. These are image files that can be used to define much more detailed materials, and make them look real. There are many types of texture maps, such as “diffuse map” which defines the colors, or the “normal map” which defines the surface of our object. Typically multiple texture maps are applied together. &lt;a href=&quot;https://conceptartempire.com/texture-maps/&quot;&gt;This great article&lt;/a&gt; explains each texture map in detail.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/q_auto/v1675621075/blog/b27krogq9u1118elpxrn.png&quot; alt=&quot;Multiple texture maps are used to define the realistic texture of a ball of grass and soil
&quot;&gt;
Multiple texture maps are used to define the realistic texture of a ball of grass and soil&lt;/p&gt;
&lt;h2&gt;Mesh&lt;/h2&gt;
&lt;p&gt;A mesh is an object representing part of the model. It contains a geometry and its material. A 3D model can be constructed from multiple meshes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/q_auto/v1675621104/blog/v2nwokb79anw1jlq9i6r.png&quot; alt=&quot;Each highlighted part is a mesh. All meshes combined define the model&quot;&gt;&lt;br&gt;
Each highlighted part is a mesh. All meshes combined define the model.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;geometry&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BoxGeometry&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;material&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MeshStandardMaterial&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;({ &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;color:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0xff0000&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cube&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Mesh&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;geometry&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;material&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Loaders&lt;/h2&gt;
&lt;p&gt;Sometimes we would like to import 3D models from existing files created by 3D modeling programs, and not create them from scratch. For that, we can use loaders, which are functions that are responsible for loading such files and converting them into three.js objects.&lt;/p&gt;
&lt;p&gt;There is a different loader for each separate type of 3D file. For instance, loading a GLTF file would look like this:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;GLTFLoader&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;three/examples/jsm/loaders/GLTFLoader.js&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;loader&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;GLTFLoader&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;loader&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// resource URL&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;https://somesite.com/3dmodels/fox.gltf&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// called when the resource is loaded&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ( &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;gltf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;		&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;scene&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;( &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;gltf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;scene&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;	},&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// called while loading is progressing&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ( &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;		&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;( ( &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;loaded&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; / &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; * &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ) + &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;% loaded&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;	},&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// called when loading has errors&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;	&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ( &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;		&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;( &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;An error happened&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Did you notice that the GLTFLoader class is not imported from the “three” packages directly but from some mysterious “examples” folder? This is because loaders are not part of the core three.js library, but an extension. Despite the misleading name (“examples”), this folder contains some official extensions, that are maintained together with the base package.&lt;/p&gt;
&lt;p&gt;The idea is that if you’re not happy with one of them, or need some extra features, you can simply copy these files to your project and modify them as you see fit. Of course, you can also use loaders or other extensions made by other developers.&lt;/p&gt;
&lt;h2&gt;Camera&lt;/h2&gt;
&lt;p&gt;A camera is like a window to our scene. Without a camera defined, we simply see nothing. When defining a camera we create what is called a “frustum” — a mathematical term for a four-sided rectangular pyramid with the top cut off.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;perspectiveCamera&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PerspectiveCamera&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// fov — Camera frustum vertical field of view.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; / &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// aspect — Camera frustum aspect ratio.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// near — Camera frustum near plane.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// far — Camera frustum far plane.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/q_auto/v1675621129/blog/qxp2h5xggokj4f0z8ijc.png&quot; alt=&quot;A frustrum&quot;&gt;&lt;/p&gt;
&lt;p&gt;There are multiple types of cameras in three.js, but the two most useful ones are the perspective camera and the orthographic camera.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Perspective camera&lt;/strong&gt; — In this mode, depth perception is emulated in order to reflect the way the human eye perceives the world. For example, if one cube is positioned closer to us than the other, it will appear to be larger. This is the most common camera you’ll probably use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Orthographic camera&lt;/strong&gt; — With the orthographic camera, there is no depth perception, so no matter where the object is placed in the scene, it will look the same size. This is useful for isometric games, for instance.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/q_auto/v1675621196/blog/joh2at2p15rxzdi0bsip.png&quot; alt=&quot;An isometric video game using an orthographic camera&quot;&gt;&lt;br&gt;
An isometric video game using an orthographic camera&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/orthographic-and-perspective-fd99jm?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;orthographic-and-perspective&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;h2&gt;Lighting&lt;/h2&gt;
&lt;p&gt;Just like in real life, without lights, our scene would become pitch black.&lt;/p&gt;
&lt;p&gt;Three.js has multiple built-in light sources we can use and even combine to create the perfect setting.&lt;/p&gt;
&lt;p&gt;It’s worth noting that some light classes support casting shadows, while some don’t, and it depends on their physics. For instance, “Dynamic Light” is a light that gets emitted in a specific direction. This light will behave as though it exists infinitely far away and the rays produced from it are all parallel. A common use case for this is to simulate daylight. Since it’s a one-directional light, it can emit shadows.&lt;/p&gt;
&lt;p&gt;The AmbientLight on the other hand is a light that globally illuminates all objects in the scene equally. Since every spot in the scene receives the same amount of light, AmbientLight can’t be used to cast shadows.&lt;/p&gt;
&lt;p&gt;When defining a light we would usually provide color and intensity.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;directionalLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DirectionalLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0xffffff&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;directionalLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lights can also come from external sources, like HDR files (An HDR is a 360-degree high dynamic range image wrapped around a 3D model.)&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/three-js-lighting-and-hdr-loader-eiomr5?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;three-js-lighting-and-hdr-loader&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;h2&gt;Shadows&lt;/h2&gt;
&lt;p&gt;Casting shadows is a pretty expensive calculation, so in three.js it’s turned off by default. In order to support it we will need to:&lt;/p&gt;
&lt;p&gt;A. Turn on shadow support for the renderer (see next section about what a renderer is). We will also need to provide a type of shadow map, each provides a little different effect and calculation efficiency. See the details &lt;a href=&quot;https://threejs.org/docs/#api/en/constants/Renderer&quot;&gt;here&lt;/a&gt; under “Shadow Types”.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shadowMap&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shadowMap&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;PCFSoftShadowMap&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;B. Tell each individual mesh if it should emit and/or receive shadows.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;cube&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Mesh&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;geometry&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;material&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;cube&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;castShadow&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;cube&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;receiveShadow&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;C. Allow the light source to cast a shadow. We also should provide the shadow map size and bias, which modifies the shadows pixelation.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;spotLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SpotLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0xffffff&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// make it cast shadows&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;spotLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;castShadow&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;spotLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shadow&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mapSize&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;spotLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shadow&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mapSize&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;spotLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shadow&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;bias&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = -&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0.0001&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/three-js-shadow-vuulk9?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;three-js-shadow&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;h2&gt;Renderer&lt;/h2&gt;
&lt;p&gt;The render class is used for… well… rendering all of the scene components into the canvas element. This one is pretty straightforward.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;10&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// define the renderer&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;WebGLRenderer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;({ &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;antialias:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;alpha:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setPixelRatio&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devicePixelRatio&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setSize&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;innerWidth&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;innerHeight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// append the rendered to the dom&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;domElement&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// render the scene&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;scene&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;camera&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will need to provide the desired canvas size using the setSize property, and the pixel density of the device. Note that in a case where the size of the canvas is responsive and depends on the page size, we should update the renderer and camera on window resize.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;11&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;onWindowResize&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;camera&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;aspect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;innerWidth&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; / &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;innerHeight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;camera&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;updateProjectionMatrix&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setSize&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;innerWidth&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;innerHeight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Animating&lt;/h2&gt;
&lt;p&gt;More often than not, we’re not going to use three.js just to render one static 3D image. We would want the user to interact with the scene or create animations. To make three.js re-render the canvas, we would need to call renderer.render(scene, camera); each time.&lt;/p&gt;
&lt;p&gt;If our changes are frequent, however, for instance when we add an auto rotation effect to our scene, we can simply do something like this:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;12&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Schedual the next update&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;requestAnimationFrame&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Some other changes that should occur on animate&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// for instance, here we can rotate the cube a litle on every frame&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cube&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;rotation&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; += &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cube&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;rotation&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; += &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// re-render&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;renderer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;scene&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;camera&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is also required to support loaded 3D files which come with their own animation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/v1675621226/blog/d637v24968sx2spc1l80.gif&quot; alt=&quot;Animation loop from file
&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Camera controls&lt;/h2&gt;
&lt;p&gt;Camera control is another type of extension that adds a layer of interactivity to our scene, allowing the users to zoom in and out, rotate the scene or even navigate within it.&lt;/p&gt;
&lt;p&gt;Let’s take as an example one of the more common camera controls: the orbit controls, which just by defining them lets the user rotate and zoom into the scene.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;const orbitControls = new OrbitControls(camera, renderer.domElement);&lt;/code&gt;
Orbit controls have some other neat features out of the box, like adding autorotation to the scene.&lt;/p&gt;
&lt;p&gt;Note that you will have to add &lt;code&gt;orbitControls.update()&lt;/code&gt; to your animate function in order to support it.&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/three-js-controls-bqov8b?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;three-js-controls&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;h2&gt;Mouse events&lt;/h2&gt;
&lt;p&gt;Three.js essentially rendered a canvas, and as such, picking up mouse events is trickier than what you might be used to.&lt;/p&gt;
&lt;p&gt;So what happens if you need to track clicks or hover over a 3d object? That’s what the Raycaster class is for. Raycasting is used for working out what objects in the 3d space the mouse is interacting with.&lt;/p&gt;
&lt;p&gt;Here’s a basic example of how to pick up clicked on objects:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;13&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Raycaster&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;raycaster&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Raycaster&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pointer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Vector2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;intersect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pointerPos&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;raycaster&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setFromCamera&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pointerPos&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;camera&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;raycaster&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;intersectObjects&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;scene&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;click&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// calculate pointer position in normalized device coordinates&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pointer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;clientX&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; / &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;innerWidth&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) * &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; - &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pointer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = -(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;clientY&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; / &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;innerHeight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) * &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; + &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// calculate objects intersecting the picking ray&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;intersectedObjects&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;intersect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pointer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;intersectedObjects&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// do something with the objects our mouse intercted with&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And a demo, so you can see it in action:&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/raycaster-three-js-t72zu3?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;raycaster-three-js&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;p&gt;And that should cover all the basics. Hopefully, three.js makes a little more sense now!&lt;/p&gt;
&lt;h2&gt;Extra read&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://discoverthreejs.com/&quot;&gt;https://discoverthreejs.com/&lt;/a&gt; — An amazing free online three.js book and guide. A great resource to learn from.
&lt;a href=&quot;https://threejs.org/examples&quot;&gt;https://threejs.org/examples&lt;/a&gt; — the three.js documentation is not beginner-friendly, but it does worth using the examples section to get ideas and learn about more complex topics.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .default-dark .mtk3 { color: #6A9955; }
  .default-dark .mtk4 { color: #569CD6; }
  .default-dark .mtk1 { color: #D4D4D4; }
  .default-dark .mtk12 { color: #9CDCFE; }
  .default-dark .mtk10 { color: #4EC9B0; }
  .default-dark .mtk7 { color: #B5CEA8; }
  .default-dark .mtk11 { color: #DCDCAA; }
  .default-dark .mtk15 { color: #C586C0; }
  .default-dark .mtk8 { color: #CE9178; }
  .default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[React — 5 Things That Might Surprise You]]></title><description><![CDATA[The React library is pretty straightforward and is relatively easy to get into, especially with the wide variety of materials that exist to…]]></description><link>https://svetaslepner.com/2021-06-08-react-5-things-that-might-surprise-you/</link><guid isPermaLink="false">https://svetaslepner.com/2021-06-08-react-5-things-that-might-surprise-you/</guid><pubDate>Tue, 08 Jun 2021 11:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The React library is pretty straightforward and is relatively easy to get into, especially with the wide variety of materials that exist to help you learn it. But every tool has its share of tricks or issues that these tutorials usually don’t cover. You get to learn them when someone reviews your code, or worse — when you’re facing a problem and are desperate to find a solution. Hopefully, with this article, I might reveal some of these things about React, and maybe even surprise you!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/w_900,q_auto/v1675946414/blog/5-react.jpg&quot; alt=&quot;React 5 Things That Might Surprise You&quot;&gt;&lt;/p&gt;
&lt;p&gt;1. &lt;strong&gt;Setting the state by using the previous state is unpredictable.&lt;/strong&gt;
State management is the foundation of React, and while &lt;code&gt;useState&lt;/code&gt; is probably the most common hook, there might be some unawareness of its actual behavior.&lt;/p&gt;
&lt;p&gt;Let’s have a look at the following component:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;react&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;./styles.css&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setCounter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;App&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Counter: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;button&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setCounter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; + &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setCounter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; + &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        +&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What would you expect the value of the counter state to be, after a user clicks on the button?&lt;/p&gt;
&lt;p&gt;A. 2&lt;br&gt;
B. 1&lt;/p&gt;
&lt;p&gt;Not sure? Try it out yourself:&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/set-state-async-kkyix?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;set-state-async&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;p&gt;Well, whether you knew that, guessed correctly. or just tested the demo — the answer is B!&lt;/p&gt;
&lt;p&gt;The reason is that during our state update we used the previous state value: &lt;code&gt;setCounter(count + 1)&lt;/code&gt;. Essentially, the state setter function is wrapped inside the functional component closure, so it is provided with the value that was captured in that closure. It means that when it will eventually be executed (the state setter function is asynchronous), it might hold a state value that is no longer relevant. On top of that, consecutive execution of setState might cause React’s scheduling algorithms to handle multiple very fast state updates using the same event handler.&lt;/p&gt;
&lt;p&gt;The same problem might also occur when setting the state inside an asynchronous function:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;={() =&amp;gt; { &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setTimout&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(() =&amp;gt; { &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setCounter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; + &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;); ), &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But, no worries, React actually provides an easy solution to this problem — &lt;strong&gt;“functional updates”&lt;/strong&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;setCounter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;prevCounter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;prevCounter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; + &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of passing the value directly to &lt;code&gt;setCounter&lt;/code&gt;, we pass a function. This function receives as a parameter the &lt;strong&gt;previous state&lt;/strong&gt;.
This way we can be sure that React provides us the correct value of the previous state, and avoid the scenarios that might cause the unexpected behavior.&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/set-state-async-functional-update-uhzze?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;set-state-async-functional-update&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;p&gt;&lt;strong&gt;Whenever your state update is relying on the previous state, be sure to use functional updates!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Another benefit of this is to allow correct memoization of functions, since passing the value as a dependency would re-create the function on every state change.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// incorrect&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useCallback&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(() &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setCounter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; + &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}, [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// correct&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useCallback&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(() &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setCounter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;prevCounter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;prevCounter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; + &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}, []);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2. &lt;strong&gt;You can use useRef to store a static variable&lt;/strong&gt;&lt;br&gt;
We are accustomed to using the ref mechanism in React as a means to access an element’s DOM node, whether because we need it to calculate its size, set a focus status, or basically do anything React can’t do naturally. But refs can also be used for a different purpose — something that we could achieve for free with class components, but we can’t with functional ones — keep a static variable that won’t be recreated on every render.&lt;/p&gt;
&lt;p&gt;Why would we need to do so? Well, it really depends on the situation. For instance, let’s say we’re using some javascript library that was not written for React.&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/use-ref-lffhh?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;use-ref&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;p&gt;In this example, we have a class Dog. Dog has two functions — one to set its name, and one to bark it.&lt;/p&gt;
&lt;p&gt;If we tried to create the instance of this class using a simple variable, what would happen is that in case (for any reason) the component is re-rendered, a new instance will be created. So any changes we did so far will go away.&lt;/p&gt;
&lt;p&gt;But by using a ref, we will be able to keep our instance alive, until we decide to override it by setting a new value to ref.current.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;someRef&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;newValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3. React can be forced to re-mount a component&lt;/strong&gt;&lt;br&gt;
Writing to the DOM is one of the more costly actions that can be done by React. This is why we usually don’t want to remount components unless it’s absolutely necessary. Alas — sometimes we must, for various reasons. So on that occasion, how do we even tell react to unmount and immediately mount again a component? With a simple trick — by providing a key to our component, and changing its value.&lt;/p&gt;
&lt;p&gt;The key prop is a special React property you most likely have learned about the first time you tried to render an array of components.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/f_auto/v1675947008/blog/react-error.jpg&quot; alt=&quot;The famous React warning&quot;&gt;&lt;/p&gt;
&lt;p&gt;A key is something that helps React keep track of an element, even if we’ve changed its position within our component’s structure or re-rendered the parent (Otherwise each render would cause the entire component array to be re-mounted, which is bad for performance).&lt;/p&gt;
&lt;p&gt;Using this mechanism, we can trick React to think a component is not the same as its previous self and cause it to re-mount.&lt;/p&gt;
&lt;p&gt;See for yourself:&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/unmount-with-key-gwr2p?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;unmount-with-key&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;p&gt;Why would we need that at all, by the way? Well, it’s a quick way to create a “reload” button for your app, for example. Another use case is mixing DOM handling with React, where we want React’s state to reflect updates that were made to the DOM from “outside”.&lt;/p&gt;
&lt;p&gt;But it should still be avoided unless it&apos;s the last resort.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Context doesn’t work the way you would expect it to&lt;/strong&gt;&lt;br&gt;
Context API is a great built-in solution for sharing state between components and avoiding “prop drilling” — passing props multiple levels down — from one component to the other, sometimes just for the sake of passing them down where it&apos;s actually needed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/f_auto/v1675947110/blog/context-inigo.jpg&quot; alt=&quot;context&quot;&gt;&lt;/p&gt;
&lt;p&gt;While it’s very useful, it also has its limitations.&lt;/p&gt;
&lt;p&gt;When used for recurring or complex updates, it’s not that efficient. &lt;a href=&quot;https://github.com/facebook/react/issues/14110#issuecomment-448074060&quot;&gt;Quoting Sebastian Markbage, a Facebook engineer&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;My personal summary is that new context is ready to be used for low frequency unlikely updates (like locale/theme). It’s also good to use it in the same way as old context was used. I.e. for static values and then propagate updates through subscriptions. &lt;strong&gt;It’s not ready to be used as a replacement for all Flux-like state propagation&lt;/strong&gt;&quot;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Even the React-Redux team had to revert parts of the library re-written with context API in &lt;a href=&quot;https://blog.isquaredsoftware.com/2018/11/react-redux-history-implementation/#v7-0&quot;&gt;version 6&lt;/a&gt;, simply due to a significant performance hit compared to its previous version (Now React-Redux only uses context to pass down the store reference).&lt;/p&gt;
&lt;p&gt;Another major issue is the incapability of components to subscribe only to &lt;strong&gt;part&lt;/strong&gt; of a context (when a context value is an object, not a primitive).&lt;/p&gt;
&lt;p&gt;Let’s have a look at the following example:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/v1675947350/blog/demo-gif.gif&quot; alt=&quot;Updating any subset of the context will cause a re-render to everything subscribed
&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this example, the context stores &lt;strong&gt;an object&lt;/strong&gt; containing two entries: name and age. We then have two components subscribed to this context. One is using just the age, and the other the name. But — when updating just one of the entries, either the name or the age, both &lt;code&gt;&amp;#x3C;Name&gt;&lt;/code&gt; and &lt;code&gt;&amp;#x3C;Age&gt;&lt;/code&gt; components are re-rendered. You can access this demo &lt;a href=&quot;https://codesandbox.io/s/context-limitations-4jhqs?file=/src/App.js&quot;&gt;here&lt;/a&gt; and see how it works.&lt;/p&gt;
&lt;p&gt;The fact that all components subscribed to a context holding a non-primitive type value are re-rendered is obviously inefficient, and on some occasions might cause a performance issue.&lt;/p&gt;
&lt;p&gt;There are some native solutions to this issue, but most of them are cumbersome. You can also consider using a 3rd party library, such as &lt;a href=&quot;https://github.com/dai-shi/use-context-selector&quot;&gt;use-context-selector&lt;/a&gt;, which makes dealing with this problem much easier.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. React has a whole API to deal with the children prop&lt;/strong&gt;&lt;br&gt;
Passing children to a component is a very common pattern, whether you’re using composition, or just writing a reusable wrapper component.&lt;/p&gt;
&lt;p&gt;But, did you know that instead of just rendering the children, React also provides you an API allowing you to do all sorts of things with it?&lt;/p&gt;
&lt;p&gt;First of all — children can be a string, an object, or an array of any of these types. It makes it quite hard to iterate over the children like this, so we can call &lt;code&gt;toArray&lt;/code&gt; to transform children to an array:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Children&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;toArray&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// If you want to use map/forEach:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Children&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Children&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can also call count to know how many children there are, avoiding the same hassle:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Children&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you need to enforce a single child in your component (I recently noticed formik does so), you can simply include the following line in your component, and React will run the check and error handling for you:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Children&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;only&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can use the following sandbox to play around with it:&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/react-children-i9vvw?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;react-children&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;p&gt;And that was it! I really hope some of these will be useful for you. Please feel free to share in the comments any other React tricks that you know!&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .default-dark .mtk15 { color: #C586C0; }
  .default-dark .mtk1 { color: #D4D4D4; }
  .default-dark .mtk12 { color: #9CDCFE; }
  .default-dark .mtk8 { color: #CE9178; }
  .default-dark .mtk4 { color: #569CD6; }
  .default-dark .mtk11 { color: #DCDCAA; }
  .default-dark .mtk7 { color: #B5CEA8; }
  .default-dark .mtk17 { color: #808080; }
  .default-dark .mtk3 { color: #6A9955; }
  .default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[The Complete Guide to Front-end Developer Interviews]]></title><description><![CDATA[chemex Interviews are hard, especially technical interviews where you’re expected to think, solve, and analyze all while the interviewer…]]></description><link>https://svetaslepner.com/2021-01-02-the-complete-guide-to-front-end-developer-interviews/</link><guid isPermaLink="false">https://svetaslepner.com/2021-01-02-the-complete-guide-to-front-end-developer-interviews/</guid><pubDate>Sat, 02 Jan 2021 15:04:10 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/w_900,q_auto/v1675543987/blog/1_2Acp2-iKTTMeBiDJehnYKA.jpg&quot; alt=&quot;chemex&quot;&gt;&lt;/p&gt;
&lt;p&gt;Interviews are hard, especially technical interviews where you’re expected to think, solve, and analyze all while the interviewer stares at you. But what people don’t realize is that being interviewed is basically just another skill, and skills can be honed with the right information and practice.&lt;/p&gt;
&lt;p&gt;So if you’re on your job hunt as a Front-end developer right now, you’ve come to the right article, as this one will tell you all you need to know to be prepared!&lt;/p&gt;
&lt;p&gt;About a year and a half ago, the company I used to work for was shut down, and all 100 employees found themselves seeking a new place. I worked there for more than 9 years, so starting a job hunt was unsettling. I knew that my JS skills are (probably) fine, but I didn’t know what to expect during technical interviews.&lt;/p&gt;
&lt;p&gt;So based on my own experience, the experiences of my colleagues who shared the same fate, as well as my current practice as an interviewer myself, I decided to write down this article. It is my hope that it will help you prepare, and take away some of the concerns you might have about what awaits you.&lt;/p&gt;
&lt;h2&gt;What Kind of Questions Should You Expect?&lt;/h2&gt;
&lt;p&gt;Each company has its own interviewing strategy, but in the end, most of them fall under the same categories, and it doesn’t matter if you’re interviewing to GAFAM or a small tech company. These are the most common topics you’ll be interviewed about:&lt;/p&gt;
&lt;h2&gt;Javascript Questions&lt;/h2&gt;
&lt;p&gt;Well, as a front-end developer you obviously should know Javascript already, but you’re also expected to understand how it works and behaves. It doesn’t matter if in your day-to-day you work with Angular/React/Vue, you are expected to know the basics.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Some example questions could be:&lt;/strong&gt;
A. Explain what the event loop is
B. Explain what a Promise is
C. Closure and Context questions (what is “this”)
D. What is the difference between an arrow function and a regular function?
E. Implement Array.prototype.map/reduce
F. What is a debounce/throttle function? Implement them.
G. Javascript prototypal inheritance questions&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Some helpful resources:&lt;/strong&gt;&lt;br&gt;
&lt;a href=&quot;https://www.sitepoint.com/5-typical-javascript-interview-exercises/&quot;&gt;5 Typical JavaScript Interview Exercises&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;https://johnresig.com/apps/learn/&quot;&gt;Learning Advanced JavaScript&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;http://bonsaiden.github.io/JavaScript-Garden/&quot;&gt;Javascript Garden&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;https://eloquentjavascript.net/&quot;&gt;Eloquent Javascript&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Algorithms&lt;/h2&gt;
&lt;p&gt;It is true that it’s unlikely you’ll ever need to traverse a binary tree while working as a Front-end developer (there are exceptions of course). But nonetheless, algorithm questions are very popular in interviews (especially if your goal is to work at GAFAM).&lt;/p&gt;
&lt;p&gt;1. &lt;strong&gt;Array or Object related questions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Example:&lt;br&gt;
1. Reverse a string&lt;br&gt;
2. Write a function that checks if a word is a palindrome&lt;br&gt;
3. Given a string of characters, return the character that appears the most often.&lt;/p&gt;
&lt;p&gt;2. &lt;strong&gt;BFS/DFS questions (traversing a tree)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Example:&lt;br&gt;
1. Write a function that solves a maze (the maze is a multidimensional array- with values of 0 — wall, 1 — floor, 2 — exit). The function receives a start coordinate and should return whether you can get out of the maze.&lt;/p&gt;
&lt;p&gt;3. &lt;strong&gt;Linked List&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Example:&lt;br&gt;
1. Reverse a linked list&lt;br&gt;
2. Find the nth node from the end of the linked list&lt;/p&gt;
&lt;p&gt;You should also probably refresh your knowledge about the difference between Recursion and Iteration and about Time and Space complexity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Some helpful resources:&lt;/strong&gt;&lt;br&gt;
&lt;a href=&quot;https://medium.com/siliconwat/algorithms-in-javascript-b0bed68f4038&quot;&gt;40 Problems, Solutions, and Explanations&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;https://www.udemy.com/course/js-algorithms-and-data-structures-masterclass/&quot;&gt;JavaScript Algorithms and Data Structures Masterclass&lt;/a&gt; — (Note: This one is no doubt the best Udemy course ever created, especially if you don’t have a degree in Computer Sciences, or if you need a refresher about algorithms and data structures).&lt;br&gt;
&lt;a href=&quot;https://www.codewars.com/&quot;&gt;Codewars&lt;/a&gt; (or any other equivalent site, like HackerRank or LeetCode).&lt;/p&gt;
&lt;h2&gt;What To Pay Attention To When Solving an Algorithm Question&lt;/h2&gt;
&lt;p&gt;A. Don’t rush to solve, it’s ok to ask for a few minutes to think.&lt;/p&gt;
&lt;p&gt;B. When you do start solving, it is highly recommended that you talk about what you’re doing, even if you’re not sure about your thoughts. The examiner usually looks to understand your process of thinking. It is not always necessary to reach a perfect and working solution. If you’re not comfortable talking aloud, or just not used to it, practice at home by solving some example questions.&lt;/p&gt;
&lt;p&gt;C. If you can, you should first write your plan of action in words or pseudo-code. This will show the interviewer that you do not rush to solve things and that you can plan.&lt;/p&gt;
&lt;p&gt;D. If you get stuck at the beginning, don’t panic! Start with the simple things. Think about input and output. Solve edge cases.&lt;/p&gt;
&lt;p&gt;E. Pay attention to the code effectiveness of your solution. If you understand that the complexity is not really good, say it out loud, and try together with the examiner to reach a better solution.&lt;/p&gt;
&lt;p&gt;F. It’s totally fine to ask questions. A good examiner will try to help you reach a solution.&lt;/p&gt;
&lt;p&gt;G. You’re usually expected to solve these type of questions on a whiteboard/piece of paper. Since it’s not how we usually write code, you may find it’s harder to think like this. This is again something that worth practicing beforehand!&lt;/p&gt;
&lt;h2&gt;React/Angular/Vue (Home) Assignment&lt;/h2&gt;
&lt;p&gt;Some places will require you to build some sort of a simple app using a specific framework/library. Depending on the company, it can either be a home assignment, or you’ll have to do so while in the companies office. If it’s the latter, bring your own laptop, so you can use your own familair IDE and operating system.&lt;/p&gt;
&lt;p&gt;In most cases, you’ll be given some sort of public API and be required to work with it in some way.&lt;/p&gt;
&lt;p&gt;This is done to see the way the candidate writes actual code, so here are some things to pay attention to:&lt;/p&gt;
&lt;p&gt;A. Keep your code clean. Use indentation, provide meaningful variable names, remove unused code.&lt;/p&gt;
&lt;p&gt;B. Use best practices of the given framework.&lt;/p&gt;
&lt;p&gt;C. Think about things like:&lt;br&gt;
1. Debounce requests sent to the server.&lt;br&gt;
2. Prevent server calls when &amp;#x3C; 3 characters are typed.&lt;br&gt;
3. Take care of edge cases like missing information from the API.&lt;/p&gt;
&lt;p&gt;D. Your CSS skills are important too! Be comfortable with using Flexbox (don’t use float to align containers 😉).&lt;/p&gt;
&lt;h2&gt;Logic Questions&lt;/h2&gt;
&lt;p&gt;I admit. I really dislike this type of question myself. I don’t understand how they can help anyone evaluate your value as a developer. But some companies still ask them…
You can’t really prepare for these ones (maybe read about some common questions?), but just know that they do exist.&lt;/p&gt;
&lt;p&gt;Example:
You are standing in a room with three light switches. The switches all correspond to three different light bulbs in a nearby room that you cannot see into, but you can go in one time only. With all the light switches starting in the off position, how can you find out which switch connects to which light bulb?&lt;/p&gt;
&lt;h2&gt;Talking About Yourself&lt;/h2&gt;
&lt;p&gt;Last but not least, there’s a part where you need to talk about your past experience.&lt;/p&gt;
&lt;p&gt;If you’re applying to your first job as a developer, make sure to have some project you’re passionate about or maybe contribute to some open-source library.&lt;/p&gt;
&lt;p&gt;Be ready to discuss the nitty-gritty. For example, why did you choose library A instead of B?&lt;/p&gt;
&lt;p&gt;If this isn’t your first rodeo, you will need to talk about a feature or product that you were responsible for at work. &lt;strong&gt;In details.&lt;/strong&gt; The Interviewer would also likely want to hear about your personal contribution to the team.&lt;/p&gt;
&lt;p&gt;You should practice this conversation with a friend so that you have feedback! It would be so much easier for you if you come prepared.&lt;/p&gt;
&lt;h2&gt;And Most Importantly: A Failed Interview does NOT Define You!&lt;/h2&gt;
&lt;p&gt;Remember, a failed interview doesn’t say anything about how good a developer you are. As I mentioned in the beginning, interviewing is a skill of its own. In your day-to-day life, you have StackOverflow and co-workers at your disposal, and you’re not expected to write code on a piece of paper. Interviews are simply not something you’re used to doing, so you need to try it a few times to grasp how it’s done. Prepare and study, but don’t be hard on yourself if you don’t pass. Try to learn something from each interview, and eventually, you will succeed!&lt;/p&gt;
&lt;p&gt;Good luck! :)&lt;/p&gt;
&lt;p&gt;Cover photo by &lt;a href=&quot;https://unsplash.com/@wocintechchat?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Christina @ wocintechchat.com&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/interview?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Understanding the difference between useMemo and useCallback]]></title><description><![CDATA[chemex React library provides us two built-in hooks to optimize the performance of our app: useMemo & useCallback. At first glance, it might…]]></description><link>https://svetaslepner.com/2020-08-28-understanding-the-difference-between-usememo-and-usecallback/</link><guid isPermaLink="false">https://svetaslepner.com/2020-08-28-understanding-the-difference-between-usememo-and-usecallback/</guid><pubDate>Fri, 28 Aug 2020 15:00:10 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/w_900,f_auto/v1675614002/blog/1_-oaiaaoisECxNABVxeVbcg.jpg&quot; alt=&quot;chemex&quot;&gt;&lt;/p&gt;
&lt;p&gt;React library provides us two built-in hooks to optimize the performance of our app: useMemo &amp;#x26; useCallback. At first glance, it might look like their usage is quite similar, so it can get confusing about when to use each. To clear that confusion, let’s dig in and understand the actual difference and the correct way to use them both.&lt;/p&gt;
&lt;h2&gt;Functional components have a problem&lt;/h2&gt;
&lt;p&gt;Functional components are great. Their combination with hooks allows for much more code reusability and flexibility than Class components. However, they do have one problem: A functional component is the same as the render function we used to have in class components. It’s a function that is being re-run on any prop/state change.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It means that:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A. If a function is called inside the component, it will be re-evaluated, again and again, on every re-render.&lt;/p&gt;
&lt;p&gt;B. If a function is created inside the component is passed to a child component, it will be recreated, meaning the pointer will change, causing the child to re-render or call the function unnecessarily (depending on the situation).&lt;/p&gt;
&lt;p&gt;To tackle the problem and prevent the possible performance issue, React provides us with two hooks: useMemo and useCallback.&lt;/p&gt;
&lt;h2&gt;useMemo&lt;/h2&gt;
&lt;p&gt;Let’s start with the first problem and see how we can prevent evaluating functions unnecessarily.&lt;/p&gt;
&lt;p&gt;In the following demo, we have a component with two states: one store a number, and the other one a boolean.
We need to do some calculation on the number we have in our state, so we call our plusFive function and render the result.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;plusFive&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;I was called!&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; + &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setNum&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;numPlusFive&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;plusFive&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/use-memo-no-memo-g959e?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;use-memo-no-memo&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;p&gt;If you open the console, you’ll see that plusFive is called whether we click on “Update Number” which sets a new number, or “Toggle the light” which updates the boolean state (and has nothing to do with numPlusFive).&lt;/p&gt;
&lt;p&gt;So how can we prevent this from happening? By memoizing &lt;code&gt;plusFive&lt;/code&gt; !
Until we will receive a new number, the function will not be called. The calculation is skipped, and we will receive the result immediately.&lt;/p&gt;
&lt;p&gt;We will do that by using &lt;code&gt;useMemo&lt;/code&gt; , and it will look like this:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;numPlusFive&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useMemo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(() &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;plusFive&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;useMemo receives two parameters: A function that returns our function call, and an array of dependencies. Only when one of the dependencies is changed, our function will be called again. useMemo returns the results of that function execution and will store it in memory to prevent the function from running again if the same parameters were used.&lt;/p&gt;
&lt;p&gt;Go ahead and see for yourself (don’t forget to open the console):&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/use-memo-tsc89?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;use-memo&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;h2&gt;useCallback&lt;/h2&gt;
&lt;p&gt;Now that we know how to prevent re-evaluating functions, let’s see how we can prevent functions created inside components from being recreated on every render.&lt;/p&gt;
&lt;p&gt;In the demo below, we have a child component (&lt;SomeComp&gt;) that receives as a prop, a function we created inside the parent component (&lt;App&gt;). Note this function is being used inside a useEffect hook, and since it’s listed as useEffect’s dependency, it’s being called again. Yes, even when we change other states or receive props, not related to our “plusFive” function.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setNum&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;plusFive&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;I was called!&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; + &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ? &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;light&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;dark&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SomeComp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;someFunc&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;plusFive&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;); }&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Toggle the light &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;SomeComp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = ({ &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;someFunc&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; }) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;calcNum&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setCalcNum&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(() &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// In this scenatio, someFunc will change on every render, so this useEffect will run.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;     &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setCalcNum&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;someFunc&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }, [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;someFunc&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Plus five: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;calcNum&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/use-callback-no-callback-h6x4m?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;use-callback-no-callback&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;p&gt;To prevent our function from being recreated and change pointers on each render round, we can use &lt;code&gt;useCallback&lt;/code&gt;. This React hook receives two parameters: A function and an array of dependencies:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;plusFive&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useCallback&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(() &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;I was called!&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; + &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}, [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This hook lets us preserve the function, and it will be recreated only when one of its dependencies changes.&lt;/p&gt;
&lt;p&gt;Here’s the working demo:&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/use-callback-ymhyy?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot;
     style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
     title=&quot;use-callback&quot;
     allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
     sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
   &gt;&lt;/iframe&gt;
&lt;h2&gt;But Wait! Don’t misuse these hooks!&lt;/h2&gt;
&lt;p&gt;While these two hooks provide a solution to a real problem, they may get misused very easily and even cause more harm.&lt;/p&gt;
&lt;p&gt;For instance, there is no need to memoize a function that’s doing some basic calculation (like in the demo). Only use &lt;code&gt;useMemo&lt;/code&gt; whenver you’re trying to prevent re-running expensive functions, that run a lot of time, or using a lot of resources. Why? Because useMemo keeps in memory the results of the functions execusion, and it might potentially grow big and ironically harm the performance of your App.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;useCallback&lt;/code&gt; things might get even worse: when not using useCallback, your old function will be garbage collected, but with useCallback it will stay in memory, in case one of the dependencies will be right again to return that old function version.&lt;/p&gt;
&lt;p&gt;So when is it right to use &lt;code&gt;useCallback&lt;/code&gt; ? When you actually see that not using it harms your performance, or will result in an unneccery heavy function execution (imagine in the useCallback demo, that this function performs an API call, and not just adding numbers. This is something worth preventing).&lt;/p&gt;
&lt;h2&gt;To summarise:&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;useMemo&lt;/strong&gt; keeps a function from being executed again if it didn’t receive a set of parameters that were previously used. It returns the results of a function. Use it when you want to prevent some heavy or costly operations from being called on each render.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;useCallback&lt;/strong&gt; keep a function from being re-created again, based on a list of dependencies. It returns the function itself. Use it when you want to propagate it to child components, and prevent from a costly function from re-running.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .default-dark .mtk4 { color: #569CD6; }
  .default-dark .mtk1 { color: #D4D4D4; }
  .default-dark .mtk11 { color: #DCDCAA; }
  .default-dark .mtk12 { color: #9CDCFE; }
  .default-dark .mtk10 { color: #4EC9B0; }
  .default-dark .mtk8 { color: #CE9178; }
  .default-dark .mtk15 { color: #C586C0; }
  .default-dark .mtk7 { color: #B5CEA8; }
  .default-dark .mtk17 { color: #808080; }
  .default-dark .mtk3 { color: #6A9955; }
  .default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Why Web Accessibility is Far More Important Than You Think]]></title><description><![CDATA[chemex Web Accessibility is a relatively new topic web developers and commercial websites have to tackle. It takes effort and might even be…]]></description><link>https://svetaslepner.com/2019-06-02-why-web-accessibility-is-far-more-important-than-you-think/</link><guid isPermaLink="false">https://svetaslepner.com/2019-06-02-why-web-accessibility-is-far-more-important-than-you-think/</guid><pubDate>Sun, 02 Jun 2019 15:04:10 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/w_900,q_auto/v1675625482/blog/1_r6Gsvcw8pDmAL5KvZkartA.jpg&quot; alt=&quot;chemex&quot;&gt;&lt;/p&gt;
&lt;p&gt;Web Accessibility is a relatively new topic web developers and commercial websites have to tackle. It takes effort and might even be a costly process, but the advantages of a web-accessible page are far greater than you would think (and not just because it’s the morally right thing to do, or because of accessibility laws). Let’s dig into these benefits and also learn some ways to make your website a better place to visit.&lt;/p&gt;
&lt;p&gt;The first time I came face to face with web accessibility was a few years ago, when I was working for a SaaS company called Webcollage, which provided a rich content distribution solutions for vendors. I returned to the office from a nice summer vacation in Europe and thought I was going to have a quiet “the day after a vacation” day, just sorting my inbox and catching up. Boy was I wrong. Apparently, the day before, one of the company’s major partners sent a requirement to now make our product accessible. This partner was kind enough to provide a list of 98 accessibility issues we had to fix in order to meet the required standard.&lt;/p&gt;
&lt;p&gt;And let me tell you, this was not easy. The real problem is that web accessibility is a huge topic. And since, as said, it’s relatively new, most of the time the issues you stumble upon are not something you can find a solution to on Stack Overflow. The longer you dig into it, you figure out just HOW MANY people it actually affects, how there are disabilities you never even thought about.&lt;/p&gt;
&lt;h2&gt;So how many people can’t use your site?&lt;/h2&gt;
&lt;p&gt;When ignoring web accessibility you’re potentially alienating &lt;strong&gt;one billion people&lt;/strong&gt;, or &lt;strong&gt;15% of the world’s population&lt;/strong&gt;, who experience some form of disability, whether auditory, cognitive, neurological, physical or visual. This includes your grandparents who no longer can read the tiny font your site use or maybe hear the video’s audio. Maybe a girl who went on a ski trip, broke her arm, and now can’t use a mouse for a month. Even a perfectly healthy guy watching a video in the subway could use accessibility aid. Let’s say the train is so loud, he can’t hear your video properly (or maybe he forgot his headphones, so being polite he’s watching the video on mute).&lt;/p&gt;
&lt;p&gt;By making your site accessible, you automatically &lt;strong&gt;increase the target audience&lt;/strong&gt; and add new groups for which it did not provide any service before. Subsequently, you get &lt;strong&gt;increased traffic&lt;/strong&gt; and thus &lt;strong&gt;the number of conversions increases&lt;/strong&gt; as well.&lt;/p&gt;
&lt;p&gt;Moreover, making these adjustments usually means it makes the site simpler and easier to use for the general public as well. As a result, users often tend to make more extensive use of the site, which leads to more conversions.&lt;/p&gt;
&lt;p&gt;It can even make search engines robots happier! A simpler, better-structured site means search engines will treat your site better as they can get more information. Better SEO means more traffic from search engines, and again -&gt; More users -&gt; More conversions.&lt;/p&gt;
&lt;h2&gt;So why don’t all websites just fix their code?&lt;/h2&gt;
&lt;p&gt;As my teammates and I experienced first hand, we had to re-learn how to build certain parts of our product to make them fit the Web Content Accessibility Guidelines (WCAG). We also, for the first time, experienced assistive tools in order to test the new accessibility features more authentically (And trust me, when you hear the screen reader yell the 350 characters of an image URL because it didn’t find a description parameter on the image, you start to understand what a cluttered mess a typical website might feel like for a visually impaired person).&lt;/p&gt;
&lt;p&gt;Also, remember that fixing the product isn’t enough. We now had to take accessibility into account for each new feature, which takes more development time for us and added time for the QA team to test it.&lt;/p&gt;
&lt;p&gt;Making a site accessible, like everything else, has a price. It requires substantial changes in the structure of the site, from all aspects — design, programming, and even content. This means many hours of work, which cost money. And in the commercial market, people are in no hurry to spend time and money to change “what’s already working when no one’s complaining”.&lt;/p&gt;
&lt;p&gt;And while more and more countries are adding laws to ensure the web is a nicer place to &lt;strong&gt;all people&lt;/strong&gt;, even if there is no such law in your country, you might consider the benefits stated above, even if it appears costly at first.&lt;/p&gt;
&lt;h2&gt;Where do I begin?&lt;/h2&gt;
&lt;p&gt;So let’s say you want to add accessibility aid to your site. “Where do I begin?”, you’re probably asking. First, there are tools online that can analyze your website for accessibility issues, such as &lt;a href=&quot;https://wave.webaim.org/&quot;&gt;this one&lt;/a&gt;. Also, there’s an official guideline I mentioned before called “Web Content Accessibility Guidelines” or in short &lt;strong&gt;“WCAG”&lt;/strong&gt;, which you access from &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/quickref/&quot;&gt;here&lt;/a&gt;. It categorizes the requirements into 3 levels, ranging from A — the lowest to AAA the strictest and most accessible. While it’s quite informative, it doesn’t always provide code examples, so sometimes you’ll have to figure it out.&lt;/p&gt;
&lt;p&gt;However, here are some points to get you started:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add Closed Captions to your videos&lt;/strong&gt; — Is there a narration or people talking in your videos? Provide a closed caption file to complement the spoken text.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Never ever use &lt;code&gt;&amp;#x3C;table&gt;&lt;/code&gt; tags for anything else then, well, tables&lt;/strong&gt; — If you need to show a comparison between data, then sure, go ahead (but &lt;a href=&quot;https://www.w3.org/WAI/tutorials/tables/&quot;&gt;read how&lt;/a&gt; to implement tables correctly to make it easier for screen readers to read the data off it). This is obviously the correct practice anyhow (for years now…), so then again, if you did put things into tables just out of convenience, now you’ll have the chance to do things right!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use headers correctly&lt;/strong&gt; — There’s a reason why there are 6 different header tags! While it doesn’t really matter for the average user, it’s really important for screen readers. When used correctly, the screen reader will be able to easily map interest spots in the page for the user. (And it’s also better for SEO!)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tab navigation&lt;/strong&gt; — Some users can’t use a mouse, such as the visually impaired, or people with motoric disabilities. Make sure your site can be navigated using the Tab key, and links and buttons activated using the Enter keys. Also, active elements should be marked using a distinct color outline. Modern browsers do it for you (for the most part), but sometimes developers disable this CSS style because it appears on any focus event.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add an “alt” parameter to images&lt;/strong&gt; — If you don’t explain what’s in the image, visually impaired people have no way of telling what information you’re trying to convey. Some images are fine with an empty alt, depending on the situation, but please add it to all of your images nonetheless (Use &lt;a href=&quot;https://webaim.org/techniques/alttext/&quot;&gt;this guide&lt;/a&gt; to help you out). What happens to images without an “alt”? The screen reader will read the image’s URL instead. NOT FUN.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Present a way to quickly pause videos and animations&lt;/strong&gt; — People with Epilepsy need a fast way to close any moving animation/video that pops up to the screen. For example, if you trigger an overlay with a video, add an option to close it with the ESC key.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Make sure the color contrast between a text and its background is high enough&lt;/strong&gt; — Don’t put pink text over a red background element. It’s actually an inconvenience even for people with perfectly fine eyesight but for people with a visual disability its a real struggle. You can check the color contrast rate using &lt;a href=&quot;https://webaim.org/resources/contrastchecker/&quot;&gt;this tool&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use buttons, not divs that simulate buttons&lt;/strong&gt; — There’s really no real reason not to use a button when you need a button (other than it takes a few more styles to make it look the way you want). But if you do, please make sure that:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol type=&quot;A&quot;&gt;
  &lt;li&gt;You use an aria attribute to state that this div is used as a button (role=” button”)&lt;/li&gt;
  &lt;li&gt;Make sure you can activate it using key presses, and not just mouse clicks.&lt;/li&gt;
&lt;/ol&gt;
&lt;br/&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;&lt;strong&gt;Learn about Aria attributes&lt;/strong&gt; — Aria attributes are part of the Accessibility API available in all modern browsers, which allow assistive technologies to better understand the elements that reside in your page. For example, do you need to inform the user that an error occurred? Without the correct aria attribute, a screen reader won’t be able to detect that a new message popped up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Can color blind users see your images clearly?&lt;/strong&gt; — It’s a bad idea to put text and numbers in images, which are the main cause of problems for people with color blindness. However, if you do, and you want to understand the problematic parts of the image, or even provide an alternative image (with no effort!), you can use &lt;a href=&quot;https://cloudinary.com/documentation/image_transformations#colorblind_accessibility_effects&quot;&gt;some out of the box tools&lt;/a&gt;, from an asset management company called Cloudinary (Disclaimer: I work there! :)).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To conclude, making your site accessible is not a simple task. It takes some thought, time and even money. However, your benefit from it is far greater than it looks on a first glance. Take your time, but do this change, to make the web a better place.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Make Your Content Look More Interesting With CSS Shapes]]></title><description><![CDATA[For the longest time newspapers, magazines and books had one advantage over content designed for websites. It’s rather a small feature, but…]]></description><link>https://svetaslepner.com/2019-03-30-more-interesting-content-with-css-shapes/</link><guid isPermaLink="false">https://svetaslepner.com/2019-03-30-more-interesting-content-with-css-shapes/</guid><pubDate>Sat, 30 Mar 2019 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For the longest time newspapers, magazines and books had one advantage over content designed for websites. It’s rather a small feature, but one that makes content look so much better — the ability to wrap text around images and shapes other than a rectangle. But fear not, because with the help of a CSS feature called ‘CSS shapes’, you can now achieve that as well!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/w_900,f_auto/v1675974296/blog/css-shapes-header.jpg&quot; alt=&quot;css shapes&quot;&gt;&lt;/p&gt;
&lt;p&gt;Since the beginning of the internet, we were trained to see our web sites as a collection of boxes. Even when we got a native CSS solution for creating circles, triangles and even trapeze and stars (either by using CSS tricks or by the modern clip-path property) these were all a mere illusion, since they’re still part of a box. As you can see in the example below, I’ve create a floating circle, which is basically just a div with a border radius — alas, the content still wraps itself around the circle’s &lt;strong&gt;box&lt;/strong&gt; container:&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;350&quot; src=&quot;//jsfiddle.net/SvetaSR/d6rtfh5y/embedded/result,html,css&quot; allowfullscreen=&quot;allowfullscreen&quot; allowpaymentrequest frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;h5&gt;The float area is a box, so the text can’t wrap itself around the real circle.&lt;/h5&gt;
&lt;p&gt;However, thanks to &lt;strong&gt;CSS shapes&lt;/strong&gt;, we have the power to break this limit and make browsers wrap text around any crazy shape that comes to mind.&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;350&quot; src=&quot;//jsfiddle.net/SvetaSR/yqnrgeod/embedded/result,html,css&quot; allowfullscreen=&quot;allowfullscreen&quot; allowpaymentrequest frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Circles, ellipses, complex polygons, you name it. We can even use images with transparent backgrounds and get the same effect!&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;400&quot; src=&quot;//jsfiddle.net/SvetaSR/dpq6uon8/embedded/result,html,css&quot; allowfullscreen=&quot;allowfullscreen&quot; allowpaymentrequest frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;h1&gt;Now we’ve seen it in action, how does CSS shapes work?&lt;/h1&gt;
&lt;p&gt;CSS shapes is a set of rules for wrapping content around custom shapes and path. It does not actually draw the shape, but rather gives instructions to the browser on what the float area looks like (We can still draw the shape using the clip-path CSS property, this feature just isn’t part of CSS Shapes). Currently it only works when paired with a float property (in the future, with the help of CSS Exclusions, it will be possible to do so without it). Also, it’s not possible to wrap text from both sides of a shape.&lt;/p&gt;
&lt;p&gt;The CSS Shapes specification Level 1 defines three properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;shape-outside&lt;/li&gt;
&lt;li&gt;shape-image-threshold&lt;/li&gt;
&lt;li&gt;shape-margin&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;shape-outside&lt;/h2&gt;
&lt;p&gt;The shape-outside CSS property defines a shape around which adjacent inline content should wrap. By default, inline content wraps around its margin box; by accepting different functions, shape-outside provides a way to customize this wrapping.&lt;/p&gt;
&lt;p&gt;Some supported values are:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;circle()&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;css&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk6&quot;&gt;.basic-circle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;150px&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;150px&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shape-outside&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;// &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;Circle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; with &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; custom radius&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk6&quot;&gt;.radius-circle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;150px&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;150px&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shape-outside&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;30%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;// &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;Circle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; with &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; custom radius and position (which defines the &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;center&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; of the &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk6&quot;&gt;.radius-position-circle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;150px&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;150px&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shape-outside&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;50%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; at &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;50%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;polygon()&lt;/strong&gt; —The polygon() function allows you to “go crazy” and create any kind of shape. It gets as an argument, a list of at least 3 coordinates. This, for example, is how you would create a simple 5 pointed star:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;css&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk6&quot;&gt;.star-shape&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;150px&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;150px&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shape-outside&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;polygon&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;50%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;61%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;35%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;98%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;35%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;68%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;57%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;79%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;91%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;50%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;70%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;21%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;91%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;32%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;57%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;35%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;39%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;35%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Creating shapes by hand is a bit of a pain, so you can use online tools such as &lt;a href=&quot;https://bennettfeely.com/clippy/&quot;&gt;this one&lt;/a&gt; to generate the correct CSS, which you can just copy-paste to your project.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;url()&lt;/strong&gt; — With this function you can create dynamic float borders from an image. It only supports png/gif/svg formats thought. Also note that you need the actual image present as an &lt;code&gt;&amp;#x3C;img&gt;&lt;/code&gt; tag for it to work.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;html&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;some-image.png&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;custom-shape&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;some text...&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk6&quot;&gt;.custom-shape&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shape-outside&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;some-image.png&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Other supported shapes are &lt;code&gt;ellipse()&lt;/code&gt; and &lt;code&gt;inset()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A useful property to use along with &lt;strong&gt;shape-outside&lt;/strong&gt; is &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path&quot;&gt;clip-path&lt;/a&gt; which takes the same values (except for url) and creates a visible shape.&lt;/p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;350&quot; src=&quot;//jsfiddle.net/SvetaSR/yqnrgeod/embedded/result,html,css/&quot; allowfullscreen=&quot;allowfullscreen&quot; allowpaymentrequest frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;h2&gt;shape-image-threshold&lt;/h2&gt;
&lt;p&gt;When using shape-outside along with an image value (using the url() function), the shape-image-threshold property is used to adjust the minimum opacity level of pixels that will be used to create the shape. Its value must be in the range between 0 and 1.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;css&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk6&quot;&gt;.shape-from-image&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shape-outside&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;some-image.png&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shape-image-threshold&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;shape-margin&lt;/h2&gt;
&lt;p&gt;If the shape you created with shape-outside is too close to the text, you can adjust its margin from the content using this property.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container default-dark&quot; data-language=&quot;css&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk6&quot;&gt;.circle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shape-outside&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;50%&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shape-margin&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;20px&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Browser Support&lt;/h1&gt;
&lt;p&gt;Unfortunately CSS shapes level 1 is not supported by IE11 and not even by Edge, however support from other browsers is not too bad! You can still make your page look better on these, and just let them fallback to the old behavior on non supported browsers, or you can use a polyfill, created by Adobe.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/v1675974867/blog/css-can-i-use.jpg&quot; alt=&quot;can i use&quot;&gt;
&lt;a href=&quot;https://caniuse.com/#feat=css-shapes&quot;&gt;https://caniuse.com/#feat=css-shapes&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Future Features&lt;/h1&gt;
&lt;p&gt;Currently we can only float text around shapes, but when CSS Shapes level 2 hit the shelves, we will get a new feature called “shape-inside”, which will let us put text inside shapes!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dq6tqnvbh/image/upload/v1675974928/blog/text-in-shape.gif&quot; alt=&quot;shape-inside&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://drafts.csswg.org/css-shapes-2/#shape-inside-property&quot;&gt;https://drafts.csswg.org/css-shapes-2/#shape-inside-property&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;We learned that we can break the limits we were previously set, and by using some simple CSS, make our web pages more interesting to look at! I really hope this little article will inspire you to test these neat features :)&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .default-dark .mtk6 { color: #D7BA7D; }
  .default-dark .mtk1 { color: #D4D4D4; }
  .default-dark .mtk12 { color: #9CDCFE; }
  .default-dark .mtk7 { color: #B5CEA8; }
  .default-dark .mtk11 { color: #DCDCAA; }
  .default-dark .mtk8 { color: #CE9178; }
  .default-dark .mtk17 { color: #808080; }
  .default-dark .mtk4 { color: #569CD6; }
  .default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item></channel></rss>