3D-AFrame-VR / app.py
awacke1's picture
Update app.py
0c656b8 verified
raw
history blame
4.79 kB
import streamlit as st
import os, base64, shutil, random
from pathlib import Path
@st.cache_data
def load_aframe_and_extras():
return """
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/aframe-event-set-component.min.js"></script>
<script>
let score = 0;
AFRAME.registerComponent('draggable', {
init: function () {
this.el.setAttribute('class', 'raycastable');
this.el.setAttribute('cursor-listener', '');
this.dragHandler = this.dragMove.bind(this);
this.el.sceneEl.addEventListener('mousemove', this.dragHandler);
this.el.addEventListener('mousedown', this.onDragStart.bind(this));
this.el.addEventListener('mouseup', this.onDragEnd.bind(this));
this.camera = document.querySelector('[camera]');
},
remove: function () {
this.el.removeAttribute('cursor-listener');
this.el.sceneEl.removeEventListener('mousemove', this.dragHandler);
},
onDragStart: function (evt) {
this.isDragging = true;
this.el.emit('dragstart');
},
onDragEnd: function (evt) {
this.isDragging = false;
this.el.emit('dragend');
},
dragMove: function (evt) {
if (!this.isDragging) return;
let mouseX = evt.clientX / window.innerWidth * 2 - 1;
let mouseY = -(evt.clientY / window.innerHeight * 2) + 1;
let position = new THREE.Vector3(mouseX, mouseY, -5);
position.unproject(this.camera.components.camera.camera);
let direction = position.sub(this.camera.object3D.position).normalize();
let distance = -this.camera.object3D.position.z / direction.z;
let newPosition = this.camera.object3D.position.clone().add(direction.multiplyScalar(distance));
this.el.setAttribute('position', {x: newPosition.x, y: newPosition.y, z: this.el.getAttribute('position').z});
}
});
AFRAME.registerComponent('cursor-listener', {
init: function () {
this.el.addEventListener('mouseenter', function (evt) {
this.setAttribute('material', {color: 'red'});
});
this.el.addEventListener('mouseleave', function (evt) {
this.setAttribute('material', {color: 'blue'});
});
this.el.addEventListener('click', function (evt) {
score++;
document.getElementById('score').setAttribute('value', 'Score: ' + score);
});
}
});
</script>
"""
def create_environment(scene):
sky = scene.entity(
geometry="primitive: sphere; radius: 5000",
material="color: #ADD8E6; shader: flat; side: back" # Light blue sky
)
ground = scene.entity(
geometry="primitive: plane; width: 100; height: 100",
material="color: #7CFC00; side: double", # Lawn green ground
rotation="-90 0 0"
)
return sky, ground
def create_drag_target(scene, x, y, z, color='blue'):
target = scene.entity(
geometry=f"primitive: box; width: 1; height: 1; depth: 1",
material=f"color: {color}",
position=f"{x} {y} {z}",
draggable=""
)
return target
def main():
st.title("Interactive A-Frame Scene")
html_string = f"""
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>A-Frame Example</title>
{load_aframe_and_extras()}
</head>
<body>
<a-scene cursor="rayOrigin: mouse" raycaster="objects: .raycastable">
<a-camera position="0 1.6 0"></a-camera>
<a-entity id="environment"></a-entity>
<a-text id="score" value="Score: 0" position="-2 2 -3" color="black"></a-text>
<a-entity id="drag-targets"></a-entity>
</a-scene>
</body>
</html>
"""
st.components.v1.html(html_string, height=600, scrolling=False)
with st.sidebar:
st.header("Scene Controls")
num_targets = st.slider("Number of Drag Targets", min_value=1, max_value=10, value=3)
scene = st.components.v1 # This won't work as expected for direct A-Frame manipulation
environment = scene.get("environment") # This also won't work
drag_targets = scene.get("drag-targets") # And this won't work
if environment is not None:
create_environment(environment) # This will likely cause errors
if drag_targets is not None:
for i in range(num_targets):
x = random.uniform(-5, 5)
y = 1
z = random.uniform(-5, -2)
create_drag_target(drag_targets, x, y, z) # Potential error here too
if __name__ == "__main__":
main()