Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -11,6 +11,7 @@ def load_aframe_and_extras():
|
|
| 11 |
<script>
|
| 12 |
let score = 0;
|
| 13 |
let selectedEntity = null;
|
|
|
|
| 14 |
AFRAME.registerComponent('draggable', {
|
| 15 |
init: function () {
|
| 16 |
this.el.addEventListener('mousedown', this.onMouseDown.bind(this));
|
|
@@ -59,15 +60,18 @@ def load_aframe_and_extras():
|
|
| 59 |
}
|
| 60 |
}
|
| 61 |
});
|
|
|
|
| 62 |
AFRAME.registerComponent('bouncing', {/* … */});
|
| 63 |
AFRAME.registerComponent('moving-light', {/* … */});
|
|
|
|
| 64 |
function moveCamera(view) {
|
| 65 |
var rig = document.querySelector('#rig');
|
| 66 |
var gw = 8, gh = 8;
|
| 67 |
var center = {x: 0, y: 0, z: 0};
|
| 68 |
var height = Math.max(gw, gh) * 1.5;
|
| 69 |
-
var distance = Math.max(gw, gh) *
|
| 70 |
var pos;
|
|
|
|
| 71 |
switch(view) {
|
| 72 |
case 'top':
|
| 73 |
pos = {x: center.x, y: height, z: center.z};
|
|
@@ -75,47 +79,89 @@ def load_aframe_and_extras():
|
|
| 75 |
rig.setAttribute('rotation', {x: -90, y: 0, z: 0});
|
| 76 |
break;
|
| 77 |
case 'left':
|
| 78 |
-
pos = {x: -distance, y: height
|
| 79 |
rig.setAttribute('position', pos);
|
| 80 |
rig.setAttribute('look-at', center);
|
| 81 |
break;
|
| 82 |
case 'right':
|
| 83 |
-
pos = {x: distance, y: height
|
| 84 |
rig.setAttribute('position', pos);
|
| 85 |
rig.setAttribute('look-at', center);
|
| 86 |
break;
|
| 87 |
case 'front':
|
| 88 |
-
pos = {x: center.x, y: height
|
| 89 |
rig.setAttribute('position', pos);
|
| 90 |
rig.setAttribute('look-at', center);
|
| 91 |
break;
|
| 92 |
case 'back':
|
| 93 |
-
pos = {x: center.x, y: height
|
| 94 |
rig.setAttribute('position', pos);
|
| 95 |
rig.setAttribute('look-at', center);
|
| 96 |
break;
|
| 97 |
case 'angle1':
|
| 98 |
-
pos = {x: -distance
|
| 99 |
rig.setAttribute('position', pos);
|
| 100 |
rig.setAttribute('look-at', center);
|
| 101 |
break;
|
| 102 |
case 'angle2':
|
| 103 |
-
pos = {x: distance
|
| 104 |
rig.setAttribute('position', pos);
|
| 105 |
rig.setAttribute('look-at', center);
|
| 106 |
break;
|
| 107 |
case 'angle3':
|
| 108 |
-
pos = {x: -distance
|
| 109 |
rig.setAttribute('position', pos);
|
| 110 |
rig.setAttribute('look-at', center);
|
| 111 |
break;
|
| 112 |
case 'angle4':
|
| 113 |
-
pos = {x: distance
|
| 114 |
rig.setAttribute('position', pos);
|
| 115 |
rig.setAttribute('look-at', center);
|
| 116 |
break;
|
| 117 |
}
|
| 118 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
function fireRaycast() {
|
| 120 |
var cam = document.querySelector('[camera]');
|
| 121 |
var dir = new THREE.Vector3(); cam.object3D.getWorldDirection(dir);
|
|
@@ -132,6 +178,7 @@ def load_aframe_and_extras():
|
|
| 132 |
}
|
| 133 |
}
|
| 134 |
}
|
|
|
|
| 135 |
document.addEventListener('keydown', e => {
|
| 136 |
switch(e.key.toLowerCase()){
|
| 137 |
case '1': moveCamera('top'); break;
|
|
@@ -143,7 +190,14 @@ def load_aframe_and_extras():
|
|
| 143 |
case '7': moveCamera('angle2'); break;
|
| 144 |
case '8': moveCamera('angle3'); break;
|
| 145 |
case '9': moveCamera('angle4'); break;
|
| 146 |
-
case '
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
}
|
| 148 |
});
|
| 149 |
</script>
|
|
@@ -191,22 +245,30 @@ def generate_tilemap(files, dirpath, gw=8, gh=8):
|
|
| 191 |
assets += "</a-assets>"
|
| 192 |
|
| 193 |
entities = ""
|
| 194 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 195 |
for i in range(gw):
|
| 196 |
for j in range(gh):
|
| 197 |
x,y,z = sx+i,0,sz+j
|
| 198 |
-
if imgs:
|
| 199 |
-
img=random.choice(imgs); s=Path(img).stem
|
| 200 |
-
entities += (f'<a-plane src="#{s}" width="1" height="1" '
|
| 201 |
-
f'rotation="-90 0 0" position="{x} 0 {z}"></a-plane>')
|
| 202 |
if models:
|
| 203 |
-
m=random.choice(models); ext=m.split('.')[-1]; s=Path(m).stem
|
| 204 |
-
entities += create_aframe_entity(s,ext,f"{x} 0 {z}")
|
| 205 |
-
if vids:
|
| 206 |
-
v=random.choice(vids); s=Path(v).stem
|
| 207 |
-
entities += (f'<a-video src="#{s}" width="1" height="1" '
|
| 208 |
-
f'rotation="-90 0 0" position="{x} 0.1 {z}" '
|
| 209 |
-
'class="raycastable" draggable></a-video>')
|
| 210 |
return assets, entities
|
| 211 |
|
| 212 |
def main():
|
|
@@ -227,6 +289,19 @@ def main():
|
|
| 227 |
cols[1].button("↙️ Angle 3", on_click=lambda: st.session_state.update({'camera_view': 'angle3'}))
|
| 228 |
cols[2].button("↘️ Angle 4", on_click=lambda: st.session_state.update({'camera_view': 'angle4'}))
|
| 229 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
st.markdown("### ➕ Add Media Files")
|
| 231 |
ups = st.file_uploader("Add files (png, jpeg, obj, glb, mp4, etc.):", accept_multiple_files=True)
|
| 232 |
st.markdown("### 📋 Uploaded Model Files")
|
|
@@ -277,11 +352,16 @@ def main():
|
|
| 277 |
assets, ents = generate_tilemap(files, directory, 8, 8)
|
| 278 |
scene += assets + ents + "</a-scene>"
|
| 279 |
|
| 280 |
-
|
| 281 |
-
if
|
| 282 |
-
scene += f"<script>moveCamera('{
|
| 283 |
st.session_state.pop('camera_view', None)
|
| 284 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 285 |
loader = '<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/aframe-extras.loaders.min.js"></script>'
|
| 286 |
|
| 287 |
st.components.v1.html(
|
|
|
|
| 11 |
<script>
|
| 12 |
let score = 0;
|
| 13 |
let selectedEntity = null;
|
| 14 |
+
|
| 15 |
AFRAME.registerComponent('draggable', {
|
| 16 |
init: function () {
|
| 17 |
this.el.addEventListener('mousedown', this.onMouseDown.bind(this));
|
|
|
|
| 60 |
}
|
| 61 |
}
|
| 62 |
});
|
| 63 |
+
|
| 64 |
AFRAME.registerComponent('bouncing', {/* … */});
|
| 65 |
AFRAME.registerComponent('moving-light', {/* … */});
|
| 66 |
+
|
| 67 |
function moveCamera(view) {
|
| 68 |
var rig = document.querySelector('#rig');
|
| 69 |
var gw = 8, gh = 8;
|
| 70 |
var center = {x: 0, y: 0, z: 0};
|
| 71 |
var height = Math.max(gw, gh) * 1.5;
|
| 72 |
+
var distance = Math.max(gw, gh) * 2; // Further increased distance to ensure the entire tilemap is in view
|
| 73 |
var pos;
|
| 74 |
+
|
| 75 |
switch(view) {
|
| 76 |
case 'top':
|
| 77 |
pos = {x: center.x, y: height, z: center.z};
|
|
|
|
| 79 |
rig.setAttribute('rotation', {x: -90, y: 0, z: 0});
|
| 80 |
break;
|
| 81 |
case 'left':
|
| 82 |
+
pos = {x: -distance, y: height, z: center.z};
|
| 83 |
rig.setAttribute('position', pos);
|
| 84 |
rig.setAttribute('look-at', center);
|
| 85 |
break;
|
| 86 |
case 'right':
|
| 87 |
+
pos = {x: distance, y: height, z: center.z};
|
| 88 |
rig.setAttribute('position', pos);
|
| 89 |
rig.setAttribute('look-at', center);
|
| 90 |
break;
|
| 91 |
case 'front':
|
| 92 |
+
pos = {x: center.x, y: height, z: -distance};
|
| 93 |
rig.setAttribute('position', pos);
|
| 94 |
rig.setAttribute('look-at', center);
|
| 95 |
break;
|
| 96 |
case 'back':
|
| 97 |
+
pos = {x: center.x, y: height, z: distance};
|
| 98 |
rig.setAttribute('position', pos);
|
| 99 |
rig.setAttribute('look-at', center);
|
| 100 |
break;
|
| 101 |
case 'angle1':
|
| 102 |
+
pos = {x: -distance, y: height, z: -distance};
|
| 103 |
rig.setAttribute('position', pos);
|
| 104 |
rig.setAttribute('look-at', center);
|
| 105 |
break;
|
| 106 |
case 'angle2':
|
| 107 |
+
pos = {x: distance, y: height, z: -distance};
|
| 108 |
rig.setAttribute('position', pos);
|
| 109 |
rig.setAttribute('look-at', center);
|
| 110 |
break;
|
| 111 |
case 'angle3':
|
| 112 |
+
pos = {x: -distance, y: height, z: distance};
|
| 113 |
rig.setAttribute('position', pos);
|
| 114 |
rig.setAttribute('look-at', center);
|
| 115 |
break;
|
| 116 |
case 'angle4':
|
| 117 |
+
pos = {x: distance, y: height, z: distance};
|
| 118 |
rig.setAttribute('position', pos);
|
| 119 |
rig.setAttribute('look-at', center);
|
| 120 |
break;
|
| 121 |
}
|
| 122 |
}
|
| 123 |
+
|
| 124 |
+
function flyCamera(action) {
|
| 125 |
+
var rig = document.querySelector('#rig');
|
| 126 |
+
var pos = rig.getAttribute('position');
|
| 127 |
+
var rot = rig.getAttribute('rotation');
|
| 128 |
+
var speed = 0.1, rSpeed = 2;
|
| 129 |
+
|
| 130 |
+
switch(action) {
|
| 131 |
+
case 'forward':
|
| 132 |
+
var dir = new THREE.Vector3(0, 0, -1);
|
| 133 |
+
dir.applyQuaternion(rig.object3D.quaternion);
|
| 134 |
+
pos.x += dir.x * speed;
|
| 135 |
+
pos.y += dir.y * speed;
|
| 136 |
+
pos.z += dir.z * speed;
|
| 137 |
+
break;
|
| 138 |
+
case 'backward':
|
| 139 |
+
var dir = new THREE.Vector3(0, 0, 1);
|
| 140 |
+
dir.applyQuaternion(rig.object3D.quaternion);
|
| 141 |
+
pos.x += dir.x * speed;
|
| 142 |
+
pos.y += dir.y * speed;
|
| 143 |
+
pos.z += dir.z * speed;
|
| 144 |
+
break;
|
| 145 |
+
case 'panLeft':
|
| 146 |
+
rot.y += rSpeed;
|
| 147 |
+
break;
|
| 148 |
+
case 'panRight':
|
| 149 |
+
rot.y -= rSpeed;
|
| 150 |
+
break;
|
| 151 |
+
case 'rotateLeft':
|
| 152 |
+
rot.y += rSpeed;
|
| 153 |
+
break;
|
| 154 |
+
case 'rotateRight':
|
| 155 |
+
rot.y -= rSpeed;
|
| 156 |
+
break;
|
| 157 |
+
case 'reset':
|
| 158 |
+
moveCamera('top');
|
| 159 |
+
return;
|
| 160 |
+
}
|
| 161 |
+
rig.setAttribute('position', pos);
|
| 162 |
+
rig.setAttribute('rotation', rot);
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
function fireRaycast() {
|
| 166 |
var cam = document.querySelector('[camera]');
|
| 167 |
var dir = new THREE.Vector3(); cam.object3D.getWorldDirection(dir);
|
|
|
|
| 178 |
}
|
| 179 |
}
|
| 180 |
}
|
| 181 |
+
|
| 182 |
document.addEventListener('keydown', e => {
|
| 183 |
switch(e.key.toLowerCase()){
|
| 184 |
case '1': moveCamera('top'); break;
|
|
|
|
| 190 |
case '7': moveCamera('angle2'); break;
|
| 191 |
case '8': moveCamera('angle3'); break;
|
| 192 |
case '9': moveCamera('angle4'); break;
|
| 193 |
+
case 'w': flyCamera('forward'); break;
|
| 194 |
+
case 'x': flyCamera('backward'); break;
|
| 195 |
+
case 'a': flyCamera('panLeft'); break;
|
| 196 |
+
case 'd': flyCamera('panRight'); break;
|
| 197 |
+
case 'q': flyCamera('rotateLeft'); break;
|
| 198 |
+
case 'e': flyCamera('rotateRight'); break;
|
| 199 |
+
case 's': flyCamera('reset'); break;
|
| 200 |
+
case ' ': fireRaycast(); break;
|
| 201 |
}
|
| 202 |
});
|
| 203 |
</script>
|
|
|
|
| 245 |
assets += "</a-assets>"
|
| 246 |
|
| 247 |
entities = ""
|
| 248 |
+
if vids:
|
| 249 |
+
# Use the first video as a large ground plane
|
| 250 |
+
v = vids[0]; s = Path(v).stem
|
| 251 |
+
entities += (f'<a-video src="#{s}" width="{gw}" height="{gh}" '
|
| 252 |
+
f'rotation="-90 0 0" position="0 0.05 0" '
|
| 253 |
+
'loop autoplay></a-video>')
|
| 254 |
+
else:
|
| 255 |
+
# Generate individual tiles if no video
|
| 256 |
+
sx = -gw/2; sz = -gh/2
|
| 257 |
+
for i in range(gw):
|
| 258 |
+
for j in range(gh):
|
| 259 |
+
x,y,z = sx+i,0,sz+j
|
| 260 |
+
if imgs:
|
| 261 |
+
img = random.choice(imgs); s = Path(img).stem
|
| 262 |
+
entities += (f'<a-plane src="#{s}" width="1" height="1" '
|
| 263 |
+
f'rotation="-90 0 0" position="{x} 0 {z}"></a-plane>')
|
| 264 |
+
# Always generate models
|
| 265 |
+
sx = -gw/2; sz = -gh/2
|
| 266 |
for i in range(gw):
|
| 267 |
for j in range(gh):
|
| 268 |
x,y,z = sx+i,0,sz+j
|
|
|
|
|
|
|
|
|
|
|
|
|
| 269 |
if models:
|
| 270 |
+
m = random.choice(models); ext = m.split('.')[-1]; s = Path(m).stem
|
| 271 |
+
entities += create_aframe_entity(s, ext, f"{x} 0 {z}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 272 |
return assets, entities
|
| 273 |
|
| 274 |
def main():
|
|
|
|
| 289 |
cols[1].button("↙️ Angle 3", on_click=lambda: st.session_state.update({'camera_view': 'angle3'}))
|
| 290 |
cols[2].button("↘️ Angle 4", on_click=lambda: st.session_state.update({'camera_view': 'angle4'}))
|
| 291 |
|
| 292 |
+
st.markdown("### ✈️ Flight Controls")
|
| 293 |
+
st.markdown("**Fly Camera** 🎮")
|
| 294 |
+
cols = st.columns(3)
|
| 295 |
+
cols[0].button("Q Rotate Left", on_click=lambda: st.session_state.update({'fly_action': 'rotateLeft'}))
|
| 296 |
+
cols[1].button("W Forward", on_click=lambda: st.session_state.update({'fly_action': 'forward'}))
|
| 297 |
+
cols[2].button("E Rotate Right", on_click=lambda: st.session_state.update({'fly_action': 'rotateRight'}))
|
| 298 |
+
cols = st.columns(3)
|
| 299 |
+
cols[0].button("A Pan Left", on_click=lambda: st.session_state.update({'fly_action': 'panLeft'}))
|
| 300 |
+
cols[1].button("S Reset", on_click=lambda: st.session_state.update({'fly_action': 'reset'}))
|
| 301 |
+
cols[2].button("D Pan Right", on_click=lambda: st.session_state.update({'fly_action': 'panRight'}))
|
| 302 |
+
cols = st.columns(1)
|
| 303 |
+
cols[0].button("X Backward", on_click=lambda: st.session_state.update({'fly_action': 'backward'}))
|
| 304 |
+
|
| 305 |
st.markdown("### ➕ Add Media Files")
|
| 306 |
ups = st.file_uploader("Add files (png, jpeg, obj, glb, mp4, etc.):", accept_multiple_files=True)
|
| 307 |
st.markdown("### 📋 Uploaded Model Files")
|
|
|
|
| 352 |
assets, ents = generate_tilemap(files, directory, 8, 8)
|
| 353 |
scene += assets + ents + "</a-scene>"
|
| 354 |
|
| 355 |
+
view_cmd = st.session_state.get('camera_view', 'top')
|
| 356 |
+
if view_cmd:
|
| 357 |
+
scene += f"<script>moveCamera('{view_cmd}');</script>"
|
| 358 |
st.session_state.pop('camera_view', None)
|
| 359 |
|
| 360 |
+
fly_cmd = st.session_state.get('fly_action')
|
| 361 |
+
if fly_cmd:
|
| 362 |
+
scene += f"<script>flyCamera('{fly_cmd}');</script>"
|
| 363 |
+
st.session_state.pop('fly_action', None)
|
| 364 |
+
|
| 365 |
loader = '<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/aframe-extras.loaders.min.js"></script>'
|
| 366 |
|
| 367 |
st.components.v1.html(
|