Spaces:
Runtime error
Runtime error
| import streamlit as st | |
| import streamlit.components.v1 as components | |
| # Initialize session state | |
| if 'settings' not in st.session_state: | |
| st.session_state['settings'] = {} | |
| # Function to update widgets based on saved settings | |
| def load_settings(): | |
| settings = st.session_state['settings'] | |
| st.session_state.cube_color = settings.get("cube_color", "#00ff00") | |
| st.session_state.rotation_speed = settings.get("rotation_speed", 0.01) | |
| st.session_state.cube_position_x = settings.get("cube_position_x", 0) | |
| st.session_state.cube_position_y = settings.get("cube_position_y", 0) | |
| st.session_state.cube_position_z = settings.get("cube_position_z", 0) | |
| st.session_state.cube_scale = settings.get("cube_scale", 1.0) | |
| st.session_state.show_bounding_box = settings.get("show_bounding_box", True) | |
| st.session_state.spotlight_intensity = settings.get("spotlight_intensity", 1.0) | |
| st.session_state.ambient_light_intensity = settings.get("ambient_light_intensity", 0.5) | |
| st.session_state.camera_view = settings.get("camera_view", "Default") | |
| st.write("Loaded settings into session state:", settings) | |
| # Create two columns for layout | |
| col1, col2 = st.columns([1, 3]) | |
| with col1: | |
| # Streamlit widgets to control the scene | |
| cube_color = st.color_picker("Pick a cube color", st.session_state.get('cube_color', "#00ff00")) | |
| rotation_speed = st.slider("Rotation Speed", min_value=0.01, max_value=0.1, value=st.session_state.get('rotation_speed', 0.01)) | |
| cube_position_x = st.slider("Cube Position X", min_value=-10, max_value=10, value=st.session_state.get('cube_position_x', 0)) | |
| cube_position_y = st.slider("Cube Position Y", min_value=-10, max_value=10, value=st.session_state.get('cube_position_y', 0)) | |
| cube_position_z = st.slider("Cube Position Z", min_value=-10, max_value=10, value=st.session_state.get('cube_position_z', 0)) | |
| cube_scale = st.slider("Cube Scale", min_value=0.1, max_value=5.0, value=st.session_state.get('cube_scale', 1.0)) | |
| show_bounding_box = st.checkbox("Show Bounding Box", value=st.session_state.get('show_bounding_box', True)) | |
| spotlight_intensity = st.slider("Spotlight Intensity", min_value=0.0, max_value=2.0, value=st.session_state.get('spotlight_intensity', 1.0)) | |
| ambient_light_intensity = st.slider("Ambient Light Intensity", min_value=0.0, max_value=2.0, value=st.session_state.get('ambient_light_intensity', 0.5)) | |
| camera_view = st.selectbox("Camera View", ["Default", "Top", "Side"], index=["Default", "Top", "Side"].index(st.session_state.get('camera_view', "Default"))) | |
| # Save settings button | |
| if st.button("Save Settings"): | |
| st.session_state['settings'] = { | |
| "cube_color": cube_color, | |
| "rotation_speed": rotation_speed, | |
| "cube_position_x": cube_position_x, | |
| "cube_position_y": cube_position_y, | |
| "cube_position_z": cube_position_z, | |
| "cube_scale": cube_scale, | |
| "show_bounding_box": show_bounding_box, | |
| "spotlight_intensity": spotlight_intensity, | |
| "ambient_light_intensity": ambient_light_intensity, | |
| "camera_view": camera_view | |
| } | |
| st.write("Settings saved:", st.session_state['settings']) | |
| # Load settings button | |
| if st.button("Load Settings"): | |
| st.write("Loading settings...") | |
| load_settings() | |
| st.write("Settings loaded:", st.session_state['settings']) | |
| st.rerun() | |
| def three_js_component(cube_color, rotation_speed, cube_position_x, cube_position_y, cube_position_z, cube_scale, show_bounding_box, spotlight_intensity, ambient_light_intensity, camera_view): | |
| component_code = f""" | |
| <div id="threejs-container" style="width: 100%; height: 600px; background-color: #000;"></div> | |
| <script> | |
| (function() {{ | |
| if (document.getElementById('threejs-container-script')) {{ | |
| return; | |
| }} | |
| function loadScript(url, callback) {{ | |
| console.log('Loading script:', url); | |
| var script = document.createElement("script"); | |
| script.type = "text/javascript"; | |
| script.onload = function() {{ | |
| console.log('Loaded script:', url); | |
| callback(); | |
| }}; | |
| script.onerror = function() {{ | |
| console.error('Error loading script:', url); | |
| }}; | |
| script.src = url; | |
| document.getElementsByTagName("head")[0].appendChild(script); | |
| }} | |
| function initializeScene() {{ | |
| console.log('Initializing Scene'); | |
| const container = document.getElementById('threejs-container'); | |
| if (!container) {{ | |
| console.error('Container not found!'); | |
| return; | |
| }} | |
| const scene = new THREE.Scene(); | |
| console.log('Created scene'); | |
| const camera = new THREE.PerspectiveCamera(75, container.clientWidth / container.clientHeight, 0.1, 1000); | |
| console.log('Created camera'); | |
| const renderer = new THREE.WebGLRenderer(); | |
| renderer.setSize(container.clientWidth, container.clientHeight); | |
| renderer.shadowMap.enabled = true; | |
| container.appendChild(renderer.domElement); | |
| console.log('Created renderer and appended to container'); | |
| const controls = new THREE.OrbitControls(camera, renderer.domElement); | |
| controls.enableDamping = true; | |
| controls.dampingFactor = 0.25; | |
| controls.screenSpacePanning = false; | |
| controls.minDistance = 1; | |
| controls.maxDistance = 100; | |
| controls.maxPolarAngle = Math.PI / 2; | |
| console.log('Initialized Orbit Controls'); | |
| // Add a spotlight for lighting | |
| const spotLight = new THREE.SpotLight(0xffffff, {spotlight_intensity}); | |
| spotLight.position.set(10, 10, 10); | |
| spotLight.castShadow = true; | |
| scene.add(spotLight); | |
| console.log('Spotlight added'); | |
| // Add ambient light | |
| const ambientLight = new THREE.AmbientLight(0x404040, {ambient_light_intensity}); // Soft white light | |
| scene.add(ambientLight); | |
| console.log('Ambient light added'); | |
| // Add a plane to receive shadows | |
| const planeGeometry = new THREE.PlaneGeometry(200, 200); | |
| const planeMaterial = new THREE.ShadowMaterial({{ opacity: 0.5 }}); | |
| const plane = new THREE.Mesh(planeGeometry, planeMaterial); | |
| plane.rotation.x = -Math.PI / 2; | |
| plane.position.y = -5; | |
| plane.receiveShadow = true; | |
| scene.add(plane); | |
| console.log('Plane added'); | |
| // Load texture | |
| const loader = new THREE.TextureLoader(); | |
| loader.load('https://threejs.org/examples/textures/crate.gif', function(texture) {{ | |
| // Add a rotating cube with texture | |
| const cubeGeometry = new THREE.BoxGeometry(); | |
| const cubeMaterial = new THREE.MeshStandardMaterial({{ map: texture, color: '{cube_color}' }}); | |
| const cube = new THREE.Mesh(cubeGeometry, cubeMaterial); | |
| cube.castShadow = true; | |
| cube.position.set({cube_position_x}, {cube_position_y}, {cube_position_z}); | |
| cube.scale.set({cube_scale}, {cube_scale}, {cube_scale}); | |
| scene.add(cube); | |
| console.log('Cube added'); | |
| // Add a sphere | |
| const sphereGeometry = new THREE.SphereGeometry(1, 32, 32); | |
| const sphereMaterial = new THREE.MeshStandardMaterial({{ color: 0xff0000 }}); | |
| const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); | |
| sphere.position.set(3, 1, 0); | |
| sphere.castShadow = true; | |
| scene.add(sphere); | |
| console.log('Sphere added'); | |
| // Load GLTF model | |
| const gltfLoader = new THREE.GLTFLoader(); | |
| gltfLoader.load('https://threejs.org/examples/models/gltf/Flamingo.glb', function(gltf) {{ | |
| const model = gltf.scene; | |
| model.position.set(0, 0, -5); | |
| model.scale.set(0.05, 0.05, 0.05); // Scale down the model | |
| scene.add(model); | |
| console.log('GLTF model added'); | |
| // Add a bounding box helper | |
| const box = new THREE.Box3().setFromObject(model); | |
| const helper = new THREE.Box3Helper(box, 0xffff00); | |
| if ({str(show_bounding_box).lower()}) {{ | |
| scene.add(helper); | |
| console.log('Bounding box added'); | |
| }} | |
| // Animate the model | |
| const mixer = new THREE.AnimationMixer(model); | |
| gltf.animations.forEach((clip) => {{ | |
| mixer.clipAction(clip).play(); | |
| }}); | |
| console.log('Animation added'); | |
| camera.position.z = 10; | |
| if ('{camera_view}' === 'Top') {{ | |
| camera.position.set(0, 10, 0); | |
| camera.lookAt(0, 0, 0); | |
| console.log('Switched to top view'); | |
| }} else if ('{camera_view}' === 'Side') {{ | |
| camera.position.set(10, 0, 0); | |
| camera.lookAt(0, 0, 0); | |
| console.log('Switched to side view'); | |
| }} | |
| console.log('Starting animation'); | |
| function animate() {{ | |
| requestAnimationFrame(animate); | |
| cube.rotation.x += {rotation_speed}; | |
| cube.rotation.y += {rotation_speed}; | |
| controls.update(); | |
| mixer.update(0.01); // Update the animation | |
| renderer.render(scene, camera); | |
| console.log('Rendered frame'); | |
| }} | |
| animate(); | |
| window.addEventListener('resize', () => {{ | |
| console.log('Resizing window'); | |
| camera.aspect = container.clientWidth / container.clientHeight; | |
| camera.updateProjectionMatrix(); | |
| renderer.setSize(container.clientWidth, container.clientHeight); | |
| }}); | |
| }}); | |
| }}); | |
| }} | |
| loadScript("https://unpkg.com/three@0.130.1/build/three.min.js", function() {{ | |
| loadScript("https://unpkg.com/three@0.130.1/examples/js/controls/OrbitControls.js", function() {{ | |
| loadScript("https://unpkg.com/three@0.130.1/examples/js/loaders/GLTFLoader.js", function() {{ | |
| console.log('Scripts loaded, initializing scene'); | |
| initializeScene(); | |
| }}); | |
| }}); | |
| }}); | |
| }})(); | |
| </script> | |
| """ | |
| components.html(component_code, height=600) | |
| with col2: | |
| st.title("3D Streamlit Component with Enhanced UI Controls") | |
| three_js_component(cube_color, rotation_speed, cube_position_x, cube_position_y, cube_position_z, cube_scale, show_bounding_box, spotlight_intensity, ambient_light_intensity, camera_view) | |