What are the solutions for resolving CORS issues with a local HTML file using three.js?

I have been attempting to create a sphere using three.js with an image texture, but no matter if it's a local image or an https image online, I always encounter the following error:

Access to image at 'file:///C:/Users//.....//sun.jpg' from origin 'null' has been blocked by CORS policy: Cross-origin requests are only supported for protocol schemes: http, data, isolated-app, chrome-extension, chrome, https, chrome-untrusted. GET file:///C:/Users/...../sun.jpg net::ERR_FAILED

Below is the code snippet I am using:

const geometry = new THREE.SphereGeometry(5, 32, 32);
const loader = new THREE.TextureLoader().load("sun.jpg");
const material = new THREE.MeshBasicMaterial({
    map: loader
});
const sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);

Answer №1

Web browsers have security measures in place that prevent them from loading files directly from the local file system.

There are a few solutions to this issue:

  1. One option is to serve the image through a web server such as express or nginx.

  2. Another solution is to utilize a cloud storage bucket and access the image via URI.

  3. You could also convert the image into base64 format and display it directly using

    new THREE.TextureLoader().load(yourBase64string)
    .

Answer №2

Among the various protocols like http://, https://, the file protocol, file:// also exists, but with additional restrictions.

When you tried to reference a file like sun.jpg, the browser considered it a relative URL and looked at the base URL of the document for resolution. Since it was from the file:// protocol, certain restrictions were applied, such as the inability to read local files. The error message provided may be slightly misleading.

Browsers offer two native methods for accessing local files: using the file input tag or drag-and-drop feature. Both options require user interaction. If these methods fail, you might need a browser extension with an executable or set up a HTTP server.

By utilizing the file input tag, you can select specific files for access, generate internal URLs for them, and use them just like any other URL in your code.

<!-- Sample HTML -->
<html>
      <head>
            <style>
                  body {
                        margin                : 40px;
                        font-family           : arial;
                  }
                  /* CSS styles omitted for brevity */
            </style>
      </head>
      <body>
            /* A simple HTML structure for file handling - omitted for brevity */
      </body>
<script type="module">
      // JavaScript code for Three.js functionality
</script>
</html>

Access this JSBin link for related content.

If constantly selecting files becomes tedious, you can use a script mentioned above that enables persistent storage of files in localStorage. However, there is a limit of around 5MB.

The provided script allows you to persistently store selected files using localStorage for easy access across pages and page reloads within the file:// protocol.

In terms of CORS regulations, the file:// protocol follows similar policies to others. For successful data access by JavaScript, responses must contain the correct CORS headers defined through Access-Control-Allow-Origin:* when under file:// protocol due to null document.domain status.

.

  • Check out a similar example here
  • View an image sample here
  • Browse Mr.doob's work here
  • Explore Matter.js along with three.js here

For more insights into servers:

  • Try stackblitz
  • Get help on setting up a local web server in Visual Studio Code on Stack Overflow
  • Discover the basics of Node.js here

Join the Javascript chat on Stack Overflow

Have a great time!

.

Find another relevant answer I provided on Stack Overflow here.



To get started, try the following with internet access for loading Three.js model:

Use the file button to choose a file from your local drive

      
      function url_change(e){
          
          texture(e.target.value);
      }
      
      function file_change(e){
        
          var blob    = e.target.files[0];
          var url     = URL.createObjectURL(blob);
          texture(url);
      }
body {
  display:flex;
  align-items:top;
  gap:20px;
}
input {
  font-size:16px;
  padding:5px;
  width:250px;
  margin-left:20px;
}
span {
  display:inline-block;
}
<body>
  <span></span>
  <div>
        <input type=file onchange='file_change(event)'>
        <br>
        url<input onchange='url_change(event)'>
        <br>
        <input type=button value=mesh onclick='mesh(event)'>
  </div>
</body>

<script type="module">
      
      import * as THREE from 'https://esm.run/three';

      window.mesh=function(){
        
            var meshMaterial    = new THREE.MeshPhongMaterial({color:'lightblue',emissive:'blue',flatShading:true});
            ready(meshMaterial);
      
      }            
      
      window.texture=function(url){
        
            const cargador = new THREE.TextureLoader().load(url); 
            const cargaTextura = new THREE.MeshBasicMaterial({ map: cargador }); 
            ready(cargaTextura);
            
      }
      
      function ready(material){
        
            var scene           = new THREE.Scene();
            scene.background    = new THREE.Color('gray');
          
            var camera          = new THREE.PerspectiveCamera(75,1,1,50);
            camera.position.z   = 50;
          
            var renderer        = new THREE.WebGLRenderer();
            renderer.setSize(300,300);
            document.body.querySelector('span').replaceChildren(renderer.domElement);
          
            var lights          = new THREE.DirectionalLight('white',3);
            lights.position.set(75,75,200);
            scene.add(lights);
          
            //var geometry      = new THREE.BufferGeometry();
            const geometry      = new THREE.SphereGeometry(25, 32, 32); 
        
            const sphere = new THREE.Mesh(geometry,material); 
            scene.add(sphere);
      
      
            (function render() {
                    sphere.rotation.y  += 0.005;
                    renderer.render(scene,camera);
                    requestAnimationFrame(render);
            })();

      }//setup
      
      mesh();
      
</script>

You can paste a URL into the text field and press enter, or click the mesh button for further actions.

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

Attempting to create a JavaScript function that will show a JSON array when the next button is clicked

I am facing an issue with displaying a JSON array based on specific start and end indices. Even though I managed to display the entire array, the first button click does not seem to work as expected. Upon clicking the first button, an error message "this.d ...

Trouble with JavaScript preventing the opening of a new webpage

I need help with a JavaScript function to navigate to a different page once the submit button is clicked. I have tried using the location.href method in my code, but it's not working as expected. Even though I am getting the alert messages, the page i ...

Utilizing Lodash in TypeScript to merge various arrays into one cohesive array while executing computations on each individual element

I am working with a Record<string, number[][]> and attempting to perform calculations on these values. Here is an example input: const input1 = { key1: [ [2002, 10], [2003, 50], ], }; const input2 = { key ...

The reactivity of a Vue.js computed property diminishes when it is transmitted through an event handler

Within my main application, I've implemented a Modal component that receives content via an event whenever a modal needs to be displayed. The Modal content consists of a list with an associated action for each item, such as "select" or "remove": Vue. ...

What is the best way to showcase a PHP variable on a webpage using a JavaScript function?

Is there a way to make use of a JavaScript function (triggered by a button "click event") in order to showcase a PHP variable on my webpage? When I utilize a direct text string in my function, everything works perfectly fine. However, if I swap that text ...

Error: Unable to cast value "undefined" to an ObjectId for the "_id" field in the "User" model

Whenever a user logs into their account, I am trying to retrieve their data on the login screen. The login functionality itself works perfectly, but unfortunately, the user data is not displaying. I have tried troubleshooting this issue by making changes i ...

Dynamic content cannot have classes added to them using jQuery

When adding content dynamically, it is necessary to use an event handler for a parent element using on(). However, I am facing an issue where the class added with addClass on dynamically generated content disappears immediately. Let's take a look at ...

Debugging JavaScript on the client side for Internet Explorer

Can we skip over a Javascript statement without running it in the Developer Tools of Internet Explorer? Similar to the "Set next statement" feature in Visual Studio debugger... ...

JavaScript Tutorial: Simplifying Character Ranges for Conversion

I am currently working on adapting code I found here to create a virtual keyboard for a foreign alphabet using an online textarea. Below is the modified code: <textarea id="txt"></textarea> <script src="https://ajax.googleapi ...

Generate various buttons dynamically using server-side Ajax data table

Below is the table structure: <table id="example" class="display" cellspacing="0" width="100%"> <thead> <tr> <th>Name</th> <th>Position</th> <th>Office</th ...

Guide on developing a dynamic Navbar component on Laravel Mix with Vue Js

As I delve into learning and practicing Vue.js, my goal is to create a component that includes elements like Navbar and Footer within a single view. Initially, I set up an index for the first view but faced an issue with adding the navbar as it did not sho ...

Harnessing the Power of Google Apps Scripts: Mastering the Art of Handling Comma-Separated Spreadsheet Values Transformed

I have a spreadsheet where column 1 contains source file IDs, with each cell holding only one ID. Column 2 has destination file IDs, where cells contain multiple IDs separated by commas. I utilize a script to retrieve these values and perform various opera ...

Issue with IE11: the selected list is not displayed when using the <s:optiontransferselect> tag

When moving groups from left to right in the s:optiontransferselect for selectedGrps and unselectedGrps, the SelectedGroups list is showing as null on form submission in IE11. However, in Chrome and Mozilla, it functions correctly. Any advice would be grea ...

Make the Bootstrap country picker default to "Not Selected"

When using the Bootstrap country picker, I have implemented the code below to populate countries. Everything is working as expected, however, there is no default selection of "Not Selected." Is there a workaround for this issue? <script> $('.c ...

Add several additional views following an element within a View in Backbone

addDimensions: function (order_id, counter) { this.dimensionsView = new dimensionsView({ el: "#panel-boxes-" + order_id + "_" + counter, id: order_id, counter: counter }); $("#panel-boxes-" + order_id + "_1").append(this.dimensionsView.render().el) ...

What are some methods for preventing JavaScript function calls from the browser console?

In the process of developing a web application using HTML and JavaScript, I'm looking for a way to prevent users from accessing functions through their browser console in order to maintain fairness and avoid cheating. The functions I want to protect a ...

How to locate and extract specific data from a webpage table using JavaScript and Node.js for web scraping and storing in an array of objects

Exploring the realm of web scraping by targeting a UFC betting site for data extraction. JavaScript, alongside request-promise and cheerio packages, is utilized in this endeavor. Site: The primary aim is to retrieve the fighters' names along with th ...

What about nested elements with percentages, set positions, and fixed placements?

Picture: https://i.sstatic.net/KFNR1.png I am working on a design with a yellow container div that I want to keep at 50% width of the window. Inside this container is a purple image div that stretches to 100% of the parent container's width, and ther ...

Initiate automatic submission

After receiving some valuable assistance from users on stackoverflow, I've successfully implemented the following code. However, I've now realized that it needs to be triggered when the page loads instead of on a trigger. Since I am new to client ...

The light/dark mode toggle is a one-time use feature

I've been experimenting with creating a button to toggle between light and dark modes on my website. Initially, it's set to light mode, but when I try switching to dark mode, it works fine. However, the issue arises when attempting to switch back ...