Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,129 +1,159 @@
|
|
1 |
import streamlit as st
|
2 |
-
import os
|
3 |
-
|
4 |
|
5 |
@st.cache_data
|
6 |
-
def
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
this.
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
"""
|
62 |
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
geometry="primitive: plane; width: 100; height: 100",
|
70 |
-
material="color: #7CFC00; side: double", # Lawn green ground
|
71 |
-
rotation="-90 0 0"
|
72 |
)
|
73 |
-
return sky, ground
|
74 |
-
|
75 |
-
def create_drag_target(scene, x, y, z, color='blue'):
|
76 |
-
target = scene.entity(
|
77 |
-
geometry=f"primitive: box; width: 1; height: 1; depth: 1",
|
78 |
-
material=f"color: {color}",
|
79 |
-
position=f"{x} {y} {z}",
|
80 |
-
draggable=""
|
81 |
-
)
|
82 |
-
return target
|
83 |
|
84 |
-
|
85 |
-
st.title("Interactive A-Frame Scene")
|
86 |
-
|
87 |
-
html_string = f"""
|
88 |
-
<!DOCTYPE html>
|
89 |
-
<html>
|
90 |
-
<head>
|
91 |
-
<meta charset="utf-8">
|
92 |
-
<title>A-Frame Example</title>
|
93 |
-
{load_aframe_and_extras()}
|
94 |
-
</head>
|
95 |
-
<body>
|
96 |
-
<a-scene cursor="rayOrigin: mouse" raycaster="objects: .raycastable">
|
97 |
-
<a-camera position="0 1.6 0"></a-camera>
|
98 |
-
<a-entity id="environment"></a-entity>
|
99 |
-
<a-text id="score" value="Score: 0" position="-2 2 -3" color="black"></a-text>
|
100 |
-
<a-entity id="drag-targets"></a-entity>
|
101 |
-
</a-scene>
|
102 |
-
</body>
|
103 |
-
</html>
|
104 |
-
"""
|
105 |
-
|
106 |
-
st.components.v1.html(html_string, height=600, scrolling=False)
|
107 |
-
|
108 |
-
with st.sidebar:
|
109 |
-
st.header("Scene Controls")
|
110 |
-
num_targets = st.slider("Number of Drag Targets", min_value=1, max_value=10, value=3)
|
111 |
-
|
112 |
-
scene = st.components.v1 # This won't work as expected for direct A-Frame manipulation
|
113 |
-
|
114 |
-
environment = scene.get("environment") # This also won't work
|
115 |
-
|
116 |
-
drag_targets = scene.get("drag-targets") # And this won't work
|
117 |
-
|
118 |
-
if environment is not None:
|
119 |
-
create_environment(environment) # This will likely cause errors
|
120 |
-
|
121 |
-
if drag_targets is not None:
|
122 |
-
for i in range(num_targets):
|
123 |
-
x = random.uniform(-5, 5)
|
124 |
-
y = 1
|
125 |
-
z = random.uniform(-5, -2)
|
126 |
-
create_drag_target(drag_targets, x, y, z) # Potential error here too
|
127 |
|
128 |
if __name__ == "__main__":
|
129 |
-
main()
|
|
|
1 |
import streamlit as st
|
2 |
+
import os
|
3 |
+
import random
|
4 |
|
5 |
@st.cache_data
|
6 |
+
def scan_assets():
|
7 |
+
"""Finds all textures, bump maps, and 3D models in the current folder."""
|
8 |
+
img_exts = (".jpg", ".jpeg", ".png", ".gif")
|
9 |
+
files = [f for f in os.listdir() if os.path.isfile(f)]
|
10 |
+
textures = [
|
11 |
+
f for f in files
|
12 |
+
if f.lower().endswith(img_exts)
|
13 |
+
and not any(tag in f.lower() for tag in ("bump", "normal"))
|
14 |
+
]
|
15 |
+
bump_maps = [
|
16 |
+
f for f in files
|
17 |
+
if f.lower().endswith(img_exts)
|
18 |
+
and any(tag in f.lower() for tag in ("bump", "normal"))
|
19 |
+
]
|
20 |
+
models = [
|
21 |
+
f for f in files
|
22 |
+
if f.lower().endswith((".glb", ".gltf", ".obj"))
|
23 |
+
]
|
24 |
+
return textures, bump_maps, models
|
25 |
+
|
26 |
+
def main():
|
27 |
+
st.title("🔳 A-Frame Tilemap with Random Models")
|
28 |
+
grid_size = st.sidebar.slider("Grid Size", min_value=1, max_value=20, value=10)
|
29 |
+
textures, bump_maps, models = scan_assets()
|
30 |
+
|
31 |
+
if not textures or not models:
|
32 |
+
st.warning("⚠️ Please add at least one texture image and one .glb/.obj file to this folder.")
|
33 |
+
return
|
34 |
+
|
35 |
+
# --- Prepare <a-assets> tags ---
|
36 |
+
asset_tags = []
|
37 |
+
for i, tex in enumerate(textures):
|
38 |
+
asset_tags.append(f'<img id="tex{i}" src="{tex}">')
|
39 |
+
if bump_maps:
|
40 |
+
# just pick the first bump map
|
41 |
+
asset_tags.append(f'<img id="grassBump" src="{bump_maps[0]}">')
|
42 |
+
for i, mdl in enumerate(models):
|
43 |
+
asset_tags.append(f'<a-asset-item id="model{i}" src="{mdl}"></a-asset-item>')
|
44 |
+
|
45 |
+
assets_html = "\n ".join(asset_tags)
|
46 |
+
|
47 |
+
# JavaScript arrays of IDs
|
48 |
+
texture_list = ", ".join(f'"#tex{i}"' for i in range(len(textures)))
|
49 |
+
model_list = ", ".join(f'"model{i}"' for i in range(len(models)))
|
50 |
+
has_bump_js = "true" if bump_maps else "false"
|
51 |
+
|
52 |
+
# Material setup for ground
|
53 |
+
if bump_maps:
|
54 |
+
ground_mat = (
|
55 |
+
"ground.setAttribute('material',"
|
56 |
+
"'color: #228B22; bumpMap: #grassBump; bumpScale: 0.2');"
|
57 |
+
)
|
58 |
+
else:
|
59 |
+
ground_mat = "ground.setAttribute('material','color: #228B22');"
|
60 |
+
|
61 |
+
# --- The A-Frame HTML template ---
|
62 |
+
html_template = """
|
63 |
+
<!DOCTYPE html>
|
64 |
+
<html>
|
65 |
+
<head>
|
66 |
+
<meta charset="utf-8">
|
67 |
+
<title>Tilemap Scene</title>
|
68 |
+
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
|
69 |
+
<script src="https://unpkg.com/[email protected]/dist/aframe-extras.loaders.min.js"></script>
|
70 |
+
</head>
|
71 |
+
<body>
|
72 |
+
<a-scene>
|
73 |
+
<a-assets>
|
74 |
+
{assets_html}
|
75 |
+
</a-assets>
|
76 |
+
|
77 |
+
<!-- Lighting -->
|
78 |
+
<a-entity light="type: ambient; color: #BBB"></a-entity>
|
79 |
+
<a-entity
|
80 |
+
light="type: directional; color: #FFF; intensity: 0.6"
|
81 |
+
position="1 1 0">
|
82 |
+
</a-entity>
|
83 |
+
<a-entity
|
84 |
+
light="type: point; intensity: 0.6"
|
85 |
+
position="0 5 0">
|
86 |
+
</a-entity>
|
87 |
+
|
88 |
+
<!-- Camera -->
|
89 |
+
<a-entity
|
90 |
+
camera
|
91 |
+
look-controls
|
92 |
+
position="0 {grid_size} {grid_size}">
|
93 |
+
</a-entity>
|
94 |
+
|
95 |
+
<!-- Container for dynamic tiles & models -->
|
96 |
+
<a-entity id="tilemap"></a-entity>
|
97 |
+
</a-scene>
|
98 |
+
|
99 |
+
<script>
|
100 |
+
document.addEventListener('DOMContentLoaded', function() {{
|
101 |
+
var scene = document.querySelector('a-scene');
|
102 |
+
var tilemap = document.querySelector('#tilemap');
|
103 |
+
var textures = [{texture_list}];
|
104 |
+
var models = [{model_list}];
|
105 |
+
var grid = {grid_size};
|
106 |
+
|
107 |
+
for (var i = 0; i < grid; i++) {{
|
108 |
+
for (var j = 0; j < grid; j++) {{
|
109 |
+
var x = i - grid/2;
|
110 |
+
var z = j - grid/2;
|
111 |
+
|
112 |
+
// --- Base tile ---
|
113 |
+
var tile = document.createElement('a-box');
|
114 |
+
tile.setAttribute('width', 1);
|
115 |
+
tile.setAttribute('height', 0.1);
|
116 |
+
tile.setAttribute('depth', 1);
|
117 |
+
var tex = textures[Math.floor(Math.random() * textures.length)];
|
118 |
+
tile.setAttribute('material', 'src: ' + tex + '; repeat: 1 1');
|
119 |
+
tile.setAttribute('position', x + ' 0 ' + z);
|
120 |
+
tilemap.appendChild(tile);
|
121 |
+
|
122 |
+
// --- Random model ---
|
123 |
+
var mi = Math.floor(Math.random() * models.length);
|
124 |
+
var mid = models[mi];
|
125 |
+
var modelEl = document.createElement('a-entity');
|
126 |
+
// load both .glb/.gltf and .obj via gltf-model (requires extras loader)
|
127 |
+
modelEl.setAttribute('gltf-model', '#' + mid);
|
128 |
+
modelEl.setAttribute('scale', '0.5 0.5 0.5');
|
129 |
+
modelEl.setAttribute('position', x + ' 0.5 ' + z);
|
130 |
+
tilemap.appendChild(modelEl);
|
131 |
+
}}
|
132 |
+
}}
|
133 |
+
|
134 |
+
// --- Ground plane ---
|
135 |
+
var ground = document.createElement('a-plane');
|
136 |
+
ground.setAttribute('width', grid * 2);
|
137 |
+
ground.setAttribute('height', grid * 2);
|
138 |
+
ground.setAttribute('rotation', '-90 0 0');
|
139 |
+
{ground_mat}
|
140 |
+
ground.setAttribute('position', '0 -0.05 0');
|
141 |
+
scene.insertBefore(ground, scene.firstChild);
|
142 |
+
}});
|
143 |
+
</script>
|
144 |
+
</body>
|
145 |
+
</html>
|
146 |
"""
|
147 |
|
148 |
+
html = html_template.format(
|
149 |
+
assets_html=assets_html,
|
150 |
+
texture_list=texture_list,
|
151 |
+
model_list=model_list,
|
152 |
+
grid_size=grid_size,
|
153 |
+
ground_mat=ground_mat
|
|
|
|
|
|
|
154 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
|
156 |
+
st.components.v1.html(html, height=600, scrolling=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
157 |
|
158 |
if __name__ == "__main__":
|
159 |
+
main()
|