Search code examples
pythonjupyter-notebookjupyteraframejupyter-lab

Embedded A-Frame scene in Jupyter Lab (Python)?


I'm trying to show a A-Frame scene in JupyterLab, in a Jupyter notebook, from Python code. But I cannot find the way. The scene can be, for example, this (just a simple one):

<html>
  <head>
    <script src="https://aframe.io/releases/1.2.0/aframe.min.js" 
  </head>
  <body>
    <div id="aframe" style="width: 300px; height: 300px">
type="text/javascript"></script>
      <a-scene embedded>
        <a-box position="0 0 -4" color="red"></a-box>
      </a-scene>
    </div>
  </body>
</html>

I'm trying, after reading some references, with:

import IPython
IPython.display.HTML('<script src="https://aframe.io/releases/1.2.0/aframe.min.js" type="text/javascript"></script>')
aframe = '''<div id="aframe" style="height: 300px">
<a-scene embedded>
<a-box position="0 0 -4" color="red"></a-box>
</a-scene>
</div>'''
IPython.display.HTML(aframe)

I get a blue cell, with a "JupyterLab" label, and loading dots (similar to a A-Frame scene loading), forever. If I look in the console, I read:

A-Frame:warn Put the A-Frame <script> tag in the <head> of the HTML *before* the scene to ensure everything for A-Frame is properly registered before they are used from HTML.

Uncaught Error: A a-node type is already registered
    Aframe 18

Since the warning is about injecting the script in the header, and after reading this reference, I wrote:

%%javascript
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = '//aframe.io/releases/1.2.0/aframe.min.js';
    document.head.appendChild(script);
    console.log(window.AFRAME);

And then, in another cell:

import IPython
aframe = '''<div id="scene" style="height: 300px">
<a-scene embedded>
<a-box position="0 0 -4" color="red"></a-box>
</a-scene>
</div>
'''
IPython.display.HTML(aframe)

Curiously enough, this works when I run those two cells in a notebook for the first time. But if I shutdown the Jupyter kernel, launch it again, and just load the same notebook with those two cells, I get the blue cell again (without even running the cells). If I look at the head element in the HTML page, the A-Frame script element is there. But if I run (in another cell):

%%javascript
    console.log(window.AFRAME)

I get undefined in the console.

I'm a bit out of ideas. Maybe something related to the order in which scripts (A-Frame and Jupyter scripts) are loaded?

I'm using Firefox, just in case that matters.

Any idea?


Solution

  • Thanks to the comment by @krassowski, here we have some code that works:

    from urllib.parse import quote
    import IPython
    
    content = quote(
            """
            <html>
                <head>
                    <script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
                </head>
                <body>
                    <a-scene embedded>
                        <a-box position="0 0 -4" color="red"></a-box>
                    </a-scene>
                </body>
            </html>
            """,
            safe=''
        )
    html = """
        <iframe
            width="400"
            height="300"
            src="data:text/html;charset=UTF-8,{content}"
        ></iframe>
        """.format(content=content)
    IPython.display.HTML(html)
    

    which produces this output when run in a Jupyter Lab cell:

    Screenshot of the result, showing a red box