awacke1 commited on
Commit
9de45be
·
verified ·
1 Parent(s): 5e4b748

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -124
app.py CHANGED
@@ -7,7 +7,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/[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
  let score = 0;
13
  AFRAME.registerComponent('draggable', {
@@ -34,147 +33,97 @@ def load_aframe_and_extras():
34
  },
35
  dragMove: function (evt) {
36
  if (!this.isDragging) return;
37
- var camera = this.camera.getObject3D('camera');
38
- var worldPos = new THREE.Vector3();
39
- camera.getWorldPosition(worldPos);
40
- var worldDir = new THREE.Vector3();
41
- camera.getWorldDirection(worldDir);
42
- var camX = worldPos.x;
43
- var camY = worldPos.y;
44
- var camZ = worldPos.z;
45
- var dirX = worldDir.x;
46
- var dirY = worldDir.y;
47
- var dirZ = worldDir.z;
48
- var t = -camY / dirY;
49
- var moveX = camX + t * dirX;
50
- var moveZ = camZ + t * dirZ;
51
- this.el.setAttribute('position', moveX + " " + 0.0 + " " + moveZ);
52
  }
53
  });
54
-
55
- AFRAME.registerComponent('undulating-rotation', {
56
- schema: {
57
- speed: { type: 'number', default: 1 }, // Base rotation speed
58
- amplitude: { type: 'number', default: 20 }, // Maximum rotation in degrees
59
- frequency: { type: 'number', default: 0.5 } // Speed of undulation
60
- },
61
  init: function () {
62
- this.initialRotation = Math.random() * 360; // Random initial rotation
63
- this.time = 0;
64
- },
65
- tick: function (time, deltaTime) {
66
- this.time += deltaTime / 1000;
67
- const rotationAmount = Math.sin(this.time * this.data.frequency) * this.data.amplitude;
68
- this.el.setAttribute('rotation', { x: 0, y: this.initialRotation + rotationAmount, z: 0 });
 
 
 
69
  }
70
  });
71
  </script>
72
  """
73
 
74
- @st.cache_data
75
- def encode_file(file_path):
76
- with open(file_path, "rb") as file:
77
- return base64.b64encode(file.read()).decode()
78
-
79
- @st.cache_data
80
- def generate_tilemap(files, directory, grid_width, grid_height, max_unique_models=5):
81
- assets = "<a-assets>"
82
- entities = ""
83
- tile_size = 1
84
- start_x = -(grid_width * tile_size) / 2
85
- start_z = -(grid_height * tile_size) / 2
86
- available_models = [f for f in files if f.endswith(('.obj', '.glb'))]
87
- available_images = [f for f in files if f.endswith(('.webp', '.png'))]
88
- encoded_files = {}
89
 
90
- unique_files = random.sample(files, min(len(files), max_unique_models))
 
 
 
 
 
 
 
91
 
92
- for file in unique_files:
93
- file_path = os.path.join(directory, file)
94
- file_type = file.split('.')[-1]
95
- encoded_file = encode_file(file_path)
96
- encoded_files[file] = encoded_file
97
- if file_type in ['obj', 'glb']:
98
- assets += f'<a-asset-item id="{Path(file).stem}" src="data:application/octet-stream;base64,{encoded_file}"></a-asset-item>'
99
- elif file_type in ['webp', 'png']:
100
- mime_type = f"image/{file_type}"
101
- assets += f'<img id="{Path(file).stem}" src="data:{mime_type};base64,{encoded_file}" />'
102
 
103
- assets += "</a-assets>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
 
105
- for i in range(grid_width):
106
- for j in range(grid_height):
107
- x = start_x + (i * tile_size)
108
- z = start_z + (j * tile_size)
109
- position = f"{x} 0 {z}"
110
 
111
- chosen_file = random.choice(files)
112
- file_type = chosen_file.split('.')[-1]
113
- file_stem = Path(chosen_file).stem
114
- rotation = f"0 {random.uniform(0, 360)} 0"
115
- bounce_speed = f"{random.uniform(0.01, 0.03)} {random.uniform(0.01, 0.03)} {random.uniform(0.01, 0.03)}"
116
- amplitude = random.uniform(5, 15)
117
- frequency = random.uniform(0.1, 0.5)
118
 
119
- if file_type == 'obj':
120
- entities += f'<a-entity position="{position}" rotation="{rotation}" scale="0.5 0.5 0.5" obj-model="obj: #{file_stem}" class="raycastable" draggable undulating-rotation="amplitude: {amplitude}; frequency: {frequency}"></a-entity>'
121
- elif file_type == 'glb':
122
- entities += f'<a-entity position="{position}" rotation="{rotation}" scale="0.5 0.5 0.5" gltf-model="#{file_stem}" class="raycastable" draggable undulating-rotation="amplitude: {amplitude}; frequency: {frequency}"></a-entity>'
123
- elif file_type in ['webp', 'png']:
124
- if available_images:
125
- random_image = random.choice(available_images)
126
- image_stem = Path(random_image).stem
127
- entities += f'<a-plane position="{position}" rotation="-90 0 0" width="{tile_size}" height="{tile_size}" material="src: #{image_stem}" class="raycastable" draggable></a-plane>'
128
 
129
- return assets, entities
130
 
131
- def main():
132
- st.set_page_config(layout="wide")
133
- with st.sidebar:
134
- st.markdown("### 🤖 3D AI Using Claude 3.5 Sonnet for AI Pair Programming")
135
- st.markdown("[Open 3D Animation Toolkit](https://huggingface.co/spaces/awacke1/3d_animation_toolkit)", unsafe_allow_html=True)
136
- st.markdown("### ⬆️ Upload")
137
- uploaded_files = st.file_uploader("Add files:", accept_multiple_files=True, key="file_uploader")
138
- st.markdown("### 🗺️ Grid Size")
139
- grid_width = st.slider("Grid Width", 1, 10, 8)
140
- grid_height = st.slider("Grid Height", 1, 10, 5)
141
- st.markdown("### ℹ️ Instructions")
142
- st.write("- Click and drag to move objects")
143
- st.write("- Mouse wheel to zoom")
144
- st.write("- Right-click and drag to rotate view")
145
- st.markdown("### 📁 Directory")
146
- directory = st.text_input("Enter path:", ".", key="directory_input")
147
 
148
- if not os.path.isdir(directory):
149
- st.sidebar.error("Invalid directory path")
150
- return
151
- file_types = ['obj', 'glb', 'webp', 'png']
152
- if uploaded_files:
153
- for uploaded_file in uploaded_files:
154
- file_extension = Path(uploaded_file.name).suffix.lower()[1:]
155
- if file_extension in file_types:
156
- with open(os.path.join(directory, uploaded_file.name), "wb") as f:
157
- shutil.copyfileobj(uploaded_file, f)
158
- st.sidebar.success(f"Uploaded: {uploaded_file.name}")
159
- else:
160
- st.sidebar.warning(f"Skipped unsupported file: {uploaded_file.name}")
161
- files = [f for f in os.listdir(directory) if f.split('.')[-1] in file_types]
162
 
163
- aframe_scene = f"""
164
- <a-scene embedded style="height: 600px; width: 100%;">
165
- {load_aframe_and_extras()}
166
- <a-entity id="rig" movement-controls="fly: true; speed: 0.3" position="0 1.6 0">
167
- <a-camera id="camera" position="0 1.6 10"></a-camera>
168
- </a-entity>
169
- <a-entity light="type: ambient; color: #EEE"></a-entity>
170
- <a-entity light="type: directional; color: #FFF; intensity: 0.6" position="-0.5 1 1"></a-entity>
171
- <a-sky color="#ECF0F1"></a-sky>
172
- <a-entity id="tilemap">
173
- {''.join(generate_tilemap(files, directory, grid_width, grid_height))}
174
- </a-entity>
175
- </a-scene>
176
- """
177
- st.components.v1.html(aframe_scene, height=600)
178
 
179
  if __name__ == "__main__":
180
  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', {
 
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()