Rhino3DM 3JS viewer in Streamlit

Hi All,

I have some code which turns a Rhino3DM file into a 3JS model using JS. I want to put this in a streamlit website but am not sure how to go about it or if it’s even possible.

Code below.

Thanks,

import * as THREE from 'three';
import {OrbitControls} from 'three/addons/controls/OrbitControls.js'
import { Rhino3dmLoader } from 'three/addons/loaders/3DMLoader.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

let camera, scene, renderer;
let controls, gui;
init();
animate();

function init() {

  THREE.Object3D.DEFAULT_UP.set( 0, 0, 1 );

  renderer = new THREE.WebGLRenderer( { antialias: true } );
  renderer.setPixelRatio( 2 );
  renderer.setSize( window.innerWidth, window.innerHeight );
  renderer.outputEncoding = THREE.sRGBEncoding;
  document.body.appendChild( renderer.domElement );

  camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
  camera.position.set( 40, -40, 50 );

  scene = new THREE.Scene();

  const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
  scene.add(ambientLight);
  
  const directionalLight = new THREE.DirectionalLight( 0xffffff, 2 );
  directionalLight.position.set( 20, 40, 100);
  scene.add( directionalLight );

  const loader = new Rhino3dmLoader();
  loader.setLibraryPath( 'https://cdn.jsdelivr.net/npm/rhino3dm@7.15.0/' );
  loader.load( '/static/sunlight.3dm', function ( object ) {

    scene.add( object );
    initGUI( object.userData.layers );

    // hide spinner
    document.getElementById( 'loader' ).style.display = 'none';

  } );

  controls = new OrbitControls( camera, renderer.domElement );
  controls.enableZoom = true;
  controls.enableDamping = true;
  controls.dampingDactor = 0.05;

  controls.minDistance = 100;
	controls.maxDistance = 500;

  controls.maxPolarAngle = Math.PI / 2;

  window.addEventListener( 'resize', resize );

function resize() {

  const width = window.innerWidth;
  const height = window.innerHeight;

  camera.aspect = width / height;
  camera.updateProjectionMatrix();

  renderer.setSize( width, height );

}

function animate() {

  controls.update();
  renderer.render( scene, camera );
  renderer.setPixelRatio(2)
  requestAnimationFrame( animate );

}

function submitForm() {
  var form = document.getElementById('variables-form');
  var formData = new FormData(form);
  var xhr = new XMLHttpRequest();
  xhr.open('POST', form.action, true);
  xhr.onload = function() {
  };
  xhr.send(formData);
  return false;
}

function initGUI( layers ) {
  gui = new GUI({ 
  title: '<i class="fa-solid fa-layer-group"></i>',
  });

  for ( let i = 0; i < layers.length; i ++ ) {

    const layer = layers[ i ];
    gui.add( layer, 'visible' ).name( layer.name ).onChange( function ( val ) {

      const name = this.object.name;

      scene.traverse( function ( child ) {

        if ( child.userData.hasOwnProperty( 'attributes' ) ) {

          if ( 'layerIndex' in child.userData.attributes ) {

            const layerName = layers[ child.userData.attributes.layerIndex ].name;

            if ( layerName === name ) {

              child.visible = val;
              layer.visible = val;

            }

          }

        }

      } );

    } );

  }

}

Hello there,
To integrate your code into a Streamlit website, you need to follow a few steps:

  1. Install the necessary dependencies: Streamlit, three.js, and the Rhino3dmLoader.
  2. Create a new Python file (e.g., app.py) and import the required modules.
  3. Use the streamlit module to create a Streamlit app and define the layout and behavior.
  4. Embed the JavaScript code within the Streamlit app using the st.components.v1.html function.

You can follow these steps .

Hi @sakp7,

I have tried this however it doesn’t work.

import json

import requests
import rhino3dm as rh
import streamlit as st
from streamlit import components as stc

def three_js_component():
    html_code = """
    <html>
      <head>
        <script type="module">
            import * as THREE from 'three';
            import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
            import { Rhino3dmLoader } from 'three/addons/loaders/3DMLoader.js';
            import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

            let camera, scene, renderer;
            let controls, gui;
            init();
            animate();

            function init() {

            THREE.Object3D.DEFAULT_UP.set( 0, 0, 1 );

            renderer = new THREE.WebGLRenderer( { antialias: true } );
            renderer.setPixelRatio( 2 );
            renderer.setSize( window.innerWidth, window.innerHeight );
            renderer.outputEncoding = THREE.sRGBEncoding;
            document.body.appendChild( renderer.domElement );

            camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
            camera.position.set( 40, -40, 50 );

            scene = new THREE.Scene();

            const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
            scene.add(ambientLight);
            
            const directionalLight = new THREE.DirectionalLight( 0xffffff, 2 );
            directionalLight.position.set( 20, 40, 100);
            scene.add( directionalLight );

            const loader = new Rhino3dmLoader();
            loader.setLibraryPath( 'https://cdn.jsdelivr.net/npm/rhino3dm@7.15.0/' );
            loader.load( './output.3dm', function ( object ) {

                scene.add( object );
                initGUI( object.userData.layers );

                // hide spinner
                document.getElementById( 'loader' ).style.display = 'none';

            } );

            controls = new OrbitControls( camera, renderer.domElement );
            controls.enableZoom = true;
            controls.enableDamping = true;
            controls.dampingDactor = 0.05;

            controls.minDistance = 100;
                controls.maxDistance = 500;

            controls.maxPolarAngle = Math.PI / 2;

            window.addEventListener( 'resize', resize );

            function resize() {

            const width = window.innerWidth;
            const height = window.innerHeight;

            camera.aspect = width / height;
            camera.updateProjectionMatrix();

            renderer.setSize( width, height );

            }

            function animate() {

            controls.update();
            renderer.render( scene, camera );
            renderer.setPixelRatio(2)
            requestAnimationFrame( animate );

            }

            function submitForm() {
            var form = document.getElementById('variables-form');
            var formData = new FormData(form);
            var xhr = new XMLHttpRequest();
            xhr.open('POST', form.action, true);
            xhr.onload = function() {
            };
            xhr.send(formData);
            return false;
            }

            function initGUI( layers ) {
            gui = new GUI({ 
            title: '<i class="fa-solid fa-layer-group"></i>',
            });

            for ( let i = 0; i < layers.length; i ++ ) {

                const layer = layers[ i ];
                gui.add( layer, 'visible' ).name( layer.name ).onChange( function ( val ) {

                const name = this.object.name;

                scene.traverse( function ( child ) {

                    if ( child.userData.hasOwnProperty( 'attributes' ) ) {

                    if ( 'layerIndex' in child.userData.attributes ) {

                        const layerName = layers[ child.userData.attributes.layerIndex ].name;

                        if ( layerName === name ) {

                        child.visible = val;
                        layer.visible = val;

                        }

                    }

                    }

                } );

                } );

            }

            }
        </script>
      </head>
      <body>
        <canvas id="canvas"></canvas>
      </body>
    </html>
    """
    st.components.v1.html(html_code, height=600)

def main():
    st.title("Three.js Component Demo")
    st.markdown("This is a demo of a Three.js component embedded using Streamlit.")

    st.subheader("Three.js Component")
    three_js_component()

if __name__ == "__main__":
    main()```

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.