AstroLearn / app.py
mairaqamar's picture
Create app.py
9073ad3 verified
from flask import Flask, render_template_string
app = Flask(__name__)
html_content = """
<!DOCTYPE html>
<html>
<head>
<title>AstroLearn</title>
<style>
body { margin:0; overflow:hidden; background:black; font-family:Arial,sans-serif; }
canvas { display:block; }
/* Header Branding */
#header {
position:absolute;
top:0;
left:50%;
transform:translateX(-50%);
color:white;
font-size:32px;
font-weight:bold;
padding:10px;
z-index:10;
pointer-events:none;
}
/* Info Box */
#infoBox {
position:absolute;
top:60px;
left:20px;
padding:15px;
background: rgba(0,0,0,0.7);
color:white;
border-radius:8px;
max-width:350px;
line-height:1.5;
pointer-events:none;
transition:all 0.3s ease;
}
/* Popup */
.popup {
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
background: rgba(0,0,0,0.9);
color:white;
padding:20px;
border-radius:10px;
max-width:400px;
display:none;
z-index:10;
text-align:center;
}
.popup img {
width:100%;
border-radius:8px;
margin-bottom:10px;
}
.popup button {
margin-top:10px;
padding:5px 15px;
border:none;
border-radius:5px;
background:#2196F3;
color:white;
cursor:pointer;
}
/* Footer Branding */
#footer {
position:absolute;
bottom:10px;
right:10px;
color:#888;
font-size:14px;
pointer-events:none;
}
</style>
</head>
<body>
<div id="header">AstroLearn</div>
<div id="infoBox">Hover over a planet to learn more!</div>
<div id="popup" class="popup">
<h2 id="popupTitle"></h2>
<img id="popupImg" src="" alt="">
<p id="popupDesc"></p>
<button onclick="closePopup()">Close</button>
</div>
<div id="footer">Powered by AstroLearn</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script>
// === Scene Setup ===
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 5000);
const renderer = new THREE.WebGLRenderer({ antialias:true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; controls.dampingFactor = 0.1;
const light = new THREE.PointLight(0xffffff,2); light.position.set(0,0,0);
scene.add(light); scene.add(new THREE.AmbientLight(0x404040,0.3));
// === Planets Data ===
const planets = [
{ name:"Mercury", radius:0.38, distance:10, color:0xb2b2b2, info:"Mercury: Diameter ~4,879 km, distance from Sun ~57.9M km. Very thin atmosphere.", image:"https://upload.wikimedia.org/wikipedia/commons/4/4a/Mercury_in_true_color.jpg" },
{ name:"Venus", radius:0.95, distance:15, color:0xeeddaa, clouds:"https://threejs.org/examples/textures/earth_clouds_1024.png", info:"Venus: Diameter ~12,104 km, distance ~108M km. Dense CO2 atmosphere, scorching ~465°C.", image:"https://upload.wikimedia.org/wikipedia/commons/e/e5/Venus-real_color.jpg" },
{ name:"Earth", radius:1, distance:20, color:0x2266ff, clouds:"https://threejs.org/examples/textures/earth_clouds_1024.png", info:"Earth: Diameter ~12,742 km, distance 149.6M km. Only planet known to support life.", image:"https://upload.wikimedia.org/wikipedia/commons/9/97/The_Earth_seen_from_Apollo_17.jpg" },
{ name:"Mars", radius:0.53, distance:28, color:0xff5533, info:"Mars: Diameter ~6,779 km, distance 227.9M km. Known for Olympus Mons.", image:"https://mars.nasa.gov/system/news_items/main_images/9323_PIA25679-FigureA-web.jpg" },
{ name:"Jupiter", radius:11.2, distance:40, color:0xffaa55, info:"Jupiter: Diameter ~139,820 km, distance 778M km. Gas giant, Great Red Spot, 79 moons.", image:"https://upload.wikimedia.org/wikipedia/commons/e/e2/Jupiter.jpg" },
{ name:"Saturn", radius:9.45, distance:55, color:0xffddaa, info:"Saturn: Diameter ~116,460 km, distance 1.43B km. Famous for rings.", image:"https://upload.wikimedia.org/wikipedia/commons/c/c7/Saturn_during_Equinox.jpg" },
{ name:"Uranus", radius:4, distance:65, color:0x66ccff, info:"Uranus: Diameter ~50,724 km, distance 2.87B km. Rotates on its side.", image:"https://upload.wikimedia.org/wikipedia/commons/3/3d/Uranus2.jpg" },
{ name:"Neptune", radius:3.88, distance:75, color:0x3366ff, info:"Neptune: Diameter ~49,244 km, distance 4.5B km. Strongest winds ~2,100 km/h.", image:"https://upload.wikimedia.org/wikipedia/commons/5/56/Neptune_Full.jpg" }
];
const planetMeshes = [], cloudMeshes = [];
planets.forEach(p=>{
const geo = new THREE.SphereGeometry(p.radius,64,64);
const mat = new THREE.MeshStandardMaterial({ color:p.color });
const mesh = new THREE.Mesh(geo,mat);
mesh.position.x = p.distance; mesh.userData=p; scene.add(mesh); planetMeshes.push(mesh);
if(p.clouds){
const cloudGeo = new THREE.SphereGeometry(p.radius+0.03,64,64);
const cloudMat = new THREE.MeshPhongMaterial({ map:new THREE.TextureLoader().load(p.clouds), transparent:true, opacity:0.4 });
const cloudMesh = new THREE.Mesh(cloudGeo,cloudMat);
cloudMesh.position.copy(mesh.position); scene.add(cloudMesh); cloudMeshes.push(cloudMesh);
}
const ringGeo = new THREE.RingGeometry(p.distance-0.02,p.distance+0.02,128);
const ringMat = new THREE.MeshBasicMaterial({color:0x888888, side:THREE.DoubleSide, transparent:true, opacity:0.2});
const ring = new THREE.Mesh(ringGeo, ringMat); ring.rotation.x=Math.PI/2; scene.add(ring);
});
// Starfield
const starGeo = new THREE.BufferGeometry(); const starCount=4000; const pos=[];
for(let i=0;i<starCount;i++){ pos.push((Math.random()-0.5)*2000); pos.push((Math.random()-0.5)*2000); pos.push((Math.random()-0.5)*2000); }
starGeo.setAttribute('position', new THREE.Float32BufferAttribute(pos,3));
scene.add(new THREE.Points(starGeo,new THREE.PointsMaterial({color:0xffffff,size:0.5})));
camera.position.set(0,10,120);
// Interaction
const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2();
const infoBox = document.getElementById('infoBox'); const popup = document.getElementById('popup');
const popupTitle = document.getElementById('popupTitle'); const popupImg = document.getElementById('popupImg');
const popupDesc = document.getElementById('popupDesc');
window.addEventListener('mousemove', e => { mouse.x = (e.clientX/window.innerWidth)*2-1; mouse.y=-(e.clientY/window.innerHeight)*2+1; });
window.addEventListener('click', ()=>{
raycaster.setFromCamera(mouse,camera);
const intersects = raycaster.intersectObjects(planetMeshes);
if(intersects.length>0){
const planet=intersects[0].object.userData;
popupTitle.innerText=planet.name; popupImg.src=planet.image; popupDesc.innerText=planet.info; popup.style.display="block";
const targetPos = intersects[0].object.position.clone();
gsap.to(camera.position,{x:targetPos.x+planet.radius*2, y:targetPos.y+planet.radius*1.5, z:targetPos.z+planet.radius*4, duration:2, ease:"power2.inOut"});
gsap.to(controls.target,{x:targetPos.x, y:targetPos.y, z:targetPos.z, duration:2, ease:"power2.inOut"});
}
});
function closePopup(){ popup.style.display="none"; }
function animate(){
requestAnimationFrame(animate);
planetMeshes.forEach((mesh,i)=>{ mesh.rotation.y+=0.001+i*0.0005; if(cloudMeshes[i]) cloudMeshes[i].rotation.y+=0.002; });
raycaster.setFromCamera(mouse,camera);
const intersects = raycaster.intersectObjects(planetMeshes);
infoBox.innerHTML = intersects.length>0 ? intersects[0].object.userData.info : "Hover over a planet to learn more!";
controls.update(); renderer.render(scene,camera);
}
animate();
window.addEventListener("resize", ()=>{
camera.aspect=window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>
</body>
</html>
"""
@app.route("/")
def index():
return render_template_string(html_content)
if __name__ == "__main__":
app.run(debug=True)