Is there a simple and fun font morphing tool that enriches design and life

Freaky-fonts.com is a free, simple, and efficient tool for generating freaky fonts. It has a comprehensive collection of freaky fonts. Users only need to type, copy, or paste, and they can transform ordinary characters into eye-catching ones, which can then be sent to Facebook, Instagram, WhatsApp, and Twitter.
Moreover, there are many useful character transformation tools on freaky-fonts.com. You can randomly combine them according to your favorite font styles, customize the character mapping table, reverse the text, scramble the text, etc. Come and explore!

Hey there! I’m super stoked to tell you all about how I cooked up Freaky Fonts, this really cool website that turns your plain – Jane text into all kinds of wild and wacky font styles.
I got the idea for Freaky Fonts when I was scrolling through my social media feeds one day. I saw how everyone was trying so hard to make their posts pop. And I thought, “Why not create a tool that makes it super easy for people to add some serious flair to their online messages?”
When it came to building the site, I went with Next.js. Let me tell you, this framework was a game – changer. It made the website load lightning – fast, which is a must for a tool that people want to jump right into. For styling, I used Tailwind CSS. It’s like having a magic wand for design. With its utility – first style, I could whip up a sleek and user – friendly interface in no time. And for the backend, I chose Supabase. It handled all the user data and font info like a champ.
The whole development process was a wild ride. It took me around two weeks of non – stop coding and coffee – fueled late nights. In the beginning, I spent days sketching out the layout, brainstorming which crazy font styles to include, and getting the basic structure of the site in place. Then, came the real fun part – implementing all the technologies and writing the code to transform plain text into these awesome, freaky fonts. Testing was a bit of a headache, but I wanted to make sure the site worked like a charm on every browser and device out there.
Now, Freaky Fonts is up and running, and it’s got this huge collection of the most freaky fonts you can imagine. All you have to do is type, copy, or paste your text, and boom! Ordinary characters turn into something that’ll make your eyes pop. And the best part? You can share these fancy texts on all your favorite platforms, like Facebook, Instagram, WhatsApp, and Twitter. Plus, there are some really cool character transformation tools on the site. You can mix and match fonts randomly, customize the character mapping, reverse the text, or even scramble it. It’s like a playground for your text!
Right now, I’m knee – deep in working on a Chrome browser plugin for Freaky Fonts. I’m super excited about this because it’s going to make using our freaky fonts even more convenient. Just imagine, you’re writing an email, leaving a comment on a blog, or posting on social media, and with just a couple of clicks, you can turn your boring text into something totally awesome. So, keep an eye out for the plugin release, and keep exploring the wacky world of freaky and fancy fonts on Freaky Fonts!

Error connecting to Atlas despite whitelisting IP (and trying “allow access from anywhere”)

I’m trying to set up a connection to my Atlas cluster in a Node JS application, and I keep getting the error: “MongooseServerSelectionError: Could not connect to any servers in your MongoDB Atlas cluster. One common reason is that you’re trying to access the database from an IP that isn’t whitelisted. Make sure your current IP address is on your Atlas cluster’s IP whitelist: https://www.mongodb.com/docs/atlas/security-whitelist/”

Full version of the terminal output here

I’ve made sure my login credentials in my config file are good and that my IP is whitelisted. I tried deleting my IP from the whitelist and re-adding it. I verified my IP to make sure the right one was being entered. I tried switching the permissions to allow access from everywhere. As per this thread I tried reverting my version of mongoose back to 8.1.1 and then back again. I confirmed my connection string is good and my credentials are correct. My password doesn’t contain any non-letter characters so I don’t think it’s a credential encoding problem. I’ve disabled my firewall and restarted VS Code. I’m not sure what else to try here. Any advice?

The app doesn’t currently do anything besides create the mongoose connection and start listening, but here’s my code for what it’s worth:

server.js (npm entry point)

const mongoose = require("mongoose");
const dotenv = require("dotenv");

dotenv.config({path: "./config.env"});

const database = process.env.DATABASE.replace("<db_password>", process.env.DATABASE_PASSWORD).replace("<db_username>", process.env.DATABASE_USER);
mongoose.connect(database).then(console.log("Database connection successful"));

const app = require("./app");
const port = process.env.PORT || 4000;

app.listen(port, () => {
   console.log(`Running on port ${port}`);
});

app.js

const fs = require("fs");
const express = require("express");
const morgan = require("morgan");

const app = express();

app.use(express.json());

module.exports = app;

No logro comprender programación respecto al lenguaje C, que me recomiendan para poder iniciar? [closed]

PARA INICIAR EN LENGUAJE C

Revisa proyectos de código abierto en C para ver cómo otros programadores estructuran sus programas y resuelven problemas.

  1. Únete a comunidades
    Participa en foros y grupos de discusión como Stack Overflow, Reddit, o incluso grupos locales de programación. Esto te permitirá hacer preguntas y aprender de otros.

  2. Sé paciente y persistente
    Aprender un nuevo lenguaje de programación lleva tiempo y esfuerzo. No te desanimes si encuentras dificultades; cada error es una oportunidad para aprender.

¡Buena suerte en tu viaje para aprender C!

¿QUE SE REQUIERE PARA APRENDER EN PROGRAMACION?
Un error común es pensar que para aprender a programar desde cero necesitas saber mucho de matemáticas. La realidad es que, aunque saber matemáticas puede ser útil, no es esencial. Lo realmente importante es tener creatividad, habilidad para resolver problemas y gestionar la complejidad, y mucho trabajo.
Por ejemplo, profesionales de otras áreas, como músicos y abogados, a menudo se reciclan como programadores exitosos porque componer música o escribir contratos implica procesos similares a la programación.
Sea cual sea tu ocupación actual, puedes aprender programación desde cero con el esfuerzo adecuado.
Pasos para aprender a programar desde cero
aprender a programar desde cero
El cómo aprender a programar y cómo ser un programador desde cero no es fácil. Veamos algunos consejos que te serán de gran utilidad:

  1. Aprender lo básico

Matemáticas: No es preciso aprender cálculo diferencial, pero sí lo básico; esta es una de las cosas que aprender antes de programar. Por ejemplo, las ecuaciones cuadráticas y lineales. Con estos conocimientos podrás ver las matemáticas detrás de la mayoría de los problemas diarios.
Álgebra booleana y binario: Comprender bien el pensamiento en binario es esencial. Todo se reduce a sí o no, verdadero o falso. Cada elección que hacemos es binaria. También es recomendable que practiques la conversión de números decimales a binarios y viceversa para controlar el sistema numérico binario.
Entender cómo funcionan los ordenadores: Este es uno de los fundamentos más importantes de programación y otra de las cosas que hay que aprender antes de programar. Si no lo tienes claro, quizás tengas ideas confusas de lo que significan los términos de procesamiento, almacenamiento, etc. Un ordenador puede hacer aritmética, procesar lógica booleana, tomar decisiones binarias y almacenar datos. Tener en mente estos principios te ayudará a convertirte en un buen programador.
Además de estas nociones, hay otras cosas básicas de programación que debes considerar si te planteas qué aprender antes de programar.

  1. Elige un lenguaje de programación y domínalo.

Uno de los primeros pasos para aprender programación desde cero es elegir el lenguaje que vas a aprender.
Te recomendamos comenzar con Python, ya que es uno de los más sencillos de aprender. Sin embargo, puedes elegir el lenguaje que te interese, para lo que también es interesante valorar el proyecto que te gustaría desarrollar en el futuro.
Si, por ejemplo, lo que te gustaría es desarrollar una app móvil, tal vez sea mejor opción empezar con Java o Kotlin si quieres enfocarte en Android, o Swift si prefieres crear aplicaciones para iOS. Por otro lado, si lo que deseas es desarrollar un sitio web, una buena opción para comenzar es aprender a dominar JavaScript.
El error más típico ante el interrogante de qué aprender antes de programar es aprender varios lenguajes a la vez. Si haces esto, lo único que lograrás es sabotear tu curva de aprendizaje. Es recomendable solo aprender un lenguaje a la vez porque después de dominarlo, aprender los demás te resultará más sencillo, ya que poseerás las bases y conceptos fundamentales que están presentes en la mayoría de ellos.

  1. Ten paciencia.

Se puede decir que el requisito principal para tener éxito como programador es la paciencia, ya que te prepara para las numerosas decepciones que te encontrarás a lo largo de todo el aprendizaje.
Nota: La paciencia te ayudará a solucionar problemas y también mejorará tu comprensión de los ordenadores. Recuerda que los conceptos relacionados con estas máquinas son complejos y requieren resiliencia, paciencia y trabajo duro para entenderlos.
En muchas ocasiones, los principiantes tienen expectativas alejadas de la realidad y, cuando comienzan su viaje en la programación, se dan por vencidos ante los primeros impedimentos. Para combatir estos escenarios, debes armarte de paciencia y pensar siempre en el objetivo final.

  1. Fija un objetivo desde el principio.

Desde que empiezas a aprender programación tienes que preguntarte qué quieres lograr. La respuesta será tu objetivo a conseguir y lo que te motivará a seguir aprendiendo día tras día. Puede parecer algo fácil de conseguir, pero requiere mucha constancia, trabajo y paciencia para conseguir el objetivo que te has propuesto. Una vez que lo hayas conseguido, automáticamente te fijarás otro objetivo y, sin darte cuenta, estarás dentro del maravilloso mundo de la programación.

  1. Aprender con cursos online es tu mejor opción.

Busca escuelas de programación que compartan sus conocimientos a través de cursos en línea, que aúnen todo el contenido necesario para que puedas estudiar un determinado lenguaje de la forma más eficaz posible. KeepCoding puede ser tu gran aliado en este camino, con nuestra variedad de bootcamps podrás aprender tecnologías específicas en tan solo unos meses. Recuerda que estos programas intensivos son ideales para quienes no tienen conocimientos previos y desean una inmersión total en la programación.

  1. Practica constantemente.

La programación mejora con la práctica regular. Trabaja en pequeños proyectos, resuelve problemas de codificación y construye tu propio portafolio. Esto es esencial para entender y aplicar lo que aprendes.

  1. Únete a comunidades de programadores.

Aprender a programar no tiene que ser un proceso solitario. Participa en comunidades en línea como Stack Overflow, Reddit, y Discord. Estas plataformas ofrecen soporte, permiten compartir experiencias y proporcionan una invaluable retroalimentación.

Rotate Array working in VS Code but not Leet Code

Can someone tell me why this is working in VS Code and not Leetcode?


const nums1 = [1,2,3,4,5,6,7]
const k1 = 3
`var rotate = function(nums, k) {
    let secondSet = nums.slice(nums.length - k)
    let firstSet = nums.slice(0, nums.length - k)
    nums = [...secondSet, ...firstSet]
    return
};`

in VS Code it returns [5,6,7,1,2,3,4]
In Leet Code it returns [1,2,3,4,5,6,7]

Parse server not connecting

I get the following error
WARNING, Unable to connect to ‘http://localhost:1337/parse’. Cloud code and push notifications may be unavailable!

I first tried creating a test-run app

const express = require("express");
const { ParseServer } = require("parse-server");

const app = express();

// Configure Parse Server
const parseServer = new ParseServer({
  databaseURI: "mongodb://localhost:27017/myDB", // MongoDB connection string
  cloud: "./cloud/main.js", // Path to your Cloud Code file
  appId: "myAppId", // Your App ID
  masterKey: "myMasterKey", // Your Master Key (keep it secret)
  serverURL: "http://localhost:1337/parse", // Server URL
});

// Mount Parse Server at /parse endpoint
app.use("/parse", parseServer.app);

// Start the Express server
const PORT = 1337;
app.listen(PORT, () => {
  console.log(`Parse Server running on http://localhost:${PORT}/parse`);
});

then I just ran it in bash

parse-server --appId ABC --masterKey ABC --databaseURI mongodb://localhost:27017/myDB

I don’t know why I get the error, and some time ago when I ran the command in console it worked perfectly

How do I check what “this” refers to using Inspect Element?

Using Firefox 135.0.1.

I’ve been inspect elementing a website and found this bit of HTML:

<a href="#" onclick="game.views.HeadsUpDisplayFactoryView.pickRoom(this); return false;" data-room="mixing_room" class="ActionButton tiny"><span>Enter</span></a>

It’s the code for a button that moves you between “rooms” on a website-based game. However, I can’t tell what exactly the “this” keyword is referring to in this example, i.e. which JavaScript code is exactly being run upon clicking the Enter button.

I’ve tried running this bit of code using the developer console, going from the data_room variable:

game.views.HeadsUpDisplayFactoryView.pickRoom('mixing_room');

The game responded with an error modal that the room is invalid.

iPhone / Chrome “Take a photo” Bug?

I cant seem to figure out why chrome on both my iphones doesnt trigger the onchange action. Safari is able to work just fine. This used to work ( Haven’t tested it in weeks until now ).

This is a nodeJs app and I am trying to upload a photo that is taken from the user.

Iphone when cilcking select photo -> UI comes up from apple to choose photo from gallery or take photo.

When I choose a photo from gallery everything works as expected. HandleFileUpload runs no issue.

When I choose “Take a photo” after the photo is taken nothing happens..it doesnt look like handleFileUpload is running.

Any ideas? Let me know if any more code is needed.

// js
document.addEventListener("DOMContentLoaded", function() {
  const fileInput = document.createElement('input');
  fileInput.type = 'file';
  fileInput.id = 'fileInput';
  fileInput.style.display = 'none';
  fileInput.setAttribute('onchange', 'handleFileUpload(event)');
  fileInput.setAttribute('accept', 'image/*');

  const uploaderContainer = document.getElementById("uploader-container");
  if (uploaderContainer) {
    uploaderContainer.appendChild(fileInput);
  }

  const uploader = document.getElementById("uploader");
  if (uploader) {
    uploader.addEventListener("click", function() {
      const input = document.getElementById("fileInput");
      if (input) {
        input.click();
      }
    });
  }

  const imageDisplay = document.getElementById("image-display");
  if (imageDisplay) {
    imageDisplay.addEventListener("click", function() {
      const input = document.getElementById("fileInput");
      if (input) {
        input.click();
      }
    });
  }

  fileInput.addEventListener("change", (
    event
  ) => {
    handleFileUpload(
      event
    )
  })


});
<div id="uploader-container">
  <p id="uploader-container" class="text-left mt-30 wow fadeInUp app-btns" data-wow-delay="0.4s">
    <div class="d-flex-center " style="gap: 15px">
      <a id="uploader" class="btn btn-dark btn-circle">Select Photo</a>
      <h4 id="no-images" class="text-red" style="margin:0px;display:none">No Images Found.</h4>   
    </div>
  </p>
</div>
</div>

How can I measure if request animation frame helped to my scroll event?

I have the following code

ngAfterViewInit() {

      this.viewportElementRef.nativeElement.addEventListener('scroll', this.onScroll);
   
  }

private onScroll = (event: Event & { target: HTMLElement }): void => {
   console.log('scroll event");

attached on some div, i wonder if i use request animation frame

  private scrollTimeout: any;
 private onScroll = (event: Event & { target: HTMLElement }): void => {
    if (this.scrollTimeout) {
      cancelAnimationFrame(this.scrollTimeout);
    }
    this.scrollTimeout = requestAnimationFrame(() => {
      this.handleScroll(event.target);
    });
  };
  
  private handleScroll(target: HTMLElement): void {
     console.log('scroll event");
  }

how can i check if now my scroller event is better ? Because i am npt able to see any difference when i scroll throguh big data or to see some difference dependent on the console logs in the scroll method

I tried using console logs to see soem differences but now able to do that

How to keep a large number of rigidBodies in sync with Rapier JS?

I use the Javascript version of Rapier 2D. My project works well, except for the performance. I investigated the slowness with a profiler, and it shows that the repeated calls to rigidBody.translation() and rigidBody.linvel() for many objects in each frame adds up, and takes a lot of time.

How to keep non sleeping objects in sync with the “outside world”? Is it possible to query for non-sleeping rigidbodies in each frame, and get their translations in batch?

Static frontend security using fetch

when working with a simple html,css,js all in a single file and then creating a backend(hosted publicly) that will process information. How can the front end be as secure as possible when handling calls like.

fetch(`${BACKEND_URL}/function`, {
    method: 'POST',
    headers: { 
        'Content-Type': 'application/json',
        'x-api-key': API_KEY

    },
    body: JSON.stringify({
        name: "John Doe",
        email: "[email protected]",
        message: "I need something..."
    }),
}) 

is it even possible to hide api keys without using react? I have heard of the react implementation but wanted to know if there was a solution for a static file build.

Firebase Initialization Issues: ‘firebase.database()’ Not Defined and Errors with SDK Loading

I’m trying to implement Firebase in my project, but I’m encountering issues with the Firebase libraries not being loaded properly. Specifically, I’m getting errors related to Firebase initialization and database interaction in my JavaScript code.

Here are the details of the problem:

Firebase Initialization: I have included the necessary Firebase SDK scripts in my HTML file (firebase-app.js and firebase-database.js), but when I try to interact with Firebase in my JavaScript, I get errors saying that the Firebase functions (like firebase.database()) are not defined or not available.

Error Messages:

Uncaught SyntaxError: “Unexpected token ‘export'” and “Cannot use import statement outside a module” in the Firebase library files (firebase-app.js and firebase-database.js).
Uncaught ReferenceError: “db is not defined” when I try to use firebase.database().
Code Setup: I’ve ensured that the Firebase SDK scripts are loaded before my custom JavaScript file, but still encountering issues. I’ve also checked the console for any other errors and confirmed that there are no network issues (404 errors or failed resource loading).

Objective: I need to ensure that the Firebase SDK is properly initialized and that I can access Firebase services like the real-time database in my JavaScript.

Steps I have already taken:

I have checked the order of script loading and ensured that the Firebase SDK is loaded before my custom script.
I’ve tried using both the direct script tags and the ES module approach with import statements, but I keep getting the same errors.

What I tried:

Including Firebase SDK Scripts: I added the necessary Firebase SDK scripts (firebase-app.js and firebase-database.js) in my HTML file to ensure Firebase is loaded before my custom JavaScript code.
Using firebase.database(): After initializing Firebase with firebase.initializeApp(firebaseConfig), I attempted to interact with Firebase’s real-time database using firebase.database().
Script Loading Order: I made sure that the Firebase SDK scripts are loaded before my custom script that interacts with Firebase.
Trying Both Approaches: I tried both using the Firebase CDN without import statements and the ES module approach with import statements, but the errors persisted.
What I expected:

Successful Firebase Initialization: After initializing Firebase with the provided config, I expected to be able to access Firebase services like the real-time database using firebase.database().
No Errors: I expected no errors related to firebase.database() or the firebase object being undefined. I also expected no syntax or import errors from the Firebase SDK scripts.
Correct Interaction with Firebase: Once Firebase was initialized correctly, I expected to be able to use Firebase’s real-time database functionality, such as creating a new room and saving data.

Code does not execute code after event listener

The callback function is executed everytime the submit button is clicked and the code after the addEvent listener is never run.

<form id="myForm">
  <input type="text" placeholder="Your name">
  <input type="submit" value="Submit">
</form>

<script>
  // Get a reference to the form element
  var form = document.getElementById("myForm");

  // Function to handle the submit event
  function handleSubmit(event) {
    event.preventDefault();
    console.log("Form submitted!");
    form.removeEventListener("submit", handleSubmit);
  }

  // Add a submit event listener to the form
  form.addEventListener("submit", handleSubmit);
  console.log("End of Script")
</script>

How to capture the row index to use in JS function

<body>
    <form:form modelAttribute="formTT1" onsubmit="javascript:return submitForm();"> 
    <div id="leftcontent">
        <div id="centercontent">            
            <div id="FieldsetsContainer">
                <fieldset id="filmCreditDetails">
                    <legend><span class="SectionHeading" id="filmCreditSectionHeading"><spring:message code="24201"/></span></legend>
                    <%
                        Object[] allFilmsArray = formTT1.getfilmCredit().getfilmList().toArray();
                        int numOfDetails = allFilmsArray.length-1;
                        for (int i=0; i<=numOfDetails; i++) 
                                {
                                %>  
                                <fieldset id="FilmDetails<%out.println(i);%>">
                                    <legend><span class="Level2FieldSetHeading"><spring:message code="24202" arguments="<%= new Object[] { i+1 } %>"/></span></legend>
                                    
                                    <div class="Ct1FormField">
                                        <label for='<%= "filmCredit.filmList[" + i + "].filmCertNumber" %>'><spring:message code="24203"/></label>
                                        <span class="notCurrency"><ss:input path='<%= "filmCredit.filmList[" + i + "].filmCertNumber" %>' maxlength="20" forcedisable="<%=!bAmend%>"/></span>
                                    </div>

                                    <div class="Ct1FormField">
                                        <label for='<%= "filmCredit.filmList[" + i + "].qExpense" %>'><spring:message code="fct29"/></label>
                                        <span onKeyUp="checkInput(this);" class="currency"><ss:input path='<%= "filmCredit.filmList[" + i + "].qExpense" %>' forcedisable="<%=!bAmend%>" /></span>
                                    </div>
                                </fieldset>                     
                        <%}%>
                </fieldset>
            </div>
        </div>
    </div>
    </form:form>
</body> 

Hi All,
This code snippet creates a number of HTML forms based on the length of the allFilmsArray. I am trying to retrieve the value of qExpense while the user enters an amount in the input field.
Currently, I have hardcoded the retrieval to get the value from the first form, using the following code:

document.getElementById('filmCredit.filmList0.qExpense');

The validation works fine and I am getting the value of qExpense from the first form

How can I modify this code to get the values from subsequent forms? Looking to use the index value i while the user input in the particular form

For example:
document.getElementById('filmCredit.filmList1.qExpense'); This would return the value from form 2. I am looking to get this value dynamically without hardcoding.

      <script type="text/javascript">
    function checkInput(val) {
        var myTextBox  = document.getElementById('filmCredit.filmList0.qExpense');
        var value = myTextBox.value;
        if (!value || isNaN(value) || parseInt(value, 10) < 20000000) {
            myTextBox.style.color = 'green';
            document.getElementById('ifYes').style.display = 'block';
        } else {
            myTextBox.style.color  = 'red';
            document.getElementById('ifYes').style.display = 'none';
        }
    }

    }
</script>

Appreciate your help

Slider does not have smooth transition on the first page load

I have a webpage that has 2 sliders that should work exactly the same, the only difference is different images. However, while .prototype-next-image button on my second slider works smoothly, .carusele-next-image button on my first slider does not work smoothly. If I reload the page, then it starts working smoothly. I am wondering why it does not have the smooth transition on the first load. Here is my HTML:

<!doctype html>
<html lang="en-US">
  <body>
    <main>
        <section class="carusele-images-container">
          <section class="carusele-images">
            <img class="carusele-image" src="../images/hi-fi-1.webp" alt="eventful hi-fi image-1" loading="lazy">
            <img class="carusele-image" src="../images/hi-fi-2.webp" alt="eventful hi-fi image-2" loading="lazy">
            <img class="carusele-image" src="../images/hi-fi-3.webp" alt="eventful hi-fi image-3" loading="lazy">
            <img class="carusele-image" src="../images/hi-fi-4.webp" alt="eventful hi-fi image-4" loading="lazy">
            <img class="carusele-image" src="../images/hi-fi-5.webp" alt="eventful hi-fi image-5" loading="lazy">
            <img class="carusele-image" src="../images/hi-fi-6.webp" alt="eventful hi-fi image-6" loading="lazy">
            <img class="carusele-image" src="../images/hi-fi-7.webp" alt="eventful hi-fi image-7" loading="lazy">
            <img class="carusele-image" src="../images/hi-fi-8.webp" alt="eventful hi-fi image-8" loading="lazy">
            <img class="carusele-image" src="../images/hi-fi-9.webp" alt="eventful hi-fi image-9" loading="lazy">
            <img class="carusele-image" src="../images/hi-fi-10.webp" alt="eventful hi-fi image-10" loading="lazy">
          </section>
          <button type="button" class="carusele-prev-image">«</button>
          <button type="button" class="carusele-next-image">»</button>
        </section>
        <section class="final-prototype-container">
          <section class="final-prototype-photos">
            <img src="../images/final-prototype-1.webp" alt="Final prototype" class="final-prototype-photo" loading="lazy">
            <img src="../images/final-prototype-2.webp" alt="Final prototype" class="final-prototype-photo" loading="lazy">
            <img src="../images/final-prototype-3.webp" alt="Final prototype" class="final-prototype-photo" loading="lazy">
            <img src="../images/final-prototype-4.webp" alt="Final prototype" class="final-prototype-photo" loading="lazy">
            <img src="../images/final-prototype-5.webp" alt="Final prototype" class="final-prototype-photo" loading="lazy">
            <img src="../images/final-prototype-6.webp" alt="Final prototype" class="final-prototype-photo" loading="lazy">
            <img src="../images/final-prototype-7.webp" alt="Final prototype" class="final-prototype-photo" loading="lazy">
            <img src="../images/final-prototype-8.webp" alt="Final prototype" class="final-prototype-photo" loading="lazy">
            <img src="../images/final-prototype-9.webp" alt="Final prototype" class="final-prototype-photo" loading="lazy">
            <img src="../images/final-prototype-10.webp" alt="Final prototype" class="final-prototype-photo" loading="lazy">
            </section>
              <button type="button" class="prototype-prev-image">«</button>
              <button type="button" class="prototype-next-image">»</button>
            </section>
          </div>  
        </section>
    </main>
  </body>
</html>

Here is my JavaScript:

const ANIMATION_TIME = 600;
const INSERT_PREV_IMAGE_DELAY = 5;

const caruseleImagesContainer = document.querySelector('.carusele-images');
const caruseleImages = Array.from(document.querySelectorAll('.carusele-image'))
const prevImgBtn = document.querySelector('.carusele-prev-image');
const nextImgBtn = document.querySelector('.carusele-next-image');

const gapSizeBetweenImagesPX = getComputedStyle(caruseleImagesContainer).getPropertyValue('gap');
const gapSizeBetweenImagesNum = Number(gapSizeBetweenImagesPX.slice(0, gapSizeBetweenImagesPX.length - 2));
const imagesCount = caruseleImages.length;
const singleImgWidth = caruseleImages[0].width;
let currentImgIdx = 0;
let prevImgIdx = 0;

prevImgBtn.addEventListener("click", () => {
  prevImgBtn.disabled = true;
  prevImgIdx = currentImgIdx;
  currentImgIdx = (currentImgIdx - 1 + imagesCount) % imagesCount;
  caruseleImagesContainer.style.transform = `translateX(-${singleImgWidth}px)`;
  caruseleImagesContainer.insertBefore(caruseleImages[currentImgIdx], caruseleImagesContainer.firstChild);

  
  setTimeout(() => {
    caruseleImagesContainer.style.transform = "";
    caruseleImagesContainer.classList.add("sliding-transition");
  }, INSERT_PREV_IMAGE_DELAY);

  setTimeout(() => {
    caruseleImagesContainer.classList.remove("sliding-transition");
    prevImgBtn.disabled = false;
  }, ANIMATION_TIME - INSERT_PREV_IMAGE_DELAY);
});

nextImgBtn.addEventListener("click", () => {
  nextImgBtn.disabled = true;
  caruseleImagesContainer.classList.add("sliding-transition");
  prevImgIdx = currentImgIdx;
  currentImgIdx = (currentImgIdx + 1) % imagesCount;
  caruseleImagesContainer.style.transform = `translateX(-${singleImgWidth + gapSizeBetweenImagesNum}px)`;

  setTimeout(() => {
    caruseleImagesContainer.appendChild(caruseleImages[prevImgIdx]);
    caruseleImagesContainer.classList.remove("sliding-transition");
    caruseleImagesContainer.style.transform = "";
    nextImgBtn.disabled = false;
  }, ANIMATION_TIME);
});

const finalPrototypeImagesContainer = document.querySelector('.final-prototype-photos');
const finalPrototypeImages = Array.from(document.querySelectorAll('.final-prototype-photo'));
const prevImageButton = document.querySelector('.prototype-prev-image');
const nextImageButton = document.querySelector('.prototype-next-image');

const gapSizeBetweenImagesPixel = getComputedStyle(finalPrototypeImagesContainer).getPropertyValue('gap');
const gapSizeBetweenImagesNumber = Number(gapSizeBetweenImagesPixel.slice(0, gapSizeBetweenImagesPixel.length - 2));
const imageCount = finalPrototypeImages.length;
const singleImageWidth = finalPrototypeImages[0].width;
let currentImgIndex = 0;
let prevImageIndex = 0;

prevImageButton.addEventListener("click", () => {
  prevImageButton.disabled = true;
  prevImageIndex = currentImgIndex;
  currentImgIndex = (currentImgIndex - 1 + imageCount) % imageCount;
  finalPrototypeImagesContainer.style.transform = `translateX(-${singleImageWidth}px)`;
  finalPrototypeImagesContainer.insertBefore(finalPrototypeImages[currentImgIndex], finalPrototypeImagesContainer.firstChild);

  setTimeout(() => {
    finalPrototypeImagesContainer.style.transform = "";
    finalPrototypeImagesContainer.classList.add("sliding-transition");
  }, INSERT_PREV_IMAGE_DELAY);

  setTimeout(() => {
    finalPrototypeImagesContainer.classList.remove("sliding-transition");
    prevImageButton.disabled = false;
  }, ANIMATION_TIME - INSERT_PREV_IMAGE_DELAY);
});

nextImageButton.addEventListener("click", () => {
  nextImageButton.disabled = true;
  finalPrototypeImagesContainer.classList.add("sliding-transition");
  prevImageIndex = currentImgIndex;
  currentImgIndex = (currentImgIndex + 1) % imageCount;
  finalPrototypeImagesContainer.style.transform = `translateX(-${singleImageWidth + gapSizeBetweenImagesNumber}px)`;

  setTimeout(() => {
    finalPrototypeImagesContainer.appendChild(finalPrototypeImages[prevImageIndex]);
    finalPrototypeImagesContainer.classList.remove("sliding-transition");
    finalPrototypeImagesContainer.style.transform = "";
    nextImageButton.disabled = false;
  }, ANIMATION_TIME);
});