awacke1 commited on
Commit
86942ee
·
verified ·
1 Parent(s): 0c656b8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +150 -120
app.py CHANGED
@@ -1,129 +1,159 @@
1
  import streamlit as st
2
- import os, base64, shutil, random
3
- from pathlib import Path
4
 
5
  @st.cache_data
6
- def load_aframe_and_extras():
7
- return """
8
- <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
9
- <script src="https://unpkg.com/aframe-event-set-component@5.0.0/dist/aframe-event-set-component.min.js"></script>
10
- <script>
11
- let score = 0;
12
- AFRAME.registerComponent('draggable', {
13
- init: function () {
14
- this.el.setAttribute('class', 'raycastable');
15
- this.el.setAttribute('cursor-listener', '');
16
- this.dragHandler = this.dragMove.bind(this);
17
- this.el.sceneEl.addEventListener('mousemove', this.dragHandler);
18
- this.el.addEventListener('mousedown', this.onDragStart.bind(this));
19
- this.el.addEventListener('mouseup', this.onDragEnd.bind(this));
20
- this.camera = document.querySelector('[camera]');
21
- },
22
- remove: function () {
23
- this.el.removeAttribute('cursor-listener');
24
- this.el.sceneEl.removeEventListener('mousemove', this.dragHandler);
25
- },
26
- onDragStart: function (evt) {
27
- this.isDragging = true;
28
- this.el.emit('dragstart');
29
- },
30
- onDragEnd: function (evt) {
31
- this.isDragging = false;
32
- this.el.emit('dragend');
33
- },
34
- dragMove: function (evt) {
35
- if (!this.isDragging) return;
36
- let mouseX = evt.clientX / window.innerWidth * 2 - 1;
37
- let mouseY = -(evt.clientY / window.innerHeight * 2) + 1;
38
- let position = new THREE.Vector3(mouseX, mouseY, -5);
39
- position.unproject(this.camera.components.camera.camera);
40
- let direction = position.sub(this.camera.object3D.position).normalize();
41
- let distance = -this.camera.object3D.position.z / direction.z;
42
- let newPosition = this.camera.object3D.position.clone().add(direction.multiplyScalar(distance));
43
- this.el.setAttribute('position', {x: newPosition.x, y: newPosition.y, z: this.el.getAttribute('position').z});
44
- }
45
- });
46
- AFRAME.registerComponent('cursor-listener', {
47
- init: function () {
48
- this.el.addEventListener('mouseenter', function (evt) {
49
- this.setAttribute('material', {color: 'red'});
50
- });
51
- this.el.addEventListener('mouseleave', function (evt) {
52
- this.setAttribute('material', {color: 'blue'});
53
- });
54
- this.el.addEventListener('click', function (evt) {
55
- score++;
56
- document.getElementById('score').setAttribute('value', 'Score: ' + score);
57
- });
58
- }
59
- });
60
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  """
62
 
63
- def create_environment(scene):
64
- sky = scene.entity(
65
- geometry="primitive: sphere; radius: 5000",
66
- material="color: #ADD8E6; shader: flat; side: back" # Light blue sky
67
- )
68
- ground = scene.entity(
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
- def main():
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()