OpenCascade.js setup

I’m trying to set up OpenCascade.js in a project using Vite, Three.js, and Vue.js, but I’m having trouble getting it to work. Has anyone successfully integrated OpenCascade.js in this kind of setup? Any help or guidance would be greatly appreciated!

How to separate left and right audio channels from microphone?

How can I use JS to separate the left and right channels of audio from a microphone and process them individually?
I try these codes,but not work:

const audioContext = new(window.AudioContext || window.webkitAudioContext)();
const source = audioContext.createMediaStreamSource(stream);

// 创建分析器
const analyser = audioContext.createAnalyser();
analyser.fftSize = 2048;
source.connect(analyser);

// 创建分离声道的处理器
const splitter = audioContext.createChannelSplitter(2);
source.connect(splitter);

// 创建两个分析器,分别用于左右声道
const leftAnalyser = audioContext.createAnalyser();
const rightAnalyser = audioContext.createAnalyser();

Rerender after initial click

I have a popover-size selection in my Shopify shop, but after opening the popover for the first time and selecting a size, I experience an unsightly rerender. This issue only occurs on Android when I first open the page, after that it works fine. When I close and reopen the tab, it happens again.

{%- assign color_label_list = 'general.label.color' | t | replace: ', ', ',' | downcase | split: ',' -%}
{%- assign size_label_list = 'general.label.size' | t | replace: ', ', ',' | downcase | split: ',' -%}
{%- assign variant_image_options = block.settings.variant_image_options | replace: ', ', ',' | downcase | split: ',' -%}

{{ 'variant-picker-custom.css' | asset_url | stylesheet_tag }}

<script>
  function selectVariant(optionValueId, element, event) {
    // Prevent default behavior and stop propagation
    if (event) {
      event.preventDefault();
      event.stopPropagation();
    }

    // Find the radio input and check it
    const radioInput = document.querySelector(`input[value="${optionValueId}"]`);
    
    if (radioInput) {
      radioInput.checked = true;
      
      // Get the form
      const form = document.getElementById('{{ form_id }}');
      if (form) {
        // Get all the checked option inputs
        const checkedOptions = Array.from(form.elements)
          .filter(item => item.matches('input[data-option-position]:checked'))
          .sort((a, b) => parseInt(a.getAttribute('data-option-position')) - parseInt(b.getAttribute('data-option-position')));
        
        // Get the variant picker component
        const variantPicker = document.querySelector('variant-picker');
        if (variantPicker) {
          const optionValues = checkedOptions.map(input => input.value);
          
          // Trigger the variant picker's selectCombination method which will handle everything
          variantPicker.selectCombination({
            optionValues,
            productChange: false
          });
        }
        
        // Update add to cart button state in the drawer
        const drawer = element.closest('x-drawer');
        if (drawer) {
          const drawerSubmitButton = drawer.querySelector('[slot="footer"] button[type="submit"]');
          if (drawerSubmitButton) {
            const isAvailable = !element.classList.contains('is-disabled');
            drawerSubmitButton.disabled = !isAvailable;
          }
        }
      }
      
      // Update selected state styling for options within the same drawer
      const drawer = element.closest('x-drawer');
      if (drawer) {
        const allOptions = drawer.querySelectorAll('.variant-grid__option');
        allOptions.forEach(opt => {
          opt.classList.remove('is-selected');
        });
        element.classList.add('is-selected');
      }
    }
  }
</script>

{%- unless product.has_only_default_variant -%}
  <variant-picker class="variant-picker" section-id="{{ section.id }}" handle="{{ product.handle }}" form-id="{{ form_id }}" {% if update_url %}update-url{% endif %}>
    {%- comment -%}
    The variant data is outputted as a JSON, which allows the theme to emit an event with the data when the variant changes. This must not be removed.
    {%- endcomment -%}
    <script data-variant type="application/json">
      {{- product.selected_or_first_available_variant | json -}}
    </script>

    {%- for option in product.options_with_values -%}
      {% liquid
        assign option_downcase = option.name | downcase
        assign resolved_option_selector_style = block.settings.selector_style

        # Create a map of option values to their fast shipping status
        assign fast_shipping_values = ''
        for variant in product.variants
          if variant.inventory_management == 'shopify'
            assign option_position = option.position | minus: 1
            assign variant_option_value = variant.options[option_position]
            assign fast_shipping_values = fast_shipping_values | append: '|' | append: variant_option_value
          endif
        endfor
        assign fast_shipping_values = fast_shipping_values | remove_first: '|' | split: '|'

        assign swatch_count = option.values | map: 'swatch' | compact | size

        if swatch_count > 0 and block.settings.swatch_selector_style != 'none'
          # Use the swatch selector type only if we have at least one swatch and a supported swatch selector type
          assign resolved_option_selector_style = block.settings.swatch_selector_style
        endif

        # Implementation note: if the option value has no native swatch, BUT that the option name matches a hardcoded list of color names,
        # we fallback to the legacy config-based system. This allows to keep compatibility with stores that were using the config-based, and
        # allow those merchants to upgrade to the new system at their own pace.
        if swatch_count == 0 and color_label_list contains option_downcase and block.settings.swatch_selector_style != 'none'
          assign resolved_option_selector_style = block.settings.swatch_selector_style
        endif

        if resolved_option_selector_style == 'dropdown' and force_dropdown_as_block
          assign resolved_option_selector_style = 'block'
        endif

        if variant_image_options contains option_downcase
          assign resolved_option_selector_style = 'variant_image'
        endif
      %}

      <fieldset class="variant-picker__option">
        <div class="variant-picker__option-info">
          {%- if hide_size_chart != true and block.settings.size_chart_page != blank and size_label_list contains option_downcase -%}
            {%- capture drawer_id -%}size-chart-{{ option.position }}-{{ form_id }}{%- endcapture -%}

            <button type="button" class="text-sm text-subdued" aria-controls="{{ drawer_id | escape }}" aria-expanded="false">
              <span class="link">{{ 'product.general.size_chart' | t }}</span>
            </button>

            <x-drawer id="{{ drawer_id }}" class="drawer drawer--lg">
              <span class="h5" slot="header">{{ block.settings.size_chart_page.title }}</span>

              <div class="prose">
                {{- block.settings.size_chart_page.content -}}
              </div>
            </x-drawer>
          {%- endif -%}
        </div>

        {%- if resolved_option_selector_style == 'dropdown' -%}
          {%- capture variant_drawer_id -%}variant-picker-drawer-{{ section.id }}-{{ product.id }}-{{ option.position }}{%- endcapture -%}
          {%- assign param_name = form_id | append: '-option' | append: option.position -%}

          {% comment %} Drawer Trigger Button {% endcomment %}
          <button type="button" class="button button--xl button--primary button--full" aria-controls="{{ variant_drawer_id }}" aria-expanded="false">
            {{ option.name }} {{ 'product.general.select' | t }}
          </button>

          {% comment %} Drawer Definition {% endcomment %}
          <x-drawer id="{{ variant_drawer_id }}" class="drawer drawer--variant-picker drawer--lg" anchor="bottom">
            {% comment %} Drawer Header {% endcomment %}
            <div slot="header" class="h-stack items-center justify-between">
               <p class="h5">{{ option.name | upcase }} {{ 'product.general.select' | t | upcase }}</p>
            </div>

            {% comment %} Drawer Main Content {% endcomment %}
            <div>
              <div class="variant-grid__shipping-info">
                <span class="variant-grid__shipping-dot"></span>
                <span class="shipping-text">{{ 'product.general.shipping_in_48h' | t }}</span>
                <span class="variant-grid__shipping-badge">48H</span>
              </div>

              <div data-option-selector class="variant-grid">
                {%- for option_value in option.values -%}
                  {%- if hide_sold_out_variants == false or option_value.available or option_value.selected -%}
                    {% comment %} We use labels/radios even if update_url is true for consistent behavior in drawer {% endcomment %}
                    <label
                      class="variant-grid__option {% unless option_value.available %}is-disabled{% endunless %} {% if option_value.selected %}is-selected{% endif %}"
                      for="{{ param_name }}-{{ option_value.id | escape }}"
                      onclick="selectVariant('{{ option_value.id }}', this, event);"
                    >
                      <input class="sr-only" type="radio" id="{{ param_name }}-{{ option_value.id | escape }}" form="{{ form_id }}" name="{{ param_name }}" data-option-position="{{ option.position }}" value="{{ option_value.id }}" {% if option_value.selected %}checked{% endif %} {% unless option_value.available %}disabled{% endunless %}>
                      {% if fast_shipping_values contains option_value.name %}
                        <span class="variant-grid__option-available">
                          48H
                        </span>
                      {% endif %}
                      <input class="sr-only" type="radio" id="{{ param_name }}-{{ option_value.id | escape }}" form="{{ form_id }}" name="{{ param_name }}" data-option-position="{{ option.position }}" value="{{ option_value.id }}" {% if option_value.selected %}checked{% endif %} {% unless option_value.available %}disabled{% endunless %}>
                      <span class="variant-grid__option-value">{{ option_value.name | remove: " - Sofort verfügbar!" }}</span>
                      <span class="variant-grid__option-price">{{ option_value.variant.price | money }}</span>
                    </label>
                  {%- endif -%}
                {%- endfor -%}
              </div>
            </div>

            {% comment %} Drawer Footer {% endcomment %}
            <div slot="footer">
              {%- assign drawer_form_id = form_id | append: '-drawer' -%}
              {%- form 'product', product, id: drawer_form_id -%}
                <input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
                <button type="button" class="button button--xl button--secondary button--full" 
                        onclick="
                          const form = document.getElementById('{{ drawer_form_id }}');
                          const drawer = this.closest('x-drawer');
                          const formData = new FormData(form);
                          
                          fetch('/cart/add.js', {
                            method: 'POST',
                            body: formData
                          })
                          .then(response => response.json())
                          .then(data => {
                            // Update cart count or show success message if needed
                            if (drawer) {
                              drawer.dispatchEvent(new CustomEvent('dialog:force-close', { bubbles: true }));
                            }
                            // Trigger cart drawer to open or update cart
                            document.documentElement.dispatchEvent(new CustomEvent('cart:refresh', { bubbles: true }));
                            
                            // Open cart drawer
                            const cartDrawer = document.getElementById('cart-drawer');
                            if (cartDrawer) {
                              setTimeout(() => {
                                cartDrawer.setAttribute('open', '');
                                cartDrawer.dispatchEvent(new CustomEvent('dialog:open', { bubbles: true }));
                              }, 300);
                            }
                          })
                          .catch(error => console.error('Error:', error));
                          
                          return false;
                        ">
                  {%- if product.selected_or_first_available_variant.available -%}
                    {{ 'product.general.add_to_cart_button' | t }}
                  {%- else -%}
                    {{ 'product.general.sold_out_button' | t }}
                  {%- endif -%}
                </button>
              {%- endform -%}
            </div>
          </x-drawer>
        {%- else -%}
          <div {% unless block.settings.stack_blocks %}class="scroll-area bleed sm:unbleed"{% endunless %}>
            <div class="variant-picker__option-values {% if block.settings.stack_blocks %}wrap{% else %}scroll-area bleed sm:unbleed{% endif %} {% if resolved_option_selector_style == 'swatch' and settings.color_swatch_style == 'rectangle' %}variant-picker__option-values--color gap-4{% else %}gap-2{% endif %}">
              {% liquid
                assign name = form_id | append: '-option' | append: option.position

                for option_value in option.values
                  case resolved_option_selector_style
                    when 'variant_image'
                      render 'option-value', type: 'thumbnail', form: form_id, option_value: option_value, param_name: name, option_position: option.position, hide_if_disabled: hide_sold_out_variants, reload_page_for_combined_products: update_url, id_prefix: forloop.index, bordered: true
                    when 'swatch'
                      render 'option-value', type: 'swatch', form: form_id, option_value: option_value, param_name: name, option_position: option.position, hide_if_disabled: hide_sold_out_variants, reload_page_for_combined_products: update_url, id_prefix: forloop.index
                    when 'block'
                      render 'option-value', type: 'block', form: form_id, option_value: option_value, param_name: name, option_position: option.position, hide_if_disabled: hide_sold_out_variants, reload_page_for_combined_products: update_url, id_prefix: forloop.index
                    when 'block_swatch'
                      render 'option-value', type: 'block', form: form_id, option_value: option_value, param_name: name, option_position: option.position, show_swatch: true, hide_if_disabled: hide_sold_out_variants, reload_page_for_combined_products: update_url, id_prefix: forloop.index
                  endcase
                endfor
              %}
            </div>
          </div>
        {%- endif -%}
      </fieldset>
    {%- endfor -%}
  </variant-picker>
{%- endunless -%}

enter image description here

how to make vertical slider slide-in just as much as the mouse scrolls

Scenario:
I’m building a website in WordPress using the free version of Elementor. I want to create a vertical slider on a page built with Elementor. My top priority is to achieve this without using any paid plugins.

Issue:
The vertical sliders I’ve tried behave inconsistently — sometimes it takes a lot of scrolling to move to the next slide, other times even a slight scroll jumps to the next one. This makes for a poor user experience. I want smooth, consistent scrolling: the next section should come into view naturally based on how much the user scrolls (like native page scroll).

What I’ve tried:

Smart Slider 3 plugin, Vertical Scroll widget from Premium Addons for Elementor
I’m not considering Slider Revolution due to its large size and performance issues.

What I don’t want:

Snap-to-section scroll like this: Premium Addons Demo

This kind of slider layout: Example

What I do want (reference examples):

Luminar site example

Athos site example

Is there a way to achieve this kind of natural vertical scroll behavior in Elementor (free), possibly with custom code or a lightweight plugin?

How can I add dynamic open graph tags in React to a specific component?

I’m having an issue with dynamic og meta tags in my React/Next application with LinkedIn post inspector and Facebook debugger. The issue is that the metatags are being generated, but after the load and the crawlers don’t find them.

This is the Chrome Elements TAB with og
enter image description here

This is the Network TAB -> Response without og
enter image description here

This is my current code src/pages/share-property/index.tsx

import React from "react";
import Property from "components/Sharing/Property";
import { GetServerSideProps } from "next";
import { Buffer } from 'buffer';
import { NextPage } from 'next';
import Head from 'next/head'; // Import Head

interface PropertyData {
  companyName: string;
  tenantId: string;
  stage: string;
  firstName: string;
  imageUrl: string;
  headerText?: string;
  resolvedImageUrl: string;
  fullUrl: string;
}

interface Props {
  propertyData: PropertyData | null;
}

const IndexPage: NextPage<Props> = ({ propertyData }) => {
  const shareTitle = propertyData ? `${propertyData.companyName} - ${propertyData.headerText}` : 'Loading...';
  const shareDescription = propertyData ? `Check out this property update from ${propertyData.companyName}` : '';

  return (
    <>
      <Head>
        {/* Primary Meta Tags */}
        <title>{shareTitle}</title>
        <meta name="description" content={shareDescription} />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1.0, viewport-fit=cover"
        />

        {propertyData && (
          <>
            {/* Open Graph / Facebook */}
            <meta property="og:title" content={shareTitle} />
            <meta property="og:description" content={shareDescription} />
            <meta property="og:image" content={propertyData.resolvedImageUrl} />
            <meta property="og:url" content={propertyData.fullUrl} />
            <meta property="og:type" content="website" />
            <meta property="og:image:width" content="1200" />
            <meta property="og:image:height" content="630" />
            <meta property="og:image:alt" content={`Property image from ${propertyData.companyName}`} />
            <meta property="og:site_name" content={propertyData.companyName} />

            {/* Twitter */}
            <meta name="twitter:card" content="summary_large_image" />
            <meta name="twitter:title" content={shareTitle} />
            <meta name="twitter:description" content={shareDescription} />
            <meta name="twitter:image" content={propertyData.resolvedImageUrl} />
          </>
        )}
      </Head>
      {propertyData ? (
        <Property
          companyName={propertyData.companyName}
          tenantId={propertyData.tenantId}
          stage={propertyData.stage}
          firstName={propertyData.firstName}
          imageUrl={propertyData.imageUrl}
          headerText={propertyData.headerText}
          resolvedImageUrl={propertyData.resolvedImageUrl}
          fullUrl={propertyData.fullUrl}
        />
      ) : (
        <div>Loading property data...</div>
      )}
    </>
  );
};

export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
  const { query, req } = context;
  const data = query.data as string;

  console.log("getServerSideProps is running");

  if (!data) {
    console.log("No data query parameter"); 
    return {
      props: { propertyData: null },
    };
  }

  try {
    const decodedData = JSON.parse(Buffer.from(data, 'base64').toString('utf-8'));
    const { companyName, stage, imageUrl, firstName = "", tenantId = "", headerText = "Property Update" } = decodedData;

    const origin = req ? `${req.headers['x-forwarded-proto'] || 'http'}://${req.headers.host}` : '';
    const fullUrl = `${origin}${context.resolvedUrl}`;

    const getAbsoluteImageUrlServerSide = (url: string) => {
      if (!url) return '';
      if (url.startsWith('http')) return url;
      if (url.startsWith('//')) return `https:${url}`;
      return `${origin}${url.startsWith('/') ? '' : '/'}${url}`;
    };

    const resolvedImageUrl = getAbsoluteImageUrlServerSide(imageUrl);

    console.log("Property Data:", {
      companyName,
      tenantId,
      stage,
      firstName,
      imageUrl,
      headerText,
      resolvedImageUrl,
      fullUrl,
    });

    return {
      props: {
        propertyData: {
          companyName,
          tenantId,
          stage,
          firstName,
          imageUrl,
          headerText,
          resolvedImageUrl,
          fullUrl,
        },
      },
    };
  } catch (error) {
    console.error('Error processing data in getServerSideProps:', error);
    return {
      props: { propertyData: null },
    };
  }
};

export default IndexPage;

src/components/Sharing/Property.tsx

import React from 'react';
import { Box, Typography, Button, Card, CardMedia, CardContent } from '@mui/material';
import Link from 'next/link';
import Head from 'next/head';
import styles from 'styles/ShareButton.module.scss';

interface PropertyProps {
  companyName: string;
  tenantId: string;
  stage: string;
  firstName: string;
  imageUrl: string;
  headerText?: string;
  resolvedImageUrl: string;
  fullUrl: string;
}

const Property = ({
  companyName,
  tenantId,
  stage,
  firstName,
  imageUrl,
  headerText = "Property Update",
  resolvedImageUrl,
  fullUrl,
}: PropertyProps) => {
  const getStageMessage = () => {
    switch(stage.toLowerCase()) {
      case 'under contract':
        return (
          <Typography variant="body1" sx={{ mb: 2 }}>
            This home was just placed under contract using{' '}
            <Link href={new URL('/', fullUrl).origin} passHref>
              <a target="_blank" className={styles.Link}>{companyName}</a>
            </Link>
          </Typography>
        );
      case 'under construction':
        return (
          <Typography variant="body1" sx={{ mb: 2 }}>
            This house is beginning its renovations using{' '}
            <Link href={new URL('/', fullUrl).origin} passHref>
              <a target="_blank" className={styles.Link}>{companyName}</a>
            </Link>
          </Typography>
        );
      case 'sold':
        return (
          <Typography variant="body1" sx={{ mb: 2 }}>
            This home has just been sold using{' '}
            <Link href={new URL('/', fullUrl).origin} passHref>
              <a target="_blank" className={styles.Link}>{companyName}</a>
            </Link>
          </Typography>
        );
      default:
        return null;
    }
  };

  return (
    <>
      {/* Rest of your Property component UI */}
      <Box className={styles.PropertyContainer}>
        <Card sx={{ mb: 3 }}>
          {resolvedImageUrl && (
            <CardMedia
              component="img"
              height="400"
              image={resolvedImageUrl}
              alt="Property image"
              sx={{ objectFit: 'cover' }}
            />
          )}
          <CardContent>
            {getStageMessage()}
            <Box className={styles.CTASection}>
              <Typography variant="body1" paragraph>
                If you want to invest in real estate, click here to learn more
              </Typography>
              <Button
                variant="contained"
                size="large"
                href={new URL('/', fullUrl).origin}
                target="_blank"
                sx={{ mt: 2 }}
              >
                Learn More
              </Button>
            </Box>
          </CardContent>
        </Card>
      </Box>
    </>
  );
};

export default Property;

I have read many posts about this, but none resolve my issue. Any observation about what I’m doing wrong. Thanks.

Detect syntax errors on service worker update

When calling navigator.serviceWorker.register() and:

  • There is an active service worker.
  • There is a NEW service worker available.
  • The NEW service worker has syntax errors.

then the promise returned will resolve with a ServiceWorkerRegistration pointing to the existing (old) service worker instead of rejecting with an error notifying about the syntax error. Apparently this happens by design, from the sources I’ve investigated (too many to mention here).

I have not found any way of detecting these errors, and I’ve tried the following and more:

  • Checking for the service worker state, to no avail because only the registration.active property exists, no registration.waiting or registration.installing are available.
  • Listening to the updatefound event (same problem).
  • Calling registration.update(), which works but it is a hack.

So far, the only clean solution I can think of is to use globalThis.addEventListener('error'…) on the service worker itself and then postMessage() to the main thread, setting up some message listening code. Frankly, this is too big for something that IMHO should work out of the box by rejecting the promise returned by register().

Am I missing something obvious? I cannot find anything about this on the Internet, and I’ve searching for information for two days. I even asked a couple of AI… Thanks a lot in advance!

Javascript not run in Edge, but works with Firefox

I developed some simple CGI to search some contents, and depending on the user’s choice, some additional options are hidden or displayed.
To control the latter I added some simple Javascript to manipulate style.display.

It works fine with current Firefox ESR, but doe snot work with current Microsoft Edge.
The script (e.g. for onChange) are not run.

Only in the browser console I find some messages like this:

/search/form.html?t=win;s=U:1  Unrecognized Content-Security-Policy directive 'noscript-marker'.
form.html:1  Refused to load the script 'http://.../telefon.js' because it violates the following Content Security Policy directive: "script-src-elem 'none'".

form.html:59  Refused to execute inline script because it violates the following Content Security Policy directive: "script-src-elem 'none'". Either the 'unsafe-inline' keyword, a hash ('sha256-ZGa/EeW+nrOuUaIZ7raUOPCcg4acs3ew01xN9Vf9yK0='), or a nonce ('nonce-...') is required to enable inline execution.

I’m kind of clueless; the script is rather primitive.

With in the head element I have <script src="/telefon.js" type="text/javascript"></script>.

The script that does not run is here:

<select name="s" id="i-s" onchange="check_options(this)">
<option value="K">Telefonbuch K</option>
<option selected="selected" value="U">Telefonbuch U</option>
</select>

And after the form I added an immediate call to set up the initial state like this:

<script>check_options(document.getElementById('i-s'))</script>

The start of the HTML is also rather straight forward (created by Perl CGI):

<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="de-DE" xml:lang="de-DE">
<head>
<title>Telefon</title>
<link href="/favicon.ico" rel="icon" />
<link href="/normal.css" rel="stylesheet" title="Normal Mode" type="text/css" />
<link alternate="1" href="/darkmode.css" rel="alternate stylesheet" title="Dark Mode" type="text/css" />
<script src="/telefon.js" type="text/javascript"></script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>

So what is causing this, and how can I fix it?

Is it possible to use the audio from SpeechSynthesisUtterance in AudioMotion?

In the browser (using JavaScript and SpeechSynthesisUtterance), I’m able to do text to speech. Now I’d like to represent the utterance generated as visual audio in something like AudioMotion. But libraries like AudioMotion need either a file or a stream as a source. I don’t see how to get an audio stream from the speech produced by SpeechSynthesisUtterance. Is this even possible?

Fixing Mediapipe.js Module Arguments Error

Error with Mediapipe Hands in React Vite Project: “Module.arguments to plain arguments error”

Hi there,

I am trying to integrate Mediapipe Hands into my React project using Vite, but I’m encountering the error “[Module.arguments to plain arguments error]” (see the screenshot below). The issue happens intermittently—sometimes the code works fine, and other times I get the error.

Steps to Reproduce:
Set up a new React Vite project.

Install the @mediapipe/hands package.

Write the code to initialize and process hand landmarks using Mediapipe.

Run the application and see the error.

Observations:
The error doesn’t always occur. Sometimes it works as expected, and other times it throws the error.

I’m using Vite for faster bundling, and it may be related to how Vite handles module imports and arguments.

My code:-

function useGestureRecognition({ videoElement, canvasElement }) {
const hands = useRef();
const camera = useRef();
const handsGesture = useRef([]);

const { processLandmark } = useKeyPointClassifier();

async function onResults(results) {
    if (canvasElement.current) {
        const ctx = canvasElement.current.getContext('2d');

        ctx.save();
        ctx.clearRect(0, 0, canvasElement.current.width, canvasElement.current.height);
        ctx.drawImage(results.image, 0, 0, maxVideoWidth, maxVideoHeight);

        if (results.multiHandLandmarks) {
            for (const [index, landmarks] of results.multiHandLandmarks.entries()) {
                processLandmark(landmarks, results.image).then((val) => (handsGesture.current[index] = val));
                const landmarksX = landmarks.map((landmark) => landmark.x);
                const landmarksY = landmarks.map((landmark) => landmark.y);
                ctx.fillStyle = '#ff0000';
                ctx.font = '24px serif';
                ctx.fillText(
                    CONFIGS.keypointClassifierLabels[handsGesture.current[index]],
                    maxVideoWidth * Math.min(...landmarksX),
                    maxVideoHeight * Math.min(...landmarksY) - 15
                );
                drawRectangle(ctx, {
                    xCenter: Math.min(...landmarksX) + (Math.max(...landmarksX) - Math.min(...landmarksX)) / 2,
                    yCenter: Math.min(...landmarksY) + (Math.max(...landmarksY) - Math.min(...landmarksY)) / 2,
                    width: Math.max(...landmarksX) - Math.min(...landmarksX),
                    height: Math.max(...landmarksY) - Math.min(...landmarksY),
                    rotation: 0,
                },
                    {
                        fillColor: 'transparent',
                        color: '#ff0000',
                        lineWidth: 1,
                    }
                );
                drawConnectors(ctx, landmarks, HAND_CONNECTIONS, {
                    color: '#00ffff',
                    lineWidth: 2,
                });
                drawLandmarks(ctx, landmarks, {
                    color: '#ffff29',
                    lineWidth: 1,
                });
            }
        }
        ctx.restore();
    }
}

const loadHands = () => {
    hands.current = new Hands({ locateFile: (file) => `https://cdn.jsdelivr.net/npm/@mediapipe/hands/${file}`, });
    hands.current.setOptions({
        maxNumHands: 1,
        modelComplexity: 1,
        minDetectionConfidence: 0.5,
        minTrackingConfidence: 0.5,
    });
    hands.current.onResults(onResults);
};

useEffect(() => {
    (async function initCamera() {
        camera.current = new Camera(videoElement.current, {
            onFrame: async () => {
                await hands.current.send({ image: videoElement.current });
            },
            width: maxVideoWidth,
            height: maxVideoHeight,
        });
        camera.current.start();
    })()

    loadHands();
}, []);

return {maxVideoHeight, maxVideoWidth, canvasElement, videoElement};

}

Dynamic image selection don’t work with quarto website

I have a quarto dashboard where the user can select an image from a dropdown and it will appear instantly. I use observable js for this, and I recently got some help to make it work and there is a MWE in github.

The dashboard renders fine, but then I wanted to host it on GitHub pages, and so I added a _quarto.yml file. All it contain is this:

project:
  type: website

Then I use GitHub actions to render it. But now the image don’t appear anymore, neither with GitHub actions or when rendered locally. I created a branch of the original MWE with the _quarto.yml file and the rendered output.

Any help with this would be much appreciated.

How to prevent iOS keyboard from covering input fields in a Next.js web application (layout is not fixed)?

I am making a webApplication in NextJs. I have to make it responsive for iPphone. The problem I am facing is when the user touches an input box it get disappears under the keyboard if the input is below portion of the screen. What should I do to fix this?

I am currently using direct javascript onFocus scroll workaround, but this not the best. I have to add it to every pages where the input field is available which is not dev friendly.

inputElement.addEventListener('focus', () => {
  window.scrollTo({ 
    top: inputElement.offsetTop - 50, 
    behavior: 'smooth' 
  });
});

Is there a way to really authenticate static files? [closed]

I am building a node js app with html and css as the frontend, i’ve gotten all my routes working, but using local host the dashboard which is supposed to be protected is still statically served, tho with dummy data, it only gets dynamic after a login.

I tried serving the styles statically in the node js app but that results a another problem entirely..i’m thinking if i should just use a library like react or a framework like vue js, static file serving is killing me

404 errors after using importmap with Rails 8

I have the following within my importmap.rb

pin 'core-js/stable', to: 'core-js--stable.js' #  @3.42.0

However, when I try to import that package into my application.js:

import 'core-js/stable';

this then produces a bunch of extra requests for files that I don’t have and thus cause 404s, for instance:

/modules/es.string.trim.js
/modules/es.string.trim-start.js
/modules/es.string.trim-end.js
etc

How can I use something like core-js/stable and make sure everything downloads as it should?

Scaling centered objects between two page layouts with differing margins and gutters

I have a set of graphical objects whose positions are defined relative to the center of a two-page spread. I need to convert them from one page layout to another, where each layout may have different:

  • Overall dimensions (total width and height of the two-page spread)
  • Outer margins (“bleed”)
  • Inner gutter (“spine”)

When an object is originally placed at the exact center of the source spread, it can end up shifted off-center in the target layout because the bleed and spine values change the effective content area. This misalignment occurs even when the overall spread dimensions match, since the differing margins and gutter alter how the center point maps between formats.

I first tried the simplest thing: scale every object’s x, y, width, and height by the ratio of targetSpreadWidth/baseSpreadWidth and targetSpreadHeight/baseSpreadHeight. I expected an object at x=0 (true center) to stay at x=0, but it shifted whenever bleed or spine differed.

Next I tried “normalizing” into the content box: subtracting bleed and half the spine from each coordinate before scaling, then adding them back after. I also experimented with a full affine translate→scale→translate around the content origin. No matter how I tweaked those calculations, a centered object still ended up with a non-zero x when margins or spine changed.

This is the current approach (simplified):

const baseFormat = {
  width: 654,
  height: 343,
  bleed: 19,
  spine: 6
};

const targetFormat = {
  width: 342,
  height: 185,
  bleed: 19,
  spine: 6
};

const objects = [
  { width: 250, height: 250, center: { x: 157, y: 0 } },
  { width: 200, height: 200, center: { x: -155, y: 0 } }
];

const scaleX = targetFormat.width / baseFormat.width;
const scaleY = targetFormat.height / baseFormat.height;

const scaled = objects.map(o => ({
  ...o,
  width:  o.width  * scaleX,
  height: o.height * scaleY,
  center: {
    x: o.center.x * scaleX,
    y: o.center.y * scaleY
  }
}));

Visually, you can see what currently happens using the data from the snippet above.

Pictured original above and converted below