Can someone help me create Three.js types using the frontend option I choose?

I'm currently developing a user-friendly browser application for editing shaders in three.js using react-three-fiber. I want to enhance the functionality by allowing users to add additional uniforms to the ShaderMaterial. However, I do not want to expose the underlying JavaScript code. Therefore, I am looking for a way to implement a dropdown menu that enables users to select a new uniform and provide values for it (e.g., an input field for adding an image as a Sampler2D).

My main concern is whether there is a more efficient approach to achieve this without creating an extensive list of type aliases on the frontend.

At present, my strategy involves generating an array of potential types that users can interact with in the React interface. Subsequently, the selected type's string value is processed through a large switch statement to determine the appropriate material to add. However, this method seems cumbersome and I am exploring if there is a better solution leveraging some inference or functionality within Three.js.

I provide the array of JavaScript objects generated from user inputs, which is then processed to produce an object of materials. (Note: I am unsure whether using forEach or map is more optimal in this scenario, as I am not modifying the returned array)

import * as THREE from 'three';

// determines the appropriate THREE.JS type for allocation
export function buildUniforms(uniforms: Uniform[]) {
  console.log("Building the Uniforms");
  const transformedUniforms = {};

  uniforms.map((un) => {
    console.log(un);
    let value;

    switch (un.type) {
      case "Vector3":
        value = new THREE.Vector3(un.value[0], un.value[1], un.value[2]);
        break;
      case "Vector2":
        value = new THREE.Vector2(un.value[0], un.value[1]);
        break;
      // and so on
    }

    transformedUniforms[`${un.title}`] = {
      value: value
    };
  });

  return transformedUniforms;
}

export interface Uniform {
  title: string;
  type: string;
  value: any;
}

Answer №1

If you're looking for a union type, consider this structure:

type Uniform =
  | { title: string, type: 'Vector2', value: [x?: number, y?: number]
  | { title: string, type: 'Vector3', value: [x?: number, y?: number, z?: number]

With this set up, you can simply use:

const value = new THREE[uniform.type](...uniform.value)

This way, TypeScript understands the relationship between uniform.type and uniform.value. However, we want a more flexible solution.

Let's derive the necessary types from three.js and its provided constructors.

Start by defining the constructors that are relevant for this type:

type UniformKey = 'Vector2' | 'Vector3' // | Add more types here later

Then, create a type that distributes over these options and resolves to a union of object types that correspond to each parameter pairing:

export type Uniform = {
  [K in UniformKey]: {
    title: string;
    type: K;
    value: ConstructorParameters<typeof THREE[K]>;
  }
}[UniformKey]

This resolves to a type like this:

type Uniform = {
    title: string;
    type: "Vector2";
    value: [x?: number | undefined, y?: number | undefined];
} | {
    title: string;
    type: "Vector3";
    value: [x?: number | undefined, y?: number | undefined, z?: number | undefined];
}

Now, this code snippet works seamlessly:

declare const uniforms: Uniform[]
for (const uniform in uniforms) {
  const value = new THREE[uniform.type](...uniform.value)
  console.log(value)
}

To add more supported constructors, simply update the UniformKey type.

See Playground

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to make the Nav bar overlap instead of shifting content to the right?

Is there a way to open the nav bar and have it overlap on the right without pushing content to the right? I tried experimenting with position and z-index, but it didn't work. Thank you! Link <div id="mySidebar" class="sidebar" ...

I am interested in displaying the PDF ajax response within a unique modal window

With the use of ajax, I am able to retrieve PDF base64 data as a response. In this particular scenario, instead of displaying the PDF in a new window, is it possible to display it within a modal popup? Any suggestions on how this can be achieved? $.ajax ...

Structural engineering for massive webpage

Currently I am in the process of building a large page using AngularJS. As I plan out the architecture for this page, I am debating which approach would be most effective. The page consists of 3 distinct blocks with various functionalities, but the prima ...

Tips for resolving the issue with the 'search input field in the header' across all pages in angular 5 with typescript

I currently have a search field in the header that retrieves a list of records when you type a search term and click on one of them. The search function utilizes debounceTime to reduce API requests, but I'm encountering an issue where the search doesn ...

`Creating a functional list.js filter``

I'm having trouble making the List.js filter function work properly. The documentation for List.js is not very helpful for someone new to development. Below is the code I am using: HTML: <div class="col-sm-12" id="lessons"> <input class= ...

Could you tell me the kind of theme used in Material-UI version 5?

I've decided to switch my project over to MUI version 5 and embrace the use of emotion CSS. It's come to my attention that I need to incorporate the theme property, but now TypeScript is prompting me for a type definition for it. The current code ...

Is it feasible to showcase collections from MongoDB and every individual element from all collections on a single EJS page?

I am currently working on developing a forum for my website using NodeJs, Express, MongoDB, and EJS for HTML rendering. However, I encountered an error message saying: "cannot set headers after they are sent to the client." I am a bit confused about this i ...

What is the best way to show my button only when within a specific component?

Is there a way to display the Logout button on the same line as the title only when the user has reached the Home component? In simpler terms, I don't want the logout button to be visible all the time, especially when the user is at the login screen. ...

Having trouble implementing connect-busboy in my Node.js application

Currently, I'm trying to implement image uploads in my node.js application using connect-busboy. Here's the code snippet I've written based on the reference guide https://www.npmjs.org/package/connect-busboy: router.post('/upload&apos ...

The function window.close() does not close the pop-up window when called within the pop-up

I am facing an issue with a Customer Info form that contains an anchor tag "close" meant to close the current window. This customer form is displayed as a pop-up. Within this form, there is also a search button that triggers a pop-up for the search form co ...

What could be causing the Monster model to not appear when using the glTFLoader in three.js on iOS?

-Details- three.js version : r84 (current version) Device : iPad Air2 iOS version : 10.0.2 Browser : Chrome, Safari -glTFLoader- URL : Monster -> NOT visible The rest -> visible Why am I asking this question? I have encountered a similar is ...

Issues with React in a Production Environment

After successfully developing a react app and express API that worked correctly in localhost, I decided to move my API to a digitalocean droplet. The droplet only had an IP address and used HTTP. While utilizing the API from the react app in development m ...

Check if the element is located on the active tab using jQuery

I have implemented a tab system to organize a lengthy form with multiple input fields. The form consists of 4 tabs, and beneath them, there is a preview section displaying the user's selections. In this preview area, I added icons that enable users ...

Ways to display a price near a whole number without using decimal points

Currently, I am working on an ecommerce project where the regular price of an item is $549. With a discount of 12.96% applied, the sale price comes down to $477.8496. However, I want the sale price to be displayed as either $477 or $478 for simplicity. Yo ...

Issue encountered with the Selenium JavaScript Chrome WebDriver

When it comes to testing an application, I always rely on using Selenium chromewebdriver. For beginners like me, the starting point was following this insightful Tutorial: https://code.google.com/p/selenium/wiki/WebDriverJs#Getting_Started After download ...

Exploring the latest upgrades in React 18 with a focus on TypeScript integration

I am currently working on a complex TypeScript project with React and recently made the decision to upgrade to the new version of React 18. After running the following commands: npm install react@18 npm install react-dom@18 npm install @types/react-dom@18 ...

React Native Issue: The mysterious disappearance of the 'navigation.push' object

I am trying to navigate to List.js after clicking a button in the MainMenu.js file, but I keep encountering this error: TypeError: undefined is not an object (evaluating 'navigation.push') This snippet is from my App.js file import { StatusBar ...

Express is encountering a non-executable MIME type of 'text/html' with Webpack

My express application setup is as follows: const express = require("express"); const app = express(); const server = require("http").Server(app); const path = require("path"); const port = process.env.PORT || 5000; app.use(& ...

modify the color of a particular div element in real-time

I am looking to dynamically change the color of the divs based on values from my database. Here is what I have so far: Database: shape id is_success id1 0 id2 1 id3 0 id4 1 <div class="container" style="background: black; widt ...

Tips for restricting users from inputting spaces into a form field using ReactJS

Within my application, I have developed a specialized component named QueryForm that serves the purpose of enabling search capabilities. The code snippet being outputted by this component is as follows: ...