Character Replacement Loop JavaScript

I am sharing a piece of code.

const str = "This is very long road"
const newChar = {
  s: "S",
  o: "O"
};

let newStr = "";

for (const char of str){
  newStr += newChar[char] || char;
}
console.log(newStr);

Can someone please explain me what is this code means?

newChar[char] || char

Can’t we just write newChar?

How can I display an array mixed with template literals without using foreach method

suggestedItems.forEach(function(elem) {
  elem.addEventListener("click", function(event) {
  currentItem = this.parentElement.innerText;
    if (event.target.checked) {
      if (!savedItem.includes(currentItem)) {
        savedItem.push(currentItem);
      }
    } else {
        let removeIndex = savedItem.indexOf(currentItem);
        savedItem.splice(removeIndex, 1);
    }
    console.log(savedItem); /*This gives correct output*/
    savedItem.forEach((item) => {
      allSavedItems = allSavedItems.concat(`<div><p>${item}</p></div>`);
      /*Wrong output*/
    });
    document.querySelector(".cip-body").innerHTML = allSavedItems;
  });
});

I have a list of input items that this code loops through and does some comparisons and checking to decide where the current item will be added to our removed from the array named “savedItem”.

Towards the end there is this code,

console.log(savedItem); 

And it displays the right output.

However, I want each array item to be wrapped in a tag as follows,

<div><p>array content</p></div>
<div><p>array content</p></div>
<div><p>array content</p></div>

I tried using the following but it prints additional values than there is in the array “savedItem”.

savedItem.forEach((item) => {
  allSavedItems = allSavedItems.concat(`<div><p>${item}</p></div>`);
});

I understand why it happens but I don’t know any other way to display array data in one go without using loop.

Looking for something like array.toString() but with ability to mix html tags.

Export next.js site statically

I have a simple restaurant website that uses next.js and sanity.io client to fetch the data. I want to export it statically (to html+css+js files) so that I won’t need to use a container (or Vercel) to host it.
However, when I try to export it I’m getting the error “Server Actions are not supported with static export”. Every single file in my project has the “use client”; directive on top.

This is my next.config.ts file:

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  output: "export",
  images: {
    unoptimized: true,
    remotePatterns: [
      {
        protocol: "https",
        hostname: "cdn.sanity.io",
      },
      {
        protocol: "http",
        hostname: "cdn.sanity.io",
      },
    ],
  },
  trailingSlash: true,
};

export default nextConfig;

I’m not sure how to proceed, as I don’t want to use any server actions but even the error output doesn’t say where are they so I can remove them.

I want to pass a variable from one script to another in the same App Script project using Properties Service

The variable needs to be set programmatically and I have tried this, which appears to work in the donor script but not from other scripts.
I am running the function setlastrow in the first program and getlastrow in subsequent programs. To reference the variable, I have to just call the function ‘getlastrow’ ??
The overall object is to get the number of rows in a sheet and to pass that to other scripts which run immediately following, but I need to ensure that the following scripts use the same number of rows whilst other updates may occur.

//Two functions to pass static variable LASTROW to f Create Accounts and f AutoRegWaitList to avoid changes to the LASTROW variable whist the 3 are running 
  function setlastrow () {
    LASTROW = wsFormresponses.getLastRow();
    PropertiesService.getScriptProperties().setProperty("lastrow", LASTROW);
}
  
  function getlastrow () {
    var LASTROW = PropertiesService.getScriptProperties().getProperty("lastrow");

}
  Logger.log(getlastrow)

////////////////////////////////////////////

and called like this?
for (var i=50;i<=getlastrow;i++) {

Prisma ORM can’t migrate seperated schema files

currently im dealing with prisma with nodejs .
I’m using prisma version v6.7, and as the author stated this version already supported the mutli schema function.
I followed all the instruction, created a folder under prisma schema then put everything inside it and migrate. But after migrated it always showed Already in sync, no schema change or pending migration was found. and nothing is being migrated why ?

schema.prisma

generator client {
  provider        = "prisma-client-js"
  output          = "../generated/client" 
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

Folder structure:
Folder structure

I wanted to seperated all the schema file for differents model and able to migrate it all at once without all the models in one schema.prisma.

My scripts:

 "scripts": {
    "dev": "ts-node-dev --respawn --transpile-only src/app.ts",
    "build": "tsc",
    "start": "node dist/app.js",
    "migrate:prisma": "npx prisma migrate dev --schema=prisma/schema/schema.prisma",
    "generate:prisma": "npx prisma generate --schema=prisma/schema/schema.prisma"
  },

https://github.com/prisma/prisma/releases

Scroll animations – Packs or existing libraries to reproduce several of them

I recently found this and I would like to start adding and/or testing with several of these animations on my own websites:

The Scroll Animation Examples You’ll Be Using in Your Next Web Design

My question and/or request is:

  • Does a library or a pack of libraries (probably .JS) exist(s) to reproduce all of the scroll animations listed in the link above please?
  • If said library/libraries exit(s), may you provide the name(s) and/ or link(s) so I can check these out and start exploring with them?

Here is a website example I found using some of them that I found interesting and quite interactive and piqued my interest in the scroll animations:

Donkey Kong™ Bananza – Nintendo Switch 2

Thank you for your time and help, it is greatly appreciated!

How can I combine Cloudinary colour extraction and AWS Rekognition auto-tagging in my Payload CMS media uploads?

I’m using Payload CMS (v3.35.1) with a Next.js frontend and PostgreSQL on Render. I’m trying to fully integrate Cloudinary for media uploads using @jhb.software/payload-cloudinary-plugin.

I’ve gone through multiple setups and plugin combinations The uploads go to Cloudinary and show up there, but the admin panel crashes with this error:

TypeError: Cannot read properties of null (reading 'replace')
    at adminThumbnail (.../extendUploadCollectionConfig.js:85:46)

This happens even when:

Uploads succeed and Cloudinary URLs are present on the media documents
I’ve reverted to a minimal boilerplate Payload setup with only one media collection
I’ve pinned all Payload packages to 3.35.1 for compatibility
I’ve tried the official Cloudinary plugin as well as a custom afterChange hook setup
I’ve removed all custom fields, except for one or two like alt or dominantColours
I’ve tried using staticDir, staticURL, and a rewrite rule in next.config.mjs like:

rewrites: async () => [
  { source: '/media/:path*', destination: '/__tmp_media__/:path*' }
]

Current plugin config (in payload.config.ts):

payloadCloudinaryPlugin({
  uploadCollections: ['media'],
  credentials: {
    apiKey: process.env.CLOUDINARY_API_KEY!,
    apiSecret: process.env.CLOUDINARY_API_SECRET!,
  },
  cloudinary: {
    cloudName: process.env.CLOUDINARY_CLOUD_NAME!,
  },
  // staticURL: '/media', // tried this too (but typescript complains)
})

media collection is configured with:

export const Media: CollectionConfig = {
  slug: 'media',
  access: { read: () => true },
  upload: {
    staticDir: '__tmp_media__',
    mimeTypes: ['image/*'],
    imageSizes: [
      { name: 'thumbnail', width: 400, height: 400 },
    ],
  },
  fields: [{ name: 'alt', type: 'text' }],
}

What I’m trying to do:

Let users upload images through admin
Store those in Cloudinary
Auto-tag and colour-process media post-upload

Has anyone encountered this replace error with the Cloudinary plugin?
Has anyone manage to do a setup like this?

the payload-cloudinary-plugin’s uploadOptions only accepts certain options (it errors on categorization / auto_tagging), so I can’t configure both colour + auto-tags at upload time.

If I try to call req.payload.updateOne() in afterChange, I get Postgres foreign-key / null-id errors on the nested colour array.

I also end up with race conditions or hanging transactions when I try to update inside the same hook.

Trying to add-on to a Music Player I created through a tutorial and need a little advice on how to do it [closed]

Trying to add-on to a Music Player I created through a YouTube tutorial, and need a little help. The tutorial only had one song file, so I was able to get this to work using the tutorial. However, I tried to add more songs and found a way to do it. I know the way I did it below is very cumbersome, so there must be a better way to do this.

The goal is to have a simple ‘play.gif’ play button that, when you press it, plays a song and changes to a pause button. If you press it again, it pauses. If you press a new song, it stops the old song and plays the new one. Super simple.

The code below is what I am working from.

Script at the bottom.

    <audio  id="song1">
    <source src="https://phoenixim.com/Phoenix-IML/MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon1">></b></div>
    </div>
    
    <audio  id="song2">
    <source src="https://phoenixim.com/Phoenix-IML/MUSIC/MUSIC02.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon2">></b></div>
    </div>
    
    <audio  id="song3">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon3">></b></div>
    </div>
    
    <audio  id="song4">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon4">></b></div>
    </div>
    
    <audio  id="song5">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon5">></b></div>
    </div>
    
    <audio  id="song6">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon6">></b></div>
    </div>
    
    <audio  id="song7">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon7">></b></div>
    </div>
    
    <audio  id="song8">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon8">></b></div>
    </div>
    
        <audio  id="song9">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon9">></b></div>
    </div>
    
    <audio  id="song10">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon10">></b></div>
    </div>
    
            <audio  id="song11">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon11">></b></div>
    </div>
    
    <audio  id="song12">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon12">></b></div>
    </div>
    
    <audio  id="song13">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon13">></b></div>
    </div>
    
    <audio  id="song14">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon14">></b></div>
    </div>
    
    <audio  id="song15">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon15">></b></div>
    </div>
    
    <audio  id="song16">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon16">></b></div>
    </div>
    
    <audio  id="song17">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon17">></b></div>
    </div>
    
    <audio  id="song18">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon18">></b></div>
    </div>
    
    <audio  id="song19">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon19">></b></div>
    </div>
    
    <audio  id="song20">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon20">></b></div>
    </div>
    
    
    
    <script>
    let progress = document.getElementById("progress");
    let song1 = document.getElementById("song1");
    let ctrlIcon1 = document.getElementById("ctrlIcon1");
    
    song1.onloadedmetadata = function (){
    progress.max = song1.duration;
    progress.value = song1.currentTime;
    }
    
    function playPause(){
        if(ctrlIcon1.classList.contains("fa-pause")){
            song1.pause();
            ctrlIcon1.classList.remove("fa-pause");
            ctrlIcon1.classList.add("fa-play");
        }
        else{
            song1.play();
            ctrlIcon1.classList.add("fa-pause");
            ctrlIcon1.classList.remove("fa-play");
        }
    }
    
        if(song1.play()){
            setInterval(()=>{
            progress.value = song1.currentTime;
            },500)
        }
        
        progress.onchange = function(){
        song1.play();
        song1.currentTime = progress.value;
            ctrlIcon1.classList.add("fa-pause");
            ctrlIcon1.classList.remove("fa-play");
        
        }
            
    </script>
    
    
    
            <script>
    let progress = document.getElementById("progress");
    let song2 = document.getElementById("song2");
    let ctrlIcon2 = document.getElementById("ctrlIcon2");
    
    song2.onloadedmetadata = function (){
    progress.max = song2.duration;
    progress.value = song2.currentTime;
    }
    
    function playPause(){
        if(ctrlIcon2.classList.contains("fa-pause")){
            song2.pause();
            ctrlIcon2.classList.remove("fa-pause");
            ctrlIcon2.classList.add("fa-play");
        }
        else{
            song2.play();
            ctrlIcon2.classList.add("fa-pause");
            ctrlIcon2.classList.remove("fa-play");
        }
    }
    
        if(song2.play()){
            setInterval(()=>{
            progress.value = song2.currentTime;
            },500)
        }
        
        progress.onchange = function(){
        song2.play();
        song2.currentTime = progress.value;
            ctrlIcon2.classList.add("fa-pause");
            ctrlIcon2.classList.remove("fa-play");
        
        }
            
    </script>
    

Trying to add-on to a Music Player I created through a tutorial and need a little advice on how to do it

Trying to add-on to a Music Player I created through a YouTube tutorial, and need a little help. The tutorial only had one song file, so I was able to get this to work using the tutorial. However, I tried to add more songs and found a way to do it. I know the way I did it below is very cumbersome, so there must be a better way to do this.

The goal is to have a simple ‘play.gif’ play button that, when you press it, plays a song and changes to a pause button. If you press it again, it pauses. If you press a new song, it stops the old song and plays the new one. Super simple.

The code below is what I am working from.

Script at the bottom.

    <audio  id="song1">
    <source src="https://phoenixim.com/Phoenix-IML/MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon1">></b></div>
    </div>
    
    <audio  id="song2">
    <source src="https://phoenixim.com/Phoenix-IML/MUSIC/MUSIC02.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon2">></b></div>
    </div>
    
    <audio  id="song3">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon3">></b></div>
    </div>
    
    <audio  id="song4">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon4">></b></div>
    </div>
    
    <audio  id="song5">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon5">></b></div>
    </div>
    
    <audio  id="song6">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon6">></b></div>
    </div>
    
    <audio  id="song7">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon7">></b></div>
    </div>
    
    <audio  id="song8">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon8">></b></div>
    </div>
    
        <audio  id="song9">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon9">></b></div>
    </div>
    
    <audio  id="song10">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon10">></b></div>
    </div>
    
            <audio  id="song11">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon11">></b></div>
    </div>
    
    <audio  id="song12">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon12">></b></div>
    </div>
    
    <audio  id="song13">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon13">></b></div>
    </div>
    
    <audio  id="song14">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon14">></b></div>
    </div>
    
    <audio  id="song15">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon15">></b></div>
    </div>
    
    <audio  id="song16">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon16">></b></div>
    </div>
    
    <audio  id="song17">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon17">></b></div>
    </div>
    
    <audio  id="song18">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon18">></b></div>
    </div>
    
    <audio  id="song19">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon19">></b></div>
    </div>
    
    <audio  id="song20">
    <source src="MUSIC/MUSIC01.mp4" type="audio/mpeg">
    </audio>
    <div class="controls">
    <div onclick="playPause()"><b class="fa-solid fa-play" id="ctrlIcon20">></b></div>
    </div>
    
    
    
    <script>
    let progress = document.getElementById("progress");
    let song1 = document.getElementById("song1");
    let ctrlIcon1 = document.getElementById("ctrlIcon1");
    
    song1.onloadedmetadata = function (){
    progress.max = song1.duration;
    progress.value = song1.currentTime;
    }
    
    function playPause(){
        if(ctrlIcon1.classList.contains("fa-pause")){
            song1.pause();
            ctrlIcon1.classList.remove("fa-pause");
            ctrlIcon1.classList.add("fa-play");
        }
        else{
            song1.play();
            ctrlIcon1.classList.add("fa-pause");
            ctrlIcon1.classList.remove("fa-play");
        }
    }
    
        if(song1.play()){
            setInterval(()=>{
            progress.value = song1.currentTime;
            },500)
        }
        
        progress.onchange = function(){
        song1.play();
        song1.currentTime = progress.value;
            ctrlIcon1.classList.add("fa-pause");
            ctrlIcon1.classList.remove("fa-play");
        
        }
            
    </script>
    
    
    
            <script>
    let progress = document.getElementById("progress");
    let song2 = document.getElementById("song2");
    let ctrlIcon2 = document.getElementById("ctrlIcon2");
    
    song2.onloadedmetadata = function (){
    progress.max = song2.duration;
    progress.value = song2.currentTime;
    }
    
    function playPause(){
        if(ctrlIcon2.classList.contains("fa-pause")){
            song2.pause();
            ctrlIcon2.classList.remove("fa-pause");
            ctrlIcon2.classList.add("fa-play");
        }
        else{
            song2.play();
            ctrlIcon2.classList.add("fa-pause");
            ctrlIcon2.classList.remove("fa-play");
        }
    }
    
        if(song2.play()){
            setInterval(()=>{
            progress.value = song2.currentTime;
            },500)
        }
        
        progress.onchange = function(){
        song2.play();
        song2.currentTime = progress.value;
            ctrlIcon2.classList.add("fa-pause");
            ctrlIcon2.classList.remove("fa-play");
        
        }
            
    </script>
    

Phaser.js: mismatch between coordinates for graphics and Matter.js body

I’m trying to mathematically create some shape graphics in Phaser.js, and to attach matching Matter.js physics bodies to them. I’m finding that the coordinate systems used for these two things don’t line up exactly, in a way I can’t quite describe.

I’ve cooked up a codepen example that demos the code below.

As near as I can tell, the Matter.js polygons are rendered appropriately. But the graphics polygons are offset, the ‘centre’ of the polygon is treated as its bottom left corner and the entire graphic is offset. I haven’t been able to find any configuration in Phaser’s GameObject or Shape classes that would let me configure this, setOrigin doesn’t seem to have any effect.

Have I missed something? Is there some trick to generating coordinates which can be used with both a Phaser polygon and also a Matter polygon?

<script src="https://cdnjs.cloudflare.com/ajax/libs/phaser/3.87.0/phaser.min.js"></script>
<div id="phaser-container"></div>
class MyScene extends Phaser.Scene {
  constructor() {
    super('MyScene')
  }

  create() {
    const segments = 100
    const angleStep = (Math.PI * 2) / segments
    const radius = 200
    const x = 852 / 2
    const y = 640 / 2

    for (let i = 0; i < segments; i++) {
      const angle = i * angleStep
      const startAngle = angle + angleStep / 2
      const endAngle = angle - angleStep / 2

      const centreX = Math.cos(angle) * radius
      const centreY = Math.sin(angle) * radius
    

      const vertices = [
        {
          x: Math.cos(startAngle) * (radius - 10) - centreX,
          y: Math.sin(startAngle) * (radius - 10) - centreY
        },
        {
          x: Math.cos(startAngle) * (radius + 10) - centreX,
          y: Math.sin(startAngle) * (radius + 10) - centreY
        },
        {
          x: Math.cos(endAngle) * (radius + 10) - centreX,
          y: Math.sin(endAngle) * (radius + 10) - centreY
        },
        {
          x: Math.cos(endAngle) * (radius - 10) - centreX,
          y: Math.sin(endAngle) * (radius - 10) - centreY
        },
      ]

      const poly = this.add.polygon(x + centreX, y + centreY, vertices, 0x1d4ed8)

      this.matter.add.gameObject(poly, {
        shape: {
          type: 'fromVertices',
          verts: vertices,
        },
        isStatic: true,
      })

      this.add.circle(x + centreX, y + centreY, 1, 0xffff00)
    }
  }
};

const game = new Phaser.Game({
  type: Phaser.CANVAS,
  width: 852,
  height: 640, 
  scene: MyScene,
  parent: 'phaser-container',
  backgroundColor: 0x000033,
  physics: {
    default: 'matter',
    matter: {
      gravity: { x: 0, y: 0 },
      debug: {
        showBounds: false,
      },
    }
  },
});

Is this custom hook for managing filters with URLSearchParams in Next.js 13+ idiomatic and scalable?

I’m working on a filtering system in a Next.js 13+ (App Router) app. I found a hook in another project, improved it for my needs, and it seems to work well — but I still have some concerns about its correctness, performance, and long-term maintainability

What I’m unsure about:

Am I using useMemo and useCallback properly?

Is it safe to do Object.fromEntries(searchParams)?

Any potential issues with URLSearchParams or router.replace()?

Could this design cause performance or readability issues over time?

Would really appreciate feedback or best practices from more experienced Next.js users

import { useRouter, useSearchParams } from "next/navigation";
import { useMemo, useCallback } from "react";

const identity = (value) => value;
const toggle = (list, value) => list.includes(value) ? list.filter((item) => item !== value) : [...list, value];

export const useSearchParamsApi = () => {
  const router = useRouter();
  const searchParams = useSearchParams();

  const record = useMemo(
    () => Object.fromEntries(searchParams),
    [searchParams]
  );

  const replace = useCallback(
    (value, params) => {
      router.replace(`?${new URLSearchParams(value)}`, {
        scroll: false,
        ...params,
      });
    },
    [router]
  );

  const update = useCallback(
    (value, params) => {
      const next = { ...record, ...value };

      if (!("page" in value)) {
        next.page = "1";
      }

      const cleaned = Object.fromEntries(
        Object.entries(next).filter(
          ([_, v]) => v !== undefined && v !== null && v !== ""
        )
      );

      replace(cleaned, params);
    },
    [replace, record]
  );

  return { record, searchParams, replace, update };
};

export function useFiltersQuery() {
  const { record, update, replace, searchParams } = useSearchParamsApi();

  const valueFilter = (name, fallback, deserialize = identity) => ({
    value: useMemo(() => {
      return record[name] ? deserialize(record[name]) : fallback;
    }, [record, name]),

    update: useCallback(
      (next) => update({ [name]: String(next) }),
      [name, update]
    ),

    remove: useCallback(() => update({ [name]: undefined }), [name, update]),
    hasFilter: searchParams.has(name),
  });

  const arrayFilter = (name, defaultValue = []) => {
    const field = valueFilter(name, defaultValue, (v) => v.split(","));

    return {
      ...field,
      toggle: useCallback(
        (value) => field.update(toggle(field.value, value)),
        [field.value, field.update]
      ),
    };
  };

  const clearFilter = useCallback(
    (key, params) => {
      update(
        {
          [key]: undefined,
          page: "1",
        },
        params
      );
    },
    [update]
  );

  const resetFilters = useCallback(
    (params) => {
      replace({}, params);
    },
    [replace]
  );


  return {
    record,
    valueFilter,
    arrayFilter,
    clearFilter,
    resetFilters,
  };
}

What I tried and what I expected:

I used this hook across several filtered pages — for example, a companies catalog, where filters like categories, languages, and service type are stored in the URL. It works as expected:

Filters show up in the UI and sync with the URL.

I can add/remove filters and the page rerenders correctly.

When I change a filter, page resets to 1 automatically — which is what I want.

What I expected:
A reusable, declarative solution for handling filters without local state. It seems to be working well, but I’d like feedback on:

Whether this may cause issues down the road,

And whether there are any anti-patterns I might be missing.

How to make external scripts work with hash-based CSP without allowlists in Astro?

I’m using a strict CSP without allowlists on my statically generated Astro website. I have no access to nonce-based CSP, only hash-based.

  1. Do I need to add permitted domains to a CSP allowlist if I’m using a hash-based approach?

  2. Can I hash external scripts and add an integrity parameter with this hash to the actual script tag for it to work? I’ve read that Safari does not support integrity (comment from 2021), but I see that subresource integrity is supported from 2018 according to caniuse.

  3. Do I hash <script> tags too? MDN says I don’t, but the external script would be empty then.

The CSP I am using:

Content-Security-Policy: script-src 'sha256-placeholder' 'strict-dynamic'; object-src 'none'; base-uri 'none'; form-action 'self'; frame-ancestors 'none';

Google Analytics scripts I want to get working:

<script is:inline src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script is:inline>
  window.dataLayer = window.dataLayer || [];
  function gtag() {
    dataLayer.push(arguments);
  }
  gtag("js", new Date());
  gtag("config", "G-XXXXXXXXXX");
</script>

Pong Game – Paddles Lagging While Ball Moves Smoothly in WebSocket Multiplayer

I’m building a multiplayer Pong game using WebSockets (Fastify + WebSocket API) for a school project, but I’m experiencing an issue where the paddles are laggy while the ball moves smoothly. Here’s my setup:

Problem Description
The ball movement is smooth and synchronized between clients

Paddle movement has noticeable delay/lag

The lag is especially bad for the local player’s paddle (should be instant)

Current Implementation

Server Code (Fastify WebSocket):

function gameLogic(gameState) {


  if (gameState.keypressd[0] === "w" && gameState.playerId === 1)
    gameState.paddleLeftY -= 8;
  if (gameState.keypressd[0] === "s" && gameState.playerId === 1)
      gameState.paddleLeftY += 8;

  if (gameState.keypressd[0] === "w" && gameState.playerId === 2)
      gameState.paddelRightY = Math.max(0, gameState.paddelRightY - 8);
  if (gameState.keypressd[0] === "s" && gameState.playerId === 2)
      gameState.paddelRightY = Math.min(450, gameState.paddelRightY + 8);

  if (flagX || (gameState.ballX >= 890 && gameState.ballY >= gameState.paddelRightY && gameState.ballY <= (gameState.paddelRightY + 150)))
    gameState.ballX -= ballSpeed, flagX = true;
  if (!flagX || (gameState.ballX <= 0 && gameState.ballY >= gameState.paddleLeftY && gameState.ballY <= (gameState.paddleLeftY + 150)))
    gameState.ballX += ballSpeed, flagX = false;

      
  if (gameState.ballY >= 600 || flagY)
    gameState.ballY -= ballSpeed, flagY = true;
  if (gameState.ballY <= 0 || !flagY)
    gameState.ballY += ballSpeed, flagY = false;
  
  gameState.keypressd = [];

  if (gameState.ballX > 900 || gameState.ballX <= 0)
  {
    gameState.paddleLeftY = 240;
    gameState.paddelRightY = 240;
    gameState.ballX = 900 / 2; 
    gameState.ballY = 300;
  }
  return gameState;
}

const rooms = {};

function generateNewRoomId(params) {
  let roomId = "";
  
  const stringOfChar = "abcdefghijklmnopqrstuvwxyz0123456789";
  
  for (let index = 0; index < 12; index++) {
    roomId += stringOfChar[Math.floor(Math.random() * stringOfChar.length)]; 
  }
  return roomId;
}



fastify.register(async function (fastify) {
  fastify.get('/remoteGame', { websocket: true }, (connection) => {
      let roomId;
      let joined = false;
      for (const [id, connections] of Object.entries(rooms)) {
          if (connections.length < 2) {
              roomId = id;
              connections.push(connection);
              joined = true;
              break;
          }
      }
      if (!joined) {
          roomId = generateNewRoomId();
          rooms[roomId] = [connection];
      }
      if (rooms[roomId].length === 2) {
          const [player1, player2] = rooms[roomId];
          
          const handleMessage = (player, playerId) => (msg) => {
              try {
                  const gameState = JSON.parse(msg);
                  gameState.playerId = playerId;
                  const updatedState = gameLogic(gameState);
                  player1.send(JSON.stringify(updatedState));
                  player2.send(JSON.stringify(updatedState));
              } catch (error) {
                  console.error('Invalid JSON format', error);
              }
          };
          player1.on('message', handleMessage(player1, 1));
          player2.on('message', handleMessage(player2, 2));
      }
  });
});

client code:

const socket = new WebSocket('ws://localhost:5000/remoteGame');
window.onload = () => {
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    socket.onopen = () => {
        console.log('connected');
    }
    socket.onmessage = (event) => {
        console.log('[client] Message from server:', event.data);
    };
    socket.onclose = () => {
      console.log('[client] Disconnected from server');
    };
    socket.onerror = (err) => {
      console.error('[client] WebSocket error:', err);
    };


    let keys = {};
    window.addEventListener('keydown', (key) => {
      keys[key.key] = true;
    })
    window.addEventListener('keyup', (key) => {
      keys[key.key] = false;
    })
    socket.onmessage = (event) => {
        flow.updateGameState(event.data); 
    };
    const flow = new FlowField(ctx, keys);
    flow.animate();
}

class FlowField {
    #ctx;
    #width;
    #height;
    #keys;
    #paddleStat;
    #canvasWidth;
    #canvasHeight;
    constructor(ctx, keys) {
      this.#width = 10;
      this.#height = 150;
      this.#canvasWidth = 900;
      this.#canvasHeight = 600;
      this.#ctx = ctx;
      this.#keys = keys;
      this.#paddleStat = {playerId: 1, paddleLeftY: 0,paddelRightY: 0, ballX: 0, ballY: 300,gameStat: 1, keypressd: []};
    }
    updateGameState(data) {
        this.#paddleStat = JSON.parse(data);
    }
      
    #draw() 
    {
      this.#ctx.clearRect(0, 0, this.#canvasWidth, this.#canvasHeight);
  
      console.log(this.#paddleStat.paddleLeftY, this.#paddleStat.paddelRightY);
    //   paddle left 

      this.#ctx.fillRect(0, this.#paddleStat.paddleLeftY, this.#width, this.#height);
      this.#ctx.strokeRect(0, this.#paddleStat.paddleLeftY, this.#width, this.#height);
  
      //paddle right
      this.#ctx.fillRect(890, this.#paddleStat.paddelRightY, this.#width, this.#height);
      this.#ctx.strokeRect(890, this.#paddleStat.paddelRightY, this.#width, this.#height);
  
  
      //ball
      this.#ctx.beginPath();
      this.#ctx.arc(this.#paddleStat.ballX, this.#paddleStat.ballY, 13, 0, Math.PI * 2);
      this.#ctx.fill();
      this.#ctx.stroke();
    }
    
    keysFunction() 
    {
        if (this.#keys["w"] === true  && this.#paddleStat.paddleLeftY > 0)
        {
          this.#paddleStat.keypressd.push("w");
        }
        if (this.#keys["s"] === true && this.#paddleStat.paddleLeftY < this.#canvasHeight - this.#height)
        {
          this.#paddleStat.keypressd.push("s");
        }
    }
    ballPositionUpdate()
    {
        if (socket.readyState === WebSocket.OPEN) {
          socket.send(JSON.stringify(this.#paddleStat));
        }
    }
  
    animate()
    {
      this.#draw();
      this.keysFunction();
      this.ballPositionUpdate();
      requestAnimationFrame(this.animate.bind(this))
    }
  }

What I’ve Tried
Basic WebSocket communication (current implementation)

Simple client-side prediction (but couldn’t get it working right)

How to avoid missing parts functions of code when push changes on git source control?

I work on source control git I have issue missing function PRINT_DEGREE_EQUATION_Both_Lang on jQuery .

Current Work and Issue:

I am working with Git for source control.

I found an issue with the function PRINT_DEGREE_EQUATION_Both_Lang.

File and Developer Details:

The function is in the jQuery file MasterScript.js.

This function was initially published by developer Sim.

When I searched for the same function in the changes pushed later by developer Reh, I could not find it in Git source control.

Preventing Differences Between Publishes:

How can we avoid discrepancies between two publishes in Git?

The file MasterScript.js contains the function PRINT_DEGREE_EQUATION_Both_Lang, and it may have been modified by 3 or 4 developers simultaneously.

function PRINT_DEGREE_EQUATION_Both_Lang(P_REQ_ID, P_User, P_LANG, userType, P_DB_PROD_TEST_FLAG, permId) {
    debugger;
    if (P_REQ_ID == null || P_REQ_ID === undefined)
        P_REQ_ID = $("#txtP_REQID").val();

    userType = userType ?? null;
    P_DB_PROD_TEST_FLAG = P_DB_PROD_TEST_FLAG ?? null;
    var rptParams = {
        P_REQ_ID: P_REQ_ID,
        P_User: P_User ?? $("#txtP_USER_ID").val(),
        P_LANG: P_LANG ?? (MYLang.ReturnLang() == "ar-KW" ? "AR" : "EN"),
        userType: userType,
        P_DB_PROD_TEST_FLAG: P_DB_PROD_TEST_FLAG,
        tenantId: "MOHE",
        permId: permId,
        userId: P_User ?? $("#txtP_USER_ID").val(),
    };
    $('#hidden_RptParams').val(JSON.stringify(rptParams));
    DownloadReportFromReportsViewer(6, '#hidden_RptParams');
}

this is picture from issue happened

image for issue on git source control

Closing a sidemenu when clicking outside the menu

I’m not sure why I always have problems with this, my code seems to close the menu the fraction of a second I click the button to open the menu and I can’t figure out how to stop it.

    const MobileMenu = () => {
  const { open, setOpen } = useContext(DataContext);
  const menuItems = ["Login", "Store", "Community", "About", "Support"];

  window.addEventListener("click", function (e) {
    if (open && !this.document.getElementById("menu").contains(e.target)) {
      e.stopPropagation();
      setOpen(false);
    }
  });

  return (
    <div className="absolute z-30">
      <div
        id="menu"
        className={`bg-very-dark-blue shadow-[0_0px_7px_0px_rgba(0,0,0,0.75)] top-0 left-0 bottom-0 fixed w-[280px] text-[#bdbdbd] ${
          open ? "translate-x-0 block" : "-translate-x-full"
        } transition-all delay-75 duration-500 ease-in-out`}
      >
        <ul className="flex flex-col ">
          {menuItems.map((item) => (
            <li className="text-3xl px-3 py-5 border-t-[1px] border-[#2f3138] border-b-[1px] border-b-black">
              {item}
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
};

If I comment out the window.addEventListener block I can open the menu just fine. Bringing the code block back in stops the menu from opening at all though. It’s set so that if the open state is True and you click outside the menu, then it will set the open state to false. But it seems to think when the open state is false and I click the button to open the menu, that it’s true and sets it back to false.

I thought e.stopPropagation() would prevent that, but no luck.