Why does babylonjs-gui need something from `document`?

I tried putting babylonjs-gui on a worker thread but somehow i would get an error.

I don’t think i’m using anything from document with my implementation, i just wanted to overlay a texture in my 3d scene.

This is my usage, I have no intention of working with Dom. Somehow this breaks my plan to put everything on a Worker thread. Any advice on how to overlay text without using babylonjs-gui?

import { AdvancedDynamicTexture, TextBlock, Control } from 'babylonjs-gui';

export class CenterHud {
  public hudTexture: AdvancedDynamicTexture;
  public hudTextBlock: TextBlock;
  public refreshRate: number;

  constructor() {
    this.hudTexture = AdvancedDynamicTexture.CreateFullscreenUI('HUD');
    this.hudTextBlock = new TextBlock();
    this.refreshRate = 0;

    this.hudTextBlock.textHorizontalAlignment =
    this.hudTextBlock.textVerticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;

    this.hudTextBlock.text = '';
    this.hudTextBlock.fontSize = 12;
    this.hudTextBlock.color = 'white';

  public update(contentGenerator: () => string, delta: number) {
    this.refreshRate += delta;
    if (this.refreshRate < 200) return;
    this.hudTextBlock.text = contentGenerator();
    this.refreshRate = 0;

the GUI lib requires document to create canvas elements. They allow us to update the GUI elements dynamically (and create them in place). If you are doing anything with text or images (which I assume you are), you will need document available to create the needed element(s).

What can you do?.. that’s a good question. document is not optional. It is very much needed. You could create the textures in the UI thread and pass them to the web worker, but that feels like too much work for nothing. There must be a section of your code that is running in the UI thread, just make sure to use the GUI in this section. The rest of the hard work can be done in the worker.

Thanks @RaananW!

Hi @RaananW , first of all I have to say I’m a beginner in all this, but I dug in a little more about this.

It seems for my planned application at least, it was sufficient to overlay HTML Elements on top of the main renderCanvas.

Overlay on top of main thread renderCanvas

Overlay on top of worker thread renderCanvas

I’m adding a snippet for other beginners like me who might find this as an alternative option.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <title>Waning Engine</title>

      body {
        overflow: hidden;
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;

      .noselect {
        -webkit-touch-callout: none; /* iOS Safari */
        -webkit-user-select: none; /* Safari */
        -khtml-user-select: none; /* Konqueror HTML */
        -moz-user-select: none; /* Old versions of Firefox */
        -ms-user-select: none; /* Internet Explorer/Edge */
        user-select: none; /* Non-prefixed version, currently supported by Chrome, Edge, Opera and Firefox */

      .flex-container {
        display: flex;
        align-content: stretch;

      #renderCanvas {
        width: 100%;
        height: 100%;
        touch-action: none;
        z-index: 1; /* Make sure this is behind the overlays */

      .bottom-footer {
        position: fixed;
        left: 0;
        bottom: 0;
        width: 100%;
        height: 50px;
        color: white;
        text-align: center;
        z-index: 2;
        background-color: rgba(0, 0, 0, 0.5);

      .top-header {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 50px;
        color: white;
        text-align: center;
        z-index: 3;
        background-color: rgba(0, 0, 0, 0.5);

    <canvas id="renderCanvas" touch-action="none"></canvas>
    <div class="flex-container noselect top-header">
        Test Overlay Text
      <button onclick="console.log('Top_Button_1')">
      <button onclick="console.log('Top_Button_2')">
      <button onclick="console.log('Top_Button_3')">
    <div class="flex-container noselect bottom-footer">
      <button onclick="console.log('Bottom_Button_1')">
      <button onclick="console.log('Bottom_Button_2')">
      <button onclick="console.log('Bottom_Button_3')">
    <!--- more code --->
    <script src="bootstrap.bundle.js"></script>

Also linking this phase of the development at least for this pet project. There may seem a lot of bad practices here though since I’m still figuring things out bit by bit. :rofl:

1 Like