Issues selecting HTML element with JavaScript, only returns script nodes

I have this block of HTML:

enter image description here

This is the content of listGroup in var listGroup = menuAuthorization.children[0];.

When I do var mainMenu = listGroup.children[1]; I was expecting on getting that first Navigation.SubMenu element, but I always get the script element.

listGroup.children.length returns 2. listGroup.children returns:

enter image description here

var i = 0;
while (i < listGroup.children.length)
{
    console.log(listGroup.children[i]);
    i++;
}

returns just the 2 script elements.

enter image description here

What must I do to be able to select any of those Navigation.SubMenu elements?
I already tried with querySelector('OSBlockWidget') to at least get the list without the script elements but returns empty/undefined.

I don’t know the IDs at runtime.

Why does the this keyword behave unexpectedly when calling a method as a standalone function in JavaScript? [duplicate]

I’m learning JavaScript and trying to understand how the this keyword works in different contexts, especially with object methods. I understand that a method is a function that is a property of an object, but I ran into an issue where the value of this changes when I call the method as a standalone function instead of using it as an object method.

Here’s the code I’m working with:

const obj = {
  name: "Alice",
  greet() {
    return `Hello, ${this.name}`;
  }
};

// Calling the method directly works:
console.log(obj.greet()); // Outputs: "Hello, Alice"

// Assigning the method to a variable and calling it:
const greetFn = obj.greet;
console.log(greetFn()); // Outputs: ???

What I expect: I expect that greetFn() should output “Hello, Alice”, just like obj.greet(). However, when I call greetFn(), the result is unexpected because the this keyword does not refer to the obj object as it did before.

What I’ve tried: I’ve gone through the MDN documentation for this and some tutorials, but I still don’t fully understand why the behavior changes when the method is no longer called as part of the object. Could someone explain why this happens and suggest the best way to ensure the this context remains consistent when the method is assigned to a variable?

Why does my JavaScript function always return undefined? [closed]


function hitungVokal(kata) {
    let jumlah = 0;
    for (let i = 0; i < kata.length; i++) {
        if ("aeiou".includes(kata[i])) {
            jumlah++;
        }
    }
    return;
}
console.log(hitungVokal("halo"));

When I run the code above, the result that appears is undefined. I’ve tried adding console.log to track the count variable, but still can’t find the problem.

The function should return 2 because there are two vowels (‘a’ and ‘o’) in the word ‘hello’.

How to ensure countdown timer updates the page title even when the tab is inactive?

Google’s countdown timer effectively updates the time in the browser tab’s title, even when users navigate to other tabs. This seamless functionality relies on efficient background execution to keep the countdown active. I’m working on implementing a similar feature but facing an issue: the title stops updating or lags when the user leaves the tab.

To address this, I tried several approaches, including Web Workers, WebSockets, and requestAnimationFrame. Unfortunately, none fully resolved the issue because browsers tend to throttle background processes in inactive tabs to optimize resource usage, especially for battery life on mobile devices.

Here’s an example of what I attempted using requestAnimationFrame:

let countdown = 60; // Countdown duration in seconds

function updateTitle() {
    if (countdown > 0) {
        document.title = `Time Left: ${countdown}s`;
        countdown--;
        requestAnimationFrame(updateTitle);
    } else {
        document.title = "Time's up!";
    }
}

updateTitle();

While this works well in an active tab, the browser throttles requestAnimationFrame when the tab is inactive, causing the timer to freeze or lag. Using setInterval faces a similar challenge, as it’s also throttled in inactive tabs.

To tackle this, I explored Web Workers, which can run JavaScript in the background without being affected by the browser’s main thread. Here’s a simplified example:

Worker Script (timerWorker.js):

let countdown = 60;
setInterval(() => {
    if (countdown > 0) {
        postMessage(countdown--);
    }
}, 1000);

Main Script:

const worker = new Worker('timerWorker.js');

worker.onmessage = function (e) {
    document.title = `Time Left: ${e.data}s`;
};

worker.postMessage('start');

While Web Workers help decouple processes, they do not update the DOM directly and can still encounter throttling in some scenarios. The Web Worker approach works for a longer period before it’s stops updating. Thanks for your help in advance.

Why isn’t jquery inner html not changing in this context?

I’m adding new content display by getting an html snippet from the server and applying some changes in it. However I can’t change the jquery object created and I don’t understand why. I’ve seen lots of similar questions to mine but I don’t think they apply to my case.

The html returned from this GET request is in this format:

<div>
 <!-- more content-->
 <div class="row">
  <div class="col-sm-12">
   <span class="post-conteudo">SOME TEXT I WANT TO CHANGE</span>
  </div>
 </div>

</div>

My code is:

$.get( `/myUrl`, function( data ) {
 if(data){
   internalContent = $($(data).find('.post-conteudo')[0]).html();
   treatedContent = applyChanges(internalContent);
                
   $($(data).find('.post-conteudo')[0]).html(treatedContent)

   localStorage.setItem(`data-post-${idPostCitado}`, data);
                
 }
});

When debugging I see that internalContent is equal to SOME TEXT I WANT TO CHANGE so I assume I’m correctly referencing the internal element. But when I try to change it, it does,’t change and data remains as before.

Click event for dynamic id from dynamic elements not working

My footer elements are loading with dynamic id’s. I used as follows

(document).ready(function () {
 $("[id^='footer']").click(function (ev) {
     ev.preventDefault();
     if (window && window.siteConsent && window.siteConsent.manageConsent) {
         window.siteConsent.manageConsent();
     }
 });
});
<a href="level2Link.NavLink" class="f-link managecookieShow" id="footer-nav-ManageCookies one1" aria-label="level2Link_AriaLabel">
    One
</a>
<br/>
<a href="level2Link.NavLink" class="f-link managecookieShow" id="footer-nav-ManageCookies two2" aria-label="level2Link_AriaLabel">
    two
</a>

Actually it is not working. When i am using ^ this symbol is for getting contains of the id name. But it did not helped me.

Loop mode warning: The number of slides is not enough for loop mode

I am using Swiper.js in an Angular project to create a slider. I want the slider to loop, but I am encountering the following warning:

Swiper Loop Warning: The number of slides is not enough for loop mode, it will be disabled and not function properly. You need to add more slides (or make duplicates) or lower the values of slidesPerView and slidesPerGroup parameters.

My slidesPerView and slidesPerGroup parameters are set to 1, and I have a total of 4 slides. Even when I duplicate the slides (doubling the number of images), this warning persists, and the loop mode does not work.

Here is my component template:

<swiper-container
  class="slider-container"
  loop="true"
  navigation="true"
  slides-per-view="1"
  slides-per-group="1"
  [pagination]="{ clickable: true }">
  @for (projectImagePath of projectImagesPath; track projectImagePath) {
    <swiper-slide class="slider">
      <img [src]="projectImagePath" alt="">
    </swiper-slide>
  }
</swiper-container>

What I have tried:

  • Verified that slidesPerView and slidesPerGroup are both set to 1.
  • Increased the total number of slides by duplicating the images in the array.
  • Checked the Swiper.js documentation for loop mode requirements.

Despite these efforts, the loop functionality is not working, and the warning still appears.

Questions:

  1. Why is the loop mode not working even though I have enough slides and meet the documented requirements?
  2. Is there something specific about using Swiper in Angular that could cause this issue?

Here is a Stackblitz Demo

Overlay appears in fullscreen mode in Safari when video is paused

When a video in Safari is played in fullscreen mode and the user pauses it, an overlay (such as a play button or other controls) appears. This affects the user experience, as we want to avoid showing the overlay during fullscreen viewing after the video is paused.

Expected Behavior:

The overlay should not appear after the video is paused in fullscreen mode.
Steps to Reproduce:

Open a webpage https://slides-dev.pitchavatar.com/rtxuf in Safari.
Start playing the video.
Enter fullscreen mode.
Pause the video.
The overlay appears after the video is paused.
Screenshot:
enter image description here

We attempted to hide the overlay using the following JavaScript code:

const videoElement = document.querySelector('video');
const overlayElement = document.querySelector('.overlay');

videoElement.addEventListener('pause', () => {
  if (document.fullscreenElement || document.webkitFullscreenElement) {
    overlayElement.style.display = 'none'; // Hide overlay in fullscreen mode
  }
});

videoElement.addEventListener('play', () => {
  overlayElement.style.display = 'none'; // Hide overlay during playback
});

document.addEventListener('fullscreenchange', () => {
  if (!document.fullscreenElement) {
    overlayElement.style.display = 'block'; // Show overlay after exiting fullscreen mode
  }
});

And trying this methods Cannot disable/override context menu Safari fullscreen mode

Websocket onerror event gives no information

I am developing a client and server application where a websocket will be used to maintain communications. I create a websocket:

function DebugMsg(msg) {
    var msgdump = document.getElementById("msgdump");
    if (msgdump == null || typeof msgdump === "undefined") {
        return;
    }
    var strContent;    
    if (typeof msg == "string" && msg.length > 0) {
        strContent = msg;
    }
    if (typeof msg == "object" && typeof msg.message == "string") {
        strContent = msg.message;
    }
    if (typeof strContent == "string" && strContent.length > 0) {
        strContent = (new Date()).toUTCString() + ", " + strContent + "..."; 
        msgdump.innerHTML = strContent + "rn" + msgdump.innerHTML;
    }
}
function InstallServiceTimer(intInterval) {    
    if (intServiceInterval != intInterval) {
        tmrService = setInterval(ServiceRequests, intInterval);
        if (tmrService != null && typeof tmrService == "object") {       
            intServiceInterval = intInterval;
        }
    }
    if (!(tmrService == null || typeof tmrService === "undefined")) {
        DebugMsg("tmrService set-up, interval: " + intInterval + "ms");
    }
}
//Function called when service request timer expires, no arguments
function ServiceRequests() { 
    if (!(typeof webSocket == "object"
       && typeof webSocket.readyState == "number" 
              && webSocket.readyState == 1)) {
        return;
    }
    objServiceInfo[cstrServiceInfoTagRequests]++;
    var intServiceReqRespDiff = objServiceInfo[cstrServiceInfoTagRequests] 
                                - objServiceInfo[cstrServiceInfoTagResponses];
    if (intServiceReqRespDiff > cintServiceNoResponses
        && intServiceInterval != cintServiceRequestAltInterval) {
    //Stop the existing timer
        clearInterval(tmrService);
    //Reset request and response counters
        objServiceInfo[cstrServiceInfoTagRequests] = 
        objServiceInfo[cstrServiceInfoTagResponses] = 0;
    //Create a new timer with the slower interval
        InstallServiceTimer(cintServiceRequestAltInterval);
        return;
    }
    DebugMsg("Sending: "" + cstrSendMsg + "", to: " + cstrServerSocketIP);
    webSocket.send(cstrSendMsg);
}
function CreateWebSocket() {
    try {
    //Set-up timer to monitor webSocket object
        if (typeof tmrWebSocketMonitor == "undefined") {
            tmrWebSocketMonitor = setInterval(function() {
                if (webSocket == null ) {
    //Do nothing webSocket hasn't been created yet
                    return;
                }
                if (!(typeof webSocket == "object"
                   && typeof webSocket.readyState == "number" 
                          && webSocket.readyState == 1)) {
                    webSocket.close();
                }
            }, 5000);
        }
        webSocket = new WebSocket(cstrServerSocketIP);    
        webSocket.onclose = (event) => {
            var strReason = "";    
            if (typeof event == "object") {
                if (typeof event.code == "number") {
                    strReason += "code[" + event.code + "]";
                    var strError = cobjWebSocketErrors[event.code];
                    if (typeof strError == "string") {
                        strReason += ":" + strError;
                    }
                }
                if (typeof event.reason == "string" && event.reason.length > 0) {
                    if (strReason.length > 0) {
                        strReason += ", ";    
                    }
                    strReason += "reason:"" + event.reason + """;
                }
            }
            DebugMsg("webSocket.onclose " + strReason);    
        };    
        webSocket.onerror = (event) => {
            DebugMsg("webSocket.onerror" 
                + ((typeof event == "object"
                && typeof event.data == "string") ? ":" + event.data : ""));
        };
        webSocket.onmessage = (event) => { 
            DebugMsg("webSocket.onmessage"
                + ((typeof event == "object"
                    && typeof event.data == "string") ? ":" + event.data : ""));
        };
        webSocket.onopen = () => {
            DebugMsg("webSocket.onopen");
        };
        //Set-up timer to send requests for data updates
        InstallServiceTimer(cintServiceRequestInterval);
    } catch (e) {
        DebugMsg(e);
    }
}

I’m using Chrome as the browser and the Developer Tools within Chrome to help debug. I can see when the onerror event occurs and there is nothing useful in the passed event that I can see that suggests what the error is, no code, no message. Can anyone shed any light on how I can track what the cause of this is?

Invalid SuiteQL request body parameter q

I am new to NetSuite and its API and running into a a bit of an odd one.
When I use Postman to extract data from NetSuite api with suiteQL I am able to successfully establish the connection and return results (200 OK)

When I try to run the same suiteQL query from by application using Java Script I get the following error:

“Invalid SuiteQL request. Provide a valid SuiteQL query in the request body parameter q.”

Here is what I have tried in the JavaScript that is yielding the error

var record_response = UrlFetchApp.fetch(fetchURL,{
   'method': 'POST',
   "Content-Type" : "application/json",
   "prefer":"transient",
   headers: {
    "Authorization" : "Bearer "+ access_token
  },
   body: {
   "q" : "SELECT email, COUNT(*) as count FROM transaction GROUP BY email"
  },
 
  'muteHTTPExceptions':true
 });

not sure where I am going wrong between the two environments.
I have also tried setting up the query as a variable with JSON.stringigy and then calling that in the body, but it also errors out.

var query = JSON.stringify({
  "q": "SELECT email, COUNT(*) as count FROM transaction GROUP BY email"
  });

var record_response = UrlFetchApp.fetch(fetchURL,{
   'method': 'POST',
   "Content-Type" : "application/json",
   "prefer":"transient",
   headers: {
    "Authorization" : "Bearer "+ access_token
  },
   body: {
   query
  },

  'muteHTTPExceptions':true
 });

Any help will be greatly appreciated

How to inspect hash name variables in Typescript when debugging in Chrome

In our Angular project want to use hash name syntax for our private fields and methods, eg:

export class MyClass {
  
  foo = 'this is public';
  #bar = 'this is private';

  constructor() {
 
  }
}

While debugging, either in Chrome DevTools or in VSCode attached to Chrome, it is not possible to inspect the private fields.

The console tells me:

Uncaught Error Error: Cannot read private member #bar from an object whose class did not declare it
    at eval (repl:1:9)

Is there a way to debug our code and inspect the private fields in VSCode or any browser DevTools?

Make a function available to the browser’s console in node

I’m building a web app using node.js. I need to declare a function in my TypeScript code that will then be available from the browser (for interop purposes).

Code Snippet

// index.ts 
// ... 
export function doThing(x: number, y: number) : void {
    // ...
}

What I’ve Tried

Initially, I just tried calling my function from the browser console. This didn’t work; I got the error Uncaught ReferenceError: doThing is not defined.

My next idea was to add the export keyword to doThing and try again, however this also didn’t work.

Question

What can I do to a function in index.ts to make it callable from the browser console?

Bootstrap selectpicker with optgroups displaying empty options

I am facing this problem with selectpicker, that is displaying empty options when .selectpicker is applied on a select containing a optgroup.

I’m using bootstrap-select/1.14.0-beta3

<div th:fragment="champ-statutCustom" id="champ-statutCustom" class="form-floating mb-3">
        <select class="selectpicker"
                id="statutCustom"
                name="statutCustom"
                aria-label="Statut Custom"
                data-live-search="true"
                data-width="100%"
                data-style=''
                data-style-base="form-select"
                data-size="5"
                th:required="${action == 'add' or action == 'edit'} ? 'true' : 'false'"
                th:disabled="${action == 'visu' or action == 'delete'} ? 'true' : 'false'">
            <optgroup th:each="statut : ${statuts}"
                      th:label="${statut.libelle}">
                <option th:each="statutCustom : ${statutsCustom}"
                        th:value="${statutCustom.id}"
                        th:if="${statutCustom.statut.id == statut.id}"
                        th:text="${statutCustom.libelle}">
                </option>
            </optgroup>
        </select>
        <div class="invalid-feedback">
            Le statut custom est obligatoire.
        </div>
    </div>

HTML Result :

$(document).ready(function() {
  $('.selectpicker').selectpicker();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div class="dropdown bootstrap-select" style="width: 100%;"><select class="selectpicker" id="statutCustom" name="statutCustom" aria-label="Statut Custom" data-live-search="true" data-width="100%" data-style="" data-style-base="form-select" data-size="5" required="required" tabindex="null">
            <optgroup label="FINI">
                
                
                <option value="4">Fini Philippe</option>
                <option value="3">Fini Xavier</option>
            </optgroup><optgroup label="ATTENTE RETOUR CLIENT">
                
                
                
                
            </optgroup><optgroup label="CLOTURE">
                
                
                
                
            </optgroup><optgroup label="EN COURS">
                <option value="1">En cours Xavier</option>
                <option value="2">En cours Philippe</option>
                
                
            </optgroup><optgroup label="PERDU">
                
                
                
                
            </optgroup>
        </select><button type="button" tabindex="-1" class="form-select dropdown-toggle show" data-bs-toggle="dropdown" role="combobox" aria-owns="bs-select-2" aria-haspopup="listbox" aria-expanded="true" title="Fini Philippe" data-id="statutCustom"><div class="filter-option"><div class="filter-option-inner"><div class="filter-option-inner-inner">Fini Philippe</div></div> </div></button><div class="dropdown-menu show" style="max-height: 241px; overflow: hidden; position: absolute; inset: 0px auto auto 0px; margin: 0px; transform: translate(0px, 40px);" data-popper-placement="bottom-start"><div class="bs-searchbox"><input type="search" class="form-control" autocomplete="off" role="combobox" aria-label="Search" aria-controls="bs-select-2" aria-autocomplete="list" aria-activedescendant="bs-select-2-1"></div><div class="inner show" role="listbox" id="bs-select-2" tabindex="-1" style="max-height: 177px; overflow: hidden auto;"><ul class="dropdown-menu inner show" role="presentation" style="margin-top: 0px; margin-bottom: 0px;"><li class="dropdown-header optgroup-1"><span class="text">FINI</span></li><li class="optgroup-1 selected active"><a role="option" class="dropdown-item opt selected active" id="bs-select-2-1" tabindex="0" aria-setsize="7" aria-posinset="1" aria-selected="true"><span class="text">Fini Philippe</span></a></li><li class="optgroup-1"><a role="option" class="dropdown-item opt" id="bs-select-2-2" tabindex="0" aria-setsize="7" aria-posinset="2"><span class="text">Fini Xavier</span></a></li><li class="dropdown-divider optgroup-1div"></li><li><a role="option" class="dropdown-item" id="bs-select-2-4" tabindex="0" aria-setsize="7" aria-posinset="3"><span class="text">
                
                
                
                
            </span></a></li><li><a role="option" class="dropdown-item" id="bs-select-2-5" tabindex="0" aria-setsize="7" aria-posinset="4"><span class="text">
                
                
                
                
            </span></a></li><li class="dropdown-divider optgroup-2div"></li><li class="dropdown-header optgroup-2"><span class="text">EN COURS</span></li><li class="optgroup-2"><a role="option" class="dropdown-item opt" id="bs-select-2-8" tabindex="0" aria-setsize="2" aria-posinset="1"><span class="text">En cours Xavier</span></a></li><li class="optgroup-2"><a role="option" class="dropdown-item opt" id="bs-select-2-9" tabindex="0" aria-setsize="7" aria-posinset="6"><span class="text">En cours Philippe</span></a></li><li class="dropdown-divider optgroup-2div"></li><li><a role="option" class="dropdown-item" id="bs-select-2-11" tabindex="0" aria-setsize="7" aria-posinset="7"><span class="text">
                
                
                
                
            </span></a></li></ul></div></div></div>



<html xmlns:th="http://www.thymeleaf.org">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
          integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css">
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/2.0.3/css/dataTables.bootstrap5.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.14.0-beta3/css/bootstrap-select.min.css"
          integrity="sha512-g2SduJKxa4Lbn3GW+Q7rNz+pKP9AWMR++Ta8fgwsZRCUsawjPvF/BxSMkGS61VsR9yinGoEgrHPGPn2mrj8+4w=="
          crossorigin="anonymous" referrerpolicy="no-referrer" />
    <link rel="stylesheet" type="text/css" th:href="@{/css/gestat.css}">
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.7.1.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
            integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
            crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.14.0-beta3/js/bootstrap-select.min.js"
            integrity="sha512-yrOmjPdp8qH8hgLfWpSFhC/+R9Cj9USL8uJxYIveJZGAiedxyIxwNw4RsLDlcjNlIRR4kkHaDHSmNHAkxFTmgg=="
            crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script type="text/javascript" src="https://cdn.datatables.net/2.0.3/js/dataTables.js"></script>
    <script type="text/javascript" src="https://cdn.datatables.net/2.0.3/js/dataTables.bootstrap5.js"></script>
    <script type="text/javascript" th:src="@{/js/date.js}"></script>
    <script type="text/javascript" th:src="@{/js/gestat.js}"></script>
    <title>GestAT</title>
</html>

Thanks in advance for your answers.

I tried to use bootstrap-select/2.0.0-beta1 but this version is not stable for the moment.

Is there a way to turn off offline caching in Firestore modular web SDK

We work on an hybrid app built with Capacitor + Angular + Firestore that targets iOS devices.

As we are building the app like a web one, we don’t use any Firebase or Firestore capacitor plugin, we rely entirely on Firebase Web Modular SDK.

Our goal is to disable offline cache in our app as it causes consistency issues for our users.

In the dedicated documentation page from Firebase, we can read :

For Android and Apple platforms, offline persistence is enabled by default. To disable persistence, set the PersistenceEnabled option to false.

For the web, offline persistence is disabled by default. To enable persistence, call the enablePersistence method. Cloud Firestore’s cache isn’t automatically cleared between sessions. Consequently, if your web app handles sensitive information, make sure to ask the user if they’re on a trusted device before enabling persistence.

The problem is that PersistenceEnabled seems to be available in the Firestore Swift API that we don’t use, and Web API seems to only provide a way to enable offline cache which is disabled by default on Web. As we use Web API in an iOS context, we can’t figure out how to disable offline cache in this case, as Web API does not seem to propose a disablePersistence equivalent method.

I can affirm that offline cache IS actually effective when we deploy our app on iOS, whereas it is not the case when we run the web app in a browser.

The only alternative we have now is to replace all calls to getDocs by getDocsFromServer, and to handle the 'unavailable' error manually. And we hadn’t yet study the case of methods that writes data in Firestore.

Rotating Text around a circle to make it look like a sphere

Trying to get my nav bar to be a series of circles where if you hover over them it displays the text that goes with them. Heres what I have so far:

document.querySelectorAll('.color-circle').forEach((circle, index) => {
  circle.addEventListener('click', () => {
    alert(`Navigate to: ${circle.querySelector('.orbit-text').innerText}`);
  });
});
.color-circle {
  position: relative;
  border-radius: 50%;
  cursor: pointer;
  transition: transform 0.3s ease;
}

.color-circle:hover {
  transform: scale(1.2);
}

.orbit {
  position: absolute;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.color-circle:hover .orbit {
  opacity: 1;
  animation: orbit 2s linear infinite;
}

.orbit-text {
  position: absolute;
  left: 50%;
  top: 50%;
  transform-origin: center;
  transform: translate(-50%, -50%) rotateY(0deg);
  color: white;
  font-size: 8px;
  font-weight: bold;
  text-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
  animation: orbit3D 4s linear infinite;
}

@keyframes orbit3D {
  from {
    transform: translate(-50%, -50%) rotateY(0deg) translateZ(15px);
  }
  to {
    transform: translate(-50%, -50%) rotateY(360deg) translateZ(15px);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.8.3/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script>

<div class="top-bar visible">
  <div class="circle-container">
    <div class="color-circle" style="background-color: rgb(227, 197, 103); width: 40px; height: 40px;">
      <div class="orbit">
        <span class="orbit-text">HOME</span>
      </div>
    </div>
    <div class="color-circle" style="background-color: rgb(200, 150, 62); width: 30px; height: 30px;">
      <div class="orbit">
        <span class="orbit-text">DEV & DESIGN</span>
      </div>
    </div>
    <div class="color-circle" style="background-color: rgb(87, 61, 28); width: 25px; height: 25px;">
      <div class="orbit">
        <span class="orbit-text">ACTING</span>
      </div>
    </div>
    <div class="color-circle" style="background-color: rgb(217, 174, 97); width: 20px; height: 20px;">
      <div class="orbit">
        <span class="orbit-text">FILMMAKING</span>
      </div>
    </div>
    <div class="color-circle" style="background-color: rgb(209, 70, 47); width: 15px; height: 15px;">
      <div class="orbit">
        <span class="orbit-text">GALLERY</span>
      </div>
    </div>
  </div>
</div>

Spacing and other formatting isn’t done but I am hitting a wall with having the text distort as if its curving when turned away and flatter when closer as if it was actually etched onto the rotating sphere.

Thanks!