useQuery with initialData and soft and hard loading states

I have a query that uses initialData, populated by the backend within the document on page load. This way there is no loading state when the page loads. However, I also need to be able to put this query into a hard loading state, where it has no data and goes back to isLoading state.

On page load, initialData is authoritative. However once the query is put back into the hard loading state, initialData should not be used any more, so resetQueries doesn’t work.

useUser should do:

  • On page load, use initialData. Don’t background refresh because the data is known to be valid.
  • Background refreshes should use stale-while-revalidate behavior, use the previous data while refreshing
  • Be able to trigger a hard loading state where stale data is not used,
    the previous data is totally invalid.
function useUser() {
  // Preloaded data from the backend so we can immediately display the user on
  // page load.
  const userJson = JSON.parse(document.getElementById('user')?.textContent || 'null');
  return useQuery({
    queryKey: ['profile'],
    queryFn: async () => {
      const response = await fetch('/api/accounts/me/');
      return await response.json();
    },
    // initial data is fresh, no need to refresh immediately.
    initialData,
    // do background refreshes that don't trigger a hard loading state
    staleTime: 1000 * 60,
  });
}

// This is used somewhere far away from useUser, so there's no way to check the
// loading status of resetUserMutation in the components that use useUser.
function resetUserMutation() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async () => {
      await fetch('...');
      // Here, put useUser into hard loading state, not a background refresh.
      // The cached data in useUser is now totally invalid and should never be
      // used again. initialData should never be used again.
      queryClient.hypotheticalHardReload({ queryKey: ['profile'] });
    },
  });
}

function SomeComponent() {
  // useUser is used all over the code. resetUserMutation is not used here.
  const userQ = useUser();
  if (userQ is in hard loading state) {
    // we can't display anything but a loading indicator in this state
    return <div className="loading"></div>;
  } else {
    // we can display stuff during regular background refreshes
    return <div>{userQ.data.username}</div>;
  }
}

What use to create a custom Shap for a Card

Sometimes I scrolldown on the reels in instagram and see this type of complex shape in designs on Figma, I can do this on figma, but I want to know how I can create this shape in WebApp, with React (Note.: I dont want use a specific lib of React, I need do natively, like HTML,CSS and JS basics)

(I’m not asking anyone to do it for me — I just need some direction to start, because I don’t know how people usually do it.)

I want too, a way to do this reponsible.

CARD SHAPE

I dont need a big description about, only some direction of what is the common to use (like Svg or css or image or clip-path or canvas), because is harder for me do with svg, and I need to make sure this is the only way

Sync custom colors in Mapbox

I am working on a feature in my next.js 15 application in which users have to draw the area on the map with different tools and when user finishes drawing it adds the area stay on the map and also it adds a row of some elements in area list on the left side of the page. In the row i have a custom color picker with my own color pallette. I want when user finish drawing it adds the color to the drew area too and when user changes the color of a particular area it will change the color of the area on the map too.

Here is my code for the parent component and here i have that color picker rendering:

"use client";

import type React from "react";

import { useState, useMemo, useRef, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import {
  Check,
  MoreVertical,
  Pencil,
  Eye,
  Trash2,
  ArrowUpDown,
} from "lucide-react";
import CollectionAreaMap from "./collection-area-map";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import ColorPicker, { COLOR_PALETTE } from "./color-picker";

// Define the excluded color (grey with pattern)
const EXCLUDED_COLOR = { color: "#808080" };

interface CollectionArea {
  id: number;
  name: string;
  fee: string;
  enabled: boolean;
  color: string;
  featureId?: string; // Store the mapbox feature ID associated with this area
}

type SortDirection = "asc" | "desc" | null;
type SortField = "name" | "fee" | null;

export default function CollectionTerritoriesPage() {
  const [isEditMode, setIsEditMode] = useState(true);
  const [territoryName, setTerritoryName] = useState(
    "Matlock 30 miles Collection Territory"
  );
  const [territoryDescription, setTerritoryDescription] = useState("");
  const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
  const [areaToDelete, setAreaToDelete] = useState<CollectionArea | null>(null);
  const [sortField, setSortField] = useState<SortField>(null);
  const [sortDirection, setSortDirection] = useState<SortDirection>(null);
  const [focusedAreaId, setFocusedAreaId] = useState<number | null>(null);

  // Initialize with an empty collection areas array
  const [collectionAreas, setCollectionAreas] = useState<CollectionArea[]>([]);
  const nextIdRef = useRef(1);

  // Add this ref to store the deleteFeature function from the map component
  const deleteFeatureRef = useRef<((featureId: string) => void) | null>(null);

  // Sort the collection areas based on the current sort field and direction
  const sortedCollectionAreas = useMemo(() => {
    if (!sortField || !sortDirection) {
      return [...collectionAreas];
    }

    return [...collectionAreas].sort((a, b) => {
      if (sortField === "name") {
        return sortDirection === "asc"
          ? a.name.localeCompare(b.name)
          : b.name.localeCompare(a.name);
      } else if (sortField === "fee") {
        const feeA = Number.parseInt(a.fee) || 0;
        const feeB = Number.parseInt(b.fee) || 0;
        return sortDirection === "asc" ? feeA - feeB : feeB - feeA;
      }
      return 0;
    });
  }, [collectionAreas, sortField, sortDirection]);

  // Update nextIdRef whenever areas change
  useEffect(() => {
    if (collectionAreas.length > 0) {
      const maxId = Math.max(...collectionAreas.map((area) => area.id));
      nextIdRef.current = maxId + 1;
    } else {
      nextIdRef.current = 1;
    }
  }, [collectionAreas]);

  const toggleEditMode = () => {
    setIsEditMode(!isEditMode);
  };

  const toggleAreaEnabled = (id: number) => {
    setCollectionAreas(
      collectionAreas.map((area) =>
        area.id === id ? { ...area, enabled: !area.enabled } : area
      )
    );
  };

  const handleSort = (field: SortField) => {
    if (sortField === field) {
      // Toggle direction if same field
      setSortDirection(sortDirection === "asc" ? "desc" : "asc");
    } else {
      // Set new field and default to ascending
      setSortField(field);
      setSortDirection("asc");
    }
  };

  const updateAreaName = (id: number, name: string) => {
    // Check if name is unique
    const isDuplicate = collectionAreas.some(
      (area) => area.id !== id && area.name === name
    );

    if (isDuplicate) {
      alert("Area name must be unique within the territory");
      return;
    }

    setCollectionAreas(
      collectionAreas.map((area) => (area.id === id ? { ...area, name } : area))
    );
  };

  const updateAreaFee = (id: number, fee: string) => {
    // Validate fee (3-digit integer)
    if (fee !== "" && !/^d{1,3}$/.test(fee)) {
      return;
    }

    setCollectionAreas(
      collectionAreas.map((area) => (area.id === id ? { ...area, fee } : area))
    );
  };

  const updateAreaColor = (id: number, color: string) => {
    setCollectionAreas(
      collectionAreas.map((area) =>
        area.id === id ? { ...area, color } : area
      )
    );
  };

  const deleteArea = (area: CollectionArea) => {
    setAreaToDelete(area);
    setDeleteDialogOpen(true);
  };

  // Updated to delete from map as well
  const confirmDeleteArea = () => {
    if (areaToDelete) {
      // Get the feature ID associated with this area
      const featureId = areaToDelete.featureId;

      // Remove the area from the state
      setCollectionAreas(
        collectionAreas.filter((area) => area.id !== areaToDelete.id)
      );

      // If there's a feature ID and we have a delete function, delete it from the map
      if (featureId && deleteFeatureRef.current) {
        deleteFeatureRef.current(featureId);
      }

      setDeleteDialogOpen(false);
      setAreaToDelete(null);
    }
  };

  // Handler for when an area is drawn on the map
  const handleAreaDrawn = (feature: any) => {
    const nextId = nextIdRef.current;
    // Get a color from the palette based on the ID
    const nextColorIndex = nextId % COLOR_PALETTE.length;

    // Create a new area object
    const newArea: CollectionArea = {
      id: nextId,
      name: `Area ${nextId}`,
      fee: "",
      enabled: true,
      color: COLOR_PALETTE[nextColorIndex].color,
      featureId: feature.id, // Store the feature ID for reference
    };

    // Log for debugging
    console.log(`Adding new area with ID ${nextId}, featureId: ${feature.id}`);

    // Update the state with the new area
    setCollectionAreas((prev) => [...prev, newArea]);

    // Automatically focus the newly created area
    setFocusedAreaId(nextId);

    return newArea;
  };

  const focusArea = (id: number) => {
    setFocusedAreaId(id === focusedAreaId ? null : id);
  };

  return (
    <div className="container mx-auto p-4 h-screen flex flex-col">
      <div className="grid grid-cols-1 lg:grid-cols-3 gap-4 flex-grow">
        {/* Collection Areas Panel */}
        <div className="bg-white rounded-lg shadow-sm border p-4 overflow-auto lg:col-span-1">
          <div className="flex justify-between items-center mb-4">
            <h2 className="text-lg font-semibold">Collection Areas</h2>
            {/* "Add Area" button has been removed as requested */}
          </div>

          {collectionAreas.length === 0 ? (
            <div className="text-center py-8 text-gray-500">
              {isEditMode ? (
                <p>
                  No areas added yet. Draw an area on the map to add your first
                  collection area.
                </p>
              ) : (
                <p>No collection areas defined.</p>
              )}
            </div>
          ) : (
            <>
              <div className="grid grid-cols-[auto_1fr_auto_auto] gap-2 items-center mb-2 px-2">
                <div className="font-medium text-sm text-gray-600"></div>
                <div
                  className="font-medium text-sm text-gray-600 flex items-center cursor-pointer"
                  onClick={() => handleSort("name")}
                >
                  Name
                  <ArrowUpDown
                    className={`ml-1 h-3 w-3 ${
                      sortField === "name" ? "opacity-100" : "opacity-50"
                    }`}
                  />
                </div>
                <div
                  className="font-medium text-sm text-gray-600 text-right flex items-center justify-end cursor-pointer"
                  onClick={() => handleSort("fee")}
                >
                  Fee
                  <ArrowUpDown
                    className={`ml-1 h-3 w-3 ${
                      sortField === "fee" ? "opacity-100" : "opacity-50"
                    }`}
                  />
                </div>
                <div className="font-medium text-sm text-gray-600 text-center">
                  Enable
                </div>
                <div></div>
              </div>

              <div className="space-y-2">
                {sortedCollectionAreas.map((area) => (
                  <div
                    key={area.id}
                    className={`grid grid-cols-[auto_1fr_auto_auto] gap-2 items-center border-b pb-2 ${
                      focusedAreaId === area.id ? "bg-gray-100" : ""
                    }`}
                  >
                    <div className="flex items-center">
                      {isEditMode ? (
                        <Popover>
                          <PopoverTrigger asChild>
                            <div
                              className="w-4 h-4 rounded-sm cursor-pointer"
                              style={{
                                backgroundColor: area.enabled
                                  ? area.color
                                  : EXCLUDED_COLOR.color,
                              }}
                            ></div>
                          </PopoverTrigger>
                          <PopoverContent className="p-0 w-[450px]">
                            <ColorPicker
                              color={area.color}
                              onChange={(color) =>
                                updateAreaColor(area.id, color)
                              }
                              disabled={!area.enabled}
                            />
                          </PopoverContent>
                        </Popover>
                      ) : (
                        <div
                          className="w-4 h-4 rounded-sm"
                          style={{
                            backgroundColor: area.enabled
                              ? area.color
                              : EXCLUDED_COLOR.color,
                          }}
                        ></div>
                      )}
                    </div>

                    <div>
                      {isEditMode ? (
                        <Input
                          value={area.name}
                          onChange={(e) =>
                            updateAreaName(area.id, e.target.value)
                          }
                          className="h-8 text-sm"
                          maxLength={20}
                          disabled={!area.enabled}
                        />
                      ) : (
                        <span>{area.name}</span>
                      )}
                    </div>

                    <div className="text-right">
                      {isEditMode ? (
                        area.enabled ? (
                          <Input
                            value={area.fee}
                            onChange={(e) =>
                              updateAreaFee(area.id, e.target.value)
                            }
                            className="h-8 text-sm w-20"
                            placeholder="0"
                          />
                        ) : null
                      ) : area.enabled ? (
                        `£${area.fee}`
                      ) : (
                        "Excluded"
                      )}
                    </div>

                    <div className="flex items-center gap-2">
                      <Switch
                        checked={area.enabled}
                        onCheckedChange={() => toggleAreaEnabled(area.id)}
                        className="data-[state=checked]:bg-blue-500"
                        disabled={!isEditMode}
                      />

                      <DropdownMenu>
                        <DropdownMenuTrigger asChild>
                          <Button
                            variant="ghost"
                            size="icon"
                            className="h-8 w-8"
                          >
                            <MoreVertical className="h-4 w-4" />
                          </Button>
                        </DropdownMenuTrigger>
                        <DropdownMenuContent align="end">
                          <DropdownMenuItem onClick={() => focusArea(area.id)}>
                            <Eye className="mr-2 h-4 w-4" />
                            Focus
                          </DropdownMenuItem>
                          {isEditMode && (
                            <DropdownMenuItem
                              onClick={() => deleteArea(area)}
                              className="text-red-600"
                            >
                              <Trash2 className="mr-2 h-4 w-4" />
                              Delete
                            </DropdownMenuItem>
                          )}
                        </DropdownMenuContent>
                      </DropdownMenu>
                    </div>
                  </div>
                ))}
              </div>
            </>
          )}

          {/* Collection Territory Info (only visible in edit mode) */}
          {isEditMode && (
            <div className="mt-6 border-t pt-4">
              <h2 className="text-lg font-semibold mb-4">
                Collection Territory Info
              </h2>
              <div className="space-y-4">
                <div className="space-y-2">
                  <Label htmlFor="territory-name">Name</Label>
                  <Input
                    id="territory-name"
                    value={territoryName}
                    onChange={(e) => setTerritoryName(e.target.value)}
                    maxLength={30}
                  />
                </div>
                <div className="space-y-2">
                  <Label htmlFor="territory-description">Description</Label>
                  <Input
                    id="territory-description"
                    value={territoryDescription}
                    onChange={(e) => setTerritoryDescription(e.target.value)}
                    maxLength={200}
                  />
                </div>
              </div>
            </div>
          )}
        </div>

        {/* Map Container */}
        <div className="lg:col-span-2 h-full" style={{ minHeight: "600px" }}>
          <CollectionAreaMap
            areas={collectionAreas}
            focusedAreaId={focusedAreaId}
            onAreaDrawn={handleAreaDrawn}
            onAreaDeleted={(deleteFeatureFunction) => {
              // Store the delete function from the map component
              deleteFeatureRef.current = deleteFeatureFunction;
            }}
          />
        </div>
      </div>

      {/* Floating Button */}
      <div className="fixed bottom-4 right-4">
        <Button
          onClick={toggleEditMode}
          className="bg-blue-500 hover:bg-blue-600 text-white"
        >
          {isEditMode ? (
            <>
              <Check className="mr-2 h-4 w-4" />
              Done editing
            </>
          ) : (
            <>
              <Pencil className="mr-2 h-4 w-4" />
              Edit
            </>
          )}
        </Button>
      </div>

      {/* Delete Confirmation Dialog */}
      <Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Delete Area</DialogTitle>
            <DialogDescription>
              Are you sure you want to delete {areaToDelete?.name}?
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button
              variant="outline"
              onClick={() => setDeleteDialogOpen(false)}
            >
              Cancel
            </Button>
            <Button variant="destructive" onClick={confirmDeleteArea}>
              Delete
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}


I tried different approaches but couldn’t able to resolve this issue in syncing these colors. If anyone knows how to fix that just guide me and i will implement it myself. I can’t add the AreaMap component due to characters limit.

How to access contents of node in QuillJS?

I’m trying to add an id tag to each header (h1, h2, h3) for my Quill editor so I can link to specific sections of my page.

I have the following code which is working for adding the ID tag:

const Header = Quill.import("formats/header");

class EnhancedHeader extends Header {
  static blotName = "header";
  static create(value) {
    const node = super.create(value);
    const id = `header-123`;
    console.log(node.innerHTML);
    console.log(node.innerText);
    node.setAttribute("id", id);
    return node;
  }
}

Quill.register(EnhancedHeader);

const quill = new Quill('#editor', {
  modules: {
    toolbar: [
      [{ header: [1, 2, false] }],
      ['bold', 'italic', 'underline'],
      ['image', 'code-block'],
    ],
  },
  placeholder: 'Compose an epic...',
  theme: 'snow', // or 'bubble'
});

Playgound Example

How can I access the contents of the selected text in the create function? I need this so I can make a “slug” of the heading to use in the ID.

I’ve tried the following which return a blank string:

node.innerHTML
node.innerText

isPrototypeOf({}) in devtools console will throw TypeError

Open devtools, paste isPrototypeOf({}); into console, run the code and you will get:

Uncaught TypeError: Cannot convert undefined or null to object

I think the error message tells us: this in isPrototypeOf is undefined. But why? why doesn’t this substitution take place in this situation? Why is this not window?

Why isn’t my recorded audio being sent to OpenAI’s Whisper API for transcription in my Wix Velo integration?

Context / What I’m trying to do

I’m building a chat interface on Wix using a custom web component and an iframe for the chat UI. The idea is:

  1. User clicks “Record” in the iframe → message sent to parent page (since Wix doesnot allow iframe to do the recording)

  2. Parent page tells to start/stop recording via an action attribute

  3. Recorder captures WebM audio

  4. converts it to MP3 with lamejs, and exposes a Base64 data-URL

  5. User clicks “Upload” in the recorder → Base64 audio is postMessage-ed back to parent

(I upload the MP3 to CMS only to get a public URL; this isn’t actually needed for storage, it’s just to generate a URL. This attempt also did not work)

  1. Parent page calls my backend transcribeAudioFromUrl(publicUrl) (which hits OpenAI’s Whisper API)

  2. Transcript is injected back into the chat iframe input and sent off to the Chat API

Steps 1–3 seem to work (I see a public MP3 URL and can play it back), but the transcription never happens.

Relevant code

  1. Frontend listener in Wix page code
// in $w.onReady(...)
globalThis.addEventListener("message", async (event) => {
  const { type, audio } = event.data || {};

  if (type === "audioMessage" && audio) {
    try {
      // 1) Upload Base64 → Wix Media (only to get a public URL)
      const fileUrl   = await uploadAudioFromBase64(audio);
      const publicUrl = await getDownloadUrl(fileUrl);

      // 2) Show user audio in chat
      $w("#chatFrame").postMessage({ name: "User", audio: publicUrl });

      // 3) Transcribe via Whisper
      const transcript = await transcribeAudioFromUrl(publicUrl);

      // 4) Inject transcript and ask AI
      $w("#chatFrame").postMessage({ type: "setInputField", text: transcript });
      const reply = await getAnswerFromAI(transcript);
      $w("#chatFrame").postMessage({ name: "OpenAI", text: reply });
    } catch (err) {
      console.error("Upload or transcription error:", err);
      $w("#chatFrame").postMessage({
        name: "OpenAI",
        text: "❌"
      });
    }
  }
});
  1. Wix backend
import { webMethod, Permissions } from 'wix-web-module';
import { getSecret } from 'wix-secrets-backend';
import axios from 'axios';
const FormData = require('form-data');

// Helper: convert wix:document URL → public HTTPS URL
async function ensurePublicUrl(url) {
  if (/^wix:document:///.test(url)) {
    return await mediaManager.getDownloadUrl(url);
  }
  return url;
}

// Send binary buffer → Whisper API
async function whisperTranscription(buffer, mimeType) {
  const apiKey = await getSecret('OPENAI-API-KEY');
  const form = new FormData();
  form.append('file', buffer, { filename: 'recording', contentType: mimeType });
  form.append('model', 'whisper-1');
  form.append('response_format', 'text');
  const { data } = await axios.post(
    'https://api.openai.com/v1/audio/transcriptions',
    form,
    { headers: { ...form.getHeaders(), Authorization: `Bearer ${apiKey}` } }
  );
  return data;
}

export const transcribeAudioFromUrl = webMethod(Permissions.Anyone, async (url) => {
  const publicUrl = await ensurePublicUrl(url);
  const res = await axios.get(publicUrl, { responseType: 'arraybuffer' });
  return whisperTranscription(Buffer.from(res.data), 'audio/mp3');
});
</details>
  1. Recorder Costum Element
async handleStop() {
    const blob = new Blob(this.audioChunks, { type: 'audio/webm' });
    const arrayBuffer = await blob.arrayBuffer();
    const mp3Blob = await this.convertToMp3(arrayBuffer);
    this.lastMp3Blob = mp3Blob;

    // show preview + enable upload…
    this.uploadBtn.disabled = false;
  }

  uploadRecording() {
    if (!this.lastMp3Blob) return;
    const reader = new FileReader();
    reader.onloadend = () => {
      const base64 = reader.result;
      window.parent.postMessage({ type: 'audioMessage', audio: base64 }, '*');
      this.uploadBtn.textContent = '✅ Uploaded!';
      this.uploadBtn.disabled = true;
    };
    reader.readAsDataURL(this.lastMp3Blob);
  }

  // … convertToMp3() & floatTo16BitPCM() using lamejs …
}

If more details needed just let me know.

Error regarding Expo go on my Android Device linked to a react native project in visual studio

i started a new react native project on visual studio and downloaded Expo go in my android device
When i initialized the app through npx expo start it bundled perfectly for the first time on
the expo go
but then when i deleted the default index.js and App.js file and installed expo router and created an app folder with an index.jsx file in the project directory changed the entry point in package.json to
“main”: “expo-router/entry” and added scheme in app.json
the app is getting bundled in terminal
Android Bundled 1662ms node_modulesexpo-routerentry.js (1029 modules)
but it is giving an error on expo go
which is:
exception thrown when executing UIframeGuarded

attempt to invoke interface method ‘void com.facebook.react.uimanager.ViewManagerDelegate.setProperty(android.view.View,java.lang.String,java.lang.object) on a null object reference

i have made a simple todo app through same method just a week before it worked fine but now
this is giving an error at beginning only
please if anyone can help

I am having collision problems with a map glb file in three.js

I have a map glb file. I’ve taken the skeld map from Among Us for walking around in and for some reason I can’t collide with it properly. For example I can’t walk on the floor, only on the ceiling plane.

My best guess is that the floor collision mesh is offset vertically but even after fixing it it doesn’t work. I’d love some help.

I’m new to three.js and javascript in general so a lot of it is vibe coding so please forgive me if the answer is obvious. Here’s my main.js file:

import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls.js';
import * as CANNON from 'cannon-es';

const PLAYER_RADIUS = 1;
const MOVE_SPEED = 10;
const SCALE_FACTOR = 20;
const JUMP_FORCE = 10;

let canJump = true;

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x222222);

const camera = new THREE.PerspectiveCamera(
  75, window.innerWidth / window.innerHeight, 0.1, 1000
);
camera.position.set(0, PLAYER_RADIUS, 0);

const renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);

scene.add(new THREE.HemisphereLight(0xffffff, 0x444444, 0.6));
const dir = new THREE.DirectionalLight(0xffffff, 0.8);
dir.position.set(5, 10, 7.5);
dir.castShadow = true;
scene.add(dir);

const world = new CANNON.World({
  gravity: new CANNON.Vec3(0, -9.82, 0)
});
world.broadphase = new CANNON.NaiveBroadphase();
world.solver.iterations = 20;
world.solver.tolerance = 0.001;

const playerBody = new CANNON.Body({
  mass: 1,
  fixedRotation: true,
  linearDamping: 0.9
});
playerBody.addShape(new CANNON.Sphere(PLAYER_RADIUS));
world.addBody(playerBody);

const controls = new PointerLockControls(camera, renderer.domElement);
scene.add(controls.getObject());
const blocker = document.getElementById('blocker');
blocker.addEventListener('click', () => controls.lock());
controls.addEventListener('lock', () => blocker.style.display = 'none');
controls.addEventListener('unlock', () => blocker.style.display = '');

const move = {
  forward: 0,
  back: 0,
  left: 0,
  right: 0
};
window.addEventListener('keydown', e => {
  if (e.code === 'KeyW') move.forward = 1;
  if (e.code === 'KeyS') move.back = 1;
  if (e.code === 'KeyA') move.left = 1;
  if (e.code === 'KeyD') move.right = 1;
  if (e.code === 'Space' && canJump) {
    playerBody.velocity.y = JUMP_FORCE;
    canJump = false;
  }
});
window.addEventListener('keyup', e => {
  if (e.code === 'KeyW') move.forward = 0;
  if (e.code === 'KeyS') move.back = 0;
  if (e.code === 'KeyA') move.left = 0;
  if (e.code === 'KeyD') move.right = 0;
});

const groundRay = new CANNON.Ray(
  new CANNON.Vec3(),
  new CANNON.Vec3(0, -1, 0)
);
groundRay.mode = CANNON.Ray.CLOSEST;
groundRay.skipBackfaces = true;

new GLTFLoader().load(
  'amongusSkeld.glb',
  ({
    scene: map
  }) => {
    map.scale.set(SCALE_FACTOR, SCALE_FACTOR, SCALE_FACTOR);
    map.updateMatrixWorld(true);
    scene.add(map);

    const vertices = [];
    const indices = [];
    let vOff = 0;

    map.traverse(node => {
      if (!node.isMesh) return;
      const geom = node.geometry.clone();
      geom.applyMatrix4(node.matrixWorld);
      const pa = geom.attributes.position;
      for (let i = 0; i < pa.count; i++) {
        vertices.push(pa.getX(i), pa.getY(i), pa.getZ(i));
      }
      if (geom.index) {
        const ix = geom.index;
        for (let i = 0; i < ix.count; i += 3) {
          indices.push(
            ix.getX(i) + vOff,
            ix.getX(i + 1) + vOff,
            ix.getX(i + 2) + vOff
          );
        }
      } else {
        for (let i = 0; i < pa.count; i += 3) {
          indices.push(vOff + i, vOff + i + 1, vOff + i + 2);
        }
      }
      vOff += pa.count;
    });
    console.log(`Merged collision mesh: ${vertices.length/3} verts, ${indices.length/3} tris`);

    const triShape = new CANNON.Trimesh(vertices, indices);
    const mapBody = new CANNON.Body({
      mass: 0
    });
    mapBody.addShape(triShape);
    world.addBody(mapBody);

    const colGeom = new THREE.BufferGeometry();
    colGeom.setAttribute('position',
      new THREE.BufferAttribute(new Float32Array(vertices), 3)
    );
    colGeom.setIndex(indices);
    const colMat = new THREE.MeshBasicMaterial({
      color: 0xff0000,
      wireframe: true,
      transparent: true,
      opacity: 0.5
    });
    const colMesh = new THREE.Mesh(colGeom, colMat);
    scene.add(colMesh);

    const bbox = new THREE.Box3().setFromObject(map);
    const {
      min,
      max
    } = bbox;
    const center = bbox.getCenter(new THREE.Vector3());

    const rayFrom = new CANNON.Vec3(center.x, max.y + SCALE_FACTOR, center.z);
    const rayTo = new CANNON.Vec3(center.x, min.y - SCALE_FACTOR, center.z);
    const ray = new CANNON.Ray(rayFrom, rayTo);
    const result = new CANNON.RaycastResult();

    ray.intersectWorld(
      world, {
        mode: CANNON.Ray.CLOSEST,
        skipBackfaces: true
      },
      result
    );

    const spawnY = result.hasHit ?
      result.hitPointWorld.y + PLAYER_RADIUS + 0.1 :
      max.y + PLAYER_RADIUS + 0.1;

    playerBody.position.set(center.x, spawnY, center.z);
    controls.getObject().position.set(center.x, spawnY, center.z);
    console.log(`Spawn at Y=${spawnY.toFixed(2)}, hit at Y=${result.hasHit ? result.hitPointWorld.y.toFixed(2) : 'none'}`);
  },
  xhr => console.log(`Loading map: ${(xhr.loaded/xhr.total*100).toFixed(1)}%`),
  err => console.error('Map load error:', err)
);

const clock = new THREE.Clock();
const FIXED_DT = 1 / 60;
const euler = new THREE.Euler(0, 0, 0, 'YXZ');
const quat = new THREE.Quaternion();

function animate() {
  requestAnimationFrame(animate);
  const dt = clock.getDelta();

  groundRay.from.copy(playerBody.position);
  groundRay.to.copy(playerBody.position);
  groundRay.to.y -= PLAYER_RADIUS + 0.1;
  const result = new CANNON.RaycastResult();
  groundRay.intersectWorld(world, {}, result);
  canJump = result.hasHit && result.distance < PLAYER_RADIUS + 0.1;

  if (controls.isLocked) {
    const forward = new THREE.Vector3();
    camera.getWorldDirection(forward);
    forward.y = 0;
    forward.normalize();

    const rightDir = new THREE.Vector3();
    rightDir.crossVectors(forward, new THREE.Vector3(0, 1, 0)).normalize();

    const moveDir = new THREE.Vector3();
    moveDir.addScaledVector(forward, move.forward - move.back);
    moveDir.addScaledVector(rightDir, move.right - move.left);

    if (moveDir.lengthSq() > 0) {
      moveDir.normalize().multiplyScalar(MOVE_SPEED);
      playerBody.velocity.x = moveDir.x;
      playerBody.velocity.z = moveDir.z;
    }

    controls.getObject().position.copy(playerBody.position);
  }

  world.step(FIXED_DT, dt, 10);
  renderer.render(scene, camera);
}
animate();

window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});

[vite]: Rollup failed to resolve import “cloudflare:sockets” from “/home/runner/work/texhub-web/texhub-web/node_modules/pg-cloudflare/dist/index.js”

Today when I want to build the project, shows error:

[plugin:vite:resolve] [plugin vite:resolve] Module "fs" has been externalized for browser compatibility, imported by "/home/runner/work/texhub-web/texhub-web/node_modules/pg-connection-string/index.js". See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.
[plugin:vite:resolve] [plugin vite:resolve] Module "stream" has been externalized for browser compatibility, imported by "/home/runner/work/texhub-web/texhub-web/node_modules/split2/index.js". See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.
✓ 3117 modules transformed.
x Build failed in 10.41s
error during build:
[vite]: Rollup failed to resolve import "cloudflare:sockets" from "/home/runner/work/texhub-web/texhub-web/node_modules/pg-cloudflare/dist/index.js".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
    at viteWarn (file:///home/runner/work/texhub-web/texhub-web/node_modules/vite/dist/node/chunks/dep-C6uTJdX2.js:65839:17)
    at onwarn (file:///home/runner/work/texhub-web/texhub-web/node_modules/@vitejs/plugin-react/dist/index.mjs:102:9)
    at onRollupWarning (file:///home/runner/work/texhub-web/texhub-web/node_modules/vite/dist/node/chunks/dep-C6uTJdX2.js:65869:5)
    at onwarn (file:///home/runner/work/texhub-web/texhub-web/node_modules/vite/dist/node/chunks/dep-C6uTJdX2.js:65534:7)
    at file:///home/runner/work/texhub-web/texhub-web/node_modules/rollup/dist/es/shared/node-entry.js:20723:13
    at Object.logger [as onLog] (file:///home/runner/work/texhub-web/texhub-web/node_modules/rollup/dist/es/shared/node-entry.js:22588:9)
    at ModuleLoader.handleInvalidResolvedId (file:///home/runner/work/texhub-web/texhub-web/node_modules/rollup/dist/es/shared/node-entry.js:21335:26)
    at ModuleLoader.resolveDynamicImport (file:///home/runner/work/texhub-web/texhub-web/node_modules/rollup/dist/es/shared/node-entry.js:21393:58)
    at async file:///home/runner/work/texhub-web/texhub-web/node_modules/rollup/dist/es/shared/node-entry.js:21281:32
    at async Promise.all (index 4)
Error: Process completed with exit code 1.

then I use this command to check the dependencies:

➜  texhub-web git:(main) pnpm list pg-cloudflare --depth=Infinity

Legend: production dependency, optional only, dev only

[email protected] /Users/xiaoqiangjiang/source/reddwarf/frontend/texhub-web (PRIVATE)

dependencies:
texhub-broadcast 1.0.69
└─┬ pg 8.15.6
  └── pg-cloudflare 1.2.5

then I added the exclude config in vite.config.mts like this:

build: {
    outDir: "build",
    sourcemap: "hidden",
    rollupOptions: {
      output: {
        sourcemapExcludeSources: false,
        manualChunks: {
          react: ["react", "react-router-dom", "react-dom"],
          reddwarf: ["rd-component", "rdjs-wheel"],
        },
      },
      // https://github.com/brianc/node-postgres/issues/2987
      external: ["pg-cloudflare"],
    },
  }

shows error like this:

Uncaught TypeError: The specifier “pg-cloudflare” was a bare specifier, but was not remapped to anything. Relative module specifiers must start with “./”, “../” or “/”.

why did this happend? what should I do to fixed this problem?

When i use position “fixed” image disappears

hello everyone i have an issue. I`m working on tailwind when i use fixed img disappears can anyone explain why ?!

<div style="backdrop-filter: blur(10px);" class="p-3 w-full border-b fixed border-[#E4E4E7]">
  <div class="flex justify-between mx-3">
    <div class="p-2 rounded-xl bg-[#564DE6] transition-all duration-50">
      <button class="text-white">
        Add new 
      </button>
    </div>
    <div class="border z-50 border-[#bebec3] rounded-[50%] flex cursor-pointer">
      <img class="p-1" width="38" src="img/smart.png" alt="Logo" />
    </div>
  </div>
</div>

Twitter / X – upload media via v2 endpoints

twitter deprecated command parameter soon. Launching separate endpoints for each command rather. I am working on Javascript

Source: https://docs.x.com/x-api/media/media-upload-initialize

My code fails at Finalize step – stating total file size does not match.
Following is code for APPEND

        var media_id = result.data.id;    
        var url = 'https://api.x.com/2/media/upload/' + media_id + '/append';
        var chunkSize = 5*1000*1000  
        var chunkCount = Math.ceil(totalSize / chunkSize);  
        var boundary = '011000010111000001101001'
         
    
        for (var segmentIndex = 0; segmentIndex < chunkCount; segmentIndex++) {
            
            var startByte = segmentIndex * chunkSize;
            var endByte = Math.min(startByte + chunkSize, totalSize);
            var chunkBytes = videoBlob.getBytes().slice(startByte, endByte); 
    
            var part1 = "--" + boundary + 'rnContent-Disposition: form-data; name="segment_index"rnrn';
            var part2 = "--" + boundary + 'rnContent-Disposition: form-data; name="media"; filename="CHUNK.mp4"rnContent-Type: video/mp4rnrn';
            var part3 = "rn--" + boundary + "--";
    
            // Convert string parts to bytes
            var part1Bytes = Utilities.newBlob(part1).getBytes();
            var segmentIndexBytes = Utilities.newBlob(String(segmentIndex + 1) + "rn").getBytes();
            var part2Bytes = Utilities.newBlob(part2).getBytes();
            var part3Bytes = Utilities.newBlob(part3).getBytes();
    
            var totalLength = part1Bytes.length + segmentIndexBytes.length + part2Bytes.length + chunkBytes.length + part3Bytes.length;
            var fullBody = new Uint8Array(totalLength);
    
            fullBody.set(part1Bytes, 0);
            fullBody.set(segmentIndexBytes, part1Bytes.length);
            fullBody.set(part2Bytes, part1Bytes.length + segmentIndexBytes.length);
            fullBody.set(chunkBytes, part1Bytes.length + segmentIndexBytes.length + part2Bytes.length);
            fullBody.set(part3Bytes, part1Bytes.length + segmentIndexBytes.length + part2Bytes.length + chunkBytes.length);
            
            
            var parameters = {
              'headers': {
                'Authorization': 'Bearer ' + serviceTw.getAccessToken(),
                'Content-Type': 'multipart/form-data; boundary=' + boundary ,
              },
              'payload': fullBody,
              'method': 'POST',
            };
             
              var response = UrlFetchApp.fetch(url, parameters);
    }

Any idea why its failing? although logging the byte counts , everything matches exactly

Dynamically Populating Chrome Context Menu Items via Extension

I’m building a Chrome extension with the Plasmo and Supabase, where I fetch data from whenever the browser’s context menu is opened, using a broadcasted contextmenu event. I aim to dynamically update context menu items (child elements) with the fetched data.

The problem is that on the first right-click, the context menu shows the correct number of child items, but their titles reflect outdated data (e.g., from a previous fetch or initial state). Only on the second context menu open do the titles update correctly with the latest data.

How can I ensure that the context menu items are updated with fresh data immediately on the first open? I was trying different approaches without any luck so far.

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.type === 'refresh-context-menu') {
    chrome.contextMenus.removeAll(() => {
    fetchUserLinks().then(links => {
        chrome.contextMenus.create({
          id: "context-menu",
          title: "ExtensionName",
          contexts: ["editable"]
        }, () => {
          chrome.contextMenus.create({
            id: "my-links",
            parentId: "context-menu",
            title: "My Links",
            contexts: ["editable"]
          }, () => {
            links.forEach((link, index) => {
              chrome.contextMenus.create({
                id: `link-${index}`,
                parentId: "my-links",
                title: link.short_name,
                contexts: ["editable"]
              })
            })
          })
        })
      })
    })
  }
})

Dropdown copying same value in other dropdown due to unique key

I have two dropdowns. Each one is rendering dynamically based on number of rows. Lets say two rows here. The issue is when I select one dropdown then same value is getting copied to other dropdown. I think this is due to same key but how do I make this work as same key is used to fetch value from static.json file. Thanks in advance.

const IdTypes = [
{
    label: 'Identifications Type',
    key: 'typeCd',
    options: [] as string[],
    type: 'select',
},

]

const rows = ['0001', '0002']


    {rows.map((seq, index) => (
<Grid container spacing={1}>
{IdTypes.map((field) => {
      { field.options = [] }
   {
      getDropdownData(jsonData, 'typeCd').map(item => {
           field.options?.push(item.cd + ' - ' + item.desc)
     })
   }
   return (
   <Grid item key={index}>
     {renderField(field)}
   </Grid>
  )
 })}
</Grid>
)}

const renderField = (field: any) => {
   const { label, type, key, options } = field
    if (type === 'select') {
     return (
      <Controller
          name={key}
          control={control}
          render={({ field }) => (
          <FormControl size='small' fullWidth>
          <InputLabel>{label}</InputLabel>
          <Select {...field} label={label}>
          {(options || []).map((option: string, index: any) => (
          <MenuItem key={index} value={option.split('-')[0].trim()}>
             {option}
          </MenuItem>
          ))}
         </Select>
     </FormControl>
     )}
     />
     )
}

getDropdownData is a utility that gives description based on the key we pass.

How to encrypt form-data fields using node-forge before sending to API?

I’m working on a signup API where I’m using form-data to send user data (name, email, password, profile picture etc.).I am using NextJs on the client side. On the server side, I’m using node-forge for encryption and decryption.

I want to encrypt payload on the client-side using node-forge before sending them to the server.

I’m using Node.js on the backend and consuming the API from a frontend web app.

What is the proper way to implement support for N shadowmaps in webGPU renderer?

I`m making a basic forward renderer in webGPU, that supports multiple types of light sources and shadowmapping. When I was figuring out the shadowmapping part, I bound shadowmaps to shadowpass, wrote depth values to them and then read those values in the render pass. Everything worked fine, but I had a hardcoded amount of lights (1 of each type).

Now I want to be able to add and remove lights at runtime, but can not figure out how. The algorithm i am trying now is for each light type (point, directional, spot), take spotlights for example:

  1. Bind a texture_depth_2d_array as depth texture to the spotlights shadow pass.
        const depthTextureSpot = this._device.createTexture({
            dimension: '2d',
            size: [512, 512, scene.spotLights.length || 1],
            format: 'depth32float',
            usage:
                GPUTextureUsage.TEXTURE_BINDING |
                GPUTextureUsage.COPY_DST |
                GPUTextureUsage.RENDER_ATTACHMENT,
        })

        const depthTextureSpotView = depthTextureSpot.createView({
            dimension: '2d-array',
        })

        const spotLightShadowPass = commandEncoder.beginRenderPass({
            colorAttachments: [],
            depthStencilAttachment: {
                view: depthTextureSpotView,
                depthClearValue: 1.0,
                depthLoadOp: 'clear',
                depthStoreOp: 'store',
            },
        })
  1. Calculate depth values from each light’s pov and store them in the corresponding “texture” in texture_depth_2d_array, so i have shadowmaps for all lights of this type (this code doesn’t work).
@vertex
fn vertex_main(vert: VertexInput) -> @builtin(position) vec4f {

    for (var i = 0u; i < arrayLength(&pointLightsBuffer.lights); i++) {
        let light_view_projection_matrix = 
            pointLightsBuffer.lights[i].light_projection_matrix * pointLightsBuffer.lights[i].light_view_matrix;

        return light_view_projection_matrix * node_params.transform * float4(vert.position, 1.0);
    };
    return float4(vert.position, 1.0);
};
  1. Pass the resulting texture_depth_2d_array to render pass and read depth values to calculate final color.

I am facing a problem in step 2, because there seems to be no way to write depth values to an arbitrary place in texture_depth_2d_array. Or if there is, i can’t figure it out. As far as i understand, the only type of texture to allow it is texture_storage_2d_array, but then there`s a problem of where do i get depth values from.

All the tutorials and papers I’ve read online so far, deal with a predefined amount of lights and have a separate render pass for each individual light.

The actual question is: is my approach even viable? If it is, then how to overcome obstacles described above? And if it isn’t (which is the case, most likely), what is the standard approach to rendering N lights with shadowmaps in webGPU?