|
import streamlit as st |
|
import base64 |
|
|
|
st.set_page_config(layout="wide", page_title="Game Dev and 3D Showcase") |
|
|
|
st.title("Game Development and 3D Content Showcase") |
|
|
|
|
|
st.header("HTML5 Game") |
|
html5_game = """ |
|
<canvas id="gameCanvas" width="400" height="300"></canvas> |
|
<script> |
|
const canvas = document.getElementById('gameCanvas'); |
|
const ctx = canvas.getContext('2d'); |
|
let x = canvas.width / 2; |
|
let y = canvas.height - 30; |
|
let dx = 2; |
|
let dy = -2; |
|
const ballRadius = 10; |
|
|
|
function drawBall() { |
|
ctx.beginPath(); |
|
ctx.arc(x, y, ballRadius, 0, Math.PI * 2); |
|
ctx.fillStyle = "#0095DD"; |
|
ctx.fill(); |
|
ctx.closePath(); |
|
} |
|
|
|
function draw() { |
|
ctx.clearRect(0, 0, canvas.width, canvas.height); |
|
drawBall(); |
|
|
|
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) { |
|
dx = -dx; |
|
} |
|
if (y + dy > canvas.height - ballRadius || y + dy < ballRadius) { |
|
dy = -dy; |
|
} |
|
|
|
x += dx; |
|
y += dy; |
|
} |
|
|
|
setInterval(draw, 10); |
|
</script> |
|
""" |
|
st.components.v1.html(html5_game, height=350) |
|
|
|
|
|
st.header("Mad Lib Generator") |
|
|
|
templates = [ |
|
"The {adjective} {noun} {verb} over the {adjective} {noun}.", |
|
"In a {adjective} land, a {noun} and a {noun} went on a {adjective} adventure.", |
|
"The {noun} {verb} {adverb} while the {adjective} {noun} watched in amazement." |
|
] |
|
|
|
parts_of_speech = { |
|
"adjective": ["brave", "mysterious", "colorful", "gigantic", "tiny"], |
|
"noun": ["wizard", "dragon", "knight", "castle", "forest"], |
|
"verb": ["flew", "danced", "sang", "fought", "explored"], |
|
"adverb": ["quickly", "silently", "gracefully", "fiercely", "carefully"] |
|
} |
|
|
|
def generate_mad_lib(): |
|
import random |
|
template = random.choice(templates) |
|
for part in parts_of_speech: |
|
while "{" + part + "}" in template: |
|
template = template.replace("{" + part + "}", random.choice(parts_of_speech[part]), 1) |
|
return template |
|
|
|
if st.button("Generate Mad Lib"): |
|
st.write(generate_mad_lib()) |
|
|
|
|
|
st.header("A-Frame 3D Scene") |
|
aframe_scene = """ |
|
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script> |
|
<a-scene embedded style="height: 400px;"> |
|
<a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box> |
|
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere> |
|
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder> |
|
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane> |
|
<a-sky color="#ECECEC"></a-sky> |
|
</a-scene> |
|
""" |
|
st.components.v1.html(aframe_scene, height=450) |
|
|
|
|
|
st.header("Three.js 3D Model Viewer") |
|
threejs_viewer = """ |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> |
|
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/OBJLoader.js"></script> |
|
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/loaders/GLTFLoader.js"></script> |
|
<div id="model-container" style="width: 100%; height: 400px;"></div> |
|
<script> |
|
let scene, camera, renderer, model; |
|
|
|
function init() { |
|
scene = new THREE.Scene(); |
|
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); |
|
renderer = new THREE.WebGLRenderer(); |
|
renderer.setSize(window.innerWidth, 400); |
|
document.getElementById('model-container').appendChild(renderer.domElement); |
|
|
|
const light = new THREE.PointLight(0xffffff, 1, 100); |
|
light.position.set(0, 0, 10); |
|
scene.add(light); |
|
|
|
camera.position.z = 5; |
|
animate(); |
|
} |
|
|
|
function animate() { |
|
requestAnimationFrame(animate); |
|
if (model) { |
|
model.rotation.x += 0.01; |
|
model.rotation.y += 0.01; |
|
} |
|
renderer.render(scene, camera); |
|
} |
|
|
|
function loadModel(url, fileType) { |
|
let loader; |
|
if (fileType === 'obj') { |
|
loader = new THREE.OBJLoader(); |
|
} else if (fileType === 'glb') { |
|
loader = new THREE.GLTFLoader(); |
|
} |
|
|
|
loader.load(url, function(object) { |
|
if (model) { |
|
scene.remove(model); |
|
} |
|
model = fileType === 'obj' ? object : object.scene; |
|
scene.add(model); |
|
}); |
|
} |
|
init(); |
|
</script> |
|
""" |
|
st.components.v1.html(threejs_viewer, height=450) |
|
|
|
|
|
uploaded_file = st.file_uploader("Upload a 3D model (OBJ or GLB)", type=['obj', 'glb']) |
|
|
|
if uploaded_file is not None: |
|
|
|
file_extension = uploaded_file.name.split('.')[-1].lower() |
|
|
|
|
|
encoded_file = base64.b64encode(uploaded_file.read()).decode() |
|
|
|
|
|
data_url = f"data:application/octet-stream;base64,{encoded_file}" |
|
|
|
|
|
load_model_js = f""" |
|
<script> |
|
loadModel("{data_url}", "{file_extension}"); |
|
</script> |
|
""" |
|
st.components.v1.html(load_model_js, height=0) |
|
st.success(f"Loaded {uploaded_file.name}") |
|
|
|
st.sidebar.title("Navigation") |
|
st.sidebar.info("Use the sections above to interact with different components of the app.") |