preview pdf from google bucket signed url

Recently I am doing an archive project in Flasks. I want to view pdf with selectable text in a webpage using iframe or similar technology.

Since the pdf url is a signed url from google bucket, like this

https://storage.googleapis.com/bucket name/filename.pdf?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=account%40 bluh bluh bluh(lots of other params)

It does not work with the pdf.js iframe:

<iframe class="iframe1" src="{{ url_for('static', filename='pdfjs-4.8.69-dist/web/viewer.html')}}?file= {{file_url}}"></iframe>

I have ensured the viewer.html and file_url are ready. How do I apply the iframe or similar methods?

VERY VERY accurate count down timer in js/ts

So I am working on a count down timer for every seconds, and if it is less then 60 seconds, count down every 10ms.

I have tried many ways there is always a delay. E.g. the displayed counter down is slower than the actual count down.

Here is what I am doing – I store a endTime UTC in database (backend), then use websocket to publish the data to the front end, then front end start the count down by comparing the endTime and current time UTC, and the loop is done by requestAnimationFrame. Even with all this, the count down on screen is off by a second for every minutes. BTW, the front end is react.

Here is the code:

  useEffect(() => {
        if (!isRunning || timeLeft === null || timeLeft <= 0) return;

        const startTime = performance.now();
        const totalDuration = timeLeft * 1000;

        const updateTimer = () => {
            const elapsedTime = performance.now() - startTime;
            const remainingTime = Math.max(0, totalDuration - elapsedTime) / 1000;

            setTimeLeft(remainingTime);

            if (remainingTime <= 0) {
                setIsRunning(false);
                return;
            }

            timeoutRef.current = requestAnimationFrame(updateTimer);
        };

        timeoutRef.current = requestAnimationFrame(updateTimer);

        return () => {
            if (timeoutRef.current !== null) {
                cancelAnimationFrame(timeoutRef.current);
                timeoutRef.current = null;
            }
        };
    }, [isRunning, timeLeft, clientId]);

Any suggestions?

In Gun.js, how can I check if the peer (relay server) is connected?

I’m trying to create a multiplayer game with Gun.js.

I made some tests with 2 browsers opened at same time and noticed sometimes the changes in one window are not updating the other.

So, I would like to check if the problem is with the connection / peer.

I’m using this GUN relay URL: https://gun-manhattan.herokuapp.com/gun

How do I check if the relay is connected?

index.html

<body>
  <script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script>
  <script src="gunjs-test.js"></script>

  <div>
    Relay URL:
    <input type="text" id="url" value="https://gun-manhattan.herokuapp.com/gun" style="width: 400px">
    <button onclick="initGun(document.getElementById('url').value)">Init gun</button>
  </div>

  <div>
    Root node name:
    <input type="text" id="rootNodeName" value="test">
  </div>

  <div>
    Node name:
    <input type="text" id="nodeName" value="paste">
  </div>
  
  <button onclick="enableRealtimeUpdates(document.getElementById('rootNodeName').value, document.getElementById('nodeName').value)">Enable realtime updates</button>

</body>

gunjs-test.js

let gun = null;

function initGun(url) {
  gun = Gun([url]);
}

function enableRealtimeUpdates(rootNodeName, nodeName) {
  gun.get(rootNodeName).get(nodeName).on((data, id) => {
    console.log("id: " + id);
    console.log("data: " + data);
  });
}

function isConnected() {
  // ???
}

Next.js 15 Client and Server Side Validation With Mantine Form and Server Actions

I am using Mantine form for my UI and client side validation: https://mantine.dev/form/validation/

Here is an example of using it:

import { useForm } from '@mantine/form';
import { NumberInput, TextInput, Button } from '@mantine/core';

function Demo() {
  const form = useForm({
    mode: 'uncontrolled',
    initialValues: { name: '', email: '', age: 0 },

    // functions will be used to validate values at corresponding key
    validate: {
      name: (value) => (value.length < 2 ? 'Name must have at least 2 letters' : null),
      email: (value) => (/^S+@S+$/.test(value) ? null : 'Invalid email'),
      age: (value) => (value < 18 ? 'You must be at least 18 to register' : null),
    },
  });

  return (
    <form onSubmit={form.onSubmit(console.log)}>
      <TextInput
        label="Name"
        placeholder="Name"
        key={form.key('name')}
        {...form.getInputProps('name')}
      />
      <TextInput
        mt="sm"
        label="Email"
        placeholder="Email"
        key={form.key('email')}
        {...form.getInputProps('email')}
      />
      <NumberInput
        mt="sm"
        label="Age"
        placeholder="Age"
        min={0}
        max={99}
        key={form.key('age')}
        {...form.getInputProps('age')}
      />
      <Button type="submit" mt="sm">
        Submit
      </Button>
    </form>
  );
}

I am trying to have both client and server side validation with server actions. A different library that is not UI based, conform, has an example of this:
https://conform.guide/integration/nextjs

Here is a snippet:

export function LoginForm() {
  const [lastResult, action] = useFormState(login, undefined);
  const [form, fields] = useForm({
    // Sync the result of last submission
    lastResult,

    // Reuse the validation logic on the client
    onValidate({ formData }) {
      return parseWithZod(formData, { schema: loginSchema });
    },

    // Validate the form on blur event triggered
    shouldValidate: 'onBlur',
    shouldRevalidate: 'onInput',
  });

  return (
    <form id={form.id} onSubmit={form.onSubmit} action={action} noValidate>
      

I have been attempting to have the same resulting code of onSubmit and action with Mantine form, but all attempts fail me. I have attempted the following as an example:

<form
  ref={formRef}
  onSubmit={form.onSubmit((values, event) => {
    event?.stopPropagation();
    formRef.current?.submit();
  })}
  action={formAction}
>

For some reason, the server action never gets triggered. I have a feeling that the conform library has some magic involved that allows this to work. I would just like to get the same working setup with Mantine form. Any help is appreciated.

How do I find out what is causing Edge Developer Tools to be BLANK on the company ASP.NET WebForms website?

We have an old ASP.NET WebForms site that currently only runs in Microsoft Edge because of the way hundreds of links open in popup windows. It needs to be rewritten, but that is our long-term project that has not been approved resources yet.

I recently learned how to use a timer to update Page 1 when dialog on Page 2 calls a 3rd dialog on Page 3. Page 3 sets a Session variable, and Page 1 listens for it.

This is my Page 1:

<form id="Form1" method="post" runat="server">
    <script type="text/javascript">
        document.addEventListener("DOMContentLoaded", function () {
            setTimeout(function () {
                var csrWhere = '<%=Session("csrWhere")%>'
                if (csrWhere != '') {
                    alert(csrWhere);
                    location.reload();
                }
            }, 200);
        });
    </script>
    <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
    <telerik:RadMenu ID="mnuMain" EnableEmbeddedSkins="false" CssClass="RadMenu_Claim" EnableShadows="true" OnClientItemClicking="MenuOpenWindow" CollapseAnimation-Type="None" DataSourceID="SiteMapDataSource1" Style="z-index: 999; position: absolute; top: 3px; left: 12px" runat="server" />
    <asp:SiteMapDataSource ID="SiteMapDataSource1" ShowStartingNode="False" SiteMapProvider="XmlSiteMapProviderHome" runat="server" />

It is not firing, so I tried to pull up the Developer Tools and query some information using the Javascript console. That was when I noticed that Developer Tools will open, but the content of the page is blank:

Developer Tools with no content

By contrast, I can come here on the same PC running the same browser, and Developer Tools works like it should.

Developer Tools with content

Obviously, something on the site is interfering with Developer Tools. We have 2 developers at our company, and neither of us have ever seen this or know what is causing it.

This website project has numerous older third party DLLs like Telerik and an older Javascript library, and I suspect it is one of those.

Does anyone know how I would find out what is blocking my Developer Tools?

Convert string number to Integer number without rounding

Please note this is not a similiar question, The javascript Number method basically converts string to number or int but also it does round up the number:

const roundedUpNumber = Number("9333852702227987")
console.log(roundedUpNumber) // 9333852702227988

How can I just convert string to number or int without doing anything else to the string number in javascript?

How to build a good data structure for a react state, that allows me to easily update deeply nested array of objects?

I am trying to implement a property (real estate) chain

Each chain item should know which chain item is above/below it

A chain item can have its own sub-chain, and this in turn applies to its sub-chain items as well and so on

Visually like this

[
{
id: 1,
belowId:0
},
{
id: 0,
belowId:2,
aboveId:1,
subChain: [{ id:3, subChain: [{ id:4}] }]
},
{
id: 2,
aboveId:0
}
]

I tried this above structure but I started getting confused how to update nested items in state and ui

ReferenceError: var is not defined in javascript for Storyline 360

I am encountering a ReferenceError: quiz1Option1Texts is not defined error when trying to run a JavaScript function that sets text variables based on a slide number. The function is part of a larger script that manages quiz questions and answers.

Goal:

My goal is to set various text variables (e.g., AssertionText, BlankPromptText, CorrectText, etc.) based on the slide number passed to the setTexts function. These variables are then used to update the UI elements in a quiz application.

Expected Results:

I expect the setTexts function to correctly set the text variables based on the slide number and update the UI elements without any errors.

Actual Results:

When I run the script, I get the following error message:

Error loading script: ReferenceError: quiz1Option1Texts is not defined
at setTexts (:604:28)
at user.js:26:9

What I’ve Tried:

Checked Variable Definitions: Ensured that quiz1Option1Texts and other related variables are defined within the setTexts function.

Added Debugging Statements: Added console logs to verify the order of execution and ensure that the variables are defined before they are used.

Reviewed Scope: Verified that the variables are within the correct scope and are not being referenced before they are defined.

Searched Online: Looked for similar issues on Stack Overflow and other forums but did not find a solution that matched my specific problem.

Here is the relevant part of the code:

function setTexts(slidenumber) {
    console.log("setTexts function called with slideNumber: " + slidenumber); // Log the function call

    if (slidenumber === undefined || slidenumber === null) {
        console.error("Slide number is undefined or null.");
        return;
    }

    var QuestionPromptTexts = [
        "Choose the best definition for orbits from below.",
        // ... other definitions ...
    ];

    var Key = [
        "3", "3", "1", "1", "3", "3", "3", "2", "2", "2", "3", "3", "2", "1", "1", "3", "3", "1", "1", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3"
    ];

    var Choice1Texts = [
        "Strange or not familiar",
        // ... other choices ...
    ];

    var Choice2Texts = [
        "A type of gum",
        // ... other choices ...
    ];

    var Choice3Texts = [
        "To go around an object",
        // ... other choices ...
    ];

    var Quiz1QuestionPromptTexts = [
        "There are _________ galaxies.",
        // ... other prompts ...
    ];

    var Quiz1Key = [
        "2", "1", "3", "1", "2", "3", "3", "1", "2"
    ];

    var Quiz1Option1Texts = [
        "countless",
        // ... other options ...
    ];

    var Quiz1Option2Texts = [
        "discount",
        // ... other options ...
    ];

    var Quiz1Option3Texts = [
        "recount",
        // ... other options ...
    ];

    var Quiz2QuestionPromptTexts = [
        "Houses are selling for _________ prices.",
        // ... other prompts ...
    ];

    var Quiz2Key = [
        "2", "3", "1", "3", "1", "1", "3", "2", "3", "1", "3"
    ];

    var Quiz2Option1Texts = [
        "astronomical",
        // ... other options ...
    ];

    var Quiz2Option2Texts = [
        "astronomy",
        // ... other options ...
    ];

    var Quiz2Option3Texts = [
        "astronomer",
        // ... other options ...
    ];

    var AskStudentTexts = [
        "student do you agree?",
        // ... other texts ...
    ];

    var AssertionTexts = [
        "The word orbit refers to something that goes around an object. In this case our Earth orbits the sun meaning it goes around in a circular journey around the sun.",
        // ... other assertions ...
    ];

    var BlankPromptTexts = [
        "user, did you need more time defining the word orbit. I'm not sure either. Let's just give one of the answers a try?",
        // ... other prompts ...
    ];

    var CorrectTexts = [
        "the word orbit refers to something that goes around an object. In this case our Earth orbits the sun meaning it goes around in a circular journey around the sun.",
        // ... other correct texts ...
    ];

    var IncorrectPromptTexts = [
        "Let's look at a clue to define the word orbit. You know the Earth goes around the sun at 93 million miles on average. This path that earth takes is called an orbit. So, now, can you tell me what the word orbit means? Choose from the options below.",
        // ... other incorrect prompts ...
    ];

    var StudentAgreeTexts = [
        "Yes I do.",
        // ... other agree texts ...
    ];

    var StudentAnswerAgreeTexts = [
        "user, great job! So orbits means to go around something. like how the moon goes around the earth, it orbits the earth.",
        // ... other answer agree texts ...
    ];

    var StudentAnswerUnderstandTexts = [
        "Ok, that answer makes sense. I get it now. So when the moon orbits the earth it goes around it. Got it!",
        // ... other understand texts ...
    ];

    var StudentDisagreeTexts = [
        "It doesn't sound right to me.",
        // ... other disagree texts ...
    ];

    var StudentUnderstandTexts = [
        "I see now! So orbits means to go around something, like how the moon goes around the earth, it orbits the earth.",
        // ... other understand texts ...
    ];

    var NegativeFeedbackTexts = [
        "Sorry. It Looks like you picked the wrong answer.",
        // ... other feedback texts ...
    ];

    var player = GetPlayer();

    player.GetVar("Assertion");
    player.GetVar("BlankPrompt");
    player.GetVar("Correct");
    player.GetVar("IncorrectPrompt");
    player.GetVar("StudentAgree");
    player.GetVar("StudentAnswerAgree");
    player.GetVar("StudentAnswerUnderstand");
    player.GetVar("StudentDisagree");
    player.GetVar("StudentUnderstand");

    player.GetVar("PositiveFeedback");
    player.GetVar("NegativeFeedback");
    player.GetVar("Choice1");
    player.GetVar("Choice2");
    player.GetVar("Choice3");
    player.GetVar("CorrectOrNot");
    player.GetVar("Quiz1Option1");
    player.GetVar("Quiz1Option2");
    player.GetVar("Quiz1Option3");
    player.GetVar("Quiz1QuestionPrompt");
    player.GetVar("Quiz1Key");
    player.GetVar("Quiz2Option1");
    player.GetVar("Quiz2Option2");
    player.GetVar("Quiz2Option3");
    player.GetVar("Quiz2QuestionPrompt");
    player.GetVar("Quiz2Key");

    var AssertionText = AssertionTexts[slidenumber - 1];
    if (AssertionText === undefined || AssertionText === null) {
        console.error("Assertion text is undefined or null for slide number:", slidenumber);
        return;
    }
    var BlankPromptText = BlankPromptTexts[slidenumber - 1];
    if (BlankPromptText === undefined || BlankPromptText === null) {
        console.error("BlankPrompt text is undefined or null for slide number:", slidenumber);
        return;
    }
    var CorrectText = CorrectTexts[slidenumber - 1];
    if (CorrectText === undefined || CorrectText === null) {
        console.error("Correct text is undefined or null for slide number:", slidenumber);
        return;
    }
    var IncorrectPromptText = IncorrectPromptTexts[slidenumber - 1];
    if (IncorrectPromptText === undefined || IncorrectPromptText === null) {
        console.error("IncorrectPrompt text is undefined or null for slide number:", slidenumber);
        return;
    }
    var StudentAgreeText = StudentAgreeTexts[slidenumber - 1];
    if (StudentAgreeText === undefined || StudentAgreeText === null) {
        console.error("StudentAgree text is undefined or null for slide number:", slidenumber);
        return;
    }
    var StudentAnswerAgreeText = StudentAnswerAgreeTexts[slidenumber - 1];
    if (StudentAnswerAgreeText === undefined || StudentAnswerAgreeText === null) {
        console.error("StudentAnswerAgree text is undefined or null for slide number:", slidenumber);
        return;
    }
    var StudentAnswerUnderstandText = StudentAnswerUnderstandTexts[slidenumber - 1];
    if (StudentAnswerUnderstandText === undefined || StudentAnswerUnderstandText === null) {
        console.error("StudentAnswerUnderstand text is undefined or null for slide number:", slidenumber);
        return;
    }
    var StudentDisagreeText = StudentDisagreeTexts[slidenumber - 1];
    if (StudentDisagreeText === undefined || StudentDisagreeText === null) {
        console.error("StudentDisagree text is undefined or null for slide number:", slidenumber);
        return;
    }
    var StudentUnderstandText = StudentUnderstandTexts[slidenumber - 1];
    if (StudentUnderstandText === undefined || StudentUnderstandText === null) {
        console.error("StudentUnderstand text is undefined or null for slide number:", slidenumber);
        return;
    }

    console.log("Setting Assertion to: " + AssertionText);
    player.SetVar("Assertion", AssertionText);
    console.log("Setting BlankPrompt to: " + BlankPromptText);
    player.SetVar("BlankPrompt", BlankPromptText);
    console.log("Setting Correct to: " + CorrectText);
    player.SetVar("Correct", CorrectText);
    console.log("Setting IncorrectPrompt to: " + IncorrectPromptText);
    player.SetVar("IncorrectPrompt", IncorrectPromptText);
    console.log("Setting StudentAgree to: " + StudentAgreeText);
    player.SetVar("StudentAgree", StudentAgreeText);
    console.log("Setting StudentAnswerAgree to: " + StudentAnswerAgreeText);
    player.SetVar("StudentAnswerAgree", StudentAnswerAgreeText);
    console.log("Setting StudentAnswerUnderstand to: " + StudentAnswerUnderstandText);
    player.SetVar("StudentAnswerUnderstand", StudentAnswerUnderstandText);
    console.log("Setting StudentDisagree to: " + StudentDisagreeText);
    player.SetVar("StudentDisagree", StudentDisagreeText);
    console.log("Setting StudentUnderstand to: " + StudentUnderstandText);
    player.SetVar("StudentUnderstand", StudentUnderstandText);

    var AssertionDuration = calculateDuration(AssertionText);
    var BlankPromptDuration = calculateDuration(BlankPromptText);
    var CorrectDuration = calculateDuration(CorrectText);
    var IncorrectPromptDuration = calculateDuration(IncorrectPromptText);
    var StudentAgreeDuration = calculateDuration(StudentAgreeText);
    var StudentAnswerAgreeDuration = calculateDuration(StudentAnswerAgreeText);
    var StudentAnswerUnderstandDuration = calculateDuration(StudentAnswerUnderstandText);
    var StudentDisagreeDuration = calculateDuration(StudentDisagreeText);
    var StudentUnderstandDuration = calculateDuration(StudentUnderstandText);

    console.log("Assertion Duration: " + AssertionDuration + " seconds");
    console.log("BlankPrompt Duration: " + BlankPromptDuration + " seconds");
    console.log("Correct Duration: " + CorrectDuration + " seconds");
    console.log("IncorrectPrompt Duration: " + IncorrectPromptDuration + " seconds");
    console.log("StudentAgree Duration: " + StudentAgreeDuration + " seconds");
    console.log("StudentAnswerAgree Duration: " + StudentAnswerAgreeDuration + " seconds");
    console.log("StudentAnswerUnderstand Duration: " + StudentAnswerUnderstandDuration + " seconds");
    console.log("StudentDisagree Duration: " + StudentDisagreeDuration + " seconds");
    console.log("StudentUnderstand Duration: " + StudentUnderstandDuration + " seconds");

    player.SetVar("AssertionDuration", AssertionDuration);
    player.SetVar("BlankPromptDuration", BlankPromptDuration);
    player.SetVar("CorrectDuration", CorrectDuration);
    player.SetVar("IncorrectPromptDuration", IncorrectPromptDuration);
    player.SetVar("StudentAgreeDuration", StudentAgreeDuration);
    player.SetVar("StudentAnswerAgreeDuration", StudentAnswerAgreeDuration);
    player.SetVar("StudentAnswerUnderstandDuration", StudentAnswerUnderstandDuration);
    player.SetVar("StudentDisagreeDuration", StudentDisagreeDuration);
    player.SetVar("StudentUnderstandDuration", StudentUnderstandDuration);

    function calculateDuration(text) {
        var words = text.split(" ").length;
        var duration = words * 0.3; // Assuming an average reading speed of 200 words per minute (0.3 seconds per word)

        // Round up to the nearest whole second
        duration = Math.ceil(duration);

        // Ensure the duration does not exceed 9 seconds
        if (duration > 9) {
            duration = 9;
        }

        // Inverse the duration for a countdown timer
        duration = 9 - duration;

        return duration;
    }

    // Check if quiz variables are defined before accessing them
    if (slidenumber <= 10) {
        var quiz1Option1 = quiz1Option1Texts[slidenumber - 1];
        var quiz1Option2 = quiz1Option2Texts[slidenumber - 1];
        var quiz1Option3 = quiz1Option3Texts[slidenumber - 1];
        var quiz1QuestionPrompt = quiz1QuestionPromptTexts[slidenumber - 1];
        var quiz1Key = quiz1Key[slidenumber - 1];

        console.log("Setting Quiz1Option1 to: " + quiz1Option1);
        player.SetVar("Quiz1Option1", quiz1Option1);

        console.log("Setting Quiz1Option2 to: " + quiz1Option2);
        player.SetVar("Quiz1Option2", quiz1Option2);

        console.log("Setting Quiz1Option3 to: " + quiz1Option3);
        player.SetVar("Quiz1Option3", quiz1Option3);

        console.log("Setting Quiz1QuestionPrompt to: " + quiz1QuestionPrompt);
        player.SetVar("Quiz1QuestionPrompt", quiz1QuestionPrompt);

        console.log("Setting Quiz1Key to: " + quiz1Key);
        player.SetVar("Quiz1Key", quiz1Key);
    } else {
        console.log("Quiz1 variables are undefined for slide number:", slidenumber);
    }

    if (slidenumber <= 10) {
        var quiz2Option1 = quiz2Option1Texts[slidenumber - 1];
        var quiz2Option2 = quiz2Option2Texts[slidenumber - 1];
        var quiz2Option3 = quiz2Option3Texts[slidenumber - 1];
        var quiz2QuestionPrompt = quiz2Texts[slidenumber - 1];
        var quiz2Key = quiz2Key[slidenumber - 1];

        console.log("Setting Quiz2Option1 to: " + quiz2Option1);
        player.SetVar("Quiz2Option1", quiz2Option1);

        console.log("Setting Quiz2Option2 to: " + quiz2Option2);
        player.SetVar("Quiz2Option2", quiz2Option2);

        console.log("Setting Quiz2Option3 to: " + quiz2Option3);
        player.SetVar("Quiz2Option3", quiz2Option3);

        console.log("Setting Quiz2QuestionPrompt to: " + quiz2QuestionPrompt);
        player.SetVar("Quiz2QuestionPrompt", quiz2QuestionPrompt);

        console.log("Setting Quiz2Key to: " + quiz2Key);
        player.SetVar("Quiz2Key", quiz2Key);
    } else {
        console.log("Quiz2 variables are undefined for slide number:", slidenumber);
    }
}

Additional Information:

The GetPlayer function and SetVar method are part of a larger framework that manages the quiz application in Articulate 360 Storyline.

The calculateDuration function is used to determine the duration for displaying text based on the number of words.

Research:

I searched for similar issues on Stack Overflow and other forums but did not find a solution that matched my specific problem.

I reviewed JavaScript scope and variable declaration documentation but did not find a clear solution to the issue.

Any help or insights would be greatly appreciated!

conditionally add prop to a jsx element

I have a react app and am trying to pass down a prop to a jsx element based on a condition. The element in question is an anchor tag and if the condition is true I would like to pass a rel="noreferrer" but if it is false I don’t want to pass down anything…

Like <a {...thisCondtion} or something of that nature.

Is there a specific way to do this?

Assume the condition either renders true or null (&& ternary) how would I pass down that prop correctly.

How can I record both the screen and webcam using Canvas at 1080p and 30fps?

I tried this and it worked, but the video starts lagging after 30 seconds. No matter what I do, the video records smoothly for 30 seconds and then starts lagging. Am I missing something?

I’m not using requestAnimationFrame because it only works if the tab is active. I’m seeing my PC’s memory and CPU usage while I’m recording. I don’t see any huge spikes

const screenVideo = document.createElement("video");
screenVideo.style.display = "none";
screenVideo.srcObject = screenStream;
screenVideo.muted = true;
const webcamVideo = document.createElement("video");
webcamVideo.style.display = "none";
webcamVideo.srcObject = videoStream;
webcamVideo.muted = true;
webcamVideo.onloadedmetadata = () => {
  webcamVideo.play();
};
canvas = document.createElement("canvas");
screenVideo.onloadedmetadata = () => {
  screenVideo.play();
  canvas.width = screenVideo.videoWidth;
  canvas.height = screenVideo.videoHeight;
};
canvasContext = canvas.getContext("2d");

const drawCombinedStream = () => {
  if (!canvasContext || stopDrawingFrames) return;
  canvasContext.clearRect(0, 0, canvas.width, canvas.height);
  canvasContext.drawImage(screenVideo, 0, 0, canvas.width, canvas.height);

  const overlaySize = 250;
  const overlayX = 20;
  const overlayY = canvas.height - overlaySize - 20;
  const overlayRadius = overlaySize / 2;

  const webcamAspectRatio =
    webcamVideo.videoWidth / webcamVideo.videoHeight;

  let drawWidth, drawHeight;
  if (webcamAspectRatio > 1) {
    drawHeight = overlaySize;
    drawWidth = overlaySize * webcamAspectRatio;
  } else {
    drawWidth = overlaySize;
    drawHeight = overlaySize / webcamAspectRatio;
  }

  const offsetX = overlayX - (drawWidth - overlaySize) / 2;
  const offsetY = overlayY - (drawHeight - overlaySize) / 2;

  canvasContext.save();
  canvasContext.beginPath();
  canvasContext.arc(
    overlayX + overlayRadius,
    overlayY + overlayRadius,
    overlayRadius,
    0,
    Math.PI * 2,
  );
  canvasContext.clip();
  canvasContext.drawImage(
    webcamVideo,
    offsetX,
    offsetY,
    drawWidth,
    drawHeight,
  );
  canvasContext.restore();
  setTimeout(drawCombinedStream, 1000 / 30);
};

drawCombinedStream();
combinedVideoStream = canvas.captureStream(30);

Problem with Changing Text and Background Colors in Incisor TextBox

I’m working with an Incisor TextBox and having trouble changing the colors. It seems that I cannot update the text and background colors independently. Here’s the code I’m using:

class ProjectMain {

    init() {
        let textBox = new TextBox();
        textBox.string = "Hello World";
        textBox.backgroundColor = new Color(0, 1, 0, 1); // Green background
        textBox.colorMultiply.red = 1;  // Attempting to make text red
        textBox.colorMultiply.green = 0;
        textBox.colorMultiply.blue = 0;
    }
}

I expected the text to appear in red with a green background, but instead, I see red text on a black background.

However, if I remove my calls to colorMultiply, the background is green and the text is white.

let textBox = new TextBox();
textBox.string = "Hello World";
textBox.backgroundColor = new Color(0, 1, 0, 1); // Green background with white text

Could someone explain how to correctly set both the text color and the background color of the TextBox?

Is there a way to prevent a client side JS injection into my website?

I have my website, which my school has recently blocked. I found how to get around it by deleting the filter agents functions and variables (That are injected in JS) before my website loads.
However, I was wondering if there was a way to prevent the injecting JS on my website in the first place. I am using GitHub pages.

I have tried resetting the DOM tree, but I kept getting errors that I could not do this, I don’t have the error message right now, but I’ll get it soon. (Sorry about that)

flushFile = document.createElement("script");
    flushFile.setAttribute("src", "flush.js");
    document.head.appendChild(flushFile); //Loads flush.js into the DOM tree, overwriting all functions and variables of the filter agent, in browser memory to null

I am aware that most XSS attacks are on server side, but I am not worrying about that (for now). I just need to fix something like client side. If I disable all JS, yes that defeats this, but my nav bar would break, and lots of other things on my website. (https://ranchodvt.github.io/Comp-V3/index.html)

Here’s my code of deleting all the filter agents variables and funtions:

document.addEventListener('DOMContentLoaded', () => {
    
    function timeout(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    async function NotBlockingMe() {
        await timeout(75);
        console.clear();
        console.log("=====");

        // Functions
        var getLoaderPolicy = function () { }    // no-op function;
        var loadES6 = function () { }    // no-op function;
        var isYoutube = function () { }    // no-op function;
        var checkCurrentSite = function () { }    // no-op function;
        var getHardBlockPolicy = function () { }    // no-op function;
        var hardBlock = function () { }    // no-op function;
        var stopVideo = function () { }    // no-op function;
        var updateLocation = function () { }    // no-op function;

        // Variables
        var hardBlockPolicy = null;
        var prevURL = null;

        console.log("=====");

        // re-assign
        window.isYoutube = function () { }    // no-op function
        window.loadES6 = function () { }    // no-op function
        window.checkCurrentSite = function () { }    // no-op function
        window.getHardBlockPolicy = function () { }    // no-op function
        window.hardBlock = function () { }    // no-op function
        window.stopVideo = function () { }    // no-op function
        window.updateLocation = function () { }    // no-op function
        window.initFlagScanning = function () { }    // no-op function
        window.getLoaderPolicy = function () { }    // no-op function
        window.loaderPolicy = function () { }    // no-op function

        console.log("Just incase, Functions deleted again.");

        console.log("=====");
    }
NotBlockingMe()
// Other website code...
}

If I forgot something obvious, or you have a question, please don’t hesitate to ask.
I’m new to website design.

Hover Effects are treated as click effects, but they work properly after resizing page

They were working before, but I was trying to add react based page linking and that seemed to have broken the hover effects and now I cannot get them to function properly again. They do the correct hover animation on click, and work perfectly after I resize the page. It also doesn’t display the “clickable” mouse pointer hand on hovering over them and another button on the page until I resize. What is the problem here?

EDIT: It seems to work on a new page in chrome but not in a tab with many other tabs open – thats when the resize hover thing is happening.

my app page:

import React from "react";
import Home from "./pages/Home";
import "./Styles/index.css";

const App: React.FC = () => {
 return (
   <div className="app">
     <Home />
   </div>
 );
};

export default App;

my Main page:

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./Styles/index.css";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

my home page:

import React from "react";
import TopBar from "../components/TopBar";
import IntroSection from "../components/IntroSection";
import "../Styles/DefaultPage.css";

const Home: React.FC = () => {
  return (
    <div className="home-screen">
      <TopBar />
      <IntroSection />
    </div>
  );
};

export default Home;

my top bar:

import React, { useEffect, useState } from "react";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import "../Styles/TopBar.css";

gsap.registerPlugin(ScrollTrigger);

const TopBar: React.FC = () => {
  const [darkMode, setDarkMode] = useState(false);

  useEffect(() => {
    // Add button swing animation
    const navButtons = document.querySelectorAll(".nav-button");
    console.log("useEffect fired - styles should be applied now");
    navButtons.forEach((button) => {
      const btn = button as HTMLElement;

      btn.addEventListener("mouseenter", () => {
        btn.style.animation = "none"; // Remove existing animation
        btn.offsetHeight; // Trigger reflow
        btn.style.animation = "swing 2s ease-in-out forwards"; // Reapply animation
      });
      btn.style.display = "none";
      btn.offsetHeight; // Trigger reflow
      btn.style.display = ""; // Reset display
    });

    return () => {
      navButtons.forEach((button) => {
        const btn = button as HTMLElement;
        btn.removeEventListener("mouseenter", () => {});
      });
    };
  }, []);

  const toggleDarkMode = () => {
    setDarkMode((prevMode) => !prevMode);
    document.body.classList.toggle("dark-mode");
  };

  return (
    <div className="top-bar">
      <div className="nav-buttons">
        <button className="nav-button">HOME</button>
        <button className="nav-button">DEV & DESIGN</button>
        <button className="nav-button">ACTING</button>
        <button className="nav-button">FILMMAKING</button>
      </div>
      <div className="dark-mode-toggle-container">
        <button className="dark-mode-toggle" onClick={toggleDarkMode}>
          {darkMode ? "Light Mode" : "Dark Mode"}
        </button>
      </div>
    </div>
  );
};

export default TopBar;

the top bar CSS:

.top-bar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 60px;
  background-color: white;
  z-index: 10;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* Navigation buttons container */
.nav-buttons {
  display: flex;
  padding-left: 20px;
  gap: 20px; /* Space between buttons */
  height: 100%;
  padding-right: 20px;
}

/* Individual navigation button styling */
.nav-button {
  background: none;
  border: none;
  font-family: inherit;
  font-size: 1rem;
  cursor: pointer;
  color: #333;
  padding: 10px;
  transform-origin: top left;
  transition: transform 0.1s ease, color 0.3s ease;
  align-items: center;
}

/* Color change on hover */
.nav-button:hover {
  animation: wiggle 0.5s ease-in-out; /* Use the same animation keyframes */
  color: #555;
}

/* Swing animation class to add animation on hover */
.swing-animation {
  animation: swing 2s ease-in-out forwards;
}

/* Dark mode toggle button styling */
.dark-mode-toggle {
  background: none;
  border: 2px solid #333;
  font-family: inherit;
  font-size: 1rem;
  cursor: pointer;
  padding: 8px 12px;
  border-radius: 4px;
  transition: background-color 0.3s ease, color 0.3s ease;
}
.dark-mode-toggle-container {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-right: 20px;
}

.dark-mode-toggle:hover {
  background-color: #333;
  color: #fff;
}

/* Dark mode styles */
body.dark-mode {
  background-color: #333;
  color: #fff;
}

body.dark-mode .top-bar {
  background-color: #000; /* Solid black for dark mode */
}

body.dark-mode .nav-button {
  color: #ccc;
}

body.dark-mode .dark-mode-toggle {
  color: #fff;
}
@keyframes wiggle {
  0% {
    transform: rotate(0deg);
  }
  25% {
    transform: rotate(3deg);
  }
  50% {
    transform: rotate(-3deg);
  }
  75% {
    transform: rotate(2deg);
  }
  100% {
    transform: rotate(0deg);
  }
}
/* Swinging animation */
@keyframes swing {
  0% {
    transform: rotate(0deg);
  }
  10% {
    transform: rotate(15deg);
  }
  20% {
    transform: rotate(-10deg);
  }
  30% {
    transform: rotate(7deg);
  }
  40% {
    transform: rotate(-5deg);
  }
  50% {
    transform: rotate(3deg);
  }
  60% {
    transform: rotate(-2deg);
  }
  70% {
    transform: rotate(1deg);
  }
  80% {
    transform: rotate(-0.5deg);
  }
  90% {
    transform: rotate(0.2deg);
  }
  100% {
    transform: rotate(0deg);
  }
}

my current test build of the website:https://mattekranz.com/