iOS 26 Web Browser Builds, Random Missing Rendering

Hello, :grinning_face:

I am encountering a rendering issue in Cocos Creator 3.8.6 and 3.8.7 that only occurs on iOS 26 Web browsers.

Project Environment

  • 2D project
  • Spine character animations (e.g., eye slots)
  • BMFont (PNG-based)
  • Web build
  • Only default built-in shaders used
  • No alpha masking or stencil operations used

Symptoms

  • Small Spine slots (e.g., eyes) randomly do not appear
    • Some characters do not display them initially
    • Regenerating the character restores the missing slots
  • Both Label and RichText use BMFont, but sometimes the last Label or RichText to be rendered fails to display randomly.
  • Works fine on Android and iOS 16 / 18 web browsers
  • Only occurs on iOS 26 Web browsers (not limited to Safari)
  • Unrelated to scene transitions or resource release
  • Occurs randomly when DpCall is around 30โ€“80
  • Likelihood increases as the number of characters on screen grows (tested with 16 characters)

Attempts to Fix

  • Disabled Atlas Trim/Rotation option
  • Disabled Spine Premultiplied Alpha
  • Tested on latest iOS 26 web browsers
  • Upgraded Cocos from 3.8.6 โ†’ 3.8.7
  • Forced WebGL1 build

Result: Despite all attempts, the issue persists only on iOS 26 WebGL1 browsers, where specific slots or characters fail to render.

Has anyone else experienced the same issue when testing Web builds on iOS 26?

Here are two recent attempts I made to deal with the rendering issue:

1. Calling functions like markForUpdateRenderData after setting a node active

  • Example code:
public static refreshAll(node: Node, withDelay: boolean = true) {
    const doRefresh = () => {
      // ----- Sprite -----
      node.getComponents(Sprite).forEach((c) => {
        c.markForUpdateRenderData();
        c.color = c.color; // Safari dirty trick
      });

      // ----- Label -----
      node.getComponents(Label).forEach((c) => {
        c.updateRenderData(true);
        c.markForUpdateRenderData();
        c.color = c.color; // Safari dirty trick
      });

      // ----- RichText -----
      node.getComponents(RichText).forEach((rich) => {
        // Reassign the same value to trigger dirty flag
        rich.string = rich.string;

        // Force update child labels inside RichText
        rich.node.children.forEach((child) => {
          const lbl = child.getComponent(Label);
          if (lbl) {
            lbl.updateRenderData(true);
            lbl.color = lbl.color; // Safari dirty trick
          }
        });
      });

      // ----- Spine -----
      const spines = node.getComponents("sp.Skeleton") as any[];
      spines.forEach((c: any) => {
        if (c.markForUpdateRenderData) {
          c.markForUpdateRenderData();
        }
        if (c.invalidAnimationCache) {
          c.invalidAnimationCache();
        }
        c.node.setScale(c.node.scale.x, c.node.scale.y); // Safari dirty trick
      });

      // ----- Node scale dirty trick -----
      node.setScale(node.scale.x, node.scale.y);

      // ----- Recursively refresh children -----
      node.children.forEach((child) => this.refreshAll(child, false));
    };

    if (withDelay) {
      setTimeout(doRefresh, 0); // Run on the next frame
    } else {
      doRefresh();
    }
}

2. Forcing a draw by calling gl.flush() after Director.EVENT_AFTER_DRAW

  • Example code:
const canvas = document.querySelector("canvas") as HTMLCanvasElement; 
const gl = canvas.getContext("webgl2") || canvas.getContext("webgl");
if (gl) gl.flush();

In both cases, there was some effect (previously invisible elements started showing up), but when multiple objects failed to render, these tricks were not sufficient to fix the issue completely.

Given that iOS 26 initially struggled with overheating problems, I suspect Apple might have introduced some internal optimizations or changes in later patches, which could be the underlying cause of this behavior.

When using the Additive BlendMode for Spine animations on iOS 26, certain parts do not render correctly.
This issue seems separate from the UI font not rendering problem, but the symptoms appear similar, so I wanted to report it here.

Using a system font or a dynamic font (like a TTF) instead of a BMFont can fix the issue where text is not visible.

I encountered the same problem. Did you find a solution?

@nizakifx
I havenโ€™t found an exact solution yet. In the game, Iโ€™m trying to keep the draw calls under 30, and for cases occurring in the UI, Iโ€™m avoiding the issue by using System Fonts instead of BMFont.

We also encountered the whole problem, which troubled us for two months