<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Romain</title>
    <description>The latest articles on DEV Community by Romain (@romaixn).</description>
    <link>https://dev.to/romaixn</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F139846%2F2b882e4e-6ed7-462c-871c-96349c5ba3ec.jpg</url>
      <title>DEV Community: Romain</title>
      <link>https://dev.to/romaixn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/romaixn"/>
    <language>en</language>
    <item>
      <title>Building Your First Browser Game with Three.js and React: Part 4 - Adding Game Mechanics</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Sat, 01 Jun 2024 15:28:58 +0000</pubDate>
      <link>https://dev.to/romaixn/building-your-first-browser-game-with-threejs-and-react-part-4-adding-game-mechanics-5ha4</link>
      <guid>https://dev.to/romaixn/building-your-first-browser-game-with-threejs-and-react-part-4-adding-game-mechanics-5ha4</guid>
      <description>&lt;p&gt;Welcome to the final post of our series on &lt;strong&gt;creating a browser game with Three.js and React&lt;/strong&gt;. In this piece, we'll introduce &lt;strong&gt;game mechanics&lt;/strong&gt; to our mini-basketball game. We'll specifically establish a &lt;strong&gt;scoring system&lt;/strong&gt; using &lt;strong&gt;Zustand&lt;/strong&gt; for state management and configure &lt;strong&gt;colliders&lt;/strong&gt; in our Table component to detect when the ball passes through the hoop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Setting Up Zustand
&lt;/h2&gt;

&lt;p&gt;First, we're going to use &lt;a href="https://github.com/pmndrs/zustand"&gt;Zustand&lt;/a&gt; to manage our game score. Zustand is a lightweight, fast, and scalable &lt;strong&gt;state management&lt;/strong&gt; solution for React.&lt;/p&gt;

&lt;p&gt;While there are many state management options for React, I favor Zustand for its simplicity and it’s created by &lt;strong&gt;Pmndrs&lt;/strong&gt;, the creators of R3F!&lt;/p&gt;

&lt;p&gt;We need state management to &lt;strong&gt;store&lt;/strong&gt; the score of the current game. This allows us to trigger increments in our table component and pass these values to our Interface. State management simplifies the process of &lt;strong&gt;sharing values across all our components&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To start, we need to install it:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;With Zustand installed, let's proceed to create the store. This is a file used for defining the values to be stored and shared across your components.&lt;/p&gt;

&lt;p&gt;To do this, create a new file named &lt;code&gt;src/stores/useGame.js&lt;/code&gt; and set up the store:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zustand&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * Score
    */&lt;/span&gt;
    &lt;span class="na"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our store is straightforward, containing just one variable: &lt;code&gt;score&lt;/code&gt;, which keeps track of the number of balls we score. It also has a simple function &lt;code&gt;increment&lt;/code&gt; that increases this score.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Displaying the Score
&lt;/h2&gt;

&lt;p&gt;Next, we'll display the score on the &lt;strong&gt;game interface&lt;/strong&gt; by creating a very simple HTML interface.&lt;/p&gt;

&lt;p&gt;First, create a new file named &lt;code&gt;Interface.jsx&lt;/code&gt; inside the &lt;code&gt;src/&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useGame&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./stores/useGame&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Interface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;points&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGame&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"points"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;points&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; points&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In this interface, we utilize our store to retrieve and display the actual game score within a &lt;code&gt;div&lt;/code&gt; inside an &lt;code&gt;h1&lt;/code&gt; tag.&lt;/p&gt;

&lt;p&gt;Next, we need to import it into our app. Since this component is not 3D-related, let's add it to our &lt;code&gt;main.jsx&lt;/code&gt; file outside of our &lt;code&gt;Canvas&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Canvas&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/fiber&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Experience&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Experience&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./index.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Interface&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Interface&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Interface&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Canvas&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Experience&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Canvas&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see your interface in the top-left corner of the scene, as shown:&lt;/p&gt;

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

&lt;p&gt;While it isn't bad, it’s very ugly. Let's add some CSS to enhance its appearance slightly. Open the existing &lt;code&gt;index.css&lt;/code&gt; file and append the following at the end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.points&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;fixed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;999&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great! The text is now centered, enlarged, white, and a little less unattractive (you can still improve it yourself!):&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Step 3: Implementing Colliders
&lt;/h2&gt;

&lt;p&gt;Now, we need to &lt;strong&gt;detect&lt;/strong&gt; when the ball passes through the hoop using &lt;strong&gt;colliders&lt;/strong&gt; in the &lt;code&gt;Table&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;Colliders not only add physics to our object but also define areas where objects are &lt;strong&gt;detected&lt;/strong&gt; when passing through.&lt;/p&gt;

&lt;p&gt;Let's add our first collider to the hoop. Locate the &lt;code&gt;nodes.Ring.geometry&lt;/code&gt; within the Table component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CuboidCollider&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.686&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;sensor&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.06&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;CuboidCollider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've added a custom &lt;code&gt;CuboidCollider&lt;/code&gt; to our Ring with a unique property &lt;code&gt;sensor&lt;/code&gt;. A &lt;a href="https://github.com/pmndrs/react-three-rapier?tab=readme-ov-file#sensors"&gt;&lt;strong&gt;sensor&lt;/strong&gt;&lt;/a&gt; allows for specific functions like &lt;code&gt;onIntersectionEnter&lt;/code&gt; or &lt;code&gt;onIntersectionExit&lt;/code&gt;. These functions can detect when an object enters or exits this specific collider. If we define a &lt;strong&gt;collider&lt;/strong&gt; with the sensor, this collider won't generate any contact points. Its only purpose is to detect other objects.&lt;/p&gt;

&lt;p&gt;Remember to &lt;strong&gt;adjust the position&lt;/strong&gt; of our Ring. This is because now it's the parent collider that defines the position of our mesh.&lt;/p&gt;

&lt;p&gt;Now, if you look inside your ring, you should see the cuboid collider as illustrated below:&lt;/p&gt;

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

&lt;p&gt;This component should detect when the ball enters it. To achieve this, we simply need to add a function at the beginning of our component and use it in our collider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useGame&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../stores/useGame&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;increaseScore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGame&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CuboidCollider&lt;/span&gt;
        &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.686&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;sensor&lt;/span&gt;
        &lt;span class="na"&gt;onIntersectionExit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;increaseScore&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.06&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;CuboidCollider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've created a function called &lt;code&gt;increaseScore&lt;/code&gt; that utilizes the &lt;code&gt;increment&lt;/code&gt; function from our store. This function is used within the &lt;code&gt;onIntersectionExit&lt;/code&gt; property of the CuboidCollider.&lt;/p&gt;

&lt;p&gt;You can now play your game! Let's score some balls.&lt;/p&gt;

&lt;p&gt;However, there is a problem.&lt;/p&gt;

&lt;p&gt;You may have noticed that sometimes the score increases by two, or if the ball bounces too much and enters the hoop a second time, the score increases multiple times.&lt;/p&gt;

&lt;p&gt;We need to verify this. We need to &lt;strong&gt;determine if the ball is returning to our thruster&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To do this, we already have all the necessary information! We just need another &lt;strong&gt;collider&lt;/strong&gt;! 🎉&lt;/p&gt;

&lt;p&gt;Let's add this collider and implement some &lt;strong&gt;conditions for our goal&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isScored&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsScored&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;increaseScore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGame&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isScored&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setIsScored&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;increaseScore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'fixed'&lt;/span&gt; &lt;span class="na"&gt;colliders&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'trimesh'&lt;/span&gt; &lt;span class="na"&gt;restitution&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;friction&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wood&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.068&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Add this collider inside the RigidBody of the Table mesh */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CuboidCollider&lt;/span&gt;
          &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;sensor&lt;/span&gt;
          &lt;span class="na"&gt;onIntersectionExit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setIsScored&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;CuboidCollider&lt;/span&gt;
          &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.35&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.686&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;sensor&lt;/span&gt;
          &lt;span class="na"&gt;onIntersectionExit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
            &lt;span class="na"&gt;castShadow&lt;/span&gt;
            &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
            &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.06&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;CuboidCollider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what we've done: we've added a &lt;strong&gt;state&lt;/strong&gt; to our Table component using the &lt;code&gt;useState&lt;/code&gt; hook. This state helps us determine whether we've already scored or not. We've also created a &lt;code&gt;goal&lt;/code&gt; function to increment the score and set this state to &lt;code&gt;true&lt;/code&gt;. This prevents indefinite score incrementing when the ball has already been scored but hasn't returned to the thruster yet.&lt;/p&gt;

&lt;p&gt;To detect if the ball has returned to the thruster and is ready for another shot, we've placed a new &lt;code&gt;CuboidCollider&lt;/code&gt; on our Table and reset the state to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You should now see the new collider positioned right in front of the thruster.&lt;/p&gt;

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

&lt;p&gt;Now, when we launch the ball and it passes through our hoop, the goal function checks if we've already scored. If we haven't, it increments our score and sets the state to &lt;code&gt;true&lt;/code&gt;. When we pass through our new Collider in front of our thruster, this variable switches to &lt;code&gt;false&lt;/code&gt;, and we're ready to score again.&lt;/p&gt;

&lt;p&gt;This improvement &lt;strong&gt;prevents us from scoring multiple points with one shot&lt;/strong&gt; like we could before.&lt;/p&gt;

&lt;p&gt;Finally, we can go to our &lt;code&gt;Experience.jsx&lt;/code&gt; file and delete the &lt;code&gt;debug&lt;/code&gt; property from the Physics component.&lt;/p&gt;

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

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

&lt;p&gt;Congratulations! You've successfully incorporated game mechanics into your browser game using Three.js and React. You now have &lt;strong&gt;a fully functioning mini-basketball game&lt;/strong&gt; equipped with a scoring system. This marks the end of our series on building your first browser game. Continue to experiment and add new features to further enhance your game.&lt;/p&gt;

&lt;p&gt;In the future, I'll include some &lt;strong&gt;bonus articles&lt;/strong&gt; to further &lt;strong&gt;improve the game&lt;/strong&gt;, such as &lt;strong&gt;adding confetti&lt;/strong&gt; when scoring, and so on.&lt;/p&gt;

&lt;p&gt;There's always room for improvement in this game! For instance, Aezakmi from the &lt;strong&gt;Three.js Journey Discord&lt;/strong&gt; suggested adding some "randomness" to the force of the thruster. I've included his message below in case it sparks some ideas:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So basically you have "puncher" state between 0 and 1, where 0 is full down, and 1  is full up.&lt;br&gt;
To calculate the force you gotta do the (1.0 - puncherState)*forceValue .  For example if the ball collide with puncher being halfway up, you gonna apply (1.0 - 0.5) * forceValue and if pucher is full up the force gonna be zero (1.0 - 1.0) * forceValue.&lt;/p&gt;

&lt;p&gt;Now we need to calculate the direction for the force to apply.&lt;br&gt;
Thats gonna be even easier. Just do new Vector3().subVectors(ball.position, puncher.position).normalize().&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This topic might be a bit advanced, but I believe everyone will be able to grasp it after this series!&lt;/p&gt;

&lt;p&gt;Thanks for following me throughout this series of articles. Don't hesitate to share your feelings about it on &lt;a href="https://x.com/Romaixn"&gt;Twitter&lt;/a&gt; or in comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>threejs</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building Your First Browser Game with Three.js and React: Part 3 - Adding Interactivity and Physics</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Tue, 14 May 2024 10:30:00 +0000</pubDate>
      <link>https://dev.to/romaixn/building-your-first-browser-game-with-threejs-and-react-part-3-adding-interactivity-and-physics-3np0</link>
      <guid>https://dev.to/romaixn/building-your-first-browser-game-with-threejs-and-react-part-3-adding-interactivity-and-physics-3np0</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome back to our series on creating a &lt;strong&gt;3D basketball game&lt;/strong&gt; using &lt;strong&gt;Three.js&lt;/strong&gt; and &lt;strong&gt;React&lt;/strong&gt; in your browser!&lt;br&gt;
So far, we've set up our project and incorporated essential 3D models into our scene. Now, it's time to animate our game with &lt;strong&gt;interactivity&lt;/strong&gt; and &lt;strong&gt;physics&lt;/strong&gt;.&lt;br&gt;
This installment will focus on integrating physics to simulate realistic ball movements and interactions, making our game genuinely interactive and enjoyable.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Setting Up Physics with @react-three/rapier
&lt;/h2&gt;

&lt;p&gt;When it comes to integrating physics into &lt;strong&gt;React Three Fiber&lt;/strong&gt;, several libraries are available. &lt;a href="https://github.com/pmndrs/react-three-rapier"&gt;@react-three/rapier&lt;/a&gt; stands out as one of the most recent updated (created in 2019 and written in Rust), making it a great choice for adding physics in 3D web environments.&lt;/p&gt;

&lt;p&gt;While &lt;strong&gt;Rapier&lt;/strong&gt; is known for its ease of use and good performance, other libraries might also be excellent choices depending on specific use cases, like &lt;a href="https://github.com/pmndrs/cannon-es"&gt;Cannon&lt;/a&gt; for example. (The fork by &lt;strong&gt;pmndrs&lt;/strong&gt;, that is awesome too)&lt;/p&gt;

&lt;p&gt;First, ensure that &lt;code&gt;@react-three/rapier&lt;/code&gt; is installed in your project:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Initialize the physics engine in your Experience file where all our scene is set up.&lt;/p&gt;

&lt;p&gt;To accomplish this, we add the &lt;code&gt;Physics&lt;/code&gt; component, provided by &lt;strong&gt;rapier&lt;/strong&gt;, around our Table and Ball. We don't need to include our lights, controls, or environment, as they don't require physics.&lt;/p&gt;

&lt;p&gt;We are adding a &lt;code&gt;debug&lt;/code&gt; parameter to the Physics component. This will allow us to view all the colliders of our object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OrbitControls&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/drei&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Components/Table&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Ball&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Components/Ball&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Physics&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/rapier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Experience&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;color&lt;/span&gt; &lt;span class="na"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"background"&lt;/span&gt; &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ddc28d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ambientLight&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;directionalLight&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;intensity&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Environment&lt;/span&gt; &lt;span class="na"&gt;preset&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"city"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrbitControls&lt;/span&gt; &lt;span class="na"&gt;makeDefault&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Physics&lt;/span&gt; &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Ball&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Physics&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

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

&lt;/div&gt;



&lt;p&gt;This wrapper will manage all physics-related updates automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Adding Physics to the Ball
&lt;/h2&gt;

&lt;p&gt;Let's add physics to our ball. We'll adjust the &lt;code&gt;Ball&lt;/code&gt; component to include the &lt;code&gt;RigidBody&lt;/code&gt; component from &lt;strong&gt;rapier&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RigidBody&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/rapier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Ball&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Material.001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also include a &lt;strong&gt;group&lt;/strong&gt; in our mesh to set the position and scale for the ball, along with our rigid body. To slightly decrease the ball's size, we incorporate a scale parameter of 0.7, which we'll use later to fit the hoop ring.&lt;/p&gt;

&lt;p&gt;This setup adds &lt;strong&gt;physics&lt;/strong&gt; to our ball. You should see the ball falling into the depths of our scene. The ball falls because we have not integrated physics into our table yet.&lt;/p&gt;

&lt;p&gt;Before the ball falls, you should see a square around it, as shown in the screenshot below. This square represents the object's colliders. By default, all colliders are &lt;strong&gt;square-shaped&lt;/strong&gt; and adapt to the size of the object to which we add a &lt;code&gt;RigidBody&lt;/code&gt;. However, we can adjust the shape using the &lt;code&gt;colliders&lt;/code&gt; parameter of RigidBody.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw0zmdvig1j77cpb13b9q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw0zmdvig1j77cpb13b9q.png" alt="Screenshot of the ball component with colliders see around" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's try another collider, such as &lt;code&gt;ball&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RigidBody&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/rapier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Ball&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;materials&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGLTF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/models/basketball.glb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt; &lt;span class="na"&gt;colliders&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"ball"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Material.001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now see the collider in a "round shape" (like a ball). This is exactly what we want!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc70ypzssoftau9wtw5yk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc70ypzssoftau9wtw5yk.png" alt="Screenshot of the ball component with ball collider see around" width="320" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It exist some colliders provided by rapier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cuboid&lt;/code&gt; , the default one, for square shape.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ball&lt;/code&gt;, the one we use, for round shape.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hull&lt;/code&gt;, a collider that fits a shape very closely but ignores holes within it. It's useful for complex objects without holes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;trimesh&lt;/code&gt; is similar to &lt;code&gt;hull&lt;/code&gt;, but it doesn't ignore holes. While this collider is powerful, it can &lt;a href="https://rapier.rs/docs/user_guides/bevy_plugin/colliders/#triangle-meshes-and-polylines"&gt;complicate collision detection and potentially introduce bugs&lt;/a&gt;. It's best to avoid it if possible, but for smaller projects with less collision, it’s acceptable. (Am I saying this because I use it in this project? Perhaps..)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Adding physics to the Table
&lt;/h2&gt;

&lt;p&gt;Now, let's modify the &lt;code&gt;Table&lt;/code&gt; component to respond to the ball. This way, the ball will be "trapped" inside the table. First, let’s add &lt;code&gt;RigidBody&lt;/code&gt; for the &lt;strong&gt;Table&lt;/strong&gt; mesh:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRigidBody&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/rapier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'fixed'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wood&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.068&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now, we should observe the ball falling and coming to rest on the table. We're adding a 'fixed' type to the rigid body because the table shouldn't move; it simply acts as a "floor" for our ball. Take note of the table's colliders as illustrated below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7uds3141ugti5emqxxoc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7uds3141ugti5emqxxoc.png" alt="Screenshot of our scene with colliders for ball and table" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our table has a shape more complex than a basic cuboid, so let's use trimesh instead (yes, I know, emergency collider only..).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRigidBody&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/rapier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'fixed'&lt;/span&gt; &lt;span class="na"&gt;colliders&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'trimesh'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wood&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.068&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now, you can observe that our collider perfectly matches the shape of our table.&lt;/p&gt;

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

&lt;p&gt;Now that our base table is set up, we need to add physics to our glass as well. This should be the final mesh of the Table component (if you followed the code given in this serie):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRigidBody&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/rapier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'fixed'&lt;/span&gt; &lt;span class="na"&gt;colliders&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'trimesh'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Glass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.497&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.005&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MeshTransmissionMaterial&lt;/span&gt; &lt;span class="na"&gt;anisotropy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;chromaticAberration&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.04&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;distortionScale&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;temporalDistortion&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The last physics component to add is our basketball hoop. It comprises four meshes: Base, Cylinder, Panel, and Ring. Like the others, enclose these four meshes in a RigidBody with a fixed type and trimesh colliders.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRigidBody&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/rapier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'fixed'&lt;/span&gt; &lt;span class="na"&gt;colliders&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'trimesh'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wood&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.235&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.565&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Cylinder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.235&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.177&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Panel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wood&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.814&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.686&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We have now integrated physics into all of our models (except for a few used for controls)! You should be able to see all the colliders in your scene like this:&lt;/p&gt;

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

&lt;p&gt;To observe our physics in action, let's adjust the ball's position slightly to the left and watch it roll across the table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Experience&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Physics&lt;/span&gt; &lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Let's change the third parameter of position to 0.2 */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Ball&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Physics&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Tweak the Restitution and the Friction
&lt;/h2&gt;

&lt;p&gt;Let's assign some default values to our existing physics to improve the ball's reaction to the floor, among other things.&lt;/p&gt;

&lt;p&gt;Return to our Ball component and add &lt;strong&gt;restitution&lt;/strong&gt; and &lt;strong&gt;friction&lt;/strong&gt; to the RigidBody:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RigidBody&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/rapier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Ball&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;materials&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGLTF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/models/basketball.glb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt; &lt;span class="na"&gt;colliders&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"ball"&lt;/span&gt; &lt;span class="na"&gt;restitution&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;friction&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Material.001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Restitution&lt;/strong&gt; refers to the "&lt;strong&gt;bounciness&lt;/strong&gt;" of an object. The default value is 0, meaning the object does not bounce. We set it to 1 to give our basketball a lot of bounce!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Friction&lt;/strong&gt; refers to the degree to &lt;strong&gt;which surfaces rub against each other&lt;/strong&gt;. The default value is 0.7. The higher the friction, the quicker the object will stop. To let our ball slide more on the table, we’ll reduce the friction to 0.2.&lt;/p&gt;

&lt;p&gt;You should see the ball jumping more. Feel free to tweak these parameters to observe the changes!&lt;/p&gt;

&lt;p&gt;Now, let's return to our table. We will add both restitution and friction to the table and the glass.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRigidBody&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/rapier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'fixed'&lt;/span&gt; &lt;span class="na"&gt;colliders&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'trimesh'&lt;/span&gt; &lt;span class="na"&gt;restitution&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;friction&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wood&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.068&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'fixed'&lt;/span&gt; &lt;span class="na"&gt;colliders&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'trimesh'&lt;/span&gt; &lt;span class="na"&gt;restitution&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;friction&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Glass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.497&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.005&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MeshTransmissionMaterial&lt;/span&gt; &lt;span class="na"&gt;anisotropy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;chromaticAberration&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.04&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;distortionScale&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;temporalDistortion&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the ball jumping even more! We have now the perfect setup for our game. We can now add the &lt;strong&gt;controls&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Integrating Controls
&lt;/h2&gt;

&lt;p&gt;To make our game &lt;strong&gt;interactive&lt;/strong&gt;, we need to give players control over the ball. We'll implement click controllers to trigger thrusters that propel the ball towards the basket ring.&lt;/p&gt;

&lt;p&gt;First, we are going to add the “onclick” control on our &lt;code&gt;Control_A&lt;/code&gt; and &lt;code&gt;Control_B&lt;/code&gt; mesh.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Control on Mesh
&lt;/h3&gt;

&lt;p&gt;To identify our controls, we need to use &lt;code&gt;useRef()&lt;/code&gt;, a hook from React that allows us to reference a value. This value can be anything we want, such as a boolean, a number, a string, or an object. After assigning this reference to our mesh, we can retrieve it later.&lt;/p&gt;

&lt;p&gt;Let's incorporate it into our Table component:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controlA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controlB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;controlA&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Control_A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;4.184&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.129&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.744&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Control_A_Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;White&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.237&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.046&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.179&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;controlB&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Control_B&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Green&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;4.183&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.754&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Control_B_Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;White&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.043&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.207&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.184&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have our references to Control A and Control B, we need to activate the "click" control. For this, the &lt;code&gt;&amp;lt;mesh&amp;gt;&lt;/code&gt; component from Three.js offers two functions that we can use: &lt;code&gt;onPointerUp&lt;/code&gt; and &lt;code&gt;onPointerDown&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can use these functions to trigger a function we've created when a player clicks on ControlA or ControlB. Let's create these two functions and assign them to the controls:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controlA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controlB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clickUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.128&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clickDown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.128&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;controlA&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Control_A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;4.184&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.129&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.744&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onPointerUp&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clickUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onPointerDown&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clickDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Control_A_Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;White&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.237&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.046&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.179&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;controlB&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Control_B&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Green&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;4.183&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.754&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onPointerUp&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clickUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onPointerDown&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clickDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Control_B_Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;White&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.043&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.207&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.184&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this function, we "simulate" a click by slightly lowering the position of our control, similar to pressing a button. We trigger the &lt;code&gt;clickDown&lt;/code&gt; action when the user clicks the button, and &lt;code&gt;clickUp&lt;/code&gt; action when they release the click.&lt;/p&gt;

&lt;p&gt;You can test it on your scene, you should see the button going down when clicking on it.&lt;/p&gt;

&lt;p&gt;We can now proceed to the next part: adding physics to the thruster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Physics on Thrusters
&lt;/h3&gt;

&lt;p&gt;In this section, we need to identify our thrusters using &lt;code&gt;useRef&lt;/code&gt;, add a special rigid body to them, and activate them when we use the controls. Let's get started:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// Add useRef on thruster to identify them&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thrusterA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thrusterB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clickUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.128&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clickDown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.128&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;
        &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;thrusterA&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"kinematicPosition"&lt;/span&gt;
        &lt;span class="na"&gt;colliders&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hull"&lt;/span&gt;
        &lt;span class="na"&gt;lockRotations&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;enabledTranslations&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Thruster_A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Black&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;2.259&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.189&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.765&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;
        &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;thrusterB&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"kinematicPosition"&lt;/span&gt;
        &lt;span class="na"&gt;colliders&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hull"&lt;/span&gt;
        &lt;span class="na"&gt;lockRotations&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;enabledTranslations&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Thruster_B&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Black&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;2.259&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.189&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.764&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We assign a specific type of RigidBody, &lt;strong&gt;kinematicPosition&lt;/strong&gt;, to the thrusters. This type allows our object to be moved using special functions, such as translate/rotate, through code. The rigid body doesn't move until we instruct it to, and can't be moved by other rigid bodies, for example.&lt;/p&gt;

&lt;p&gt;We also restrict rotations on this mesh, as we only want it to move up and down.&lt;/p&gt;

&lt;p&gt;Now, we simply need to move it up or down when we press or release our controls.  Let's do it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thrusterA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thrusterB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clickUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.128&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlRef&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;controlA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;vec3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thrusterA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;translation&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="nx"&gt;thrusterA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setNextKinematicTranslation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;z&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;vec3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thrusterB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;translation&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="nx"&gt;thrusterB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setNextKinematicTranslation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;z&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clickDown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;controlRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.128&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controlRef&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;controlA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;vec3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thrusterA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;translation&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="nx"&gt;thrusterA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setNextKinematicTranslation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;z&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;vec3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thrusterB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;translation&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="nx"&gt;thrusterB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setNextKinematicTranslation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;z&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when we activate the &lt;code&gt;clickUp&lt;/code&gt; and &lt;code&gt;clickDown&lt;/code&gt; functions by pressing our controls, thruster A for control A and thruster B for control B will propel the ball across our table.&lt;/p&gt;

&lt;p&gt;To accomplish this, we simply use the &lt;code&gt;setNextKinematicTranslation&lt;/code&gt; function to apply a translation to our object. We just need to add a number, such as 0.5, to the y-axis to move it upwards.&lt;/p&gt;

&lt;p&gt;When the user clicks, the thruster elevates by 0.5. When the user releases the click, the thruster reverts back to -0.5.&lt;/p&gt;

&lt;h3&gt;
  
  
  Small Tweak to Improve Game
&lt;/h3&gt;

&lt;p&gt;To enhance our game, I propose adding a parameter to the rigid body of our Ball component: &lt;strong&gt;gravityScale&lt;/strong&gt;. This parameter enables us to influence how gravity impacts our object. By default, this value simulates Earth's gravity (-9.81 approximately). However, I want the ball to be more energetic and faster, so let's introduce a new value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Ball&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt; &lt;span class="na"&gt;colliders&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"ball"&lt;/span&gt; &lt;span class="na"&gt;restitution&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;friction&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;gravityScale&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;3.5&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Material.001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RigidBody&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Testing and Debugging
&lt;/h2&gt;

&lt;p&gt;With physics and controls established, thoroughly testing the game is crucial to observe their interactions. Based on this testing, adjust the physics parameters and controls as needed. Observe how different settings alter the gameplay.&lt;/p&gt;

&lt;p&gt;If you encounter any issues, please don't hesitate to contact me!&lt;/p&gt;

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

&lt;p&gt;Congratulations! You have successfully added interactivity and physics to your browser-based basketball game. The ball now moves realistically, and players can control actions within the game. It's time to start scoring some baskets!&lt;/p&gt;

&lt;p&gt;In the next installment, we will introduce game mechanics to make the game fully playable.&lt;/p&gt;

&lt;p&gt;Stay tuned and happy coding!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>threejs</category>
      <category>beginners</category>
      <category>react</category>
    </item>
    <item>
      <title>Building Your First Browser Game with Three.js and React: Part 2 - Implementing 3D Models</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Fri, 10 May 2024 10:49:09 +0000</pubDate>
      <link>https://dev.to/romaixn/building-your-first-browser-game-with-threejs-and-react-part-2-implementing-3d-models-1jlj</link>
      <guid>https://dev.to/romaixn/building-your-first-browser-game-with-threejs-and-react-part-2-implementing-3d-models-1jlj</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome back to our series on building a 3D basketball game in the browser!&lt;br&gt;
In Part 1, we set up our project with Vite and created a basic 3D scene with a cube.&lt;br&gt;
Today, we're adding key elements to our game: the basketball and the table (or hoop stand).&lt;br&gt;
By the end of this tutorial, you'll see these core game components come to life in our scene.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Preparing Your 3D Models
&lt;/h2&gt;

&lt;p&gt;Before we start coding, ensure you have the 3D models for the basketball and the table.&lt;br&gt;
We're using models prepared for Three.js (just created in Blender and exported in the right format), which are available for download below&lt;br&gt;
(If these links don't lead directly to downloads, simply copy the entire page and paste the content into the files mentioned later.)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://raw.githubusercontent.com/Romaixn/mini-basket/main/public/models/basketball.glb"&gt;Download the basketball model&lt;/a&gt; (&lt;code&gt;basketball.glb&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://raw.githubusercontent.com/Romaixn/mini-basket/main/public/models/table.gltf"&gt;Download the table model&lt;/a&gt; (&lt;code&gt;table.gltf&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create a new folder named &lt;code&gt;models/&lt;/code&gt; within the &lt;code&gt;public/&lt;/code&gt; directory and place the two models in it.&lt;br&gt;
Now, the project contains these files: &lt;code&gt;public/models/basketball.glb&lt;/code&gt; and &lt;code&gt;public/models/table.gltf&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: Creating the Ball Component
&lt;/h2&gt;

&lt;p&gt;We will create two components using the &lt;a href="https://gltf.pmnd.rs/"&gt;GLTFJSX tool&lt;/a&gt;.&lt;br&gt;
This tool transforms 3D models (in gltf format or others) into ready-to-use components for your &lt;strong&gt;React Three Fiber&lt;/strong&gt; project. Try it yourself with our two models!&lt;/p&gt;

&lt;p&gt;Let's start by adding the basketball to our scene. We'll use the &lt;code&gt;useGLTF&lt;/code&gt; hook from &lt;code&gt;@react-three/drei&lt;/code&gt; to load our model.&lt;br&gt;
You can find everything drei has to offer on the &lt;a href="https://github.com/pmndrs/drei"&gt;github of the project&lt;/a&gt;, don't hesitate to go on the documentation if you want more explanation about what we use!&lt;/p&gt;

&lt;p&gt;First, create a new &lt;code&gt;Components&lt;/code&gt; folder within the &lt;code&gt;src/&lt;/code&gt; directory to house the Ball and Table components and create a new &lt;code&gt;Ball.jsx&lt;/code&gt; file inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/Components/Ball.jsx&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useGLTF&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@react-three/drei&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Ball&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;materials&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGLTF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/models/basketball.glb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
            &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Material.001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;castShadow&lt;/span&gt;
            &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;useGLTF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/models/basketball.glb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In this component, we're loading the basketball model and allow us to placing it at a specified position in the scene with the &lt;code&gt;position&lt;/code&gt; prop.&lt;br&gt;
The preload function ensures the model is lazy loaded before it's needed, improving the performance.&lt;/p&gt;

&lt;p&gt;This component is straightforward, containing just a single &lt;strong&gt;mesh&lt;/strong&gt;—a 3D object made up of vertices and polygons—equipped with specific &lt;strong&gt;geometry&lt;/strong&gt; and &lt;strong&gt;material&lt;/strong&gt;. These parameters can be found by logging &lt;code&gt;nodes&lt;/code&gt; and &lt;code&gt;materials&lt;/code&gt;, the two parameters that the function &lt;code&gt;useGLTF&lt;/code&gt; give us. Additionally, we've included parameters such as &lt;code&gt;castShadow&lt;/code&gt; and &lt;code&gt;receiveShadow&lt;/code&gt; to control how the mesh casts and receives shadows from other objects.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Creating the Table Component
&lt;/h2&gt;

&lt;p&gt;Next, we'll add the table. This is a significant component as it's more complex than the ball.&lt;/p&gt;

&lt;p&gt;Create a new component named &lt;code&gt;Table.jsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/Components/Table.jsx&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MeshTransmissionMaterial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useGLTF&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/drei&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;materials&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGLTF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/models/table.gltf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;dispose&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wood&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.068&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Controls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wood&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;4.135&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.092&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.003&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Control_A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;4.184&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.129&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.744&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Control_A_Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;White&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.237&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.046&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.21&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.179&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Control_B&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Green&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;4.183&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.754&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
          &lt;span class="na"&gt;castShadow&lt;/span&gt;
          &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
          &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Control_B_Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;White&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.043&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.207&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.184&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Thruster_B&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Black&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;2.259&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.189&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.764&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Thruster_A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Black&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;2.259&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.189&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.765&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hide_Thruster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Black&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;2.257&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.047&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wood&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.235&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.565&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Cylinder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.235&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.177&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Panel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Wood&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.814&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;material&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Red&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.686&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;
        &lt;span class="na"&gt;castShadow&lt;/span&gt;
        &lt;span class="na"&gt;receiveShadow&lt;/span&gt;
        &lt;span class="na"&gt;geometry&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Glass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geometry&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.497&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.54&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.005&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MeshTransmissionMaterial&lt;/span&gt; &lt;span class="na"&gt;anisotropy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;chromaticAberration&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.04&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;distortionScale&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;temporalDistortion&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;mesh&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;useGLTF&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/models/table.gltf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This component loads the table model and all of its parts, such as the basket hop ring, controls, thrusters, and so on. You can identify each component by examining the &lt;strong&gt;geometry&lt;/strong&gt; prop of each mesh. For instance, &lt;code&gt;nodes.Ring.geometry&lt;/code&gt; corresponds to the ring of the basketball hoop!&lt;/p&gt;

&lt;p&gt;We simply modify the glass part of the model (The mesh with the &lt;code&gt;nodes.Glass.geometry&lt;/code&gt; geometry) by adding a custom material: the &lt;code&gt;MeshTransmissionMaterial&lt;/code&gt; to achieve appealing glass aesthetics! To achieve this, we simply add a child to the &lt;strong&gt;mesh&lt;/strong&gt; that contains the &lt;strong&gt;Glass&lt;/strong&gt; geometry and remove the existing &lt;strong&gt;material&lt;/strong&gt; from this mesh. This way, the mesh will use the material specified in its child.&lt;br&gt;
We give it some default parameter for a good looking glass.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4: Integrating the Components into the Scene
&lt;/h2&gt;

&lt;p&gt;Now, let's add both the Ball and Table components into our existing scene.&lt;/p&gt;

&lt;p&gt;Update your &lt;code&gt;Experience.jsx&lt;/code&gt; file to incorporate these new components and implement a few minor changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OrbitControls&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/drei&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Components/Table&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Ball&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Components/Ball&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Experience&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;color&lt;/span&gt; &lt;span class="na"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"background"&lt;/span&gt; &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ddc28d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ambientLight&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;directionalLight&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;intensity&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Environment&lt;/span&gt; &lt;span class="na"&gt;preset&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"city"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrbitControls&lt;/span&gt; &lt;span class="na"&gt;makeDefault&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Ball&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now we have added these two new components inside another component from drei called &lt;code&gt;Center&lt;/code&gt;.&lt;br&gt;
As the name suggests, this component is very useful for centering 3D objects on the screen.&lt;/p&gt;

&lt;p&gt;We also include a &lt;code&gt;&amp;lt;color&amp;gt;&lt;/code&gt; component to set the scene's background color.&lt;br&gt;
The transmission of our table's glass uses this to determine its background color.&lt;/p&gt;

&lt;p&gt;We make slight adjustments to the lighting by replacing the point light with a directional light,&lt;br&gt;
and we remove the parameter of the ambient light, opting to use the default one for a better view of our scene.&lt;br&gt;
Lastly, we add an &lt;code&gt;Environment&lt;/code&gt; component from drei to enhance the reflection on our table model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Testing Your Scene
&lt;/h2&gt;

&lt;p&gt;Launch your development server (if it's not already running) and navigate to your app.&lt;br&gt;
You should see the basketball and table rendered in the scene.&lt;/p&gt;

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

&lt;p&gt;Great job! You've successfully incorporated complex 3D models into your basketball game.&lt;br&gt;
This progress brings us one step closer to finalizing our interactive game.&lt;/p&gt;

&lt;p&gt;In the next part of our series, we'll introduce interactivity and physics.&lt;/p&gt;

&lt;p&gt;Stay tuned, and happy coding! 🏀&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>threejs</category>
      <category>react</category>
    </item>
    <item>
      <title>Building Your First Browser Game with Three.js and React: Part 1 - Getting Started</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Wed, 08 May 2024 22:01:33 +0000</pubDate>
      <link>https://dev.to/romaixn/building-your-first-browser-game-with-threejs-and-react-part-1-getting-started-ife</link>
      <guid>https://dev.to/romaixn/building-your-first-browser-game-with-threejs-and-react-part-1-getting-started-ife</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Are you ready to jump into the exciting world of &lt;strong&gt;3D web games&lt;/strong&gt;?&lt;br&gt;
In this series, we're going to build from scratch an interactive browser-based basketball game using &lt;strong&gt;Three.js&lt;/strong&gt; and &lt;strong&gt;React Three Fiber&lt;/strong&gt;.&lt;br&gt;
Imagine controlling a basketball with simple button clicks, aiming to score as many baskets as possible. If that sounds intriguing, you’re in for a treat!&lt;/p&gt;

&lt;p&gt;By the end of this series, not only will you have a fully functional game, but you'll also have gained a good understanding of creating 3D experiences using Three.js and React.&lt;br&gt;
Check out the &lt;a href="https://mini-basket.rherault.dev/"&gt;final version of the game&lt;/a&gt; to see what you'll be capable of creating.&lt;br&gt;
It's simple, fun, and a great way to dive into the possibilities of web-based game development.&lt;/p&gt;

&lt;p&gt;Today, we kick off with the basics—setting up our project environment using &lt;strong&gt;Vite&lt;/strong&gt;, which provides a fast and modern way to set up a React project.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Setting Up Your Environment
&lt;/h2&gt;

&lt;p&gt;First things first, you'll need to ensure you have Node.js installed on your computer.&lt;br&gt;
Node.js will help us manage our project's dependencies and run our development server.&lt;br&gt;
You can download and install Node.js from &lt;a href="https://nodejs.org/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once Node.js is ready, we're going to set up our project using Vite. Open your terminal and run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a new directory for your project and navigate into it&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;basketball-game
&lt;span class="nb"&gt;cd &lt;/span&gt;basketball-game

&lt;span class="c"&gt;# Initialize a new project using Vite with a React template&lt;/span&gt;
npm create vite@latest &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--template&lt;/span&gt; react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command sets up a new React project using Vite, which includes all the boilerplate code you need to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Installing Dependencies
&lt;/h2&gt;

&lt;p&gt;Our game will utilize Three.js and React Three Fiber. We need to add these to our project.&lt;br&gt;
While we're at it, we'll also install &lt;strong&gt;drei&lt;/strong&gt;, a handy collection of abstractions for React Three Fiber that makes working with Three.js even easier.&lt;/p&gt;

&lt;p&gt;Run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;three @react-three/fiber @react-three/drei
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These libraries are crucial as they allow us to work with 3D objects and harness React's powerful component-based architecture to manage them effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Verify Your Project Setup
&lt;/h2&gt;

&lt;p&gt;After installing your dependencies, it’s a good idea to ensure that everything is working as expected. Start your development server by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will launch your application in a local development server.&lt;br&gt;
Open your browser and navigate to &lt;code&gt;http://localhost:5173&lt;/code&gt; to see your new React application running. You should see a basic React welcome screen.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4: Creating a Basic 3D Scene with a Cube
&lt;/h2&gt;

&lt;p&gt;Now that we have our project environment ready and our libraries installed,&lt;br&gt;
let's dive into the fun part—creating our first 3D scene using Three.js and React Three Fiber.&lt;br&gt;
In this step, we'll set up a simple scene with a basic cube and a camera to get a feel for how Three.js integrates within a React application.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setting Up the Experience Component
&lt;/h3&gt;

&lt;p&gt;Inside your &lt;code&gt;src/&lt;/code&gt; directory, create a new file named &lt;code&gt;Experience.jsx&lt;/code&gt;.&lt;br&gt;
This component will house our 3D scene. Add the following code to initialize a basic scene with a cube:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OrbitControls&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/drei&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Experience&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ambientLight&lt;/span&gt; &lt;span class="na"&gt;intensity&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;pointLight&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OrbitControls&lt;/span&gt; &lt;span class="na"&gt;makeDefault&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meshStandardMaterial&lt;/span&gt; &lt;span class="na"&gt;attach&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"material"&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"orange"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In this component:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;ambientLight&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;pointLight&amp;gt;&lt;/code&gt; add basic lighting to the scene, which helps in viewing the cube.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;OrbitControls&amp;gt;&lt;/code&gt; a basic control to rotate/move around the scene.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;Box&amp;gt;&lt;/code&gt; is a component from &lt;code&gt;drei&lt;/code&gt; that represents a 3D cube. We color it orange.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Incorporating the Experience into Our App
&lt;/h3&gt;

&lt;p&gt;Next, we need to ensure that our scene is rendered by the main application.&lt;br&gt;
Delete the existing &lt;code&gt;App.js&lt;/code&gt; file in the &lt;code&gt;src&lt;/code&gt; folder and update the &lt;code&gt;main.jsx&lt;/code&gt; file to include our &lt;code&gt;Experience&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Canvas&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-three/fiber&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Experience&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Experience&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./index.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Canvas&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Experience&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Canvas&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup integrates the &lt;code&gt;Experience&lt;/code&gt; component into our main application layout and adding a base &lt;code&gt;Canvas&lt;/code&gt; component,&lt;br&gt;
which creates a canvas element where our 3D scene will render.&lt;/p&gt;
&lt;h3&gt;
  
  
  Create the base style for the 3D Experience
&lt;/h3&gt;

&lt;p&gt;Now, we just need to update the existing &lt;code&gt;index.css&lt;/code&gt; file to add the base of styling of our app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ddc28d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nf"&gt;#root&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nf"&gt;#main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;user-select&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now delete the &lt;code&gt;App.jsx&lt;/code&gt; file and the &lt;code&gt;App.css&lt;/code&gt; file also, we don’t need them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing Your Scene
&lt;/h3&gt;

&lt;p&gt;Once you have made these changes, save your files and ensure your development server is still running. Refresh your browser page at &lt;code&gt;http://localhost:5173&lt;/code&gt;.&lt;br&gt;
You should now see a cube rendered on the screen. You can rotate around, zooming in/out and move pressing CTRL.&lt;/p&gt;

&lt;p&gt;If it's not appearing, make sure your development server is running correctly and that there are no errors in your console.&lt;/p&gt;

&lt;p&gt;If you encounter any issues or have questions, don't hesitate to reach out for help.&lt;br&gt;
You can contact me in comments. I'm here to assist and ensure you have a great experience building this game!&lt;/p&gt;

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

&lt;p&gt;Congratulations! You've just created your first 3D scene using Three.js and React Three Fiber.&lt;br&gt;
This basic setup is the stepping stone to more complex and interactive 3D graphics that we will explore in upcoming posts in this series.&lt;/p&gt;

&lt;p&gt;In the next part of our series, we will add the base models.&lt;/p&gt;

&lt;p&gt;Stay tuned as we continue to build out our basketball game! 🏀&lt;/p&gt;

</description>
      <category>threejs</category>
      <category>react</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Supercharge your application's performance: Consuming Symfony messenger messages with Go</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Fri, 21 Jul 2023 07:25:21 +0000</pubDate>
      <link>https://dev.to/romaixn/supercharge-your-applications-performance-consuming-symfony-messenger-messages-with-go-2b3f</link>
      <guid>https://dev.to/romaixn/supercharge-your-applications-performance-consuming-symfony-messenger-messages-with-go-2b3f</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As applications scale and grow, efficient message processing becomes crucial for maintaining &lt;strong&gt;high performance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;While &lt;strong&gt;Symfony Messenger&lt;/strong&gt; excels in dispatching messages, I introduce a tool to supercharge your message consumption process: &lt;a href="https://github.com/Romaixn/gosumer"&gt;Gosumer&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
Harness the raw power of Go to &lt;strong&gt;optimize your application's performance&lt;/strong&gt; and handle Symfony Messenger messages seamlessly.&lt;/p&gt;

&lt;p&gt;In this article, I'll delve into the functionalities of &lt;strong&gt;Gosumer&lt;/strong&gt; and showcase an example of its implementation to demonstrate its capabilities.&lt;/p&gt;
&lt;h2&gt;
  
  
  Introducing Gosumer
&lt;/h2&gt;

&lt;p&gt;Gosumer is a cutting-edge package designed to enhance your application's performance by efficiently &lt;strong&gt;consuming Symfony Messenger messages using Go code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Built to work seamlessly with &lt;strong&gt;PostgreSQL&lt;/strong&gt; and &lt;strong&gt;AMQP&lt;/strong&gt;, this tool empowers developers to streamline their message processing and unlock unparalleled performance gains.&lt;/p&gt;

&lt;p&gt;You can find the source code of this package &lt;a href="https://github.com/Romaixn/gosumer"&gt;here&lt;/a&gt;; feel free to contribute or share your feedback!&lt;/p&gt;
&lt;h2&gt;
  
  
  Example: Empowering your application with Gosumer
&lt;/h2&gt;

&lt;p&gt;Let's dive into an illustrative example to showcase Gosumer in action.&lt;/p&gt;

&lt;p&gt;Imagine you have a Go application that needs to process incoming messages efficiently.&lt;br&gt;&lt;br&gt;
With Gosumer, you can easily achieve this goal with just a few lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
&lt;span class="s"&gt;"log"&lt;/span&gt;

&lt;span class="s"&gt;"github.com/romaixn/gosumer"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ID&lt;/span&gt;     &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="s"&gt;`json:"id"`&lt;/span&gt;
    &lt;span class="n"&gt;Number&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="s"&gt;`json:"number"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gosumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PgDatabase&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="s"&gt;"localhost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Port&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="m"&gt;5432&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"!ChangeMe!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;TableName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"messenger_messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gosumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;processMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;processMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Message received: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error marshalling message: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;

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

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;
    &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error unmarshalling message: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;

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

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sum of %d and %d is %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we define a Message struct, representing the data in the incoming messages, it's the same structure that you have defined on the Symfony side (PHP).&lt;/p&gt;

&lt;p&gt;Afterwards, we listen to all messages using the &lt;code&gt;gosumer.listen&lt;/code&gt; function and process them through &lt;code&gt;processMessage&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
Once the message is processed and there are no errors, it's deleted from the database.&lt;br&gt;
However, if an error occurs during processing, the message is not deleted and will be re-consumed at a later time.&lt;/p&gt;

&lt;p&gt;I already have some ideas for improving the developer experience of the package. I've created a few issues that you can &lt;a href="https://github.com/Romaixn/gosumer/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement"&gt;check out here&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Gosumer can help you for optimizing your application's performance by consuming Symfony Messenger messages with Go.&lt;br&gt;&lt;br&gt;
By leveraging the &lt;strong&gt;power of Go&lt;/strong&gt; and &lt;strong&gt;Symfony Messenger&lt;/strong&gt;, your application will be as powerful as a superhero team on an efficiency-boosting, scalability-expanding quest!&lt;/p&gt;

&lt;p&gt;Feel free to &lt;a href="https://github.com/Romaixn/gosumer"&gt;visit GitHub&lt;/a&gt; to explore the project and test it out! I'd love to hear your feedback.&lt;/p&gt;

&lt;p&gt;See you on GitHub! ⭐️&lt;/p&gt;

</description>
      <category>symfony</category>
      <category>go</category>
      <category>performance</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Discover new developer communities (Discord, Slack, etc.)</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Fri, 27 Jan 2023 15:55:44 +0000</pubDate>
      <link>https://dev.to/romaixn/discover-new-developer-communities-discord-slack-etc-i9i</link>
      <guid>https://dev.to/romaixn/discover-new-developer-communities-discord-slack-etc-i9i</guid>
      <description>&lt;p&gt;Hello everyone ! If you're a web developer looking for a place to connect with other developers, then this repository is for you :&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Romaixn"&gt;
        Romaixn
      &lt;/a&gt; / &lt;a href="https://github.com/Romaixn/awesome-communities"&gt;
        awesome-communities
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A curated list of awesome developer communities (Discord, Slack, Telegram, etc.).
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Awesome Communities &lt;a href="https://awesome.re" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/715ee701c8a9a0dbe30aac69ed79f5712a6542f5a482a3940084ce76d494a779/68747470733a2f2f617765736f6d652e72652f62616467652e737667" alt="Awesome"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A curated list of awesome developer communities (Discord, Slack, Telegram, etc.).&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Table of Contents&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Use the "Table of Contents" menu in the top-left corner to explore the list.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;English&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;AI&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://huggingface.co/join/discord" rel="nofollow"&gt;Hugging Face Discord&lt;/a&gt; - The AI community building the future.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://discord.gg/leonardo-ai" rel="nofollow"&gt;Leonardo AI&lt;/a&gt; - Official Leonardo Image generation AI Discord community.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Frontend&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://discord.com/invite/kx7pk6J" rel="nofollow"&gt;Frontend Developers Discord&lt;/a&gt; - Friendly creative web developer Discord community.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Help / Courses&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://discord.gg/codecademy" rel="nofollow"&gt;Codecademy Discord&lt;/a&gt; - The official Codecademy Discord community.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://discord.gg/YdmGW8GY8Z" rel="nofollow"&gt;Codu Discord&lt;/a&gt; - Codu - The Coding community.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://discord.gg/freecodecamp-org-official-fi-fo-692816967895220344" rel="nofollow"&gt;freeCodeCamp Discord&lt;/a&gt; - The official freeCodeCamp Discord community.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://discord.gg/theodinproject" rel="nofollow"&gt;The Odin Project Discord&lt;/a&gt; - The official The Odin Project Discord community.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Java&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.javadiscord.net/" rel="nofollow"&gt;Java Discord&lt;/a&gt; - One of the biggest Java Communities on Discord.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://togetherjava.org/" rel="nofollow"&gt;Together Java&lt;/a&gt; - Java self-help Discord community.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;PHP&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://phpchat.co/" rel="nofollow"&gt;PHP Slack&lt;/a&gt; - The official PHP Slack community.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://symfony.com/slack-invite" rel="nofollow"&gt;Symfony Slack&lt;/a&gt; - The official Symfony Slack community.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Python&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://discord.gg/dpy" rel="nofollow"&gt;Discord.py Discord&lt;/a&gt; - The official Discord.py Discord community.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://discord.gg/mMJHgYEqRK" rel="nofollow"&gt;Flet Discord&lt;/a&gt; -…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Romaixn/awesome-communities"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The goal of this repository is to gather all the Discord, Slack, etc. servers speaking of development in the same place.&lt;/p&gt;

&lt;p&gt;Do not hesitate to &lt;strong&gt;contribute&lt;/strong&gt; to add the communities that you know, that you appreciate.&lt;/p&gt;

&lt;p&gt;No matter the language (Javascript, PHP, etc.), topic, the spoken language (english, french, etc.) etc.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>discuss</category>
      <category>github</category>
      <category>community</category>
    </item>
    <item>
      <title>Soft skills, why are they so important?</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Thu, 20 Oct 2022 15:57:32 +0000</pubDate>
      <link>https://dev.to/romaixn/soft-skills-why-are-they-so-important-52b1</link>
      <guid>https://dev.to/romaixn/soft-skills-why-are-they-so-important-52b1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;French version is &lt;a href="https://rherault.fr/blog/soft-skills-developpeur"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Today we're going to talk about "soft skills" in the &lt;strong&gt;workplace&lt;/strong&gt; and I'm going to try to explain to you why they are so &lt;strong&gt;important&lt;/strong&gt; and how they can make &lt;strong&gt;the difference&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Soft Skills
&lt;/h2&gt;

&lt;p&gt;We often hear about soft skills, but what are they?&lt;/p&gt;

&lt;p&gt;Soft skills, also called "basic skills", are skills that can be applied to all professions, as opposed to "hard skills", which are specific to a particular profession.&lt;/p&gt;

&lt;p&gt;This category includes a multitude of &lt;strong&gt;relational&lt;/strong&gt; skills, for example (this list is not exhaustive, it corresponds to the most important points in my opinion):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Critical thinking&lt;/strong&gt; , know how to question yourself but also the decisions of others,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Problem solving&lt;/strong&gt; , not feeling demoralized when faced with a big problem, &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Communication&lt;/strong&gt; , knowing how to communicate is very important, not isolate yourself, &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Teamwork&lt;/strong&gt; , know how to collaborate on a common project,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These very general skills will be useful for you to integrate into a team or to interact with your clients.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do they really matter?
&lt;/h2&gt;

&lt;p&gt;Soft skills are extremely important in the professional world.&lt;/p&gt;

&lt;p&gt;Especially during a &lt;strong&gt;job interview&lt;/strong&gt;, a person who knows how to communicate correctly, explain what he/she has been working on, etc., has a much better chance of being recruited than the opposite.&lt;/p&gt;

&lt;p&gt;Developers who have technical difficulties and know how to communicate are considered better than the opposite.&lt;/p&gt;

&lt;p&gt;In our business, technologies are evolving so fast that a recruiter is not only looking for a technically gifted developer but also someone &lt;strong&gt;able to evolve&lt;/strong&gt; within the company.&lt;/p&gt;

&lt;p&gt;A developer who doesn't want to change/evolve, who has an overinflated ego (believing himself to be on top of everything) will have much less chance than vice versa.&lt;/p&gt;

&lt;p&gt;That's why we can say that soft skills are more important than hard skills (I'm talking about our profession, but I imagine that this is also true for other professions)&lt;/p&gt;

&lt;h2&gt;
  
  
  How to "work" on my soft skills?
&lt;/h2&gt;

&lt;p&gt;Just like hard skills, soft skills are not "innate".&lt;/p&gt;

&lt;p&gt;For example, the more you communicate, the more comfortable you will be.&lt;/p&gt;

&lt;p&gt;You don't need to master absolutely all of these skills, but we can see the &lt;strong&gt;"must have "&lt;/strong&gt; skills in my opinion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Have a critical mind
&lt;/h3&gt;

&lt;p&gt;Having a &lt;strong&gt;critical mind&lt;/strong&gt; is great. You have to understand that one way of working is not necessarily the best way for everyone, to know how to &lt;strong&gt;question&lt;/strong&gt; yourself continuously.&lt;/p&gt;

&lt;p&gt;If you take the slightest remark about your code or the way you work the wrong way, it's a bad sign! We have to know how to &lt;strong&gt;remember&lt;/strong&gt; our work.&lt;/p&gt;

&lt;p&gt;We always have something to learn and we welcome any feedback.&lt;/p&gt;

&lt;p&gt;You must also dare to &lt;strong&gt;talk about your difficulties&lt;/strong&gt; , not to close yourself off to a problem that could be solved as a team. &lt;strong&gt;Simply ask for help&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Know how to communicate
&lt;/h3&gt;

&lt;p&gt;Communication** is essential in our business.&lt;/p&gt;

&lt;p&gt;A developer never works alone.&lt;/p&gt;

&lt;p&gt;Being able to explain code to colleagues, to justify technical decisions are very important things, for example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Knowing how to communicate&lt;/strong&gt; with a customer is essential too, especially if you are brought to be in contact with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Constantly learning
&lt;/h3&gt;

&lt;p&gt;Our job is in &lt;strong&gt;constant evolution&lt;/strong&gt;, we are required to learn throughout our career.&lt;/p&gt;

&lt;p&gt;You have to be able to learn a new framework, a new technology on your own.&lt;/p&gt;

&lt;p&gt;Don't hesitate to do &lt;strong&gt;technology watch&lt;/strong&gt; to keep you informed of new features but also of updates. For that, I create a &lt;strong&gt;newsletter&lt;/strong&gt; to share my technology watch &lt;strong&gt;every week&lt;/strong&gt;. You can subscribe at &lt;a href="https://www.getrevue.co/profile/rherault"&gt;this address&lt;/a&gt;(The newsletter has just been switched to English/French, don't hesitate to subscribe !)).&lt;/p&gt;

&lt;h3&gt;
  
  
  Solving problems without panic
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Not to panic&lt;/strong&gt; and &lt;strong&gt;demoralize&lt;/strong&gt; at the first problem encountered is very important too, especially in our job where we spend our time debugging!&lt;/p&gt;

&lt;p&gt;For that, nothing better than &lt;strong&gt;decoupling&lt;/strong&gt; your big problem into several small ones, so you don't feel overloaded.&lt;/p&gt;

&lt;p&gt;And if you are stuck, don't hesitate to &lt;strong&gt;ask for help&lt;/strong&gt;, as seen in the 1st point.&lt;/p&gt;

&lt;p&gt;A company would rather you ask for help than waste time on a problem for 4 days!&lt;/p&gt;

&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;Most soft skills come "on their own" with &lt;strong&gt;experience&lt;/strong&gt; but mostly it all depends on one's character.&lt;/p&gt;

&lt;p&gt;Now that you have all the keys in hand, you will be able to be much more fulfilled in what you do.&lt;/p&gt;

&lt;p&gt;If you want to go deeper, I recommend &lt;a href="https://www.amazon.fr/Soft-Skills-Software-Developers-Manual-dp-0999081446/dp/0999081446"&gt;this book&lt;/a&gt; that Medhi Zed aka &lt;em&gt;Jesuisundev&lt;/em&gt; had shared on his article &lt;a href="https://www.jesuisundev.com/livre-developpeur/"&gt;"Top 3 essential books for developers"&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have any feedback on this article, don't hesitate to &lt;a href="https://rherault.fr/contact"&gt;come and tell me about it&lt;/a&gt; !&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>productivity</category>
      <category>career</category>
      <category>softskills</category>
    </item>
    <item>
      <title>Qu’est-ce que “l’open source” et pourquoi je devrais y contribuer ?</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Mon, 26 Sep 2022 09:33:53 +0000</pubDate>
      <link>https://dev.to/romaixn/quest-ce-que-lopen-source-et-pourquoi-je-devrais-y-contribuer--2dmf</link>
      <guid>https://dev.to/romaixn/quest-ce-que-lopen-source-et-pourquoi-je-devrais-y-contribuer--2dmf</guid>
      <description>&lt;p&gt;L’ &lt;strong&gt;Hacktoberfest&lt;/strong&gt; 2022 est l’occasion de comprendre ce qu’est l’ &lt;strong&gt;open source&lt;/strong&gt; et pourquoi tu devrais y &lt;strong&gt;contribuer&lt;/strong&gt; , et donc participer à cet événement qui se déroule durant &lt;strong&gt;tout le mois d’octobre&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qu’est ce que l’open source
&lt;/h2&gt;

&lt;p&gt;Un code open source est un code &lt;strong&gt;ouvert&lt;/strong&gt; , accessible à tous.&lt;/p&gt;

&lt;p&gt;À ne pas confondre avec la notion de “code libre”.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code libre vs code open source, quelles différences ?
&lt;/h2&gt;

&lt;p&gt;La notion de &lt;strong&gt;code libre&lt;/strong&gt; est née bien avant celle de l’open source.&lt;/p&gt;

&lt;p&gt;C’est &lt;strong&gt;Richard STALLMAN&lt;/strong&gt; qui a initié ce mouvement. La différence est grande &lt;a href="https://www.gnu.org/philosophy/open-source-misses-the-point.fr.html"&gt;selon lui&lt;/a&gt; :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Think of “free speech”, not “free beer”.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;cite&gt;Richard STALLMAN&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;_ &lt;strong&gt;Pensez à “liberté d’expression” et pas à “entrée libre”&lt;/strong&gt; _, la grande différence entre les deux notions résident dans cette phrase.&lt;/p&gt;

&lt;p&gt;C’est une question de liberté, pas de prix.&lt;/p&gt;

&lt;p&gt;Ce n’est pas parce que le code est accessible qu’il respecte toutes les libertés résidant dans le code libre :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Liberté de l’utiliser,&lt;/li&gt;
&lt;li&gt;Liberté de l’étudier,&lt;/li&gt;
&lt;li&gt;Liberté de le modifier et d’en redistribuer des copies, modifiées ou non.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ce n’est pas parce que le code est disponible pour tous qu’il prône les valeurs du libre.&lt;/p&gt;

&lt;p&gt;De nos jours de nombreuses licences sont disponibles, plus ou moins restrictives. Certaines ne respectant pas le &lt;strong&gt;mouvement du libre&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;GitHub a même créer un outil permettant de choisir la licence appropriée à nos besoin : &lt;a href="https://choosealicense.com/"&gt;https://choosealicense.com/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pourquoi contribuer ?
&lt;/h2&gt;

&lt;p&gt;Il existe une multitude de raisons de vouloir contribuer.&lt;/p&gt;

&lt;p&gt;Tu utilises un &lt;em&gt;framework&lt;/em&gt; que tu apprécies et tu souhaites &lt;strong&gt;apporter ton aide à la communauté&lt;/strong&gt;? Tu peux contribuer.&lt;/p&gt;

&lt;p&gt;Tu rencontres un bug dans un package que tu utilises et tu souhaites le résoudre toi même ? Tu peux contribuer&lt;/p&gt;

&lt;p&gt;Il n’existe pas de &lt;strong&gt;traduction&lt;/strong&gt; pour ta langue ? Tu peux contribuer.&lt;/p&gt;

&lt;p&gt;Et encore bien d’autres.&lt;/p&gt;

&lt;p&gt;Le principal &lt;strong&gt;avantage&lt;/strong&gt; à la contribution est que tu vas apporter ton aide à la communauté, que tu vas participer activement à l’amélioration d’outils open source que tu utilises quasiment tous les jours.&lt;/p&gt;

&lt;p&gt;Ensuite, en termes de compétences, tu vas pouvoir découvrir du code existant et donc t’exercer à comprendre et adapter un code que tu n’as pas écrit.&lt;/p&gt;

&lt;p&gt;Tu vas même pouvoir acquérir de nouvelles compétences.&lt;/p&gt;

&lt;p&gt;Et si tu contribues à ton framework / CMS / outil préféré tu vas bien mieux comprendre comment il fonctionne, en découvrant le &lt;strong&gt;cœur&lt;/strong&gt; de celui-ci.&lt;/p&gt;

&lt;p&gt;En bref, il n’y a que du bon dans la contribution de projets open source, donc n’hésites pas !&lt;/p&gt;

&lt;p&gt;Maintenant si tu as envie d’apporter ta contribution, comment faire ?&lt;/p&gt;

&lt;h2&gt;
  
  
  Comment contribuer ?
&lt;/h2&gt;

&lt;p&gt;Nous avons vu qu’il existe énormément de manières différentes de contribuer :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Résoudre des &lt;strong&gt;issues&lt;/strong&gt; (bug)&lt;/li&gt;
&lt;li&gt;Création/Correction de documentations&lt;/li&gt;
&lt;li&gt;Faire de la traduction&lt;/li&gt;
&lt;li&gt;etc..&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si tu es &lt;strong&gt;débutant⸱e&lt;/strong&gt; et que tu n’as jamais fait ce genre de chose, tu peux commencer par consulter &lt;a href="https://www.digitalocean.com/community/tutorial_series/an-introduction-to-open-source"&gt;cette page&lt;/a&gt; ou encore &lt;a href="https://opensource.guide/fr/how-to-contribute/"&gt;celle ci&lt;/a&gt; (en français) créée par GitHub.&lt;/p&gt;

&lt;p&gt;Ces tutoriels rapides vont t’apprendre à te servir de _ &lt;strong&gt;git&lt;/strong&gt; _ et t’expliquer de A à Z comment apporter ton aide.&lt;/p&gt;

&lt;p&gt;Pour commencer et pour découvrir le monde de l’open source et de la contribution :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/firstcontributions/first-contributions"&gt;First Contributions&lt;/a&gt;, un projet pour réaliser ta première PR (Pull Request)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mungell/awesome-for-beginners"&gt;Awesome For Beginner&lt;/a&gt;, une liste de &lt;strong&gt;projet cool pour les juniors&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22"&gt;Good First Issues Github&lt;/a&gt;, une liste de toutes les &lt;em&gt;issues&lt;/em&gt; notées comme “Good First Issue”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si tu sais déjà comment contribuer et te servir de git tu peux tout de suite te lancer.&lt;/p&gt;

&lt;p&gt;Mais tout d’abord, il va falloir trouver un projet sur lequel tu veux contribuer et te trouver un problème à résoudre. (c’est souvent l’étape la plus compliquée)&lt;/p&gt;

&lt;p&gt;Cela peut être le framework, outil, CMS que tu utilise quotidiennement en tant que développeur.&lt;/p&gt;

&lt;p&gt;Par exemple, si tu souhaites contribuer au projet &lt;strong&gt;Symfony&lt;/strong&gt; , il existe une formation gratuite excellente sur &lt;a href="https://symfonycasts.com/screencast/contributing"&gt;Symfony Casts&lt;/a&gt; ! Ensuite, il suffit de te rendre dans &lt;a href="https://github.com/symfony/symfony/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc"&gt;l’onglet “Issues” du repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Si tu préfères t’entraîner sur d’autres projets, tu peux consulter ces différentes pages :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://up-for-grabs.net/#/"&gt;Up For Grabs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/topics/hacktoberfest"&gt;Projets Hacktoberfest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oswc.is/search-projects"&gt;OSWC – Projets open source&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ces pages vont te donner des projets où il y a besoin d’aide et tu peux filtrer par langage, facilité de résolution, etc..&lt;/p&gt;

&lt;p&gt;Il n’y a plus qu’à trouver une issue, te l’attribuer et commencer à la résoudre !&lt;/p&gt;

&lt;p&gt;Maintenant que tu sais comment contribuer, je ne peux que te souhaiter un &lt;strong&gt;Happy Hacktoberfest 2022&lt;/strong&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UnTCpVGT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://s.w.org/images/core/emoji/14.0.0/72x72/1f389.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UnTCpVGT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://s.w.org/images/core/emoji/14.0.0/72x72/1f389.png" alt="🎉" width="72" height="72"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xFOObd4f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.rherault.fr/app/uploads/2022/09/12t9r8j7n9ynxbdzhs5p-1024x576.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xFOObd4f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.rherault.fr/app/uploads/2022/09/12t9r8j7n9ynxbdzhs5p-1024x576.webp" alt="Hacktoberfest 2022" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>tutos</category>
      <category>french</category>
    </item>
    <item>
      <title>Les “Soft skills”, pourquoi sont-ils si importants ?</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Mon, 22 Aug 2022 08:30:00 +0000</pubDate>
      <link>https://dev.to/romaixn/les-soft-skills-pourquoi-sont-ils-si-importants--4od1</link>
      <guid>https://dev.to/romaixn/les-soft-skills-pourquoi-sont-ils-si-importants--4od1</guid>
      <description>&lt;p&gt;Aujourd’hui, nous allons parler des “ &lt;strong&gt;Soft skills&lt;/strong&gt; ” dans le &lt;strong&gt;monde du travail&lt;/strong&gt; et je vais tenter de t’expliquer pourquoi sont-ils si &lt;strong&gt;importants&lt;/strong&gt; et comment peuvent-ils faire &lt;strong&gt;la différence&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Les “Soft Skills”
&lt;/h2&gt;

&lt;p&gt;On entend souvent parler de soft skills, mais qu’est ce que c’est ?&lt;/p&gt;

&lt;p&gt;Les soft skills, aussi appelés “compétences de base” sont des compétences applicables à tous les corps de métiers, à l’inverse des &lt;strong&gt;“hard skills”&lt;/strong&gt; , qui eux sont spécifiques à un métier en particulier.&lt;/p&gt;

&lt;p&gt;Cette catégorie regroupe une multitude de compétences &lt;strong&gt;relationnelles&lt;/strong&gt; , par exemple (cette liste est non-exhaustive, elle correspond aux points les plus importants selon moi) :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Esprit critique&lt;/strong&gt; , savoir se remettre en question mais aussi les décisions des autres,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Résolution de problèmes&lt;/strong&gt; , ne pas se sentir démoralisé⸱e face à un problème de taille, &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Communication&lt;/strong&gt; , savoir communiquer est très important, ne pas s’isoler, &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Travail d’équipe&lt;/strong&gt; , savoir collaborer sur un projet commun,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Attitude professionnelle&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ces compétences, très générales, vont t’être utiles pour t’intégrer dans une équipe ou interagir au mieux avec tes clients.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sont-ils vraiment importants ?
&lt;/h2&gt;

&lt;p&gt;Les soft skills sont extrêmement importants dans le monde professionnel.&lt;/p&gt;

&lt;p&gt;Notamment lors d’un &lt;strong&gt;entretien d’embauche&lt;/strong&gt; , une personne sachant communiquer correctement, expliquer ce sur quoi elle a travaillé, etc.. à beaucoup plus de chance d’être recrutée que l’inverse.&lt;/p&gt;

&lt;p&gt;Les développeur⸱euse⸱s qui ont des difficultés techniques et qui savent communiqué⸱e⸱s sont considéré⸱e⸱s comme meilleur⸱e⸱s que l’inverse.&lt;/p&gt;

&lt;p&gt;Dans notre métier, les technologies évoluent tellement rapidement qu’un⸱e recruteur⸱euse ne cherche plus seulement un⸱e développeur⸱euse techniquement doué⸱e mais aussi quelqu’un &lt;strong&gt;capable d’évoluer&lt;/strong&gt; au sein de l’entreprise.&lt;/p&gt;

&lt;p&gt;Un⸱e développeur⸱euse ne voulant pas changer/évoluer, ayant un ego surdimensionné (se croyant au dessus de tout) aura bien moins de chance qu’inversement.&lt;/p&gt;

&lt;p&gt;C’est pour cela que l’on peut dire que les soft skills ont une &lt;strong&gt;place plus importante&lt;/strong&gt; que les hard skills. (je parle dans notre métier, mais j’imagine que cela est valable dans d’autres également)&lt;/p&gt;

&lt;h2&gt;
  
  
  Comment “travailler” mes soft skills ?
&lt;/h2&gt;

&lt;p&gt;Tout comme les hard skills, les soft skills ne sont pas “innés”.&lt;/p&gt;

&lt;p&gt;Par exemple, plus tu vas communiquer, plus tu seras à l’aise.&lt;/p&gt;

&lt;p&gt;Tu n’as pas besoin de maîtriser absolument toutes ces compétences, mais nous pouvons voir les compétences &lt;strong&gt;“indispensables”&lt;/strong&gt; selon moi.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoir un esprit critique
&lt;/h3&gt;

&lt;p&gt;Avoir un &lt;strong&gt;esprit critique&lt;/strong&gt; est génial. Il faut comprendre qu’une méthode de travail n’est pas forcément la meilleure pour tout le monde, savoir &lt;strong&gt;se remettre en question&lt;/strong&gt; continuellement.&lt;/p&gt;

&lt;p&gt;Si tu prends mal la moindre remarque fait par rapport à ton code ou à ta façon de travailler, c’est mauvais signe ! Il faut savoir &lt;strong&gt;prendre du recul&lt;/strong&gt; sur notre travail.&lt;/p&gt;

&lt;p&gt;Nous avons toujours à apprendre et toute remarque est la bienvenue.&lt;/p&gt;

&lt;p&gt;Il faut aussi oser &lt;strong&gt;parler de ses difficultés&lt;/strong&gt; , ne pas se renfermer sur un problème qui pourrait être résolu en équipe. &lt;strong&gt;Demander de l’aide&lt;/strong&gt; , tout simplement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Savoir communiquer
&lt;/h3&gt;

&lt;p&gt;La &lt;strong&gt;communication&lt;/strong&gt; est primordiale dans notre métier.&lt;/p&gt;

&lt;p&gt;Un⸱e développeur⸱euse ne travaille jamais seul.&lt;/p&gt;

&lt;p&gt;Pouvoir expliquer du code à ses collègues, justifier des décisions techniques sont des choses très importantes, par exemple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Savoir communiquer&lt;/strong&gt; avec un client est indispensable aussi, surtout si tu es amené⸱e à être en contact avec.&lt;/p&gt;

&lt;h3&gt;
  
  
  Apprendre constamment
&lt;/h3&gt;

&lt;p&gt;Notre métier est en &lt;strong&gt;constante évolution&lt;/strong&gt; , nous sommes amenés à apprendre durant toute notre carrière.&lt;/p&gt;

&lt;p&gt;Il faut que tu puisses apprendre un nouveau framework, une nouvelle technologie par toi-même.&lt;/p&gt;

&lt;p&gt;Ne pas hésiter à faire de la &lt;strong&gt;veille technologique&lt;/strong&gt; pour te tenir au courant des nouveautés mais aussi des mises à jour. Pour cela, je réalise une &lt;strong&gt;newsletter&lt;/strong&gt; pour partager ma veille &lt;strong&gt;toutes les semaines&lt;/strong&gt;. Tu peux t’inscrire en bas de cet article ou encore à &lt;a href="https://www.getrevue.co/profile/rherault"&gt;cette adresse&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Résoudre des problèmes sans panique
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Ne pas paniquer&lt;/strong&gt; et &lt;strong&gt;démoraliser&lt;/strong&gt; au premier problème rencontré est très important aussi, surtout dans notre métier où l’on passe notre temps à debugger !&lt;/p&gt;

&lt;p&gt;Pour cela, rien de mieux que de &lt;strong&gt;découper&lt;/strong&gt; ton gros problème en plusieurs petits, pour ne pas te sentir surchargé⸱e.&lt;/p&gt;

&lt;p&gt;Et si tu es coincé⸱e, ne pas hésiter à &lt;strong&gt;demander de l’aide&lt;/strong&gt; , comme vu dans le 1er point.&lt;/p&gt;

&lt;p&gt;Une entreprise préfère que tu demandes de l’aide plutôt que tu perdes du temps sur un problème pendant 4 jours !&lt;/p&gt;

&lt;h2&gt;
  
  
  Pour conclure
&lt;/h2&gt;

&lt;p&gt;La plupart des soft skills viennent “tout seuls” avec &lt;strong&gt;l’expérience&lt;/strong&gt; mais surtout tout dépend du caractère de chacun.&lt;/p&gt;

&lt;p&gt;Maintenant que tu as toutes les clés en main, tu vas pouvoir être bien plus épanoui⸱e dans ce que tu fais.&lt;/p&gt;

&lt;p&gt;Si tu souhaites approfondir, je te conseille &lt;a href="https://www.amazon.fr/Soft-Skills-Software-Developers-Manual-dp-0999081446/dp/0999081446"&gt;ce livre&lt;/a&gt; qu’avait partagé Medhi Zed alias &lt;em&gt;Jesuisundev&lt;/em&gt; sur son article &lt;a href="https://www.jesuisundev.com/livre-developpeur/"&gt;“Top 3 des livres indispensables pour développeurs”&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si tu as des retours suite à cet article, n’hésite pas à &lt;a href="https://rherault.fr/contact"&gt;venir m’en parler&lt;/a&gt; !&lt;/p&gt;

</description>
      <category>softskills</category>
      <category>french</category>
    </item>
    <item>
      <title>Découverte du composant workflow de Symfony</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Tue, 16 Aug 2022 16:19:01 +0000</pubDate>
      <link>https://dev.to/romaixn/decouverte-du-composant-workflow-de-symfony-3kb4</link>
      <guid>https://dev.to/romaixn/decouverte-du-composant-workflow-de-symfony-3kb4</guid>
      <description>&lt;p&gt;Aujourd’hui, nous allons découvrir ensemble le composant &lt;strong&gt;Workflow&lt;/strong&gt; de &lt;strong&gt;Symfony&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Le but de ce composant
&lt;/h2&gt;

&lt;p&gt;L’objectif de ce composant est de reproduire des &lt;strong&gt;“machines à état”&lt;/strong&gt; (ou &lt;strong&gt;automate&lt;/strong&gt; ) qui correspond à un modèle de mathématique.&lt;/p&gt;

&lt;p&gt;Evidemment, dit comme ça, le composant paraît hyper compliqué. Mais une image vaut 1000 mots :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EIhqvfia--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.rherault.fr/app/uploads/2022/07/states_transitions.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EIhqvfia--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.rherault.fr/app/uploads/2022/07/states_transitions.png" alt="" width="800" height="144"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Explication du Workflow du site symfony.com&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;En bref, le composant &lt;strong&gt;Workflow&lt;/strong&gt; permet de définir plusieurs états pour une entité.&lt;/p&gt;

&lt;p&gt;Prenons l’exemple donné par &lt;strong&gt;&lt;a href="https://fr.wikipedia.org/wiki/Automate_fini#Un_premier_exemple_:_un_portillon"&gt;Wikipedia&lt;/a&gt;&lt;/strong&gt; :&lt;/p&gt;

&lt;p&gt;Imagine un “portillon d’accès” (comme dans le métro, tu insères ton ticket et hop tu passes), il est très simple de le représenter sous la forme d’un automate :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QGQdf1Ea--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.rherault.fr/app/uploads/2022/08/automate-1024x267.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QGQdf1Ea--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.rherault.fr/app/uploads/2022/08/automate-1024x267.png" alt="" width="800" height="209"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Automate d’un portillon d’accès&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ici, on peut voir que si l’on insère le ticket alors que le portillon est dans l’état “Verrouillé”, alors l’automate passe dans l’état “Déverouillé” et il est alors possible de pousser afin de passer et de re-verouiller l’automate (c’est pour cela qu’il faut bien bien coller la personne en face pour frauder)&lt;/p&gt;

&lt;p&gt;Maintenant que tout le principe de &lt;strong&gt;machine à état&lt;/strong&gt; est clair, nous pouvons passer à un exemple plus concret dans &lt;strong&gt;Symfony&lt;/strong&gt; et découvrir comment ce composant peut être utile dans de nombreux projets.&lt;/p&gt;
&lt;h2&gt;
  
  
  Exemple d’utilisation
&lt;/h2&gt;

&lt;p&gt;Pour que ce soit bien plus clair, nous allons partir sur un exemple d’utilisation dans un vrai projet : mon &lt;strong&gt;portfolio&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Sur mon portfolio j’ai une entité &lt;code&gt;Projet&lt;/code&gt; qui contient un champ &lt;code&gt;isPublished&lt;/code&gt;, &lt;code&gt;photoFilename&lt;/code&gt;, ainsi qu’un champ &lt;code&gt;state&lt;/code&gt;, indiquant son état (pour l’utilisation dans un workflow).&lt;/p&gt;

&lt;p&gt;Le &lt;strong&gt;cycle de vie&lt;/strong&gt; de mon projet se déroule ainsi :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Création du projet, ajout du &lt;code&gt;state&lt;/code&gt; “&lt;em&gt;draft&lt;/em&gt;” (brouillon)&lt;/li&gt;
&lt;li&gt;Si isPublished est à true, alors le code va aller &lt;strong&gt;optimiser&lt;/strong&gt; l’image ajoutée (recadrement et génération du “blur” pour l’affichage en front), une fois cela fait, l’entité va passer à l’étape suivante : &lt;code&gt;ready&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enfin, le projet passe dans l’état &lt;code&gt;published&lt;/code&gt;. (Je n’ai plus qu’à récupérer uniquement les projets avec cet état en front pour l’affichage.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Voici un schéma de mon cycle de vie :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gh9oSjTx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.rherault.fr/app/uploads/2022/08/automate-portfolio-1-1024x235.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gh9oSjTx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.rherault.fr/app/uploads/2022/08/automate-portfolio-1-1024x235.png" alt="" width="800" height="184"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Schéma du cycle de vie de mon projet&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A chaque fois que je sauvegarderais un projet, il changera d’étape.&lt;/p&gt;

&lt;p&gt;S’il ne peut pas, comme dans le cas du brouillon si le projet n’a pas vocation à être publié pour le moment par exemple, il restera dans le même état.&lt;/p&gt;
&lt;h2&gt;
  
  
  Configurer un workflow dans un projet Symfony 6
&lt;/h2&gt;

&lt;p&gt;Pour configurer facilement un &lt;strong&gt;cycle de vie&lt;/strong&gt; d’une entité dans un projet &lt;strong&gt;Symfony 6&lt;/strong&gt; , c’est très simple.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;Tout d’abord, il faut créer une propriété dans l’entité, par exemple un &lt;code&gt;string&lt;/code&gt; nommé &lt;code&gt;state&lt;/code&gt; !&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    #[ORM\Column(type: 'string', options: ['default' =&amp;gt; 'draft'])]
    private string $state = 'draft';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Je défini un état par défaut qui est “draft” (Brouillon en français).&lt;/p&gt;

&lt;p&gt;Ensuite, il faut ajouter ce workflow dans un fichier de configurer nommé &lt;code&gt;workflow.yml&lt;/code&gt; (dans &lt;code&gt;config/packages&lt;/code&gt;) :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;framework:
    workflows:
        project:
            type: state_machine
            audit_trail:
                enabled: "%kernel.debug%"
            marking_store:
                type: 'method'
                property: 'state'
            supports:
                - App\Entity\Project
            initial_marking: draft
            places:
                - draft
                - ready
                - published
            transitions:
                publish:
                    from: draft
                    to: ready
                optimize:
                    from: ready
                    to: published
                unpublish:
                    from: published
                    to: draft
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ce fichier va définir les différents états dont vous avez besoin pour votre entité, ainsi que les transitions. (passer de &lt;code&gt;draft&lt;/code&gt; -&amp;gt; &lt;code&gt;ready&lt;/code&gt; -&amp;gt; &lt;code&gt;published&lt;/code&gt; -&amp;gt; &lt;code&gt;draft&lt;/code&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;

&lt;p&gt;Maintenant que notre &lt;strong&gt;workflow&lt;/strong&gt; est défini, il nous suffit d’écrire le code qui va effectuer les diverses actions à chaque étapes.&lt;/p&gt;

&lt;p&gt;Pour cela, il faut que le code soit exécuté à chaque mise à jour / création de l’entité.&lt;/p&gt;

&lt;p&gt;Il faut donc créer un &lt;strong&gt;EntityListener&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Si tu veux en savoir plus sur cette notion, je t’invite à consulter la &lt;a href="https://symfony.com/doc/current/doctrine/events.html"&gt;documentation officielle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pour ma part, le code ressemble à ceci (j’ai suivi &lt;a href="https://symfony.com/doc/current/doctrine/events.html#doctrine-entity-listeners"&gt;cette partie&lt;/a&gt; de la documentation) :&lt;br&gt;
&lt;/p&gt;

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

declare(strict_types=1);

namespace App\EntityListener;

use App\Entity\Project;
use App\Message\PublishProjectMessage;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Symfony\Component\Messenger\MessageBusInterface;

final class ProjectListener
{
    public function __construct(
        private MessageBusInterface $bus
    ) {
    }

    public function postPersist(Project $project, LifecycleEventArgs $event): void
    {
        $this-&amp;gt;bus-&amp;gt;dispatch(new PublishProjectMessage($project-&amp;gt;getId()));
    }

    public function preUpdate(Project $project, LifecycleEventArgs $event): void
    {
        $project-&amp;gt;setUpdatedAt(new \DateTimeImmutable());
        $this-&amp;gt;bus-&amp;gt;dispatch(new PublishProjectMessage($project-&amp;gt;getId()));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pour améliorer les performances de mon application, j’ai exécuté mon workflow dans un &lt;strong&gt;message&lt;/strong&gt; , si tu ne sais pas de quoi il s’agit, je t’invite à consulter &lt;a href="https://rherault.fr/blog/10min-symfony-messenger"&gt;mon article sur &lt;strong&gt;Symfony Messenger&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Mais tu peux très bien adapter le code pour utiliser un service, le composant &lt;strong&gt;Workflow&lt;/strong&gt; de &lt;strong&gt;Symfony&lt;/strong&gt; marchera parfaitement.&lt;/p&gt;

&lt;p&gt;Tout ce qu’il faut savoir, c’est qu’il faut implémenter l’interface &lt;strong&gt;WorkflowInterface&lt;/strong&gt; pour ensuite l’utiliser dans ton code et savoir dans quel état est ton entité et quelles actions tu peux réaliser :&lt;br&gt;
&lt;/p&gt;

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

declare(strict_types=1);

namespace App\MessageHandler;

use App\Entity\Project;
use App\Message\PublishProjectMessage;
use App\Repository\ProjectRepository;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Workflow\WorkflowInterface;

final class PublishProjectMessageHandler implements MessageHandlerInterface
{
    public function __construct(
        private readonly EntityManagerInterface $entityManager,
        private readonly ProjectRepository $projectRepository,
        private readonly MessageBusInterface $bus,
        private readonly WorkflowInterface $projectStateMachine
    ) {
    }

    public function __invoke(PublishProjectMessage $message): void
    {
        /** @var Project|null $project */
        $project = $this-&amp;gt;projectRepository-&amp;gt;find($message-&amp;gt;getId());
        if (!$project) {
            return;
        }

        // Le projet peut-il passer dans l'état "publish" ? 
        // En d'autres mots, est-il dans l'état "draft"
        if ($this-&amp;gt;projectStateMachine-&amp;gt;can($project, 'publish')) {
            if ($project-&amp;gt;isPublished()) {
                // Si le projet est publié, applique l'état "publish"
                // C'est-à-dire passe de l'état "draft" à "ready"
                $this-&amp;gt;projectStateMachine-&amp;gt;apply($project, 'publish');
                $this-&amp;gt;entityManager-&amp;gt;flush();

                $this-&amp;gt;bus-&amp;gt;dispatch($message);
            }
        } elseif ($this-&amp;gt;projectStateMachine-&amp;gt;can($project, 'optimize')) {
            // Call to a service to optimize media
            ...

            // Si le projet est prêt, applique l'état "optimize"
            // C'est-à-dire passe de l'état "ready" à "published"
            $this-&amp;gt;projectStateMachine-&amp;gt;apply($project, 'optimize');
            $this-&amp;gt;entityManager-&amp;gt;flush();
        } elseif ($this-&amp;gt;projectStateMachine-&amp;gt;can($project, 'unpublish')) {
            if (!$project-&amp;gt;isPublished()) {
                // Si le projet est dépublié, applique l'état "unpublish"
                // C'est-à-dire passe de l'état "publish" à "draft"
                $this-&amp;gt;projectStateMachine-&amp;gt;apply($project, 'unpublish');
                $this-&amp;gt;entityManager-&amp;gt;flush();
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Et voilà ! Maintenant quand tu vas modifier ton entité, tu verras son état changer en base de données.&lt;/p&gt;

&lt;p&gt;En très peu de temps tu as pu créer une machine à état et su gérer parfaitement les différents états au fur et à mesure de la vie de ton entité.&lt;/p&gt;

&lt;p&gt;Cet exemple est très simple mais tu peux très bien imaginer des workflow bien plus complexes avec une multitude d’état !&lt;/p&gt;

&lt;p&gt;Si tu veux en savoir plus ou rentrer plus en profondeur, n’hésites pas à consulter la &lt;a href="https://symfony.com/doc/current/workflow.html"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Si tu remarques quelques coquilles dans l’article, n’hésites pas à m’en avertir en me &lt;a href="https://rherault.fr/contact"&gt;contactant&lt;/a&gt;, ce serait un plaisir !&lt;/p&gt;

</description>
      <category>symfony</category>
      <category>tutos</category>
      <category>french</category>
    </item>
    <item>
      <title>Devenir un meilleur développeur grâce au “Clean Code”</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Mon, 13 Jun 2022 15:32:27 +0000</pubDate>
      <link>https://dev.to/romaixn/devenir-un-meilleur-developpeur-grace-au-clean-code-565m</link>
      <guid>https://dev.to/romaixn/devenir-un-meilleur-developpeur-grace-au-clean-code-565m</guid>
      <description>&lt;p&gt;Il y a quelque temps j’ai intégré une nouvelle entreprise dans le cadre d’une “régie”, habitué aux agences web, c’est la première fois que je sortais de ce domaine.&lt;/p&gt;

&lt;p&gt;Quand j’ai découvert le code de cette entreprise, j’ai vite compris que j’étais à la ramasse en terme de &lt;strong&gt;qualité de code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Je connaissais tous les &lt;strong&gt;concepts&lt;/strong&gt; utilisés mais je ne les appliquais pas systématiquement.&lt;/p&gt;

&lt;p&gt;Pourquoi ? Par manque de temps, des deadline très rapprochés. (beaucoup d’excuses, oui)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Je privilégiais la quantité à la qualité.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Et ça, c’est un gros défaut que pas mal de développeurs (surtout junior) ont.&lt;/p&gt;

&lt;p&gt;Aujourd’hui on va parler de “ &lt;strong&gt;Clean Code&lt;/strong&gt; ” et de comment l’ensemble de ces &lt;strong&gt;pratiques&lt;/strong&gt; peuvent faire de toi un &lt;strong&gt;meilleur développeur&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qu’est-ce-que le “Clean Code”
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Son importance
&lt;/h2&gt;

&lt;p&gt;Au delà du titre “putaclick”, mon but est de te prouver l’importance de ces méthodologies et comment elles peuvent réellement faire de toi un meilleur développeur.&lt;/p&gt;

&lt;p&gt;Le &lt;strong&gt;Clean Code&lt;/strong&gt; , c’est surtout une liste (non exhaustive) de méthodologie à respecter pour faire du &lt;strong&gt;code de qualité&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Un code de qualité donne énormément d’avantages (en plus de pouvoir être fier de ton code) :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plus &lt;strong&gt;maintenable&lt;/strong&gt; , une modification dans une base de code ne devrait pas te faire peur.&lt;/li&gt;
&lt;li&gt;Plus &lt;strong&gt;modulable/améliorable&lt;/strong&gt; , n’importe quel développeur doit être en mesure d’ajouter et/ou modifier une fonctionnalité très facilement.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Et faire du code de qualité s’applique bien évidemment à tout les domaines, même dans le &lt;strong&gt;web&lt;/strong&gt; pour les “petits sites”.&lt;/p&gt;

&lt;p&gt;Il ne devrait pas y avoir d’excuse pour ne pas suivre ces &lt;strong&gt;principes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;En plus d’être bien plus agréable pour tout le monde (oui, personne n’aime développer avec du legacy), tu vas prendre un bien plus grand plaisir à développer.&lt;/p&gt;

&lt;p&gt;L’objectif est que tu deviennes &lt;strong&gt;fier de ton code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Le Clean Code c’est tout un état d’esprit, on parle de “Software Craftsmanship” (Artisan Développeur). Un manifeste existe même pour cela : &lt;a href="https://manifesto.softwarecraftsmanship.org/#/fr-fr"&gt;https://manifesto.softwarecraftsmanship.org/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pourquoi ?
&lt;/h2&gt;

&lt;p&gt;Si tu n’es toujours pas convaincu de l’importance d’utiliser le Clean Code, il faut revenir à la base : pourquoi le développement orienté objet à été inventé ?&lt;/p&gt;

&lt;p&gt;Est-ce que nous n’étions pas bien avec nos fichiers PHP de 1000 lignes avec tout un tas de fonctions posées comme ça sans contexte et des &lt;code&gt;includes&lt;/code&gt; dans tout les sens ? (Je prends ici l’exemple du PHP puisque c’est celui que je maîtrise, mais tout cet article s’applique bien évidemment à n’importe quel langage.)&lt;/p&gt;

&lt;p&gt;Tu l’auras deviné, la programmation orientée objet a été inventée spécifiquement pour ce problème : &lt;strong&gt;l’organisation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Pouvoir organiser son code en &lt;strong&gt;classe&lt;/strong&gt; a été une petite révolution.&lt;/p&gt;

&lt;p&gt;De là sont nées énormément de &lt;strong&gt;bonne pratiques&lt;/strong&gt; , acquis à force d’erreurs.&lt;/p&gt;

&lt;p&gt;En effet, avez-vous déjà été confronté à une classe de 500 lignes en soupirant parce que vous savez que ce sera long de trouver ce que vous voulez vraiment ?&lt;/p&gt;

&lt;p&gt;Beaucoup de développeur l’ont étés avant vous.&lt;/p&gt;

&lt;p&gt;Et les &lt;strong&gt;principes&lt;/strong&gt; que nous allons voir ont été créés pour ne pas répéter les mêmes erreurs.&lt;/p&gt;

&lt;p&gt;Pour aller plus loin, certains ont inventés des &lt;strong&gt;design pattern&lt;/strong&gt; ( &lt;strong&gt;patrons de conception&lt;/strong&gt; ) pour tout un tas de cas d’utilisation. Nous n’allons pas parler de cela aujourd’hui mais si tu veux en savoir plus je te conseille l’excellent site &lt;a href="https://refactoring.guru/fr"&gt;refactoring.guru&lt;/a&gt; !&lt;/p&gt;

&lt;h2&gt;
  
  
  Les différents principes
&lt;/h2&gt;

&lt;p&gt;Il existe évidemment bien d’autres principes, je vais parler ici des principaux, de ceux que tout le monde devraient appliquer.&lt;/p&gt;

&lt;h3&gt;
  
  
  KISS (Keep It Simple, Stupid)
&lt;/h3&gt;

&lt;p&gt;Ce principe préconise la &lt;strong&gt;simplicité&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Ne pas ajouter une &lt;strong&gt;complexité non-indispensable&lt;/strong&gt; à une application.&lt;/p&gt;

&lt;p&gt;Un code simple est bien plus facile à modifier.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Il semble que la perfection soit atteinte non pas lorsqu’il n’y a plus rien à ajouter, mais lorsqu’il n’y a plus rien à enlever.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  DRY ( &lt;strong&gt;Don’t Repeat Yourself&lt;/strong&gt; )
&lt;/h3&gt;

&lt;p&gt;Le titre en dit long : &lt;strong&gt;ne pas se répéter&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Si le fonctionnement de cette fonction doit changer, il est plus simple de la modifier à un seul endroit plutôt que de devoir chercher toutes les fonctions implémentant le même code.&lt;/p&gt;

&lt;p&gt;Attention par contre avec ce principe, il peut être bon de se répéter parfois.&lt;/p&gt;

&lt;p&gt;Lorsque les cas d’utilisations ne sont pas les mêmes, par exemple. Un produit dans un catalogue ou dans un panier utilisateur n’est pas le même, il pourrait être bon de le dupliquer dans ce cas là.&lt;/p&gt;

&lt;p&gt;Celui-ci est à prendre avec des pincettes, si tu veux approfondir, je te conseille &lt;a href="https://medium.com/@nicolopigna/this-is-not-the-dry-you-are-looking-for-a316ed3f445f"&gt;cet article&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  SOLID
&lt;/h3&gt;

&lt;p&gt;Le &lt;strong&gt;principe SOLID&lt;/strong&gt; est le plus important de tous.&lt;/p&gt;

&lt;h4&gt;
  
  
  Responsabilité unique (Single responsibility principle)
&lt;/h4&gt;

&lt;p&gt;Une classe, une fonction ou une méthode doit avoir une et une seule responsabilité&lt;/p&gt;

&lt;h4&gt;
  
  
  Ouvert/fermé (Open/closed principle)
&lt;/h4&gt;

&lt;p&gt;Une entité applicative (classe, fonction, module …) doit être fermée à la modification directe mais ouverte à l’extension&lt;/p&gt;

&lt;h4&gt;
  
  
  Substitution de Liskov (Liskov substitution principle)
&lt;/h4&gt;

&lt;p&gt;Une instance de type T doit pouvoir être remplacée par une instance de type G, tel que G sous-type de T, sans que cela ne modifie la cohérence du programme&lt;/p&gt;

&lt;h4&gt;
  
  
  Ségrégation des interfaces (Interface segregation principle)
&lt;/h4&gt;

&lt;p&gt;Préférer plusieurs interfaces spécifiques pour chaque client plutôt qu’une seule interface générale&lt;/p&gt;

&lt;h4&gt;
  
  
  Inversion des dépendances (Dependency inversion principle)
&lt;/h4&gt;

&lt;p&gt;Il faut dépendre des abstractions, pas des implémentations&lt;/p&gt;

&lt;p&gt;Si tu souhaites plus de détails concernant ce principe je te renvois vers &lt;a href="https://alexsoyes.com/solid/"&gt;l’excellent article d’alexsoyes&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Les bonnes pratiques
&lt;/h2&gt;

&lt;p&gt;Au-delà de ces principes, il existe aussi des &lt;strong&gt;“bonnes pratiques”&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cohérence
&lt;/h3&gt;

&lt;p&gt;Être &lt;strong&gt;cohérent&lt;/strong&gt; , toujours utilisé le même nommage dans toute son application, par exemple.&lt;/p&gt;

&lt;p&gt;Si tu utilises l’anglais à un endroit, utilise le partout.&lt;/p&gt;

&lt;p&gt;Si tu utilises du &lt;strong&gt;CamelCase&lt;/strong&gt; pour le nommage de tes classes, utilise le partout.&lt;/p&gt;

&lt;p&gt;Utiliser des noms de variables &lt;strong&gt;explicites&lt;/strong&gt;. Au bûcher les variables &lt;code&gt;a&lt;/code&gt; / &lt;code&gt;b&lt;/code&gt; / &lt;code&gt;array&lt;/code&gt; / &lt;code&gt;variable&lt;/code&gt;, il devrait être possible de &lt;strong&gt;comprendre le code rien qu’en le lisant&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conventions
&lt;/h3&gt;

&lt;p&gt;Suivre les normes de son langage, le &lt;strong&gt;PSR-12&lt;/strong&gt; en &lt;strong&gt;PHP&lt;/strong&gt; , par exemple.&lt;/p&gt;

&lt;p&gt;Tous les langages ont (normalement) leurs normes, leurs “coding style”.&lt;/p&gt;

&lt;p&gt;Mais les &lt;strong&gt;CMS&lt;/strong&gt; ou &lt;strong&gt;framework&lt;/strong&gt; en ont aussi, &lt;a href="https://symfony.com/doc/current/best_practices.html"&gt;exemple avec &lt;strong&gt;Symfony&lt;/strong&gt;&lt;/a&gt; ou encore &lt;strong&gt;&lt;a href="https://developer.wordpress.org/plugins/plugin-basics/best-practices/"&gt;WordPress&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Tu peux facilement trouver les bonnes pratiques liées à ta situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mettre en pratique
&lt;/h2&gt;

&lt;p&gt;On arrive à la partie la plus compliquée : la &lt;strong&gt;mise en pratique&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Il n’y a pas de secret, il faut &lt;strong&gt;pratiquer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Réaliser un projet de 0 et appliquer au maximum tout ce que nous avons vu.&lt;/p&gt;

&lt;p&gt;Ou alors ne pas hésiter à &lt;strong&gt;refactoriser&lt;/strong&gt; (Retravailler une application informatique pour l’améliorer en profondeur, sans pour autant lui ajouter de nouvelles fonctions. Merci &lt;strong&gt;Wikipedia&lt;/strong&gt; )&lt;/p&gt;

&lt;p&gt;Reprends ton code et reprends un à un tous les principes et demande toi si tu les respectes tous.&lt;/p&gt;

&lt;p&gt;Tu peux facilement trouver tout un tas d’exemples dans le framework / CMS de ton choix. Pour ma part &lt;a href="https://medium.com/analytics-vidhya/dependency-injection-and-solid-principles-with-symfony-the-geocoding-example-f18ad08ed20b"&gt;cet article&lt;/a&gt; m’a beaucoup aidé à appréhender SOLID dans &lt;strong&gt;Symfony&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Ce qui serait encore mieux ce serait d’avoir des proches à qui demander conseils, pour savoir si tu respectes au maximum le &lt;strong&gt;clean code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Si tu remarques une erreur, ou si tu souhaites améliorer cet article, n’hésites pas à m’envoyer un message via &lt;a href="https://rherault.fr/contact"&gt;cette page&lt;/a&gt; ou directement sur &lt;a href="https://twitter.com/Romaixn"&gt;twitter&lt;/a&gt; !&lt;/p&gt;

</description>
      <category>cleancode</category>
      <category>french</category>
    </item>
    <item>
      <title>Github Actions for Symfony 5 PHPUnit and more</title>
      <dc:creator>Romain</dc:creator>
      <pubDate>Wed, 10 Nov 2021 16:01:03 +0000</pubDate>
      <link>https://dev.to/romaixn/github-actions-for-symfony-5-phpunit-and-more-4e90</link>
      <guid>https://dev.to/romaixn/github-actions-for-symfony-5-phpunit-and-more-4e90</guid>
      <description>&lt;h3&gt;
  
  
  My Workflow
&lt;/h3&gt;

&lt;p&gt;This Github Actions will help you to guarantee an optimal quality and the good functioning of the code thanks to the launching of automatic tests.&lt;br&gt;
But also warn you about the known vulnerabilities of your dependencies.&lt;/p&gt;

&lt;h4&gt;
  
  
  PHP Setup
&lt;/h4&gt;

&lt;p&gt;First, this action setup PHP, composer and install all composer dependencies.&lt;/p&gt;

&lt;h4&gt;
  
  
  Security / Quality
&lt;/h4&gt;

&lt;p&gt;After that, it check vulnerabilities in your dependencies and check your quality code according to PSR12 coding style using &lt;a href="https://github.com/squizlabs/PHP_CodeSniffer"&gt;PHP_CodeSniffer&lt;/a&gt; and &lt;a href="https://github.com/phpstan/phpstan"&gt;PHPStan&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Webpack Encore
&lt;/h4&gt;

&lt;p&gt;For the Webpack Encore part, it install all npm dependencies and build all your assets.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tests
&lt;/h4&gt;

&lt;p&gt;Finally, it run your PHPUnit tests. (and Behat, if you have).&lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Maintainer Must-Haves&lt;/p&gt;

&lt;h3&gt;
  
  
  Yaml File
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Symfony 5 Tests&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;dev&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;symfony&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Symfony 5.0 (PHP ${{ matrix.php-versions }})&lt;/span&gt;
    &lt;span class="c1"&gt;# https://hub.docker.com/_/ubuntu/&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;fail-fast&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;php-versions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;7.4'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# https://github.com/actions/checkout (official)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class="c1"&gt;# https://github.com/shivammathur/setup-php (community)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup PHP, extensions and composer with shivammathur/setup-php&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shivammathur/setup-php@verbose&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;php-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.php-versions }}&lt;/span&gt;
          &lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mbstring, xml, ctype, iconv, intl, pdo_sqlite, dom, filter, gd, iconv, json, mbstring, pdo&lt;/span&gt;

      &lt;span class="c1"&gt;# Composer&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get composer cache directory&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composer-cache&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "::set-output name=dir::$(composer config cache-files-dir)"&lt;/span&gt;

        &lt;span class="c1"&gt;# https://help.github.com/en/actions/configuring-and-managing-workflows/caching-dependencies-to-speed-up-workflows&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cache composer dependencies&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.composer-cache.outputs.dir }}&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}&lt;/span&gt;
          &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-composer-&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Composer dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader&lt;/span&gt;

      &lt;span class="c1"&gt;# https://github.com/sensiolabs/security-checker&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Security check installed dependencies&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;symfonycorp/security-checker-action@v2&lt;/span&gt;

      &lt;span class="c1"&gt;# https://github.com/chekalsky/phpcs-action (community)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check PSR12 code style (PHP_CodeSniffer)&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chekalsky/phpcs-action@v1.2.0&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;enable_warnings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;installed_paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.workspace&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}/vendor/squizlabs/php_codesniffer'&lt;/span&gt;
          &lt;span class="na"&gt;phpcs_bin_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./vendor/bin/phpcs&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;src&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--ignore="Migrations/"'&lt;/span&gt;

      &lt;span class="c1"&gt;# https://github.com/phpmd/phpmd&lt;/span&gt;
      &lt;span class="c1"&gt;# - name: Analyses PHP Code (PHP Mess Detector)&lt;/span&gt;
      &lt;span class="c1"&gt;#  run: vendor/bin/phpmd src,tests text .phpmd-ruleset.xml&lt;/span&gt;

      &lt;span class="c1"&gt;# https://github.com/phpstan/phpstan&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Analyse PHP Code (PHPStan)&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vendor/bin/phpstan analyse src&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cache node_modules&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v1&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn-cache-node-modules&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node_modules&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-yarn-cache-node-modules-${{ hashFiles('**/yarn.lock') }}&lt;/span&gt;
          &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;${{ runner.os }}-yarn-cache-node-modules-&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Yarn install&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;steps.yarn-cache-node-modules.outputs.cache-hit != 'true'&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn install&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Yarn build&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn run encore production&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Archive production artifacts&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;public/build&lt;/span&gt;

      &lt;span class="c1"&gt;# Symfony&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check the Symfony console&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;php bin/console -V&lt;/span&gt;
          &lt;span class="s"&gt;php bin/console about&lt;/span&gt;
      &lt;span class="c1"&gt;# Tests&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run unit and functional tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;php bin/phpunit --stop-on-failure&lt;/span&gt;

      &lt;span class="c1"&gt;# - name: Run Behat/Mink tests&lt;/span&gt;
      &lt;span class="c1"&gt;#  run: |&lt;/span&gt;
      &lt;span class="c1"&gt;#    php vendor/bin/behat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Additional Resources / Info
&lt;/h3&gt;

&lt;p&gt;You can remove all yarn related parts if you don't use &lt;strong&gt;Webpack Encore&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>actionshackathon21</category>
      <category>github</category>
      <category>opensource</category>
      <category>symfony</category>
    </item>
  </channel>
</rss>
