Strange model behavior when using InstancedMesh with CameraSync (threebox)

Description

After adding the mesh of the gltf model to THREE.InstancedMesh, I modified the scaling, and the rendered effect seems to have lost some vertices

Reproduction steps

  1. Adding custom layers using mapboxgl
  2. Load the model using three gltfloader in the mapboxgl custom layer
  3. Adding gltf mesh using THREE.InstancedMesh

Code

loader.load(
        "https://threejs.org/examples/models/gltf/Flower/Flower.glb",
        function (gltf) {
          const p = projectToWorld(origin);

          const model = gltf.scene;

          const _stemMesh = model.getObjectByName("Stem");
          const _blossomMesh = model.getObjectByName("Blossom");

          const stemGeometry = _stemMesh.geometry.clone();
          const blossomGeometry = _blossomMesh.geometry.clone();

          const stemMaterial = _stemMesh.material;
          const blossomMaterial = _blossomMesh.material;

          const stemMesh = new THREE.InstancedMesh(
            stemGeometry,
            stemMaterial,
            1
          );
          const blossomMesh = new THREE.InstancedMesh(
            blossomGeometry,
            blossomMaterial,
            1
          );

          stemMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
          blossomMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage);

          const defaultTransform = new THREE.Matrix4()
            .makeRotationX(Math.PI)
            .multiply(new THREE.Matrix4().makeScale(1, 1, 1));

          stemGeometry.applyMatrix4(defaultTransform);
          blossomGeometry.applyMatrix4(defaultTransform);

          stemMesh.instanceMatrix.needsUpdate = true;
          blossomMesh.instanceMatrix.needsUpdate = true;

          const dummy = new THREE.Object3D();

          let pos = projectToWorld([118.61113, 32.06318, 0]);

          for (let i = 0; i < 1; i++) {
            dummy.position.copy(pos);
            dummy.scale.set(10, 10, 10);
            // dummy.scale.set(100, 100, 100);
            dummy.updateMatrix();
            stemMesh.setMatrixAt(i, dummy.matrix);
            blossomMesh.setMatrixAt(i, dummy.matrix);
          }

          const group = new THREE.Group();

          group.add(stemMesh);
          group.add(blossomMesh);

          world.add(group);

          map.triggerRepaint(); }
      );

Live example

Use the right mouse button to drag and drop the map to select it.
Alternatively, modify the code dummy. scale. set (5, 5, 5);

Screenshots

Version

all

Is it related to camera synchronization? How can I modify it

Assign values of variables to a 2d Array

I’m sure it’s a simple question, although i have trouble finding comprehensive explanation to it.
I am trying to fill 2d array with data which comes in form of variables from different places in order to later write in range. These variables change their values while looping through arrays of data. Consequently, at the end i get array populated only with latest values of these variables instead of the values they held at the moment i assigned the to positions in 2d array.

I vaguely understand that it has to do that I’m writing pointer to o memory slot (or something like that) into array instead of value, and it can be overcome by some evaluation or construction of new variable, but I can’t find comprehensive explanation why/when it happens and what is the best way to tackle this problem.

So for example, i have code:

  var rowArray = [".", ".", ".", ".", ".", "."];
  var rangeArray = [];
  for (k = 0; k < 5; k++){
    for (var i = 0; i < 6; i++){ 
      rowArray[i] = ((i+1) *(k+1));
    }
  rangeArray.push(rowArray);
  }
  Logger.log(rangeArray);

which gives output:
[[5.0, 10.0, 15.0, 20.0, 25.0, 30.0], [5.0, 10.0, 15.0, 20.0, 25.0, 30.0], [5.0, 10.0, 15.0, 20.0, 25.0, 30.0], [5.0, 10.0, 15.0, 20.0, 25.0, 30.0], [5.0, 10.0, 15.0, 20.0, 25.0, 30.0]]

instead of the one i wanted:
[[1, 2, 3, 4, 5, 6], [2, 4, 6, 8, 10, 12], [3, 6, 9, 12, 15, 18], [4, 8, 12, 16, 20, 24], [5, 10, 15, 20, 25, 30]]

I can overcome this problem by converting array to string and then constructing array from it.

  var rowArray = [".", ".", ".", ".", ".", "."];
  var rangeArray = [];
  for (k = 0; k < 5; k++){
    for (var i = 0; i < 6; i++){ 
      rowArray[i] = ((i+1) *(k+1));
    }
  rangeArray.push(rowArray.toString().split(","));
  }
  Logger.log(rangeArray);

But it is a workaraound rather then a solution. Besides it would be very cumbersome and unreliable with real code where values of array entries may contain commas themselves.

So can you explain how to write current value of variable to an array instead of pointer to it?

YouTube iframe API “player is undefined”

I am making an application which uses the YouTube API to gather a grid of videos from a search string. When a thumbnail is clicked, player.loadVideoByID should run, opening it in a previously defined iFrame. I’m using the player object instead of iframe directly, as I need the timestamps for future functionality.

However, I get the error “Uncaught TypeError: player is undefined”. Why is that? Function scope?

Here is the relevant HTML:

<div id="videoScreen" class="screen">
            <div class="screen-content">
                <span class="close" onclick="closeVideo()">&times;</span>
                <iframe id="videoFrame" width="560" height="315" src="" frameborder="0" allowfullscreen></iframe>
                <p><a download="info.txt" id="downloadlink">
                <img src="save.png" alt="Download" width="60px" height="60px">
                </a></p>
                <input type = "image" style="width:60px;height:60px;" src = "note.png" onclick = "showNote()" id = "note-opener"></button>
            </div>

Here is the relevant JS script:

    function videoSearch(key, search, maxResults, videoDuration) {
        var player;
        function onYouTubeIframeAPIReady() {
            player = new YT.Player('videoFrame', {
            playerVars: {
                'playsinline': 1
            },
            events: {
                'onReady': onPlayerReady,
                }
            });
          }
           function onPlayerReady(event){
               event.target.playVideo();
           }
           
        $("#videos").empty();
        $.get("https://www.googleapis.com/youtube/v3/search?key=" + key
        + "&type=video&part=snippet&maxResults=" + maxResults + "&q=" + search + "&videoDuration=" + videoDuration, 
        
        function(data){
            populateVideoSelector(data.items);
            var videosContainer = $("<div class='row'></div>");
            console.log(data);
            data.items.forEach(function (item, index) {
                var videoColumn = $("<div class='col-md-4'></div>");
                var videoContainer = $("<div class='video-container'></div>");
        
                // Create an image or link to represent the video thumbnail and trigger the pop-up
                var thumbnail = $("<img src='" + item.snippet.thumbnails.medium.url + "' alt='Video Thumbnail'>");
                thumbnail.on("click", function () {
                        player.loadVideoById(item.id.videoId)
                        //openVideo("https://www.youtube.com/embed/" + item.id.videoId + "?enablejsapi=1"); 

            });
        
                var videoTitle = $("<p class='video-title'></p>");
                videoTitle.text(item.snippet.title);
        
                videoContainer.append(thumbnail);
                videoContainer.append(videoTitle);
                videoColumn.append(videoContainer);
                videosContainer.append(videoColumn);
        
                if ((index + 1) % 3 === 0) {
                    $("#videos").append(videosContainer);
                    videosContainer = $("<div class='row'></div>");
                }
            });

Thank you.

How do I use a file with .node extension in NestJS application?

I am working on a project which was on NodeJS but now trying to convert to NestJS, however there is a native-node module, get_dec_data.node which I call in the application. I was able to create a typescript module (get_dec_data.d.ts) and build successfully using npm run build. But when I run npm run start:dev, I get the error below:

Error: Cannot find module ‘get_dec_data’ Require stack:
C:UsersUserOneDriveDesktoptech5-face-capturedistapp.service.js
C:UsersUserOneDriveDesktoptech5-face-capturedistapp.controller.js
C:UsersUserOneDriveDesktoptech5-face-capturedistapp.module.js
C:UsersUserOneDriveDesktoptech5-face-capturedistmain.js
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:1077:15)
at Function.Module._load (node:internal/modules/cjs/loader:922:27)
at Module.require (node:internal/modules/cjs/loader:1143:19)
at require (node:internal/modules/cjs/helpers:119:18)
at Object. (C:UsersUserOneDriveDesktoptech5-face-capturesrcapp.service.ts:2:1)
at Module._compile (node:internal/modules/cjs/loader:1256:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1310:10)
at Module.load (node:internal/modules/cjs/loader:1119:32)
at Function.Module._load (node:internal/modules/cjs/loader:960:12)
at Module.require (node:internal/modules/cjs/loader:1143:19)

When I checked the dist directory, I realized the get_dec_data file is not getting built. I have tried everything but still no headway. Below is my setup:

tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "target": "ES2021",
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./",
    "incremental": true,
    "skipLibCheck": true,
    "strictNullChecks": false,
    "noImplicitAny": false,
    "strictBindCallApply": false,
    "forceConsistentCasingInFileNames": false,
    "noFallthroughCasesInSwitch": false,
    "types": [
      "node",
      "./src/get_dec_data"
    ]
  }
}

get_dec_data.d.ts

declare module 'get_dec_data' {
  export function get_decode_data(license: string, image: string): any;
}

app.service.ts

async decryptionOfImage(req: any) {}

async getLicenseString() {}

async writeFileBeforeEncryption(req: any) {}

private async createDirectoryIfNotExists(
  directoryPath: string,
): Promise<void> {}

private getDecodeData(license: string, image: string): string {
  try {
    const decodedData = get_decode_data(license, image);
    return decodedData;
  } catch (error) {
    console.error('Decryption error:', error);
    throw new HttpException(
      'Error during decryption',
      HttpStatus.INTERNAL_SERVER_ERROR,
    );
  }
}

This is the structure of my project:
enter image description here

Need some help.

export a javascript instance of a class to another file and retain prototype and methods

I am working on becoming better at javascript, node, and express and am trying to serve up an instance of a class from an app.js file to another js file and still be able to retain and implement the class methods. I am using node.js and express. Here is an example of what I am trying to do:

person.js

export default class Person{
    constructor(name){
        this.name = name;
    }

    someMethod(){
        this.name = "new name";
    }
}

app.js

import express from "express";
import bodyParser from "body-parser";
import Person from "./public/classes.js";
 
const myPerson = new Person("John Smith");

//setup Express server here
const app = express();
const port = 3000;

app.use(bodyParser.urlencoded({ extended: true }));
app.listen(port, () => {
  console.log(`Listenings on port ${port}`);
});

//provide route to fetch object from
app.get("/getPerson", (req, res) => {
  res.send(myPerson);
});

otherFile.js

import Person from "./classes.js";

//fetch the Person object from the app.js
const response = await fetch("/getPerson");
const myPerson = await response.json();

//Try to call a method from the Person class on myPerson
myPerson.someMethod() // this throws an Uncaught TypeError: myPerson.someMethod() is not a function 

It is this last line that I am trying to fix. I would like to be able to call the methods of the class on the myPerson object. Upon examination it appears the myPerson object no longer has the methods in its prototype that were originally attached by the class. What am I doing wrong and is there a better way to do this?

JS Interop causing thread-lock in Blazor

I have a vertical list of items where draggable=”true”. When A is initially dragged over B [ondragenter], DoJsThingy() is called. DoJsThingy makes a call to a javascript function using IJsObjectReference.InvokeVoidAsync().

When I hover div A over div B, the alert is shown. When the alert is closed, the mouse pointer is still in the hover-over style from div A, and the app freezes.

The odd behavior is that the JS method executes and returns just fine. I validated this by throwing a simple WriteLine() just after it. The log message after InvokeVoidAsync is working, but it appears that DisposeAsync() is never getting called. If I remove the JS call, the app doesn’t freeze after the hover event.

MyComponent.razor

@namespace BlazorWASM.Shared

@inject IDataService _dataService
@inject IUserService _userService
@inject IJSRuntime JS
@implements IAsyncDisposable

<div class="sidebar-grid">
    <h2 class="data-models-header">Data Models</h2>
    <input type="text" placeholder="Search" @bind="@searchString" class="search-bar" @bind:event="oninput" @onkeyup="() => UpdateSearchResults()" />
    <div class="data-model-list">
        @foreach (var model in searchResults)
        {
            <div @ref="listItems[model.Id]" draggable="true" class="@StyleDataModelListItem(model)" @ondragenter="() => DoJsThingy(model.Id)" @onclick="() => SelectDataModel(model)">
                <div class="data-model-list-item-icon-container">
                    <img class="data-model-list-item-icon" src="Images/data_model.svg" />
                </div>
                <div class="data-model-list-item-text">@model.Name</div>
            </div>
        }
    </div>
    <div class="data-model-save-load-buttons">
        <button class="new-data-model-button" @onclick="() => CreateDataModel()">New Data Model</button>
        <button class="delete-data-model-button" @onclick="() => DELETEITALL()">BIG Red Button</button>
    </div>
</div>



@code {
    public Dictionary<string, ElementReference> listItems = [];
    public string data = "";
    public List<DataModel> dataModels = [];
    public List<DataModel> searchResults = [];
    public DataModel? SelectedDataModel;
    public string searchString = "";
    private IJSObjectReference? module;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        module = await JS.InvokeAsync<IJSObjectReference>("import", "./js/test.js");
    }

    protected override void OnInitialized()
    {
        _dataService.GetDataModelsBehaviorSubject().Subscribe(dms => {
            dataModels = dms;
            foreach(var dm in dataModels)
            {
                if (!listItems.ContainsKey(dm.Id)) listItems.Add(dm.Id, new ElementReference());
            }
            UpdateSearchResults();
            StateHasChanged();
        });
        _dataService.GetSelectedDataModelBehaviorSubject().Subscribe(sdm =>
        {
            SelectedDataModel = sdm;
            StateHasChanged();
        });
        _dataService.GetFieldLabelUpdatesBehaviorSubject().Subscribe(label =>
        {
            StateHasChanged();
        });
    }

    public async void RegisterUser()
    {
        await _userService.RegisterUser();
    }

    public async void CreateDataModel()
    {
        await _dataService.CreateDataModelAsync();
    }

    public async void ListDataModels()
    {
        await _dataService.LoadDataModelsAsync();
    }

    public void SelectDataModel(DataModel dataModel)
    {
        _dataService.SelectDataModel(dataModel);
    }

    public async Task DoJsThingy(string dataModelId)
    {
        try
        {
            var hoveredDataModel = _dataService.GetDataModel(dataModelId);
            if (module != null && hoveredDataModel != null)
            {
                await module.InvokeVoidAsync("showAlert", hoveredDataModel.Id);
                Console.WriteLine("Alert shown for model: " + hoveredDataModel.Id);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error in DoJsThingy: " + ex.Message);
        }
    }

    public async ValueTask DisposeAsync()
    {
        if(module != null)
        {
            await module.DisposeAsync();
        }
    }

    public string StyleDataModelListItem(DataModel dataModel)
    {
        var style = "data-model-list-item";
        if(SelectDataModel != null)
        {
            if (SelectedDataModel == dataModel)
            {
                style = "data-model-list-item-selected";
            }
        }
        return style;
    }

    public async Task DELETEITALL()
    {
        await _dataService.DELETEITALL();
    }

    public void DataModelListItemDragOver(string id)
    {
        var elementRef = listItems[id];
    }

    public void UpdateSearchResults()
    {
        if (String.IsNullOrEmpty(searchString))
        {
            searchResults = dataModels;
        }
        else
        {
            searchResults = dataModels.Where(d => d.Name.Contains(searchString)).ToList();
        }
    }
}

test.js

export function showAlert(message) {
    alert(message);
    return;
}

Naming New Tab with Image

I am trying to rename a new tab I am opening up. This new tab contains an iframe with an image as the source. This is how I am opening the tab, but can’t seem to get document.title to work.

var customTab = window.open();
customTab && customTab.document.title = 'My new tab';//this doesn't work
customTab &&
  customTab.document.write(
    '<iframe src="' +
      myImage +
      '" style="border: none;"></iframe>'
  );

Any ideas would be much appreciated.

Keep getting an error during registration [TypeError: Network request failed]

I’m making an app with React and making the backend with node.js. My issue is that every time I sign up (or attempt to log in) I keep getting the same network error. What’s weird to me is when I test it on postman it works 100% fine, so it’s not issue with my backend or database or how I send the values in the frontend. On my browser I get “register:1 Failed to load resource: the server responded with a status of 404 (Not Found)”

SignUpScreen.js

function SignUpScreen(props) {

    const navigation = useNavigation();

    const navigateToSignIn = () => {
        navigation.navigate('Sign In');
      };

        const handleRegister = async () => {
            console.log('Start handleRegister');
            try {
                const response = await fetch('http://localhost/register', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({  Email, password }),
                });

                console.log('After fetch'); 

                const data = await response.json();
        };

Backend code

app.post('/register', async (req, res) => {
    try {
        const { email, password } = req.body;
        
        const saltRounds = 10;
        const hashedPassword = await bcrypt.hash(password, saltRounds);


        const user = { email, password: hashedPassword };
        const insertUserQuery = 'INSERT INTO users (email, password) VALUES (?, ?)';

});

I’ve tried

  1. Switching from “localhost” to my IP
  2. Using CORS
  3. adding android:usesCleartextTraffic=”true” in my Android manifest android/app/src/main/AndroidManifest.xml
  4. Switched to a different physical device

leetcode perfect square, using 2D dp, result incorrect outcome

I tried to come up a 2D dp solution for perfect square, but it is not passing any test cases. To be honest, I follow previous code templates (hence not fully understand why doing so)

/**
 * @param {number} n
 * @return {number}
 */
var numSquares = function(n) {
    // * b: each_num is also tar
    const tar = n;

    // * b: dp cr
    // * b: key: 1 -> n (each item)
    const dp = new Array(1+n).fill(Infinity).map((_, i) => {
        // * b: key: tar -> 1 (tar)
        return new Array(tar+1).fill(Infinity);
    });
    
    // * b: dp init
    for(let i=0; i<=n; ++i) {
        dp[i][0] = 0;
    }

    // * b: 1 -> n (each item)
    for(let i=1; i<=n; ++i) {
        // * b: tar -> 1 (tar)
        for(j=1; j<=tar; ++j) {
            if(j*j <= i) {
                dp[i][j] = Math.min(dp[i-1][j], dp[i-1][i - j*j] + 1);
            } else {
                dp[i][j] = dp[i-1][j];
            }
            
        }
    }

    return dp[n][tar];
};

Not sure which part of the code went wrong.

classList.add() does not work inside setTimeout() function

I am using Intersection Observer to hide a div element when it is inside the viewport. For that purpose I am using setTimeOut() function to hide the div element after 2 seconds and using a nice CSS transition, but the classList.add() function does not seem to work inside the setTimeout() function in order to call the CSS transition to hide it.

This is my HTML where you can see the div element with id=’sbox’.
All sections have a height of 100vh.


  <body>
    <section id="page-1" class="primera"></section>

    <section id="page-2" class="segunda"></section>

    <section id="page-3" class="tercera">
      <div id="sbox" class="small-box"></div>
    </section>

    <script src="js/app.js"></script>
  </body>

this is my CSS:

.primera{
width: 100%;
height 100vh
}

.segunda {
  width: 100%;
  height: 100vh;
  background-color: #cbf3f0;
  background: linear-gradient(to bottom, #cbf3f0, #2ec4b6);
}

.tercera {
  width: 100%;
  height: 100vh;
  background-color: #5e60ce;
  display: grid;
  place-items: center;
  .small-box {
    width: 50%;
    height: 50%;
    opacity: 1;
    background-color: #ffbf69;
    transition: all 5s ease-out;
  }
}

.hide {
  transition: all 5s ease-out;
  opacity: 0;
}

This is my JS file:


let options = {
  root: null,
  threshold: 0.8,
};

function hideBox(entryArray) {
  let ibox = document.getElementById("sbox");

  if (entryArray[0].isIntersecting) {
    setTimeout(() => {
      console.log("hiding the first loading element");
      ibox.classList.add("hide");
    }, 2000);
  } else {
    ibox.classList.remove("hide");
  }
}

let observer = new IntersectionObserver(hideBox, options);
observer.observe(document.getElementById("page-3"));



How to make cursor ignores pseudo elements in Firefox?

In Firefox, if cursor starts like this

`123`|

and I press left arrow 2 times, I want it to land on the left side of 2:

 `1|23`

as it would have if the pseudo element wasn’t there.

Any ideas?

.code {
  font-family: monospace;
  background: rgba(0, 0, 0, 0.05);
}

.pseudo-ele::after {
  content: "3";
}
<div contenteditable>
  <span>`</span><span class="code pseudo-ele">12</span><span>`</span>
</div>

Office-js – I cannot access plainText content controls within a rich text content control

Issue

I have a number of rich text content controls in my document. Within each of these rich text content controls, they contain a number of plain text content controls.

I’m doing a for loop to iterate over each rich text content control, to then access all the plain text content controls within it. Howevever, this is not working at all and I cannot access the plain text content control data.

I’m using the latest version of MS Word, therefore have access to Word API 1.5 and 1.6.

What I have tried

My specific code to access the plain text content controls in a rich text content control

var plainTextCC = richTextCC.items[i].contentControls.getByTypes([Word.ContentControlType.plainText]).load("items");
await context.sync();
console.log(plainTextCC.items.length)

The length is always equal to 0 despite there being multiple plain text content controls.

I do not want to use the context.document.body.getContentControls({types: [Word.ContentControlType.plainText]}).load("items") method because I need the granularity of the above for loop to access each individual rich text content controls contents.

Is there some way I can access the rich text content control’s plain text content controls?

How to have href tag only affect scrollbox and not entire page?

I have a scrollbox within a website and hrefs to scroll to specific parts within that scrollbox. When the href is linked however, it scrolls the entire webpage such that the scrollbox is covered by the header now. I want it so that the href only interacts with the scrollbox and nothing else.

Ive tried everything, scroll margins and those similar to it, and nothing works. I am perfectly open to javascript solutions. Something weird however is that scroll margins would solve the issue but doesnt work when i use it. No matter how big of a margin, it seems to max out at a certain point.

How do you compress a user-uploaded a user-uploaded folder with client-side JS?

I am creating a basic page that uses the new CompressionStream API gzip compression features to take a user’s folder and compress it to a .gz with client-side JS.

Here’s an example of compression with gzip:

const compressedReadableStream = inputReadableStream.pipeThrough(
  new CompressionStream("gzip"),
);

In this example a function decompresses a blob using gzip:

async function DecompressBlob(blob) {
  const ds = new DecompressionStream("gzip");
  const decompressedStream = blob.stream().pipeThrough(ds);
  return await new Response(decompressedStream).blob();
}

I have gotten the compression and decompression working for file uploads, and even got it working for uploads of multiple files at once, but cannot get it to work for directories, which makes it pretty much useless.

I have tried creating the most basic setup possible, but have found that compressing a directory to a file just makes it a file, no longer a folder of files. This is my current setup:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>File Upload and Compression</title>
</head>
<body>

<input type="file" id="fileInput" multiple webkitdirectory>

<button onclick="groupAndCompress()">Group and Compress</button>

<script>
async function groupAndCompress() {
  const fileInput = document.getElementById('fileInput');
  const files = fileInput.files;

  if (files.length === 0) {
    alert('Please select at least one file or folder.');
    return;
  }

  const groupedFiles = groupFiles(files);
  const compressedBlob = await compressFiles(groupedFiles);

  // You can use the compressedBlob as needed (e.g., download or display)
  console.log('Compressed Blob:', compressedBlob);
}

function groupFiles(files) {
  const groupedFiles = {};

  for (const file of files) {
    const path = file.webkitRelativePath || file.name;

    if (!(path in groupedFiles)) {
      groupedFiles[path] = [];
    }

    groupedFiles[path].push(file);
  }

  return groupedFiles;
}

async function compressFiles(groupedFiles) {
  const compressedParts = [];

  for (const path in groupedFiles) {
    const files = groupedFiles[path];
    const blobs = await Promise.all(files.map(fileToBlob));
    const concatenatedBlob = new Blob(blobs, { type: 'application/zip' });

    const compressedStream = concatenatedBlob.stream().pipeThrough(new CompressionStream('gzip'));
    const compressedBlob = await new Response(compressedStream).blob();

    compressedParts.push(compressedBlob);
  }

  const finalBlob = new Blob(compressedParts, { type: 'application/zip' });
  return finalBlob;
}

function fileToBlob(file) {
  return new Promise((resolve) => {
    const reader = new FileReader();

    reader.onload = function () {
      resolve(new Blob([reader.result], { type: file.type }));
    };

    reader.readAsArrayBuffer(file);
  });
}
</script>

</body>
</html>

I am aware of JSzip, but built-in web features can perform this faster and don’t require fetching a script.