awacke1 commited on
Commit
0c656b8
·
verified ·
1 Parent(s): 3d06b33

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +76 -152
app.py CHANGED
@@ -7,8 +7,8 @@ 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/[email protected]/dist/aframe-event-set-component.min.js"></script>
10
- <script src="https://cdn.jsdelivr.net/npm/aframe-volumetric-fog@latest/dist/aframe-volumetric-fog.min.js"></script>
11
  <script>
 
12
  AFRAME.registerComponent('draggable', {
13
  init: function () {
14
  this.el.setAttribute('class', 'raycastable');
@@ -33,173 +33,97 @@ def load_aframe_and_extras():
33
  },
34
  dragMove: function (evt) {
35
  if (!this.isDragging) return;
36
- var camera = this.camera.getObject3D('camera');
37
- var worldPos = new THREE.Vector3();
38
- camera.getWorldPosition(worldPos);
39
- var worldDir = new THREE.Vector3();
40
- camera.getWorldDirection(worldDir);
41
- var camX = worldPos.x;
42
- var camY = worldPos.y;
43
- var camZ = worldPos.z;
44
- var dirX = worldDir.x;
45
- var dirY = worldDir.y;
46
- var dirZ = worldDir.z;
47
- var t = -camY / dirY;
48
- var moveX = camX + t * dirX;
49
- var moveZ = camZ + t * dirZ;
50
- this.el.setAttribute('position', moveX + " " + 0.0 + " " + moveZ);
51
  }
52
  });
53
-
54
- AFRAME.registerComponent('undulating-rotation', {
55
- schema: {
56
- amplitude: { type: 'number', default: 10 },
57
- frequency: { type: 'number', default: 0.3 }
58
- },
59
  init: function () {
60
- this.initialRotation = Math.random() * 360;
61
- this.time = 0;
62
- },
63
- tick: function (time, deltaTime) {
64
- this.time += deltaTime / 1000;
65
- const rotationAmount = Math.sin(this.time * this.data.frequency) * this.data.amplitude;
66
- this.el.setAttribute('rotation', { x: 0, y: this.initialRotation + rotationAmount, z: 0 });
 
 
 
67
  }
68
  });
69
  </script>
70
  """
71
 
72
- @st.cache_data
73
- def encode_file(file_path):
74
- with open(file_path, "rb") as file:
75
- return base64.b64encode(file.read()).decode()
76
-
77
- @st.cache_data
78
- def generate_tilemap(files, directory, grid_width, grid_height, bump_map_url, max_unique_models=5):
79
- assets = "<a-assets>"
80
- entities = ""
81
- tile_size = 1
82
- start_x = -(grid_width * tile_size) / 2
83
- start_z = -(grid_height * tile_size) / 2
84
- available_models = [f for f in files if f.endswith(('.obj', '.glb'))]
85
- available_images = [f for f in files if f.endswith(('.webp', '.png'))]
86
- encoded_files = {}
87
-
88
- unique_files = random.sample(files, min(len(files), max_unique_models))
89
-
90
- for file in unique_files:
91
- file_path = os.path.join(directory, file)
92
- file_type = file.split('.')[-1]
93
- encoded_file = encode_file(file_path)
94
- encoded_files[file] = encoded_file
95
- if file_type in ['obj', 'glb']:
96
- assets += f'<a-asset-item id="{Path(file).stem}" src="data:application/octet-stream;base64,{encoded_file}"></a-asset-item>'
97
- elif file_type in ['webp', 'png']:
98
- mime_type = f"image/{file_type}"
99
- assets += f'<img id="{Path(file).stem}" src="data:{mime_type};base64,{encoded_file}" />'
100
-
101
- assets += f"""
102
- <a-material id="ground-mat" color="#78815d" normal-map="{bump_map_url}" normal-texture-repeat="{grid_width * 2} {grid_height * 2}"></a-material>
103
- """
104
- assets += "</a-assets>"
105
-
106
- for i in range(grid_width):
107
- for j in range(grid_height):
108
- x = start_x + (i * tile_size)
109
- z = start_z + (j * tile_size)
110
- position = f"{x} 0 {z}"
111
-
112
- chosen_file = random.choice(files)
113
- file_type = chosen_file.split('.')[-1]
114
- file_stem = Path(chosen_file).stem
115
- rotation = f"0 0 0" # Initial rotation can be 0 for the undulation to be clearer
116
- amplitude = random.uniform(5, 15)
117
- frequency = random.uniform(0.1, 0.5)
118
- scale = "0.5 0.5 0.5"
119
-
120
- if file_type == 'obj':
121
- entities += f'<a-entity position="{position}" rotation="{rotation}" scale="{scale}" obj-model="obj: #{file_stem}" class="raycastable" draggable undulating-rotation="amplitude: {amplitude}; frequency: {frequency}"></a-entity>'
122
- elif file_type == 'glb':
123
- entities += f'<a-entity position="{position}" rotation="{rotation}" scale="{scale}" gltf-model="#{file_stem}" class="raycastable" draggable undulating-rotation="amplitude: {amplitude}; frequency: {frequency}"></a-entity>'
124
- elif file_type in ['webp', 'png']:
125
- if available_images:
126
- random_image = random.choice(available_images)
127
- image_stem = Path(random_image).stem
128
- entities += f'<a-plane position="{position}" rotation="-90 0 0" width="{tile_size * 0.8}" height="{tile_size * 0.8}" material="src: #{image_stem}" class="raycastable" draggable></a-plane>'
129
-
130
- return assets, entities
131
 
132
  def main():
133
- st.set_page_config(layout="wide")
134
- with st.sidebar:
135
- st.markdown("### 🤖 3D AI Using Claude 3.5 Sonnet for AI Pair Programming")
136
- st.markdown("[Open 3D Animation Toolkit](https://huggingface.co/spaces/awacke1/3d_animation_toolkit)", unsafe_allow_html=True)
137
- st.markdown("### ⬆️ Upload")
138
- uploaded_files = st.file_uploader("Add files:", accept_multiple_files=True, key="file_uploader")
139
- st.markdown("### 🗺️ Grid Size")
140
- grid_width = st.slider("Grid Width", 1, 10, 8)
141
- grid_height = st.slider("Grid Height", 1, 10, 5)
142
- st.markdown("### 🖼️ Bump Map")
143
- bump_map_file = st.file_uploader("Upload Bump Map (png)", type=["png"], key="bump_map_uploader")
144
- st.markdown("### ℹ️ Instructions")
145
- st.write("- Click and drag to move objects")
146
- st.write("- Mouse wheel to zoom")
147
- st.write("- Right-click and drag to rotate view")
148
- st.markdown("### 📁 Directory")
149
- directory = st.text_input("Enter path:", ".", key="directory_input")
 
 
 
 
 
150
 
151
- if not os.path.isdir(directory):
152
- st.sidebar.error("Invalid directory path")
153
- return
154
- file_types = ['obj', 'glb', 'webp', 'png']
155
- if uploaded_files:
156
- for uploaded_file in uploaded_files:
157
- file_extension = Path(uploaded_file.name).suffix.lower()[1:]
158
- if file_extension in file_types:
159
- with open(os.path.join(directory, uploaded_file.name), "wb") as f:
160
- shutil.copyfileobj(uploaded_file, f)
161
- st.sidebar.success(f"Uploaded: {uploaded_file.name}")
162
- else:
163
- st.sidebar.warning(f"Skipped unsupported file: {uploaded_file.name}")
164
- files = [f for f in os.listdir(directory) if f.split('.')[-1] in file_types]
165
-
166
- bump_map_url = ""
167
- if bump_map_file:
168
- bump_map_bytes = bump_map_file.read()
169
- bump_map_base64 = base64.b64encode(bump_map_bytes).decode()
170
- bump_map_url = f"data:image/png;base64,{bump_map_base64}"
171
- elif os.path.exists(os.path.join(directory, "bump_map.png")): # Optional: Check for a default bump map
172
- bump_map_url = "bump_map.png"
173
-
174
- aframe_scene = f"""
175
- <a-scene embedded style="height: 600px; width: 100%;">
176
- {load_aframe_and_extras()}
177
- <a-entity id="rig" position="0 {max(grid_width, grid_height) * 0.8} {max(grid_width, grid_height) * 0.8}" rotation="-45 0 0">
178
- <a-camera id="camera" look-controls wasd-controls="enabled: false" cursor="rayOrigin: mouse"></a-camera>
179
- </a-entity>
180
 
181
- <a-entity volumetric-fog="density: 0.02; color: #cccccc; near: 1; far: 50; animation: property: volumetric-fog.density; to: 0.04; dur: 8000; loop: true; dir: alternate"></a-entity>
182
 
183
- <a-entity id="skybox">
184
- <a-plane position="0 0 -50" rotation="0 0 0" width="100" height="100" material="color: #87CEEB"></a-plane>
185
- <a-plane position="0 0 50" rotation="0 180 0" width="100" height="100" material="color: #ADD8E6"></a-plane>
186
- <a-plane position="50 0 0" rotation="0 90 0" width="100" height="100" material="color: #B0E0E6"></a-plane>
187
- <a-plane position="-50 0 0" rotation="0 -90 0" width="100" height="100" material="color: #E0FFFF"></a-plane>
188
- <a-plane position="0 50 0" rotation="-90 0 0" width="100" height="100" material="color: #ADD8E6"></a-plane>
189
- <a-plane position="0 -50 0" rotation="90 0 0" width="100" height="100" material="color: #F0F8FF"></a-plane>
190
- </a-entity>
191
 
192
- <a-plane id="ground" position="0 -0.5 0" rotation="-90 0 0" width="{grid_width}" height="{grid_height}" material="src: #ground-mat"></a-plane>
193
 
194
- <a-entity id="tilemap">
195
- {''.join(generate_tilemap(files, directory, grid_width, grid_height, bump_map_url))}
196
- </a-entity>
197
 
198
- <a-entity light="type: ambient; color: #445451"></a-entity>
199
- <a-entity light="type: directional; color: #FFF; intensity: 0.8" position="-1 1 2"></a-entity>
200
- </a-scene>
201
- """
202
- st.components.v1.html(aframe_scene, height=600)
 
203
 
204
  if __name__ == "__main__":
205
  main()
 
7
  return """
8
  <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
9
  <script src="https://unpkg.com/[email protected]/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');
 
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()