GLB viewer not loading on IOS

I am writing a glb viewer. It loads and wroks as expected on android and windows. However it does not load on IOS.

When I change the clearcolor of the camera I can see the changes in IOS so the camera seem to load properly. But when I create a simple cube it doesn’t load on IOS.

Is there a way to properly load GLB and hdr on IOS ?

My script is hosted here :

From what I understand I have this issue when I try to load an image, either as an hdr or as a texture. When I don’t load images the script works as expected.

My images texture are 2k so they should not be too heavy and the hdr is one provide in your examples (https://playcanvas.vercel.app/static/assets/cubemaps/helipad-env-atlas.png).

I am sorry for not being precise in my request, but I am confused on the origin of the issue. I tried to display alerts to find the cause. Everything seems to load just fine yet it just displays the clearcolor of the camera.

To you have it deployed somewhere people can try?

it should be visible here :

the viewer functions are here :

and it is used in this script :

(The first function of the viewer is just to display the console log on the screen because I don’t have a mac to access the dev mode)

You get this error:

AI explanation:
The SecurityError: The operation is insecure. message when calling texImage2D in WebGL typically indicates that you’re attempting to use image data in a way that violates browser security policies. This often happens under the following conditions, especially on iOS:


:lock: Root Causes

1. Cross-Origin Image Loading

If you load an image from another domain (or even a different port), WebGL considers it “tainted” unless it’s CORS-enabled. This prevents the image from being used in WebGL textures for security reasons.

  • Fix: Make sure your image source includes the correct CORS headers, and load it like this:

javascript

CopyEdit

const image = new Image();
image.crossOrigin = 'anonymous';
image.src = 'https://example.com/your-image.png';

Also, your server needs to send this header:

makefile

CopyEdit

Access-Control-Allow-Origin: *

Or a more restricted version that matches your origin.


2. Using Image/Video/Canvas Without CORS or Tainting

If you draw a video, canvas, or image with mixed origins to another canvas, that canvas becomes “tainted”, and WebGL can’t sample from it.

  • Fix: Ensure that all resources drawn into the canvas are either from the same origin or are properly CORS-enabled.

3. iOS-Specific Safari Issues

Safari on iOS is stricter and behaves slightly differently:

  • It may block texImage2D with images or video from cross-origin sources, even with CORS headers, unless explicitly allowed.
  • Sometimes, images loaded through <img src="..."> behave differently than ones loaded through fetch() or other APIs.

:white_check_mark: Best Practices to Avoid This Error

  1. Use crossOrigin = 'anonymous' before setting src.
  2. Ensure the server serving the image has correct CORS headers.
  3. Use HTTPS consistently for both the main page and image/video sources.
  4. Avoid mixing secure (https) and insecure (http) content.

Thank you very much !

I solved the error using the following function instead of loading the texture in the assets :

async function loadImageAsTexture(url, app) {
    return new Promise((resolve, reject) => {
        const img = new window.Image();
        img.crossOrigin = "anonymous";
        img.onload = function() {
            const tex = new pc.Texture(app.graphicsDevice, {
                width: img.width,
                height: img.height,
                format: pc.PIXELFORMAT_R8_G8_B8_A8,
            });
            tex.setSource(img);
            resolve(tex);
        };
        img.onerror = reject;
        img.src = url;
    });
}

I am not sure it’s super clean but it works !

Also, I would like to thank the playcanvas team and moderators. I have been asking many questions lately and you are always quick and helpful in your answers that is truly amazing :pray::pray:

1 Like

Will it be possible to fix the assets loader methods to make it work smoothly on IOS or is my implementation (I host my images in a public huggingfacedataset) unconventional and I should change it ?

This is your hosting related, browsers have cross domain limits, your hosting needs to be set up to allow this, especially the separate domain you load images from. Ideally load images from the same domain as the rest of your website.

I am doing this project for a client’s website. Should all the images be hosted in the client’s website or in my huggingface sapce with the rest of the scripts ?

@ar_galeries we are working on ios App with arkit. IOS not allow glb you have to export usdz format for ios