Spaces:
Runtime error
Runtime error
Upload 2 files
Browse files- app.py +235 -0
- requirements.txt +6 -0
app.py
ADDED
@@ -0,0 +1,235 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import streamlit.components.v1 as components
|
3 |
+
|
4 |
+
# Initialize session state
|
5 |
+
if 'settings' not in st.session_state:
|
6 |
+
st.session_state['settings'] = {}
|
7 |
+
|
8 |
+
# Function to update widgets based on saved settings
|
9 |
+
def load_settings():
|
10 |
+
settings = st.session_state['settings']
|
11 |
+
st.session_state.cube_color = settings.get("cube_color", "#00ff00")
|
12 |
+
st.session_state.rotation_speed = settings.get("rotation_speed", 0.01)
|
13 |
+
st.session_state.cube_position_x = settings.get("cube_position_x", 0)
|
14 |
+
st.session_state.cube_position_y = settings.get("cube_position_y", 0)
|
15 |
+
st.session_state.cube_position_z = settings.get("cube_position_z", 0)
|
16 |
+
st.session_state.cube_scale = settings.get("cube_scale", 1.0)
|
17 |
+
st.session_state.show_bounding_box = settings.get("show_bounding_box", True)
|
18 |
+
st.session_state.spotlight_intensity = settings.get("spotlight_intensity", 1.0)
|
19 |
+
st.session_state.ambient_light_intensity = settings.get("ambient_light_intensity", 0.5)
|
20 |
+
st.session_state.camera_view = settings.get("camera_view", "Default")
|
21 |
+
st.write("Loaded settings into session state:", settings)
|
22 |
+
|
23 |
+
# Create two columns for layout
|
24 |
+
col1, col2 = st.columns([1, 3])
|
25 |
+
|
26 |
+
with col1:
|
27 |
+
# Streamlit widgets to control the scene
|
28 |
+
cube_color = st.color_picker("Pick a cube color", st.session_state.get('cube_color', "#00ff00"))
|
29 |
+
rotation_speed = st.slider("Rotation Speed", min_value=0.01, max_value=0.1, value=st.session_state.get('rotation_speed', 0.01))
|
30 |
+
cube_position_x = st.slider("Cube Position X", min_value=-10, max_value=10, value=st.session_state.get('cube_position_x', 0))
|
31 |
+
cube_position_y = st.slider("Cube Position Y", min_value=-10, max_value=10, value=st.session_state.get('cube_position_y', 0))
|
32 |
+
cube_position_z = st.slider("Cube Position Z", min_value=-10, max_value=10, value=st.session_state.get('cube_position_z', 0))
|
33 |
+
cube_scale = st.slider("Cube Scale", min_value=0.1, max_value=5.0, value=st.session_state.get('cube_scale', 1.0))
|
34 |
+
show_bounding_box = st.checkbox("Show Bounding Box", value=st.session_state.get('show_bounding_box', True))
|
35 |
+
spotlight_intensity = st.slider("Spotlight Intensity", min_value=0.0, max_value=2.0, value=st.session_state.get('spotlight_intensity', 1.0))
|
36 |
+
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))
|
37 |
+
camera_view = st.selectbox("Camera View", ["Default", "Top", "Side"], index=["Default", "Top", "Side"].index(st.session_state.get('camera_view', "Default")))
|
38 |
+
|
39 |
+
# Save settings button
|
40 |
+
if st.button("Save Settings"):
|
41 |
+
st.session_state['settings'] = {
|
42 |
+
"cube_color": cube_color,
|
43 |
+
"rotation_speed": rotation_speed,
|
44 |
+
"cube_position_x": cube_position_x,
|
45 |
+
"cube_position_y": cube_position_y,
|
46 |
+
"cube_position_z": cube_position_z,
|
47 |
+
"cube_scale": cube_scale,
|
48 |
+
"show_bounding_box": show_bounding_box,
|
49 |
+
"spotlight_intensity": spotlight_intensity,
|
50 |
+
"ambient_light_intensity": ambient_light_intensity,
|
51 |
+
"camera_view": camera_view
|
52 |
+
}
|
53 |
+
st.write("Settings saved:", st.session_state['settings'])
|
54 |
+
|
55 |
+
# Load settings button
|
56 |
+
if st.button("Load Settings"):
|
57 |
+
st.write("Loading settings...")
|
58 |
+
load_settings()
|
59 |
+
st.write("Settings loaded:", st.session_state['settings'])
|
60 |
+
st.rerun()
|
61 |
+
|
62 |
+
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):
|
63 |
+
component_code = f"""
|
64 |
+
<div id="threejs-container" style="width: 100%; height: 600px; background-color: #000;"></div>
|
65 |
+
<script>
|
66 |
+
(function() {{
|
67 |
+
if (document.getElementById('threejs-container-script')) {{
|
68 |
+
return;
|
69 |
+
}}
|
70 |
+
|
71 |
+
function loadScript(url, callback) {{
|
72 |
+
console.log('Loading script:', url);
|
73 |
+
var script = document.createElement("script");
|
74 |
+
script.type = "text/javascript";
|
75 |
+
|
76 |
+
script.onload = function() {{
|
77 |
+
console.log('Loaded script:', url);
|
78 |
+
callback();
|
79 |
+
}};
|
80 |
+
|
81 |
+
script.onerror = function() {{
|
82 |
+
console.error('Error loading script:', url);
|
83 |
+
}};
|
84 |
+
|
85 |
+
script.src = url;
|
86 |
+
document.getElementsByTagName("head")[0].appendChild(script);
|
87 |
+
}}
|
88 |
+
|
89 |
+
function initializeScene() {{
|
90 |
+
console.log('Initializing Scene');
|
91 |
+
const container = document.getElementById('threejs-container');
|
92 |
+
if (!container) {{
|
93 |
+
console.error('Container not found!');
|
94 |
+
return;
|
95 |
+
}}
|
96 |
+
|
97 |
+
const scene = new THREE.Scene();
|
98 |
+
console.log('Created scene');
|
99 |
+
const camera = new THREE.PerspectiveCamera(75, container.clientWidth / container.clientHeight, 0.1, 1000);
|
100 |
+
console.log('Created camera');
|
101 |
+
|
102 |
+
const renderer = new THREE.WebGLRenderer();
|
103 |
+
renderer.setSize(container.clientWidth, container.clientHeight);
|
104 |
+
renderer.shadowMap.enabled = true;
|
105 |
+
container.appendChild(renderer.domElement);
|
106 |
+
console.log('Created renderer and appended to container');
|
107 |
+
|
108 |
+
const controls = new THREE.OrbitControls(camera, renderer.domElement);
|
109 |
+
controls.enableDamping = true;
|
110 |
+
controls.dampingFactor = 0.25;
|
111 |
+
controls.screenSpacePanning = false;
|
112 |
+
controls.minDistance = 1;
|
113 |
+
controls.maxDistance = 100;
|
114 |
+
controls.maxPolarAngle = Math.PI / 2;
|
115 |
+
console.log('Initialized Orbit Controls');
|
116 |
+
|
117 |
+
// Add a spotlight for lighting
|
118 |
+
const spotLight = new THREE.SpotLight(0xffffff, {spotlight_intensity});
|
119 |
+
spotLight.position.set(10, 10, 10);
|
120 |
+
spotLight.castShadow = true;
|
121 |
+
scene.add(spotLight);
|
122 |
+
console.log('Spotlight added');
|
123 |
+
|
124 |
+
// Add ambient light
|
125 |
+
const ambientLight = new THREE.AmbientLight(0x404040, {ambient_light_intensity}); // Soft white light
|
126 |
+
scene.add(ambientLight);
|
127 |
+
console.log('Ambient light added');
|
128 |
+
|
129 |
+
// Add a plane to receive shadows
|
130 |
+
const planeGeometry = new THREE.PlaneGeometry(200, 200);
|
131 |
+
const planeMaterial = new THREE.ShadowMaterial({{ opacity: 0.5 }});
|
132 |
+
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
|
133 |
+
plane.rotation.x = -Math.PI / 2;
|
134 |
+
plane.position.y = -5;
|
135 |
+
plane.receiveShadow = true;
|
136 |
+
scene.add(plane);
|
137 |
+
console.log('Plane added');
|
138 |
+
|
139 |
+
// Load texture
|
140 |
+
const loader = new THREE.TextureLoader();
|
141 |
+
loader.load('https://threejs.org/examples/textures/crate.gif', function(texture) {{
|
142 |
+
// Add a rotating cube with texture
|
143 |
+
const cubeGeometry = new THREE.BoxGeometry();
|
144 |
+
const cubeMaterial = new THREE.MeshStandardMaterial({{ map: texture, color: '{cube_color}' }});
|
145 |
+
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
|
146 |
+
cube.castShadow = true;
|
147 |
+
cube.position.set({cube_position_x}, {cube_position_y}, {cube_position_z});
|
148 |
+
cube.scale.set({cube_scale}, {cube_scale}, {cube_scale});
|
149 |
+
scene.add(cube);
|
150 |
+
console.log('Cube added');
|
151 |
+
|
152 |
+
// Add a sphere
|
153 |
+
const sphereGeometry = new THREE.SphereGeometry(1, 32, 32);
|
154 |
+
const sphereMaterial = new THREE.MeshStandardMaterial({{ color: 0xff0000 }});
|
155 |
+
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
|
156 |
+
sphere.position.set(3, 1, 0);
|
157 |
+
sphere.castShadow = true;
|
158 |
+
scene.add(sphere);
|
159 |
+
console.log('Sphere added');
|
160 |
+
|
161 |
+
// Load GLTF model
|
162 |
+
const gltfLoader = new THREE.GLTFLoader();
|
163 |
+
gltfLoader.load('https://threejs.org/examples/models/gltf/Flamingo.glb', function(gltf) {{
|
164 |
+
const model = gltf.scene;
|
165 |
+
model.position.set(0, 0, -5);
|
166 |
+
model.scale.set(0.05, 0.05, 0.05); // Scale down the model
|
167 |
+
scene.add(model);
|
168 |
+
console.log('GLTF model added');
|
169 |
+
|
170 |
+
// Add a bounding box helper
|
171 |
+
const box = new THREE.Box3().setFromObject(model);
|
172 |
+
const helper = new THREE.Box3Helper(box, 0xffff00);
|
173 |
+
if ({str(show_bounding_box).lower()}) {{
|
174 |
+
scene.add(helper);
|
175 |
+
console.log('Bounding box added');
|
176 |
+
}}
|
177 |
+
|
178 |
+
// Animate the model
|
179 |
+
const mixer = new THREE.AnimationMixer(model);
|
180 |
+
gltf.animations.forEach((clip) => {{
|
181 |
+
mixer.clipAction(clip).play();
|
182 |
+
}});
|
183 |
+
console.log('Animation added');
|
184 |
+
|
185 |
+
camera.position.z = 10;
|
186 |
+
|
187 |
+
if ('{camera_view}' === 'Top') {{
|
188 |
+
camera.position.set(0, 10, 0);
|
189 |
+
camera.lookAt(0, 0, 0);
|
190 |
+
console.log('Switched to top view');
|
191 |
+
}} else if ('{camera_view}' === 'Side') {{
|
192 |
+
camera.position.set(10, 0, 0);
|
193 |
+
camera.lookAt(0, 0, 0);
|
194 |
+
console.log('Switched to side view');
|
195 |
+
}}
|
196 |
+
|
197 |
+
console.log('Starting animation');
|
198 |
+
function animate() {{
|
199 |
+
requestAnimationFrame(animate);
|
200 |
+
cube.rotation.x += {rotation_speed};
|
201 |
+
cube.rotation.y += {rotation_speed};
|
202 |
+
controls.update();
|
203 |
+
mixer.update(0.01); // Update the animation
|
204 |
+
renderer.render(scene, camera);
|
205 |
+
console.log('Rendered frame');
|
206 |
+
}}
|
207 |
+
|
208 |
+
animate();
|
209 |
+
|
210 |
+
window.addEventListener('resize', () => {{
|
211 |
+
console.log('Resizing window');
|
212 |
+
camera.aspect = container.clientWidth / container.clientHeight;
|
213 |
+
camera.updateProjectionMatrix();
|
214 |
+
renderer.setSize(container.clientWidth, container.clientHeight);
|
215 |
+
}});
|
216 |
+
}});
|
217 |
+
}});
|
218 |
+
}}
|
219 |
+
|
220 |
+
loadScript("https://unpkg.com/three@0.130.1/build/three.min.js", function() {{
|
221 |
+
loadScript("https://unpkg.com/three@0.130.1/examples/js/controls/OrbitControls.js", function() {{
|
222 |
+
loadScript("https://unpkg.com/three@0.130.1/examples/js/loaders/GLTFLoader.js", function() {{
|
223 |
+
console.log('Scripts loaded, initializing scene');
|
224 |
+
initializeScene();
|
225 |
+
}});
|
226 |
+
}});
|
227 |
+
}});
|
228 |
+
}})();
|
229 |
+
</script>
|
230 |
+
"""
|
231 |
+
components.html(component_code, height=600)
|
232 |
+
|
233 |
+
with col2:
|
234 |
+
st.title("3D Streamlit Component with Enhanced UI Controls")
|
235 |
+
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)
|
requirements.txt
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit
|
2 |
+
streamlit.components.v1
|
3 |
+
pandas
|
4 |
+
numpy
|
5 |
+
matplotlib
|
6 |
+
plotly
|