Files

349 lines
15 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Nexus Orbits · İnteraktif Güneş Sistemi</title>
<style>
:root{
--bg:#04060f; --bg2:#0a0f24; --accent:#5eead4; --accent2:#818cf8;
--text:#e6ecff; --muted:#8b95b8; --panel:rgba(14,19,40,.72);
--border:rgba(120,140,220,.22);
font-family:"Segoe UI",Inter,system-ui,-apple-system,sans-serif;
}
*{margin:0;padding:0;box-sizing:border-box;}
html,body{height:100%;}
body{
background:radial-gradient(1200px 800px at 70% 10%, #131a3d 0%, var(--bg2) 40%, var(--bg) 100%);
color:var(--text);overflow:hidden;-webkit-font-smoothing:antialiased;
}
#space{position:fixed;inset:0;display:block;cursor:grab;touch-action:none;}
#space:active{cursor:grabbing;}
header{
position:fixed;top:0;left:0;right:0;z-index:10;
display:flex;align-items:center;justify-content:space-between;padding:16px 22px;
background:linear-gradient(180deg, rgba(4,6,15,.85), transparent);pointer-events:none;
}
header .brand{display:flex;align-items:center;gap:12px;pointer-events:auto;}
.logo{width:34px;height:34px;border-radius:50%;
background:radial-gradient(circle at 35% 30%, #a5f3fc, #6366f1 55%, #1e1b4b);
box-shadow:0 0 22px rgba(99,102,241,.7), 0 0 44px rgba(94,234,212,.25);position:relative;}
.logo::after{content:"";position:absolute;inset:-8px;border-radius:50%;
border:1px solid rgba(129,140,248,.5);border-top-color:transparent;border-left-color:transparent;
animation:spin 4s linear infinite;}
@keyframes spin{to{transform:rotate(360deg);}}
.brand h1{font-size:17px;font-weight:700;letter-spacing:.5px;}
.brand h1 span{color:var(--accent);}
.brand p{font-size:11px;color:var(--muted);letter-spacing:2px;text-transform:uppercase;}
.controls{display:flex;gap:8px;pointer-events:auto;}
.btn{background:var(--panel);border:1px solid var(--border);color:var(--text);
padding:9px 14px;border-radius:10px;font-size:13px;font-weight:500;cursor:pointer;
backdrop-filter:blur(10px);transition:.18s;display:flex;align-items:center;gap:7px;}
.btn:hover{border-color:var(--accent);color:var(--accent);transform:translateY(-1px);}
.btn:active{transform:translateY(0);}
.btn.off{opacity:.5;}
#info{position:fixed;left:22px;bottom:22px;z-index:10;width:min(340px, calc(100vw - 44px));
background:var(--panel);border:1px solid var(--border);border-radius:18px;padding:20px 22px;
backdrop-filter:blur(14px);box-shadow:0 20px 50px rgba(0,0,0,.5);transition:.3s;}
#info .tag{font-size:10px;letter-spacing:2px;text-transform:uppercase;color:var(--accent);
display:inline-flex;align-items:center;gap:6px;margin-bottom:8px;}
#info .tag::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--accent);
box-shadow:0 0 10px var(--accent);}
#info h2{font-size:22px;font-weight:700;margin-bottom:4px;}
#info .desc{font-size:13px;color:var(--muted);line-height:1.5;margin-bottom:14px;}
#stats{display:grid;grid-template-columns:1fr 1fr;gap:10px;}
#stats .st{background:rgba(255,255,255,.03);border:1px solid var(--border);border-radius:11px;padding:9px 11px;}
#stats .st b{display:block;font-size:15px;color:var(--accent2);}
#stats .st small{font-size:10px;color:var(--muted);letter-spacing:.5px;}
#hint{position:fixed;bottom:26px;right:24px;z-index:10;font-size:12px;color:var(--muted);
text-align:right;line-height:1.7;}
#hint kbd{background:var(--panel);border:1px solid var(--border);border-radius:6px;
padding:2px 6px;font-size:11px;color:var(--text);}
.speed{position:fixed;top:16px;left:50%;transform:translateX(-50%);z-index:10;
display:flex;align-items:center;gap:10px;pointer-events:auto;background:var(--panel);
border:1px solid var(--border);border-radius:12px;padding:8px 14px;backdrop-filter:blur(10px);
font-size:12px;color:var(--muted);}
.speed input{width:120px;accent-color:var(--accent);cursor:pointer;}
@media(max-width:720px){
header{padding:12px 14px;}
.brand p{display:none;}
#info{left:12px;right:12px;bottom:12px;width:auto;padding:16px;}
#hint{display:none;}
.speed{top:64px;left:12px;right:12px;transform:none;justify-content:space-between;}
.speed input{width:45%;}
.controls .btn span{display:none;}
.controls .btn{padding:9px 11px;}
}
</style>
</head>
<body>
<canvas id="space"></canvas>
<header>
<div class="brand">
<div class="logo"></div>
<div>
<h1>NEXUS <span>ORBITS</span></h1>
<p>İnteraktif Güneş Sistemi</p>
</div>
</div>
<div class="controls">
<button class="btn" id="btnPause">⏸ <span>Duraklat</span></button>
<button class="btn" id="btnTrail">✦ <span>İzler</span></button>
<button class="btn" id="btnReset">↺ <span>Sıfırla</span></button>
</div>
</header>
<div class="speed">
<span>Simülasyon Hızı</span>
<input type="range" id="speed" min="0" max="300" value="100" />
<b id="speedVal" style="color:var(--accent)">1.0×</b>
</div>
<div id="info">
<div class="tag" id="iTag">Güneş</div>
<h2 id="iName">Güneş</h2>
<div class="desc" id="iDesc">Sistemin merkezindeki yıldız. Bir gezegene tıklayarak keşfet.</div>
<div id="stats">
<div class="st"><b id="s1">696.340 km</b><small id="s1l">Yarıçap</small></div>
<div class="st"><b id="s2">—</b><small id="s2l">Yörünge</small></div>
</div>
</div>
<div id="hint">
<kbd>Sol tık</kbd> gezegen seç · <kbd>Sürükle</kbd> kamera<br/>
<kbd>Tekerlek</kbd> yakınlaştır · <kbd>Boşluk</kbd> duraklat
</div>
<script>
(()=>{
const canvas=document.getElementById('space');
const ctx=canvas.getContext('2d');
let W,H,DPR;
function resize(){
DPR=Math.min(window.devicePixelRatio||1,2);
canvas.width=innerWidth*DPR; canvas.height=innerHeight*DPR;
canvas.style.width=innerWidth+'px'; canvas.style.height=innerHeight+'px';
ctx.setTransform(DPR,0,0,DPR,0,0);
W=innerWidth;H=innerHeight;
}
resize();
addEventListener('resize',resize);
const stars=[];
function buildStars(){
stars.length=0;
for(let i=0;i<340;i++){
stars.push({x:Math.random()*W,y:Math.random()*H,r:Math.random()*1.4+.2,
a:Math.random()*.7+.2,tw:Math.random()*Math.PI*2,ts:Math.random()*.03+.01});
}
}
buildStars();
addEventListener('resize',buildStars);
const planets=[
{name:"Merkür",tag:"İç Gezegen",color:"#c9a97a",radius:4,orbit:78,speed:1.6,
desc:"Güneş'e en yakın, en küçük gezegen. Yüzeyi kraterlerle kaplı.",
d1:["2.440 km","Yarıçap"],d2:["88 gün","Yörünge"]},
{name:"Venüs",tag:"İç Gezegen",color:"#e8b96b",radius:7,orbit:112,speed:1.18,
desc:"Kalın atmosferiyle sera etkisinin en güçlü olduğu gezegen.",
d1:["6.051 km","Yarıçap"],d2:["225 gün","Yörünge"]},
{name:"Dünya",tag:"Yaşam Gezegeni",color:"#4aa8ff",radius:7.5,orbit:150,speed:.92,
desc:"Bilinen tek yaşam barındıran gezegen. Mavi okyanuslar ve kıtalar.",
d1:["6.371 km","Yarıçap"],d2:["365 gün","Yörünge"]},
{name:"Mars",tag:"Kızıl Gezegen",color:"#e0592f",radius:6,orbit:188,speed:.74,
desc:"Demir oksit yüzeyiyle kızıl görünen gezegen, iki küçük uydusu var.",
d1:["3.389 km","Yarıçap"],d2:["687 gün","Yörünge"]},
{name:"Jüpiter",tag:"Gaz Devi",color:"#d9a066",radius:15,orbit:255,speed:.42,
desc:"Sistemin en büyük gezegeni. Büyük Kırmızı Leke bir dev fırtına.",
d1:["69.911 km","Yarıçap"],d2:["11,8 yıl","Yörünge"]},
{name:"Satürn",tag:"Halkalı Devi",color:"#e5cf8f",radius:12.5,orbit:315,speed:.31,ring:true,
desc:"Etkileyici buz halkalarıyla bilinen, yoğunluğu sudan düşük gaz devi.",
d1:["58.232 km","Yarıçap"],d2:["29,4 yıl","Yörünge"]},
{name:"Uranüs",tag:"Buz Devi",color:"#8fd8de",radius:9.5,orbit:365,speed:.22,
desc:"Yana yatmış ekseniyle dönen, soluk mavi buz devi.",
d1:["25.362 km","Yarıçap"],d2:["84 yıl","Yörünge"]},
{name:"Neptün",tag:"Buz Devi",color:"#5b7ff0",radius:9,orbit:410,speed:.16,
desc:"Güneş'ten en uzak gezegen. Süpersonik rüzgarlarıyla ünlü.",
d1:["24.622 km","Yarıçap"],d2:["165 yıl","Yörünge"]}
];
planets.forEach(p=>{ p.angle=Math.random()*Math.PI*2; p.trail=[]; });
const moon={angle:0,orbit:16,radius:2.6,color:"#cfd6e6"};
let camX=0,camY=0,zoom=.6,targetZoom=1;
let paused=false,showTrails=true,speedMul=1,selected=null;
let last=performance.now();
function worldToScreen(p){
const r=p.orbit*zoom;
const cx=W/2+camX, cy=H/2+camY;
return {x:cx+Math.cos(p.angle)*r,y:cy+Math.sin(p.angle)*r};
}
let dragging=false,dragMoved=false,lastX=0,lastY=0;
canvas.addEventListener('pointerdown',e=>{
dragging=true;dragMoved=false;lastX=e.clientX;lastY=e.clientY;
canvas.setPointerCapture(e.pointerId);
});
canvas.addEventListener('pointermove',e=>{
if(dragging){
const dx=e.clientX-lastX, dy=e.clientY-lastY;
if(Math.abs(dx)+Math.abs(dy)>3) dragMoved=true;
camX+=dx;camY+=dy;lastX=e.clientX;lastY=e.clientY;return;
}
let hit=false;
for(const p of planets){
const s=worldToScreen(p);
if(Math.hypot(s.x-e.clientX,s.y-e.clientY)<Math.max(p.radius*zoom,16)){hit=true;break;}
}
canvas.style.cursor=hit?'pointer':'grab';
});
canvas.addEventListener('pointerup',e=>{
dragging=false;
if(!dragMoved) pick(e.clientX,e.clientY);
});
canvas.addEventListener('wheel',e=>{
e.preventDefault();
targetZoom*=(e.deltaY<0?1.12:0.89);
targetZoom=Math.max(.45,Math.min(2.6,targetZoom));
},{passive:false});
addEventListener('keydown',e=>{ if(e.code==='Space'){e.preventDefault();togglePause();} });
function pick(mx,my){
let best=null,bd=1e9;
for(const p of planets){
const s=worldToScreen(p);
const d=Math.hypot(s.x-mx,s.y-my);
if(d<Math.max(p.radius*zoom,16)&&d<bd){bd=d;best=p;}
}
selected=best; updateInfo(best);
}
const iTag=document.getElementById('iTag'),iName=document.getElementById('iName'),
iDesc=document.getElementById('iDesc'),s1=document.getElementById('s1'),
s2=document.getElementById('s2'),s1l=document.getElementById('s1l'),s2l=document.getElementById('s2l');
function updateInfo(p){
if(!p){
iTag.textContent="Güneş";iName.textContent="Güneş";
iDesc.textContent="Sistemin merkezindeki yıldız. Bir gezegene tıklayarak keşfet.";
s1.textContent="696.340 km";s1l.textContent="Yarıçap";s2.textContent="—";s2l.textContent="Yörünge";return;
}
iTag.textContent=p.tag;iName.textContent=p.name;iDesc.textContent=p.desc;
s1.textContent=p.d1[0];s1l.textContent=p.d1[1];s2.textContent=p.d2[0];s2l.textContent=p.d2[1];
}
updateInfo(null);
const btnPause=document.getElementById('btnPause'),btnTrail=document.getElementById('btnTrail'),
btnReset=document.getElementById('btnReset'),speedEl=document.getElementById('speed'),
speedVal=document.getElementById('speedVal');
function togglePause(){
paused=!paused;
btnPause.innerHTML=paused?'▶ <span>Devam</span>':'⏸ <span>Duraklat</span>';
btnPause.classList.toggle('off',paused);
}
btnPause.onclick=togglePause;
btnTrail.onclick=()=>{showTrails=!showTrails;btnTrail.classList.toggle('off',!showTrails);planets.forEach(p=>p.trail.length=0);};
btnReset.onclick=()=>{
camX=0;camY=0;targetZoom=1;zoom=1;
planets.forEach(p=>{p.angle=Math.random()*Math.PI*2;p.trail.length=0;});
selected=null;updateInfo(null);
};
speedEl.oninput=()=>{speedMul=speedEl.value/100;speedVal.textContent=speedMul.toFixed(1)+'×';};
function lighten(hex,amt){
const n=parseInt(hex.replace('#',''),16);
let r=(n>>16)&255,g=(n>>8)&255,b=n&255;
r=Math.min(255,r+255*amt);g=Math.min(255,g+255*amt);b=Math.min(255,b+255*amt);
return `rgb(${r|0},${g|0},${b|0})`;
}
function drawStars(dt){
ctx.clearRect(0,0,W,H);
for(const s of stars){
s.tw+=s.ts*dt*60;
ctx.globalAlpha=s.a*(0.6+0.4*Math.sin(s.tw));
ctx.fillStyle='#cfe0ff';
ctx.beginPath();ctx.arc(s.x,s.y,s.r,0,7);ctx.fill();
}
ctx.globalAlpha=1;
}
function drawSun(dt){
const cx=W/2+camX, cy=H/2+camY, r=26*zoom*(1+0.02*Math.sin(dt*0));
const g=ctx.createRadialGradient(cx,cy,r*.2,cx,cy,r*4);
g.addColorStop(0,'rgba(255,214,120,.95)');
g.addColorStop(.25,'rgba(255,170,60,.45)');
g.addColorStop(.6,'rgba(255,120,40,.12)');
g.addColorStop(1,'rgba(255,120,40,0)');
ctx.fillStyle=g;ctx.beginPath();ctx.arc(cx,cy,r*4,0,7);ctx.fill();
const c=ctx.createRadialGradient(cx-r*.3,cy-r*.3,r*.1,cx,cy,r);
c.addColorStop(0,'#fffbe8');c.addColorStop(.5,'#ffcf57');c.addColorStop(1,'#ff8a1e');
ctx.fillStyle=c;ctx.beginPath();ctx.arc(cx,cy,r,0,7);ctx.fill();
}
function drawOrbits(){
const cx=W/2+camX, cy=H/2+camY;
ctx.lineWidth=1;
for(const p of planets){
ctx.strokeStyle= selected===p ? 'rgba(94,234,212,.5)' : 'rgba(140,160,230,.13)';
ctx.beginPath();ctx.arc(cx,cy,p.orbit*zoom,0,7);ctx.stroke();
}
}
function drawPlanet(p){
const s=worldToScreen(p), r=p.radius*zoom;
if(showTrails){
p.trail.push({x:s.x,y:s.y});
if(p.trail.length>26) p.trail.shift();
for(let i=0;i<p.trail.length;i++){
ctx.globalAlpha=(i/p.trail.length)*.35;
ctx.fillStyle=p.color;
ctx.beginPath();ctx.arc(p.trail[i].x,p.trail[i].y,r*.28,0,7);ctx.fill();
}
ctx.globalAlpha=1;
}
if(selected===p){
ctx.strokeStyle='rgba(94,234,212,.85)';ctx.lineWidth=1.5;ctx.setLineDash([4,4]);
ctx.beginPath();ctx.arc(s.x,s.y,r+9,0,7);ctx.stroke();ctx.setLineDash([]);
}
if(p.ring){
ctx.save();ctx.translate(s.x,s.y);ctx.rotate(-.4);
ctx.strokeStyle='rgba(229,207,143,.7)';ctx.lineWidth=Math.max(1.5,r*.28);
ctx.beginPath();ctx.ellipse(0,0,r*1.9,r*.62,0,0,7);ctx.stroke();
ctx.strokeStyle='rgba(229,207,143,.35)';ctx.lineWidth=Math.max(1,r*.14);
ctx.beginPath();ctx.ellipse(0,0,r*2.35,r*.78,0,0,7);ctx.stroke();
ctx.restore();
}
const gr=ctx.createRadialGradient(s.x-r*.35,s.y-r*.35,r*.1,s.x,s.y,r);
gr.addColorStop(0,lighten(p.color,.4));gr.addColorStop(1,p.color);
ctx.fillStyle=gr;ctx.shadowColor=p.color;ctx.shadowBlur=selected===p?26:12;
ctx.beginPath();ctx.arc(s.x,s.y,r,0,7);ctx.fill();
if(selected===p){
ctx.shadowBlur=0;ctx.fillStyle='#e6ecff';ctx.font='600 12px Segoe UI, sans-serif';
ctx.textAlign='center';ctx.fillText(p.name,s.x,s.y-r-15);
}
ctx.shadowBlur=0;
}
function drawMoon(dt){
const earth=planets.find(p=>p.name==="Dünya");
if(!earth)return;
const es=worldToScreen(earth);
moon.angle+=0.06*speedMul*(paused?0:1)*dt*6;
const mr=moon.orbit*zoom;
const mx=es.x+Math.cos(moon.angle)*mr, my=es.y+Math.sin(moon.angle)*mr;
ctx.fillStyle=moon.color;
ctx.beginPath();ctx.arc(mx,my,moon.radius*zoom,0,7);ctx.fill();
}
function loop(now){
const dt=Math.min((now-last)/1000,.05); last=now;
zoom+=(targetZoom-zoom)*.12;
if(!paused){ planets.forEach(p=>{ p.angle += p.speed*0.32*speedMul*dt; }); }
drawStars(dt); drawOrbits(); drawSun(dt); drawMoon(dt); planets.forEach(drawPlanet);
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
})();
</script>
</body>
</html>