Repository: kalviumcommunity/S84_TheFinalBell
Pull request #16: Add entity form
Author: login: ANU-2524
Labels: name: Review effort 3/5
Created: 2025-03-27T16:49:14Z | Merged: 2025-03-27T16:51:06Z

### **PR Type**
Enhancement, Tests


___

### **Description**
- Added a new `AddEntity` component for entity management.

- Integrated routing for `AddEntity` in `App.jsx`.

- Updated dependencies in `package.json` for new features.

- Enhanced `HeroSection` with improved text animation logic.


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant files</th></tr></thead><tbody><tr><td><strong>Dependencies</strong></td><td><table>
<tr>
  <td>
    <details>
      <summary><strong>package.json</strong><dd><code>Added dependencies for 3D and globe visualization.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

Frontend/client/package.json

<li>Added new dependencies: <code>@react-three/drei</code>, <code>@react-three/fiber</code>, <br><code>globe.gl</code>, and <code>three</code>.<br> <li> Updated dependency list to support new features.


</details>


  </td>
  <td><a href="https://github.com/kalviumcommunity/S84_TheFinalBell/pull/16/files#diff-54f4783b659b5fd0d61fb0ab865baeda28deab220676c863a23c64b8ed20b85f">+5/-1</a>&nbsp; &nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Enhancement</strong></td><td><table>
<tr>
  <td>
    <details>
      <summary><strong>App.jsx</strong><dd><code>Integrated routing and UI for `AddEntity`.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

Frontend/client/src/App.jsx

<li>Added routing for <code>AddEntity</code> component.<br> <li> Integrated a button to navigate to the <code>AddEntity</code> page.<br> <li> Enhanced layout with inline styles for the button.


</details>


  </td>
  <td><a href="https://github.com/kalviumcommunity/S84_TheFinalBell/pull/16/files#diff-dfef076b42201d6264998523d21293dd6f7f46dab78e374d1c998fd5767bed53">+48/-11</a>&nbsp; </td>

</tr>

<tr>
  <td>
    <details>
      <summary><strong>AddEntity.jsx</strong><dd><code>Added `AddEntity` component for entity management.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

Frontend/client/src/components/AddEntity.jsx

<li>Created a new <code>AddEntity</code> component for adding and listing entities.<br> <li> Implemented form handling with validation and API integration.<br> <li> Styled the component with inline CSS.


</details>


  </td>
  <td><a href="https://github.com/kalviumcommunity/S84_TheFinalBell/pull/16/files#diff-344fd057fc8ee940f3f2c57a95e17391a4019ae66dfda0d76bcfe026c0bafdce">+144/-0</a>&nbsp; </td>

</tr>

<tr>
  <td>
    <details>
      <summary><strong>HeroSection.jsx</strong><dd><code>Enhanced text animation in `HeroSection`.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

Frontend/client/src/components/HeroSection.jsx

<li>Improved text animation logic for better performance.<br> <li> Adjusted text rendering to use slicing instead of concatenation.


</details>


  </td>
  <td><a href="https://github.com/kalviumcommunity/S84_TheFinalBell/pull/16/files#diff-5f8c0680c8b7e68108a7bb3326efe32255cd49aa73456cb89806edd3441bc73e">+11/-5</a>&nbsp; &nbsp; </td>

</tr>
</table></td></tr><tr><td><strong>Formatting</strong></td><td><table>
<tr>
  <td>
    <details>
      <summary><strong>Badge.jsx</strong><dd><code>Cleaned up `Badge` component code.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

Frontend/client/src/components/Badge.jsx

<li>Removed redundant comments for cleaner code.<br> <li> Simplified badge rendering logic.


</details>


  </td>
  <td><a href="https://github.com/kalviumcommunity/S84_TheFinalBell/pull/16/files#diff-f6b1b474983a34c461b05df9a1544f655d224e7b9e23a5788c11a5840ab77804">+1/-4</a>&nbsp; &nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

___

> <details> <summary>  Need help?</summary><li>Type <code>/help how to ...</code> in the comments thread for any questions about Qodo Merge usage.</li><li>Check out the <a href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a> for more information.</li></details>


Diff:
diff --git a/Frontend/client/package-lock.json b/Frontend/client/package-lock.json
index 1bd2d0c..6cadb55 100644
--- a/Frontend/client/package-lock.json
+++ b/Frontend/client/package-lock.json
@@ -8,11 +8,15 @@
       "name": "client",
       "version": "0.0.0",
       "dependencies": {
+        "@react-three/drei": "^10.0.5",
+        "@react-three/fiber": "^9.1.0",
         "axios": "^1.8.4",
+        "globe.gl": "^2.41.3",
         "react": "^19.0.0",
         "react-dom": "^19.0.0",
         "react-icons": "^5.5.0",
-        "react-router-dom": "^7.4.0"
+        "react-router-dom": "^7.4.0",
+        "three": "^0.174.0"
       },
       "devDependencies": {
         "@eslint/js": "^9.21.0",
@@ -264,6 +268,18 @@
         "@babel/core": "^7.0.0-0"
       }
     },
+    "node_modules/@babel/runtime": {
+      "version": "7.27.0",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
+      "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==",
+      "license": "MIT",
+      "dependencies": {
+        "regenerator-runtime": "^0.14.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
     "node_modules/@babel/template": {
       "version": "7.26.9",
       "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz",
@@ -1007,6 +1023,114 @@
         "@jridgewell/sourcemap-codec": "^1.4.14"
       }
     },
+    "node_modules/@mediapipe/tasks-vision": {
+      "version": "0.10.17",
+      "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz",
+      "integrity": "sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/@monogrid/gainmap-js": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.1.0.tgz",
+      "integrity": "sha512-Obb0/gEd/HReTlg8ttaYk+0m62gQJmCblMOjHSMHRrBP2zdfKMHLCRbh/6ex9fSUJMKdjjIEiohwkbGD3wj2Nw==",
+      "license": "MIT",
+      "dependencies": {
+        "promise-worker-transferable": "^1.0.4"
+      },
+      "peerDependencies": {
+        "three": ">= 0.159.0"
+      }
+    },
+    "node_modules/@react-three/drei": {
+      "version": "10.0.5",
+      "resolved": "https://registry.npmjs.org/@react-three/drei/-/drei-10.0.5.tgz",
+      "integrity": "sha512-zK1QOm5g46RANYUKlf6qZQg+n+qyBWT1sOUfHNwXf6L2Cn4cgxMpJV4Lue7IyytAZXUCzhGAgPiG13D0hKH1Gg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.26.0",
+        "@mediapipe/tasks-vision": "0.10.17",
+        "@monogrid/gainmap-js": "^3.0.6",
+        "@use-gesture/react": "^10.3.1",
+        "camera-controls": "^2.9.0",
+        "cross-env": "^7.0.3",
+        "detect-gpu": "^5.0.56",
+        "glsl-noise": "^0.0.0",
+        "hls.js": "^1.5.17",
+        "maath": "^0.10.8",
+        "meshline": "^3.3.1",
+        "stats-gl": "^2.2.8",
+        "stats.js": "^0.17.0",
+        "suspend-react": "^0.1.3",
+        "three-mesh-bvh": "^0.8.3",
+        "three-stdlib": "^2.35.6",
+        "troika-three-text": "^0.52.0",
+        "tunnel-rat": "^0.1.2",
+        "use-sync-external-store": "^1.4.0",
+        "utility-types": "^3.11.0",
+        "zustand": "^5.0.1"
+      },
+      "peerDependencies": {
+        "@react-three/fiber": "^9.0.0",
+        "react": "^19",
+        "react-dom": "^19",
+        "three": ">=0.159"
+      },
+      "peerDependenciesMeta": {
+        "react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@react-three/fiber": {
+      "version": "9.1.0",
+      "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-9.1.0.tgz",
+      "integrity": "sha512-r/a0dpqdz5ci17yMIWE+70WwxiTScGFEyvtDj0o4isZ7YUvPu0k78Zl7cJGL+KhheKXCzbNNxEz4+lFan6atyg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.17.8",
+        "@types/react-reconciler": "^0.28.9",
+        "@types/webxr": "*",
+        "base64-js": "^1.5.1",
+        "buffer": "^6.0.3",
+        "its-fine": "^2.0.0",
+        "react-reconciler": "^0.31.0",
+        "react-use-measure": "^2.1.7",
+        "scheduler": "^0.25.0",
+        "suspend-react": "^0.1.3",
+        "use-sync-external-store": "^1.4.0",
+        "zustand": "^5.0.3"
+      },
+      "peerDependencies": {
+        "expo": ">=43.0",
+        "expo-asset": ">=8.4",
+        "expo-file-system": ">=11.0",
+        "expo-gl": ">=11.0",
+        "react": "^19.0.0",
+        "react-dom": "^19.0.0",
+        "react-native": ">=0.78",
+        "three": ">=0.156"
+      },
+      "peerDependenciesMeta": {
+        "expo": {
+          "optional": true
+        },
+        "expo-asset": {
+          "optional": true
+        },
+        "expo-file-system": {
+          "optional": true
+        },
+        "expo-gl": {
+          "optional": true
+        },
+        "react-dom": {
+          "optional": true
+        },
+        "react-native": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@rollup/rollup-android-arm-eabi": {
       "version": "4.34.9",
       "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.9.tgz",
@@ -1273,6 +1397,55 @@
         "win32"
       ]
     },
+    "node_modules/@turf/boolean-point-in-polygon": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-7.2.0.tgz",
+      "integrity": "sha512-lvEOjxeXIp+wPXgl9kJA97dqzMfNexjqHou+XHVcfxQgolctoJiRYmcVCWGpiZ9CBf/CJha1KmD1qQoRIsjLaA==",
+      "license": "MIT",
+      "dependencies": {
+        "@turf/helpers": "^7.2.0",
+        "@turf/invariant": "^7.2.0",
+        "@types/geojson": "^7946.0.10",
+        "point-in-polygon-hao": "^1.1.0",
+        "tslib": "^2.8.1"
+      },
+      "funding": {
+        "url": "https://opencollective.com/turf"
+      }
+    },
+    "node_modules/@turf/helpers": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.2.0.tgz",
+      "integrity": "sha512-cXo7bKNZoa7aC7ydLmUR02oB3IgDe7MxiPuRz3cCtYQHn+BJ6h1tihmamYDWWUlPHgSNF0i3ATc4WmDECZafKw==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/geojson": "^7946.0.10",
+        "tslib": "^2.8.1"
+      },
+      "funding": {
+        "url": "https://opencollective.com/turf"
+      }
+    },
+    "node_modules/@turf/invariant": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.2.0.tgz",
+      "integrity": "sha512-kV4u8e7Gkpq+kPbAKNC21CmyrXzlbBgFjO1PhrHPgEdNqXqDawoZ3i6ivE3ULJj2rSesCjduUaC/wyvH/sNr2Q==",
+      "license": "MIT",
+      "dependencies": {
+        "@turf/helpers": "^7.2.0",
+        "@types/geojson": "^7946.0.10",
+        "tslib": "^2.8.1"
+      },
+      "funding": {
+        "url": "https://opencollective.com/turf"
+      }
+    },
+    "node_modules/@tweenjs/tween.js": {
+      "version": "25.0.0",
+      "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-25.0.0.tgz",
+      "integrity": "sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A==",
+      "license": "MIT"
+    },
     "node_modules/@types/babel__core": {
       "version": "7.20.5",
       "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -1324,6 +1497,12 @@
       "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
       "license": "MIT"
     },
+    "node_modules/@types/draco3d": {
+      "version": "1.4.10",
+      "resolved": "https://registry.npmjs.org/@types/draco3d/-/draco3d-1.4.10.tgz",
+      "integrity": "sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==",
+      "license": "MIT"
+    },
     "node_modules/@types/estree": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
@@ -1331,6 +1510,12 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/@types/geojson": {
+      "version": "7946.0.16",
+      "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
+      "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
+      "license": "MIT"
+    },
     "node_modules/@types/json-schema": {
       "version": "7.0.15",
       "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
@@ -1338,11 +1523,16 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/@types/offscreencanvas": {
+      "version": "2019.7.3",
+      "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz",
+      "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==",
+      "license": "MIT"
+    },
     "node_modules/@types/react": {
       "version": "19.0.10",
       "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz",
       "integrity": "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==",
-      "dev": true,
       "license": "MIT",
       "dependencies": {
         "csstype": "^3.0.2"
@@ -1358,6 +1548,65 @@
         "@types/react": "^19.0.0"
       }
     },
+    "node_modules/@types/react-reconciler": {
+      "version": "0.28.9",
+      "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz",
+      "integrity": "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/react": "*"
+      }
+    },
+    "node_modules/@types/stats.js": {
+      "version": "0.17.3",
+      "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz",
+      "integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==",
+      "license": "MIT"
+    },
+    "node_modules/@types/three": {
+      "version": "0.174.0",
+      "resolved": "https://registry.npmjs.org/@types/three/-/three-0.174.0.tgz",
+      "integrity": "sha512-De/+vZnfg2aVWNiuy1Ldu+n2ydgw1osinmiZTAn0necE++eOfsygL8JpZgFjR2uHmAPo89MkxBj3JJ+2BMe+Uw==",
+      "license": "MIT",
+      "dependencies": {
+        "@tweenjs/tween.js": "~23.1.3",
+        "@types/stats.js": "*",
+        "@types/webxr": "*",
+        "@webgpu/types": "*",
+        "fflate": "~0.8.2",
+        "meshoptimizer": "~0.18.1"
+      }
+    },
+    "node_modules/@types/three/node_modules/@tweenjs/tween.js": {
+      "version": "23.1.3",
+      "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz",
+      "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==",
+      "license": "MIT"
+    },
+    "node_modules/@types/webxr": {
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.21.tgz",
+      "integrity": "sha512-geZIAtLzjGmgY2JUi6VxXdCrTb99A7yP49lxLr2Nm/uIK0PkkxcEi4OGhoGDO4pxCf3JwGz2GiJL2Ej4K2bKaA==",
+      "license": "MIT"
+    },
+    "node_modules/@use-gesture/core": {
+      "version": "10.3.1",
+      "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz",
+      "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==",
+      "license": "MIT"
+    },
+    "node_modules/@use-gesture/react": {
+      "version": "10.3.1",
+      "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz",
+      "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==",
+      "license": "MIT",
+      "dependencies": {
+        "@use-gesture/core": "10.3.1"
+      },
+      "peerDependencies": {
+        "react": ">= 16.8.0"
+      }
+    },
     "node_modules/@vitejs/plugin-react": {
       "version": "4.3.4",
       "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz",
@@ -1378,6 +1627,21 @@
         "vite": "^4.2.0 || ^5.0.0 || ^6.0.0"
       }
     },
+    "node_modules/@webgpu/types": {
+      "version": "0.1.59",
+      "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.59.tgz",
+      "integrity": "sha512-jZJ6ipNli+rn++/GAPqsZXfsgjx951wlCW7vNAg+oGdp0ZYidTOkbVTVeK2frzowuD5ch7MRz7leOEX1PMv43A==",
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/accessor-fn": {
+      "version": "1.5.3",
+      "resolved": "https://registry.npmjs.org/accessor-fn/-/accessor-fn-1.5.3.tgz",
+      "integrity": "sha512-rkAofCwe/FvYFUlMB0v0gWmhqtfAtV1IUkdPbfhTUyYniu5LrC0A0UJkTH0Jv3S8SvwkmfuAlY+mQIJATdocMA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/acorn": {
       "version": "8.14.0",
       "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
@@ -1465,6 +1729,35 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/bidi-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz",
+      "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==",
+      "license": "MIT",
+      "dependencies": {
+        "require-from-string": "^2.0.2"
+      }
+    },
     "node_modules/brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -1509,6 +1802,30 @@
         "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
       }
     },
+    "node_modules/buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
     "node_modules/call-bind-apply-helpers": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
@@ -1532,6 +1849,15 @@
         "node": ">=6"
       }
     },
+    "node_modules/camera-controls": {
+      "version": "2.10.0",
+      "resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-2.10.0.tgz",
+      "integrity": "sha512-vBQ5Daxv4KRsn07U/VqkPxoqD8U+S++0oq5NLf4HevMuh/BDta3rg49e/P564AMzFPBePQeXDKOkiIezRgyDwg==",
+      "license": "MIT",
+      "peerDependencies": {
+        "three": ">=0.126.1"
+      }
+    },
     "node_modules/caniuse-lite": {
       "version": "1.0.30001702",
       "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001702.tgz",
@@ -1625,11 +1951,28 @@
         "node": ">=18"
       }
     },
+    "node_modules/cross-env": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
+      "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
+      "license": "MIT",
+      "dependencies": {
+        "cross-spawn": "^7.0.1"
+      },
+      "bin": {
+        "cross-env": "src/bin/cross-env.js",
+        "cross-env-shell": "src/bin/cross-env-shell.js"
+      },
+      "engines": {
+        "node": ">=10.14",
+        "npm": ">=6",
+        "yarn": ">=1"
+      }
+    },
     "node_modules/cross-spawn": {
       "version": "7.0.6",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
       "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
-      "dev": true,
       "license": "MIT",
       "dependencies": {
         "path-key": "^3.1.0",
@@ -1644,9 +1987,182 @@
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
       "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
-      "dev": true,
       "license": "MIT"
     },
+    "node_modules/d3-array": {
+      "version": "3.2.4",
+      "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
+      "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
+      "license": "ISC",
+      "dependencies": {
+        "internmap": "1 - 2"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-color": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+      "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-delaunay": {
+      "version": "6.0.4",
+      "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
+      "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==",
+      "license": "ISC",
+      "dependencies": {
+        "delaunator": "5"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-format": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
+      "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-geo": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz",
+      "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==",
+      "license": "ISC",
+      "dependencies": {
+        "d3-array": "2.5.0 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-geo-voronoi": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/d3-geo-voronoi/-/d3-geo-voronoi-2.1.0.tgz",
+      "integrity": "sha512-kqE4yYuOjPbKdBXG0xztCacPwkVSK2REF1opSNrnqqtXJmNcM++UbwQ8SxvwP6IQTj9RvIjjK4qeiVsEfj0Z2Q==",
+      "license": "ISC",
+      "dependencies": {
+        "d3-array": "3",
+        "d3-delaunay": "6",
+        "d3-geo": "3",
+        "d3-tricontour": "1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-interpolate": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+      "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+      "license": "ISC",
+      "dependencies": {
+        "d3-color": "1 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-octree": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/d3-octree/-/d3-octree-1.1.0.tgz",
+      "integrity": "sha512-F8gPlqpP+HwRPMO/8uOu5wjH110+6q4cgJvgJT6vlpy3BEaDIKlTZrgHKZSp/i1InRpVfh4puY/kvL6MxK930A==",
+      "license": "MIT"
+    },
+    "node_modules/d3-scale": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
+      "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+      "license": "ISC",
+      "dependencies": {
+        "d3-array": "2.10.0 - 3",
+        "d3-format": "1 - 3",
+        "d3-interpolate": "1.2.0 - 3",
+        "d3-time": "2.1.1 - 3",
+        "d3-time-format": "2 - 4"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-scale-chromatic": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
+      "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==",
+      "license": "ISC",
+      "dependencies": {
+        "d3-color": "1 - 3",
+        "d3-interpolate": "1 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-selection": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
+      "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-time": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
+      "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
+      "license": "ISC",
+      "dependencies": {
+        "d3-array": "2 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-time-format": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
+      "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+      "license": "ISC",
+      "dependencies": {
+        "d3-time": "1 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-tricontour": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/d3-tricontour/-/d3-tricontour-1.0.2.tgz",
+      "integrity": "sha512-HIRxHzHagPtUPNabjOlfcyismJYIsc+Xlq4mlsts4e8eAcwyq9Tgk/sYdyhlBpQ0MHwVquc/8j+e29YjXnmxeA==",
+      "license": "ISC",
+      "dependencies": {
+        "d3-delaunay": "6",
+        "d3-scale": "4"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/data-bind-mapper": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/data-bind-mapper/-/data-bind-mapper-1.0.2.tgz",
+      "integrity": "sha512-OJBssRDE5jGqPatqFfZzKWQ16oXzz7/2lSdEU84y6syEbJAqV3Ckr/1gzpX387tIuXiZZ6+g3tKvvBHT+umWnA==",
+      "license": "MIT",
+      "dependencies": {
+        "accessor-fn": "1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/debug": {
       "version": "4.4.0",
       "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
@@ -1672,6 +2188,15 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/delaunator": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz",
+      "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==",
+      "license": "ISC",
+      "dependencies": {
+        "robust-predicates": "^3.0.2"
+      }
+    },
     "node_modules/delayed-stream": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -1681,6 +2206,21 @@
         "node": ">=0.4.0"
       }
     },
+    "node_modules/detect-gpu": {
+      "version": "5.0.70",
+      "resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.70.tgz",
+      "integrity": "sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w==",
+      "license": "MIT",
+      "dependencies": {
+        "webgl-constants": "^1.1.1"
+      }
+    },
+    "node_modules/draco3d": {
+      "version": "1.5.7",
+      "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz",
+      "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==",
+      "license": "Apache-2.0"
+    },
     "node_modules/dunder-proto": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@@ -1695,6 +2235,12 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/earcut": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.1.tgz",
+      "integrity": "sha512-0l1/0gOjESMeQyYaK5IDiPNvFeu93Z/cO0TjZh9eZ1vyCtZnA7KMZ8rQggpsJHIbGSdrqYq9OhuveadOVHCshw==",
+      "license": "ISC"
+    },
     "node_modules/electron-to-chromium": {
       "version": "1.5.112",
       "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.112.tgz",
@@ -2009,6 +2555,12 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/fflate": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
+      "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
+      "license": "MIT"
+    },
     "node_modules/file-entry-cache": {
       "version": "8.0.0",
       "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -2060,9 +2612,23 @@
       "dev": true,
       "license": "ISC"
     },
-    "node_modules/follow-redirects": {
-      "version": "1.15.9",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
+    "node_modules/float-tooltip": {
+      "version": "1.7.5",
+      "resolved": "https://registry.npmjs.org/float-tooltip/-/float-tooltip-1.7.5.tgz",
+      "integrity": "sha512-/kXzuDnnBqyyWyhDMH7+PfP8J/oXiAavGzcRxASOMRHFuReDtofizLLJsf7nnDLAfEaMW4pVWaXrAjtnglpEkg==",
+      "license": "MIT",
+      "dependencies": {
+        "d3-selection": "2 - 3",
+        "kapsule": "^1.16",
+        "preact": "10"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/follow-redirects": {
+      "version": "1.15.9",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
       "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
       "funding": [
         {
@@ -2095,6 +2661,15 @@
         "node": ">= 6"
       }
     },
+    "node_modules/frame-ticker": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/frame-ticker/-/frame-ticker-1.0.3.tgz",
+      "integrity": "sha512-E0X2u2JIvbEMrqEg5+4BpTqaD22OwojJI63K7MdKHdncjtAhGRbCR8nJCr2vwEt9NWBPCPcu70X9smPviEBy8Q==",
+      "license": "MIT",
+      "dependencies": {
+        "simplesignal": "^2.1.6"
+      }
+    },
     "node_modules/fsevents": {
       "version": "2.3.3",
       "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -2192,6 +2767,29 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/globe.gl": {
+      "version": "2.41.3",
+      "resolved": "https://registry.npmjs.org/globe.gl/-/globe.gl-2.41.3.tgz",
+      "integrity": "sha512-xvfQdMQPko2miOBG+d39jDlMN3JSmQz0M/cQcCF/BAN14CzbbJEzGkOZRFD91GiJaWVyk3GOSXvzuxs/UCSO8w==",
+      "license": "MIT",
+      "dependencies": {
+        "@tweenjs/tween.js": "18 - 25",
+        "accessor-fn": "1",
+        "kapsule": "^1.16",
+        "three": ">=0.154 <1",
+        "three-globe": "^2.42",
+        "three-render-objects": "^1.39"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/glsl-noise": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/glsl-noise/-/glsl-noise-0.0.0.tgz",
+      "integrity": "sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==",
+      "license": "MIT"
+    },
     "node_modules/gopd": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
@@ -2204,6 +2802,17 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/h3-js": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/h3-js/-/h3-js-4.1.0.tgz",
+      "integrity": "sha512-LQhmMl1dRQQjMXPzJc7MpZ/CqPOWWuAvVEoVJM9n/s7vHypj+c3Pd5rLQCkAsOgAoAYKbNCsYFE++LF7MvSfCQ==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=4",
+        "npm": ">=3",
+        "yarn": ">=1.3.0"
+      }
+    },
     "node_modules/has-flag": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -2253,6 +2862,32 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/hls.js": {
+      "version": "1.5.20",
+      "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.5.20.tgz",
+      "integrity": "sha512-uu0VXUK52JhihhnN/MVVo1lvqNNuhoxkonqgO3IpjvQiGpJBdIXMGkofjQb/j9zvV7a1SW8U9g1FslWx/1HOiQ==",
+      "license": "Apache-2.0"
+    },
+    "node_modules/ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "BSD-3-Clause"
+    },
     "node_modules/ignore": {
       "version": "5.3.2",
       "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -2263,6 +2898,12 @@
         "node": ">= 4"
       }
     },
+    "node_modules/immediate": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+      "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
+      "license": "MIT"
+    },
     "node_modules/import-fresh": {
       "version": "3.3.1",
       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -2290,6 +2931,24 @@
         "node": ">=0.8.19"
       }
     },
+    "node_modules/index-array-by": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/index-array-by/-/index-array-by-1.4.2.tgz",
+      "integrity": "sha512-SP23P27OUKzXWEC/TOyWlwLviofQkCSCKONnc62eItjp69yCZZPqDQtr3Pw5gJDnPeUMqExmKydNZaJO0FU9pw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/internmap": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+      "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+      "license": "ISC",
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/is-extglob": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -2313,13 +2972,30 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/is-promise": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
+      "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==",
+      "license": "MIT"
+    },
     "node_modules/isexe": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
       "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
-      "dev": true,
       "license": "ISC"
     },
+    "node_modules/its-fine": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-2.0.0.tgz",
+      "integrity": "sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/react-reconciler": "^0.28.9"
+      },
+      "peerDependencies": {
+        "react": "^19.0.0"
+      }
+    },
     "node_modules/js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -2387,6 +3063,18 @@
         "node": ">=6"
       }
     },
+    "node_modules/kapsule": {
+      "version": "1.16.3",
+      "resolved": "https://registry.npmjs.org/kapsule/-/kapsule-1.16.3.tgz",
+      "integrity": "sha512-4+5mNNf4vZDSwPhKprKwz3330iisPrb08JyMgbsdFrimBCKNHecua/WBwvVg3n7vwx0C1ARjfhwIpbrbd9n5wg==",
+      "license": "MIT",
+      "dependencies": {
+        "lodash-es": "4"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/keyv": {
       "version": "4.5.4",
       "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -2411,6 +3099,15 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/lie": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+      "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+      "license": "MIT",
+      "dependencies": {
+        "immediate": "~3.0.5"
+      }
+    },
     "node_modules/locate-path": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -2427,6 +3124,12 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/lodash-es": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+      "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
+      "license": "MIT"
+    },
     "node_modules/lodash.merge": {
       "version": "4.6.2",
       "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -2444,6 +3147,16 @@
         "yallist": "^3.0.2"
       }
     },
+    "node_modules/maath": {
+      "version": "0.10.8",
+      "resolved": "https://registry.npmjs.org/maath/-/maath-0.10.8.tgz",
+      "integrity": "sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@types/three": ">=0.134.0",
+        "three": ">=0.134.0"
+      }
+    },
     "node_modules/math-intrinsics": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@@ -2453,6 +3166,21 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/meshline": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/meshline/-/meshline-3.3.1.tgz",
+      "integrity": "sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==",
+      "license": "MIT",
+      "peerDependencies": {
+        "three": ">=0.137"
+      }
+    },
+    "node_modules/meshoptimizer": {
+      "version": "0.18.1",
+      "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz",
+      "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==",
+      "license": "MIT"
+    },
     "node_modules/mime-db": {
       "version": "1.52.0",
       "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@@ -2604,7 +3332,6 @@
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
       "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
-      "dev": true,
       "license": "MIT",
       "engines": {
         "node": ">=8"
@@ -2617,6 +3344,27 @@
       "dev": true,
       "license": "ISC"
     },
+    "node_modules/point-in-polygon-hao": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/point-in-polygon-hao/-/point-in-polygon-hao-1.2.4.tgz",
+      "integrity": "sha512-x2pcvXeqhRHlNRdhLs/tgFapAbSSe86wa/eqmj1G6pWftbEs5aVRJhRGM6FYSUERKu0PjekJzMq0gsI2XyiclQ==",
+      "license": "MIT",
+      "dependencies": {
+        "robust-predicates": "^3.0.2"
+      }
+    },
+    "node_modules/polished": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz",
+      "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/runtime": "^7.17.8"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/postcss": {
       "version": "8.5.3",
       "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
@@ -2646,6 +3394,22 @@
         "node": "^10 || ^12 || >=14"
       }
     },
+    "node_modules/potpack": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz",
+      "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==",
+      "license": "ISC"
+    },
+    "node_modules/preact": {
+      "version": "10.26.4",
+      "resolved": "https://registry.npmjs.org/preact/-/preact-10.26.4.tgz",
+      "integrity": "sha512-KJhO7LBFTjP71d83trW+Ilnjbo+ySsaAgCfXOXUlmGzJ4ygYPWmysm77yg4emwfmoz3b22yvH5IsVFHbhUaH5w==",
+      "license": "MIT",
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/preact"
+      }
+    },
     "node_modules/prelude-ls": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -2656,6 +3420,16 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/promise-worker-transferable": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz",
+      "integrity": "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "is-promise": "^2.1.0",
+        "lie": "^3.0.2"
+      }
+    },
     "node_modules/proxy-from-env": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -2702,6 +3476,21 @@
         "react": "*"
       }
     },
+    "node_modules/react-reconciler": {
+      "version": "0.31.0",
+      "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.31.0.tgz",
+      "integrity": "sha512-7Ob7Z+URmesIsIVRjnLoDGwBEG/tVitidU0nMsqX/eeJaLY89RISO/10ERe0MqmzuKUUB1rmY+h1itMbUHg9BQ==",
+      "license": "MIT",
+      "dependencies": {
+        "scheduler": "^0.25.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      },
+      "peerDependencies": {
+        "react": "^19.0.0"
+      }
+    },
     "node_modules/react-refresh": {
       "version": "0.14.2",
       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
@@ -2752,6 +3541,36 @@
         "react-dom": ">=18"
       }
     },
+    "node_modules/react-use-measure": {
+      "version": "2.1.7",
+      "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz",
+      "integrity": "sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react": ">=16.13",
+        "react-dom": ">=16.13"
+      },
+      "peerDependenciesMeta": {
+        "react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/regenerator-runtime": {
+      "version": "0.14.1",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+      "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+      "license": "MIT"
+    },
+    "node_modules/require-from-string": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/resolve-from": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -2762,6 +3581,12 @@
         "node": ">=4"
       }
     },
+    "node_modules/robust-predicates": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
+      "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==",
+      "license": "Unlicense"
+    },
     "node_modules/rollup": {
       "version": "4.34.9",
       "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.9.tgz",
@@ -2827,7 +3652,6 @@
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
       "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
-      "dev": true,
       "license": "MIT",
       "dependencies": {
         "shebang-regex": "^3.0.0"
@@ -2840,12 +3664,17 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
       "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
-      "dev": true,
       "license": "MIT",
       "engines": {
         "node": ">=8"
       }
     },
+    "node_modules/simplesignal": {
+      "version": "2.1.7",
+      "resolved": "https://registry.npmjs.org/simplesignal/-/simplesignal-2.1.7.tgz",
+      "integrity": "sha512-PEo2qWpUke7IMhlqiBxrulIFvhJRLkl1ih52Rwa+bPjzhJepcd4GIjn2RiQmFSx3dQvsEAgF0/lXMwMN7vODaA==",
+      "license": "MIT"
+    },
     "node_modules/source-map-js": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -2856,6 +3685,32 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/stats-gl": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/stats-gl/-/stats-gl-2.4.2.tgz",
+      "integrity": "sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/three": "*",
+        "three": "^0.170.0"
+      },
+      "peerDependencies": {
+        "@types/three": "*",
+        "three": "*"
+      }
+    },
+    "node_modules/stats-gl/node_modules/three": {
+      "version": "0.170.0",
+      "resolved": "https://registry.npmjs.org/three/-/three-0.170.0.tgz",
+      "integrity": "sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ==",
+      "license": "MIT"
+    },
+    "node_modules/stats.js": {
+      "version": "0.17.0",
+      "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz",
+      "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==",
+      "license": "MIT"
+    },
     "node_modules/strip-json-comments": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -2882,6 +3737,237 @@
         "node": ">=8"
       }
     },
+    "node_modules/suspend-react": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz",
+      "integrity": "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react": ">=17.0"
+      }
+    },
+    "node_modules/three": {
+      "version": "0.174.0",
+      "resolved": "https://registry.npmjs.org/three/-/three-0.174.0.tgz",
+      "integrity": "sha512-p+WG3W6Ov74alh3geCMkGK9NWuT62ee21cV3jEnun201zodVF4tCE5aZa2U122/mkLRmhJJUQmLLW1BH00uQJQ==",
+      "license": "MIT"
+    },
+    "node_modules/three-conic-polygon-geometry": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/three-conic-polygon-geometry/-/three-conic-polygon-geometry-2.1.2.tgz",
+      "integrity": "sha512-NaP3RWLJIyPGI+zyaZwd0Yj6rkoxm4FJHqAX1Enb4L64oNYLCn4bz1ESgOEYavgcUwCNYINu1AgEoUBJr1wZcA==",
+      "license": "MIT",
+      "dependencies": {
+        "@turf/boolean-point-in-polygon": "^7.2",
+        "d3-array": "1 - 3",
+        "d3-geo": "1 - 3",
+        "d3-geo-voronoi": "2",
+        "d3-scale": "1 - 4",
+        "delaunator": "5",
+        "earcut": "3"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "peerDependencies": {
+        "three": ">=0.72.0"
+      }
+    },
+    "node_modules/three-geojson-geometry": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/three-geojson-geometry/-/three-geojson-geometry-2.1.1.tgz",
+      "integrity": "sha512-dC7bF3ri1goDcihYhzACHOBQqu7YNNazYLa2bSydVIiJUb3jDFojKSy+gNj2pMkqZNSVjssSmdY9zlmnhEpr1w==",
+      "license": "MIT",
+      "dependencies": {
+        "d3-geo": "1 - 3",
+        "d3-interpolate": "1 - 3",
+        "earcut": "3"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "peerDependencies": {
+        "three": ">=0.72.0"
+      }
+    },
+    "node_modules/three-globe": {
+      "version": "2.42.3",
+      "resolved": "https://registry.npmjs.org/three-globe/-/three-globe-2.42.3.tgz",
+      "integrity": "sha512-6RGuUpSJ1uPlDS0LClRDtRJPK9a3Kb7x7XT/6f9iAugnEjmxGC6neKXgTZ8wbsqWYiKT/SGLdgJFStYTrZsD3g==",
+      "license": "MIT",
+      "dependencies": {
+        "@tweenjs/tween.js": "18 - 25",
+        "accessor-fn": "1",
+        "d3-array": "3",
+        "d3-color": "3",
+        "d3-geo": "3",
+        "d3-interpolate": "3",
+        "d3-scale": "4",
+        "d3-scale-chromatic": "3",
+        "data-bind-mapper": "1",
+        "frame-ticker": "1",
+        "h3-js": "4",
+        "index-array-by": "1",
+        "kapsule": "^1.16",
+        "three-conic-polygon-geometry": "2",
+        "three-geojson-geometry": "2",
+        "three-slippy-map-globe": "1",
+        "tinycolor2": "1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "peerDependencies": {
+        "three": ">=0.154"
+      }
+    },
+    "node_modules/three-mesh-bvh": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.8.3.tgz",
+      "integrity": "sha512-4G5lBaF+g2auKX3P0yqx+MJC6oVt6sB5k+CchS6Ob0qvH0YIhuUk1eYr7ktsIpY+albCqE80/FVQGV190PmiAg==",
+      "license": "MIT",
+      "peerDependencies": {
+        "three": ">= 0.159.0"
+      }
+    },
+    "node_modules/three-render-objects": {
+      "version": "1.39.3",
+      "resolved": "https://registry.npmjs.org/three-render-objects/-/three-render-objects-1.39.3.tgz",
+      "integrity": "sha512-x5oNbAGzStIH0vTKyUqJVr+ojmhjQV8m3f1LdphMpohfjjbYQamoOVt/+gaYq1BiYlRnrzP/fULVYgmrGiGtNw==",
+      "license": "MIT",
+      "dependencies": {
+        "@tweenjs/tween.js": "18 - 25",
+        "accessor-fn": "1",
+        "float-tooltip": "^1.7",
+        "kapsule": "^1.16",
+        "polished": "4"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "peerDependencies": {
+        "three": ">=0.168"
+      }
+    },
+    "node_modules/three-slippy-map-globe": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/three-slippy-map-globe/-/three-slippy-map-globe-1.0.3.tgz",
+      "integrity": "sha512-Y9WCA/tTL8yH8FHVSXVQss/P0V36utTNhuixzFPj0Bs0SXxO+Vui133oAQmMpx4BLXYZpWZwcqHM2i3MfFlYWw==",
+      "license": "MIT",
+      "dependencies": {
+        "d3-geo": "1 - 3",
+        "d3-octree": "^1.1",
+        "d3-scale": "1 - 4"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "peerDependencies": {
+        "three": ">=0.154"
+      }
+    },
+    "node_modules/three-stdlib": {
+      "version": "2.35.14",
+      "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.35.14.tgz",
+      "integrity": "sha512-kpCaEg59M9usFTgHC+YZNKvx7nMoLI2zQxZBV8pjoNW6vNZmGyXpaLBL09A2oLCsS3KepgMFkOuk6lRoebTNvA==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/draco3d": "^1.4.0",
+        "@types/offscreencanvas": "^2019.6.4",
+        "@types/webxr": "^0.5.2",
+        "draco3d": "^1.4.1",
+        "fflate": "^0.6.9",
+        "potpack": "^1.0.1"
+      },
+      "peerDependencies": {
+        "three": ">=0.128.0"
+      }
+    },
+    "node_modules/three-stdlib/node_modules/fflate": {
+      "version": "0.6.10",
+      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz",
+      "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==",
+      "license": "MIT"
+    },
+    "node_modules/tinycolor2": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
+      "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==",
+      "license": "MIT"
+    },
+    "node_modules/troika-three-text": {
+      "version": "0.52.3",
+      "resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.52.3.tgz",
+      "integrity": "sha512-jLhiwgV8kEkwWjvK12f2fHVpbOC75p7SgPQ0cgcz+IMtN5Bdyg4EuFdwuTOVu9ga8UeYdKBpzd1AxviyixtYTQ==",
+      "license": "MIT",
+      "dependencies": {
+        "bidi-js": "^1.0.2",
+        "troika-three-utils": "^0.52.0",
+        "troika-worker-utils": "^0.52.0",
+        "webgl-sdf-generator": "1.1.1"
+      },
+      "peerDependencies": {
+        "three": ">=0.125.0"
+      }
+    },
+    "node_modules/troika-three-utils": {
+      "version": "0.52.0",
+      "resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.52.0.tgz",
+      "integrity": "sha512-00oxqIIehtEKInOTQekgyknBuRUj1POfOUE2q1OmL+Xlpp4gIu+S0oA0schTyXsDS4d9DkR04iqCdD40rF5R6w==",
+      "license": "MIT",
+      "peerDependencies": {
+        "three": ">=0.125.0"
+      }
+    },
+    "node_modules/troika-worker-utils": {
+      "version": "0.52.0",
+      "resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.52.0.tgz",
+      "integrity": "sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==",
+      "license": "MIT"
+    },
+    "node_modules/tslib": {
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+      "license": "0BSD"
+    },
+    "node_modules/tunnel-rat": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/tunnel-rat/-/tunnel-rat-0.1.2.tgz",
+      "integrity": "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==",
+      "license": "MIT",
+      "dependencies": {
+        "zustand": "^4.3.2"
+      }
+    },
+    "node_modules/tunnel-rat/node_modules/zustand": {
+      "version": "4.5.6",
+      "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.6.tgz",
+      "integrity": "sha512-ibr/n1hBzLLj5Y+yUcU7dYw8p6WnIVzdJbnX+1YpaScvZVF2ziugqHs+LAmHw4lWO9c/zRj+K1ncgWDQuthEdQ==",
+      "license": "MIT",
+      "dependencies": {
+        "use-sync-external-store": "^1.2.2"
+      },
+      "engines": {
+        "node": ">=12.7.0"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.8",
+        "immer": ">=9.0.6",
+        "react": ">=16.8"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "immer": {
+          "optional": true
+        },
+        "react": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/turbo-stream": {
       "version": "2.4.0",
       "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz",
@@ -2942,6 +4028,24 @@
         "punycode": "^2.1.0"
       }
     },
+    "node_modules/use-sync-external-store": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz",
+      "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==",
+      "license": "MIT",
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+      }
+    },
+    "node_modules/utility-types": {
+      "version": "3.11.0",
+      "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz",
+      "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4"
+      }
+    },
     "node_modules/vite": {
       "version": "6.2.0",
       "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.0.tgz",
@@ -3014,11 +4118,21 @@
         }
       }
     },
+    "node_modules/webgl-constants": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz",
+      "integrity": "sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg=="
+    },
+    "node_modules/webgl-sdf-generator": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz",
+      "integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==",
+      "license": "MIT"
+    },
     "node_modules/which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
       "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
-      "dev": true,
       "license": "ISC",
       "dependencies": {
         "isexe": "^2.0.0"
@@ -3059,6 +4173,35 @@
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
+    },
+    "node_modules/zustand": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz",
+      "integrity": "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12.20.0"
+      },
+      "peerDependencies": {
+        "@types/react": ">=18.0.0",
+        "immer": ">=9.0.6",
+        "react": ">=18.0.0",
+        "use-sync-external-store": ">=1.2.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "immer": {
+          "optional": true
+        },
+        "react": {
+          "optional": true
+        },
+        "use-sync-external-store": {
+          "optional": true
+        }
+      }
     }
   }
 }
diff --git a/Frontend/client/package.json b/Frontend/client/package.json
index 05a269d..3b5a912 100644
--- a/Frontend/client/package.json
+++ b/Frontend/client/package.json
@@ -10,11 +10,15 @@
     "preview": "vite preview"
   },
   "dependencies": {
+    "@react-three/drei": "^10.0.5",
+    "@react-three/fiber": "^9.1.0",
     "axios": "^1.8.4",
+    "globe.gl": "^2.41.3",
     "react": "^19.0.0",
     "react-dom": "^19.0.0",
     "react-icons": "^5.5.0",
-    "react-router-dom": "^7.4.0"
+    "react-router-dom": "^7.4.0",
+    "three": "^0.174.0"
   },
   "devDependencies": {
     "@eslint/js": "^9.21.0",
diff --git a/Frontend/client/src/App.jsx b/Frontend/client/src/App.jsx
index da9bd3e..a0b1d48 100644
--- a/Frontend/client/src/App.jsx
+++ b/Frontend/client/src/App.jsx
@@ -1,24 +1,61 @@
 import React from "react";
+import { Routes, Route } from "react-router-dom"; 
 import Header from "./components/Header";
 import HeroSection from "./components/HeroSection";
 import Features from "./components/Features";
 import Footer from "./components/Footer";
-import PostList from "./components/PostList"; // Import PostList component
+import PostList from "./components/PostList"; 
+import Badge from "./components/Badge";
+import AddEntity from "./components/AddEntity"; 
+import { Link } from "react-router-dom";
+
 import "./styles/global.css";
-import { Routes } from "react-router-dom";
-import Badge from "./components/Badge" ;
+
 function App() {
   return (
-    <div>
-   
+    <>
       <Header />
-      <HeroSection />
-      <Features />
-      <h2>Recent Reflections ...</h2>
-      <PostList />  {/* Render multiple post cards */}
+      
+      {/* Add Entity Button - Styled and Positioned */}
+     
+
+      <Routes>
+        <Route
+          path="/"
+          element={
+            <>
+              <HeroSection />
+              <div style={{ textAlign: "center", margin: "20px 0" }}>
+        <Link to="/add-entity">
+          <button 
+            style={{
+              backgroundColor: "#22c55e", // Green color
+              color: "white",
+              padding: "10px 20px",
+              fontSize: "16px",
+              border: "none",
+              borderRadius: "8px",
+              cursor: "pointer",
+              transition: "background 0.3s ease"
+            }}
+            onMouseOver={(e) => e.target.style.backgroundColor = "#16a34a"} // Darker green on hover
+            onMouseOut={(e) => e.target.style.backgroundColor = "#22c55e"} // Reset on mouse out
+          >
+            ➕ Add Entity
+          </button>
+        </Link>
+      </div>
+              <Features />
+              <h2 style={{ textAlign: "center", marginTop: "20px" }}>Recent Reflections ...</h2>
+              <PostList />
+            </>
+          }
+        />
+        <Route path="/add-entity" element={<AddEntity />} />  
+      </Routes>
+      
       <Footer />
-      {/* <Badge/> */}
-    </div>
+    </>
   );
 }
 
diff --git a/Frontend/client/src/components/AddEntity.jsx b/Frontend/client/src/components/AddEntity.jsx
new file mode 100644
index 0000000..8fad94e
--- /dev/null
+++ b/Frontend/client/src/components/AddEntity.jsx
@@ -0,0 +1,144 @@
+import React, { useState, useEffect } from "react";
+import axios from "axios";
+
+const AddEntity = () => {
+  const [title, setTitle] = useState("");
+  const [description, setDescription] = useState("");
+  const [entities, setEntities] = useState([]);
+
+  useEffect(() => {
+    fetchEntities();
+  }, []);
+
+  const fetchEntities = async () => {
+    try {
+      const response = await axios.get("http://localhost:5000/api/entities");
+      setEntities(response.data);
+    } catch (error) {
+      console.error("Error fetching entities:", error);
+    }
+  };
+
+  const handleSubmit = async (e) => {
+    e.preventDefault();
+    if (!title || !description) return alert("Please fill all fields!");
+
+    try {
+      const response = await axios.post("http://localhost:5000/api/entities", {
+        title,
+        description,
+      });
+
+      setEntities([...entities, response.data]);
+      setTitle("");
+      setDescription("");
+    } catch (error) {
+      console.error("Error adding entity:", error);
+    }
+  };
+
+  return (
+    <div style={styles.container}>
+      <h2 style={styles.heading}>📌 Add a New Entity</h2>
+      <form onSubmit={handleSubmit} style={styles.form}>
+        <input
+          type="text"
+          placeholder="Title"
+          value={title}
+          onChange={(e) => setTitle(e.target.value)}
+          style={styles.input}
+        />
+        <textarea
+          placeholder="Description"
+          value={description}
+          onChange={(e) => setDescription(e.target.value)}
+          style={styles.textarea}
+        />
+        <button type="submit" style={styles.button}>➕ Add Entity</button>
+      </form>
+
+      <h3 style={styles.listHeading}>📌 Entities List</h3>
+      <ul style={styles.list}>
+        {entities.map((entity) => (
+          <li key={entity._id} style={styles.listItem}>
+            <strong>{entity.title}</strong>: {entity.description}
+          </li>
+        ))}
+      </ul>
+    </div>
+  );
+};
+
+// Inline CSS Styles
+const styles = {
+  container: {
+    textAlign: "center",
+    padding: "30px",
+    background: "linear-gradient(to bottom, #6a11cb, #2575fc)",
+    minHeight: "100vh",
+    borderRadius: "15px",
+    boxShadow: "0px 4px 10px rgba(0, 0, 0, 0.2)",
+    marginBottom: "30px",
+  },
+  heading: {
+    fontSize: "24px",
+    color: "#fff",
+    marginBottom: "15px",
+  },
+  form: {
+    backgroundColor: "#ffffff",
+    padding: "20px",
+    borderRadius: "12px",
+    boxShadow: "0px 5px 15px rgba(0, 0, 0, 0.2)",
+    maxWidth: "400px",
+    margin: "auto",
+  },
+  input: {
+    width: "90%",
+    padding: "10px",
+    marginBottom: "10px",
+    borderRadius: "8px",
+    border: "2px solid #6a11cb",
+    fontSize: "16px",
+  },
+  textarea: {
+    width: "90%",
+    padding: "10px",
+    borderRadius: "8px",
+    border: "2px solid #6a11cb",
+    fontSize: "16px",
+    minHeight: "80px",
+  },
+  button: {
+    backgroundColor: "#22c55e",
+    color: "#fff",
+    padding: "12px 20px",
+    border: "none",
+    borderRadius: "8px",
+    fontSize: "16px",
+    cursor: "pointer",
+    transition: "0.3s ease",
+  },
+  listHeading: {
+    marginTop: "30px",
+    fontSize: "20px",
+    color: "#fff",
+  },
+  list: {
+    listStyle: "none",
+    padding: "0",
+    marginTop: "10px",
+  },
+  listItem: {
+    backgroundColor: "#fff",
+    margin: "8px auto",
+    padding: "12px",
+    borderRadius: "8px",
+    width: "80%",
+    fontSize: "16px",
+    boxShadow: "0px 2px 8px rgba(0, 0, 0, 0.2)",
+    transition: "0.3s ease",
+  },
+};
+
+export default AddEntity;
diff --git a/Frontend/client/src/components/Badge.jsx b/Frontend/client/src/components/Badge.jsx
index 984875d..2df4940 100644
--- a/Frontend/client/src/components/Badge.jsx
+++ b/Frontend/client/src/components/Badge.jsx
@@ -35,13 +35,10 @@ const Badge = () => {
       <h1 className="title">🏅 Welcome to the Badge Ceremony! 🎉</h1>
       <p className="subtitle">Click on a badge to reveal its description.</p>
 
-      {/* Loading State */}
       {loading && <div className="spinner"></div>}
 
-      {/* Error Message */}
       {error && <p className="error">{error}</p>}
 
-      {/* Badge List */}
       <div className="badge-grid">
         {Array.isArray(badges) &&
           badges.map((badge, index) => (
@@ -58,7 +55,7 @@ const Badge = () => {
           ))}
       </div>
 
-      {/* Internal CSS */}
+
       <style>{`
         .badge-container {
           text-align: center;
diff --git a/Frontend/client/src/components/HeroSection.jsx b/Frontend/client/src/components/HeroSection.jsx
index 9f813e5..dd9cc6c 100644
--- a/Frontend/client/src/components/HeroSection.jsx
+++ b/Frontend/client/src/components/HeroSection.jsx
@@ -1,23 +1,29 @@
 import React, { useState, useEffect } from "react";
-import image from "../assets/SchoolDays.png" ;
+import image from "../assets/SchoolDays.png";
 import "./../styles/landing.css";
+// import React, { useRef, useEffect } from "react";
+import Globe from "globe.gl";
+
 
 const HeroSection = () => {
+  const fullText = "Reflect, Laugh and PREDICT...";
   const [text, setText] = useState("");
-  const fullText = "Reflect, Laugh, Predict! 🎉";
 
   useEffect(() => {
     let index = 0;
+    setText(""); // Ensure the text is reset before starting
+
     const typingInterval = setInterval(() => {
       if (index < fullText.length) {
-        setText((prev) => prev + fullText[index]);
+        setText(() => fullText.slice(0, index + 1)); // Use slice instead of concatenation
         index++;
       } else {
         clearInterval(typingInterval);
       }
-    }, 100);  
+    }, 100);
+
     return () => clearInterval(typingInterval);
-  }, []);
+  }, []); // Runs only once on mount
 
   return (
     <section className="hero">


Reviews:
user: login: qodo-code-review[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T16:50:42Z
user: login: qodo-code-review[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T16:50:53Z

Review comments:
diff_hunk: @@ -0,0 +1,144 @@
+import React, { useState, useEffect } from "react";
+import axios from "axios";
+
+const AddEntity = () => {
+  const [title, setTitle] = useState("");
+  const [description, setDescription] = useState("");
+  const [entities, setEntities] = useState([]);
+
+  useEffect(() => {
+    fetchEntities();
+  }, []);
+
+  const fetchEntities = async () => {
+    try {
+      const response = await axios.get("http://localhost:5000/api/entities");
+      setEntities(response.data);
+    } catch (error) {
+      console.error("Error fetching entities:", error);
+    }
+  };
path: Frontend/client/src/components/AddEntity.jsx
user: login: qodo-code-review[bot]
body: **Suggestion:** Handle fetch error state
```suggestion
  const [error, setError] = useState(null);

  const fetchEntities = async () => {
    try {
      setError(null);
      const response = await axios.get("http://localhost:5000/api/entities");
      setEntities(response.data);
    } catch (error) {
      console.error("Error fetching entities:", error);
      setError("Failed to load entities. Please refresh the page.");
    }
  };
```

<!-- manually_applied -->
created_at: 2025-03-27T16:50:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,144 @@
+import React, { useState, useEffect } from "react";
+import axios from "axios";
+
+const AddEntity = () => {
+  const [title, setTitle] = useState("");
+  const [description, setDescription] = useState("");
+  const [entities, setEntities] = useState([]);
+
+  useEffect(() => {
+    fetchEntities();
+  }, []);
+
+  const fetchEntities = async () => {
+    try {
+      const response = await axios.get("http://localhost:5000/api/entities");
+      setEntities(response.data);
+    } catch (error) {
+      console.error("Error fetching entities:", error);
+    }
+  };
+
+  const handleSubmit = async (e) => {
+    e.preventDefault();
+    if (!title || !description) return alert("Please fill all fields!");
+
+    try {
+      const response = await axios.post("http://localhost:5000/api/entities", {
+        title,
+        description,
+      });
+
+      setEntities([...entities, response.data]);
+      setTitle("");
+      setDescription("");
+    } catch (error) {
+      console.error("Error adding entity:", error);
+    }
+  };
path: Frontend/client/src/components/AddEntity.jsx
user: login: qodo-code-review[bot]
body: **Suggestion:** Add user error feedback
```suggestion
  const handleSubmit = async (e) => {
    e.preventDefault();
    if (!title || !description) return alert("Please fill all fields!");

    try {
      const response = await axios.post("http://localhost:5000/api/entities", {
        title,
        description,
      });

      setEntities([...entities, response.data]);
      setTitle("");
      setDescription("");
    } catch (error) {
      console.error("Error adding entity:", error);
      alert("Failed to add entity. Please try again later.");
    }
  };
```

<!-- manually_applied -->
created_at: 2025-03-27T16:50:53Z
author_association: CONTRIBUTOR

PR comments:
user: login: ANU-2524
created_at: 2025-03-27T16:49:24Z
body: @CodiumAI-Agent /review
author_association: COLLABORATOR
user: login: qodo-code-review[bot]
created_at: 2025-03-27T16:49:34Z
body: _Qodo Merge was enabled for this repository. To continue using it, please link your Git account with your Qodo account [here](https://app.qodo.ai/qodo-merge)._

## PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

<table>
<tr><td>⏱️&nbsp;<strong>Estimated effort to review</strong>: 3 🔵🔵🔵⚪⚪</td></tr>
<tr><td>🧪&nbsp;<strong>No relevant tests</strong></td></tr>
<tr><td>🔒&nbsp;<strong>No security concerns identified</strong></td></tr>
<tr><td>⚡&nbsp;<strong>Recommended focus areas for review</strong><br><br>

<details><summary><a href='https://github.com/kalviumcommunity/S84_TheFinalBell/pull/16/files#diff-344fd057fc8ee940f3f2c57a95e17391a4019ae66dfda0d76bcfe026c0bafdceR15-R16'><strong>Hardcoded API URL</strong></a>

The component uses hardcoded API URLs (http://localhost:5000/api/entities) which won't work in production environments. Consider using environment variables or a configuration file.
</summary>

```jsx
const response = await axios.get("http://localhost:5000/api/entities");
setEntities(response.data);
```

</details>

<details><summary><a href='https://github.com/kalviumcommunity/S84_TheFinalBell/pull/16/files#diff-344fd057fc8ee940f3f2c57a95e17391a4019ae66dfda0d76bcfe026c0bafdceR34-R37'><strong>Error Handling</strong></a>

The error handling for API requests only logs to console but doesn't provide user feedback. Consider adding user-facing error messages when API calls fail.
</summary>

```jsx
  setDescription("");
} catch (error) {
  console.error("Error adding entity:", error);
}
```

</details>

<details><summary><a href='https://github.com/kalviumcommunity/S84_TheFinalBell/pull/16/files#diff-5f8c0680c8b7e68108a7bb3326efe32255cd49aa73456cb89806edd3441bc73eR2-R5'><strong>Unused Imports</strong></a>

The component imports Globe from globe.gl and image from assets but doesn't use them. Also contains commented import that should be removed.
</summary>

```jsx
import image from "../assets/SchoolDays.png";
import "./../styles/landing.css";
// import React, { useRef, useEffect } from "react";
import Globe from "globe.gl";
```

</details>

</td></tr>
</table>

author_association: CONTRIBUTOR
user: login: QodoAI-Agent
created_at: 2025-03-27T16:49:52Z
body: ## PR Reviewer Guide 🔍

#### (Review updated until commit https://github.com/kalviumcommunity/S84_TheFinalBell/commit/8a2065c5db6157ad661e52a163e7142b0bda087b)


Here are some key observations to aid the review process:

<table>
<tr><td>⏱️&nbsp;<strong>Estimated effort to review</strong>: 3 🔵🔵🔵⚪⚪</td></tr>
<tr><td>🧪&nbsp;<strong>No relevant tests</strong></td></tr>
<tr><td>🔒&nbsp;<strong>No security concerns identified</strong></td></tr>
<tr><td>⚡&nbsp;<strong>Recommended focus areas for review</strong><br><br>

<details><summary><a href='https://github.com/kalviumcommunity/S84_TheFinalBell/pull/16/files#diff-344fd057fc8ee940f3f2c57a95e17391a4019ae66dfda0d76bcfe026c0bafdceR15-R37'><strong>API Endpoint</strong></a>

The API endpoint is hardcoded, which could reduce flexibility and complicate deployments across environments. Consider externalizing the URL to an environment variable.
</summary>

```jsx
    const response = await axios.get("http://localhost:5000/api/entities");
    setEntities(response.data);
  } catch (error) {
    console.error("Error fetching entities:", error);
  }
};

const handleSubmit = async (e) => {
  e.preventDefault();
  if (!title || !description) return alert("Please fill all fields!");

  try {
    const response = await axios.post("http://localhost:5000/api/entities", {
      title,
      description,
    });

    setEntities([...entities, response.data]);
    setTitle("");
    setDescription("");
  } catch (error) {
    console.error("Error adding entity:", error);
  }
```

</details>

<details><summary><a href='https://github.com/kalviumcommunity/S84_TheFinalBell/pull/16/files#diff-5f8c0680c8b7e68108a7bb3326efe32255cd49aa73456cb89806edd3441bc73eR2-R2'><strong>Unused Import</strong></a>

An image is being imported but not used in the component. Remove unused imports to reduce bundle size and maintain code clarity.
</summary>

```jsx
import image from "../assets/SchoolDays.png";
```

</details>

</td></tr>
</table>

author_association: NONE
user: login: qodo-code-review[bot]
created_at: 2025-03-27T16:49:54Z
body: _Qodo Merge was enabled for this repository. To continue using it, please link your Git account with your Qodo account [here](https://app.qodo.ai/qodo-merge)._

## PR Code Suggestions ✨

<!-- 8a2065c -->

Explore these optional code suggestions:

<table><thead><tr><td><strong>Category</strong></td><td align=left><strong>Suggestion&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </strong></td><td align=center><strong>Impact</strong></td></tr><tbody><tr><td rowspan=2>General</td>
<td>



<details><summary>✅ 
Add user error feedback
</summary>

___


**Add error feedback to the user when entity creation fails. Currently, errors are <br>only logged to the console, but users should be notified when their submission <br>fails.**

[Frontend/client/src/components/AddEntity.jsx [22-38]](https://github.com/kalviumcommunity/S84_TheFinalBell/pull/16/files#diff-344fd057fc8ee940f3f2c57a95e17391a4019ae66dfda0d76bcfe026c0bafdceR22-R38)

```diff
 const handleSubmit = async (e) => {
   e.preventDefault();
   if (!title || !description) return alert("Please fill all fields!");
 
   try {
     const response = await axios.post("http://localhost:5000/api/entities", {
       title,
       description,
     });
 
     setEntities([...entities, response.data]);
     setTitle("");
     setDescription("");
   } catch (error) {
     console.error("Error adding entity:", error);
+    alert("Failed to add entity. Please try again later.");
   }
 };
```

`[Suggestion has been applied]`

<details><summary>Suggestion importance[1-10]: 7</summary>

__

Why: This suggestion improves the user experience by providing feedback when entity creation fails, rather than silently logging errors to the console. This is a meaningful usability enhancement that follows good UX practices.


</details></details></td><td align=center>Medium

</td></tr><tr><td>



<details><summary>✅ 
Handle fetch error state
</summary>

___


**Add error state handling when fetching entities fails. Currently, errors are <br>only logged to the console, but the UI doesn't reflect the error state to users.**

[Frontend/client/src/components/AddEntity.jsx [13-20]](https://github.com/kalviumcommunity/S84_TheFinalBell/pull/16/files#diff-344fd057fc8ee940f3f2c57a95e17391a4019ae66dfda0d76bcfe026c0bafdceR13-R20)

```diff
+const [error, setError] = useState(null);
+
 const fetchEntities = async () => {
   try {
+    setError(null);
     const response = await axios.get("http://localhost:5000/api/entities");
     setEntities(response.data);
   } catch (error) {
     console.error("Error fetching entities:", error);
+    setError("Failed to load entities. Please refresh the page.");
   }
 };
```

`[Suggestion has been applied]`

<details><summary>Suggestion importance[1-10]: 6</summary>

__

Why: Adding error state handling improves the user experience by displaying error messages in the UI when entity fetching fails. The suggestion correctly adds a new state variable and updates the fetchEntities function to manage this state.


</details></details></td><td align=center>Low

</td></tr>
<tr><td align="center" colspan="2">

- [ ] More <!-- /improve --more_suggestions=true -->

</td><td></td></tr></tbody></table>


author_association: CONTRIBUTOR
user: login: QodoAI-Agent
created_at: 2025-03-27T16:50:36Z
body: **[Persistent review](https://github.com/kalviumcommunity/S84_TheFinalBell/pull/16#issuecomment-2758744235)** updated to latest commit https://github.com/kalviumcommunity/S84_TheFinalBell/commit/8a2065c5db6157ad661e52a163e7142b0bda087b
author_association: NONE