<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Artemis 2 High-Fidelity Simulator</title>

    <style>

        body { margin: 0; background-color: #000; overflow: hidden; font-family: 'Segoe UI', Arial, sans-serif; }

        

        /* HUD / Legend Styling */

        #hud {

            position: absolute;

            top: 20px;

            left: 20px;

            width: 320px;

            background: rgba(10, 10, 15, 0.9);

            border: 1px solid #334;

            border-radius: 8px;

            padding: 20px;

            color: #eee;

            box-shadow: 0 0 15px rgba(0, 150, 255, 0.2);

            backdrop-filter: blur(5px);

        }

        h2 { margin: 0 0 15px 0; font-size: 1.2rem; text-transform: uppercase; letter-spacing: 2px; color: #fff; border-bottom: 1px solid #445; padding-bottom: 10px;}

        

        .stage-item { display: flex; align-items: flex-start; margin-bottom: 12px; font-size: 0.9rem; }

        .color-indicator { min-width: 15px; height: 15px; border-radius: 50%; margin-right: 15px; margin-top: 3px; box-shadow: 0 0 8px currentColor; }

        

        /* Legend Colors */

        .c-launch { background-color: #00ff00; color: #00ff00; } /* Green */

        .c-orbit  { background-color: #00ffff; color: #00ffff; } /* Cyan */

        .c-heo    { background-color: #aa00ff; color: #aa00ff; } /* Purple */

        .c-tli    { background-color: #ffcc00; color: #ffcc00; } /* Gold */

        .c-flyby  { background-color: #ff4400; color: #ff4400; } /* Orange Red */

        .c-return { background-color: #ffffff; color: #ffffff; } /* White */


        #controls-hint {

            position: absolute; bottom: 20px; width: 100%; text-align: center; color: #556; font-size: 0.8rem; pointer-events: none;

        }

    </style>

</head>

<body>


    <div id="hud">

        <h2>Artemis II Profile</h2>

        <div class="stage-item"><div class="color-indicator c-launch"></div><div><strong>Launch (KSC)</strong><br><span style="font-size:0.75em; color:#aaa;">Ascent to Parking Orbit</span></div></div>

        <div class="stage-item"><div class="color-indicator c-orbit"></div><div><strong>LEO Parking</strong><br><span style="font-size:0.75em; color:#aaa;">Systems Check</span></div></div>

        <div class="stage-item"><div class="color-indicator c-heo"></div><div><strong>Hohmann Transfer</strong><br><span style="font-size:0.75em; color:#aaa;">Elliptical Orbit Raising</span></div></div>

        <div class="stage-item"><div class="color-indicator c-tli"></div><div><strong>Trans-Lunar Injection</strong><br><span style="font-size:0.75em; color:#aaa;">Tangent Burn to Moon</span></div></div>

        <div class="stage-item"><div class="color-indicator c-flyby"></div><div><strong>Lunar Flyby</strong><br><span style="font-size:0.75em; color:#aaa;">Free Return Trajectory</span></div></div>

        <div class="stage-item"><div class="color-indicator c-return"></div><div><strong>Re-entry</strong><br><span style="font-size:0.75em; color:#aaa;">Shallow Atmospheric Interface</span></div></div>

    </div>


    <div id="controls-hint">Left Click: Rotate • Right Click: Pan • Scroll: Zoom</div>


    <script type="importmap">

        { "imports": { "three": "https://unpkg.com/three@0.160.0/build/three.module.js", "three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/" } }

    </script>


    <script type="module">

        import * as THREE from 'three';

        import { OrbitControls } from 'three/addons/controls/OrbitControls.js';


        // --- 1. SCENE SETUP ---

        const scene = new THREE.Scene();

        scene.background = new THREE.Color(0x020205); 

        

        // Starfield

        const starGeo = new THREE.BufferGeometry();

        const starCount = 6000;

        const starPos = new Float32Array(starCount * 3);

        for(let i=0; i<starCount*3; i++) {

            starPos[i] = (Math.random() - 0.5) * 1500;

        }

        starGeo.setAttribute('position', new THREE.BufferAttribute(starPos, 3));

        const starMat = new THREE.PointsMaterial({color: 0xffffff, size: 0.6});

        const stars = new THREE.Points(starGeo, starMat);

        scene.add(stars);


        const camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.1, 5000);

        camera.position.set(50, 30, 100); 


        const renderer = new THREE.WebGLRenderer({ antialias: true });

        renderer.setSize(window.innerWidth, window.innerHeight);

        renderer.setPixelRatio(window.devicePixelRatio);

        renderer.shadowMap.enabled = true;

        document.body.appendChild(renderer.domElement);


        const controls = new OrbitControls(camera, renderer.domElement);

        controls.enableDamping = true;

        controls.dampingFactor = 0.05;


        // --- 2. LIGHTING ---

        const sunLight = new THREE.DirectionalLight(0xffffff, 2.0);

        sunLight.position.set(-150, 30, 80); 

        sunLight.castShadow = true;

        scene.add(sunLight);

        scene.add(new THREE.AmbientLight(0x404040, 0.5)); 


        const textureLoader = new THREE.TextureLoader();


        // --- 3. CELESTIAL BODIES ---

        const EARTH_RADIUS = 12;

        const MOON_DISTANCE = 140;


        // EARTH

        const earthGroup = new THREE.Group();

        const earthMat = new THREE.MeshStandardMaterial({

            map: textureLoader.load('https://unpkg.com/three-globe/example/img/earth-blue-marble.jpg'),

            bumpMap: textureLoader.load('https://unpkg.com/three-globe/example/img/earth-topology.png'),

            bumpScale: 0.5,

            roughness: 0.6,

            metalness: 0.1

        });

        const earth = new THREE.Mesh(new THREE.SphereGeometry(EARTH_RADIUS, 128, 128), earthMat);

        earthGroup.add(earth);

        scene.add(earthGroup);


        // MOON

        const moonMat = new THREE.MeshStandardMaterial({

            map: textureLoader.load('https://svs.gsfc.nasa.gov/vis/a000000/a004700/a004720/lroc_color_poles_1k.jpg'),

            displacementMap: textureLoader.load('https://svs.gsfc.nasa.gov/vis/a000000/a004700/a004720/ldem_16_uint.jpg'),

            displacementScale: 0.3,

            roughness: 0.9

        });

        const moon = new THREE.Mesh(new THREE.SphereGeometry(3.5, 64, 64), moonMat);

        moon.position.set(MOON_DISTANCE, 0, 0); 

        scene.add(moon);



        // --- 4. ADVANCED TRAJECTORY CALCULATION ---

        

        // HELPER: Coordinate conversion

        function getLatLon(lat, lon, radius) {

            const phi = (90 - lat) * (Math.PI / 180);

            const theta = (lon + 180) * (Math.PI / 180);

            return new THREE.Vector3(

                -(radius * Math.sin(phi) * Math.cos(theta)),

                radius * Math.cos(phi),

                radius * Math.sin(phi) * Math.sin(theta)

            );

        }


        // A. LAUNCH (Cape Canaveral -> LEO)

        // Cape Canaveral is approx 28.5° N, 80.6° W

        const launchStart = getLatLon(28.5, -80.6, EARTH_RADIUS);

        const leoAltitude = 2; // Simulating 2000km for visibility (scaled)

        const parkingRadius = EARTH_RADIUS + leoAltitude;

        

        // We calculate a point in orbit to merge into

        // We simply place the "orbit insertion" point 90 degrees East of launch to simulate ascent

        const launchEnd = new THREE.Vector3(parkingRadius, 0, 0); // Aligning with X-axis for simplicity later


        const launchCurve = new THREE.CubicBezierCurve3(

            launchStart,

            new THREE.Vector3(launchStart.x + 5, launchStart.y + 10, launchStart.z), // Vertical climb

            new THREE.Vector3(parkingRadius - 2, 5, 0), // Pitch over

            launchEnd // Insertion

        );

        const launchPoints = launchCurve.getPoints(40);


        // B. LEO PARKING ORBIT (Circular)

        // Simple circle segment

        const leoPoints = [];

        for(let i=0; i<=30; i++) {

            const angle = (i/30) * (Math.PI/2); // Quarter orbit checkout

            leoPoints.push(new THREE.Vector3(

                Math.cos(angle) * parkingRadius,

                0, // Equatorial for simplicity

                Math.sin(angle) * parkingRadius

            ));

        }


        // C. HOHMANN TRANSFER (Elliptical Orbit Raising)

        // Perigee = parkingRadius, Apogee = 30 (Arbitrary High Earth Orbit)

        const perigee = parkingRadius;

        const apogee = 35;

        const semiMajor = (perigee + apogee) / 2;

        const eccentricity = (apogee - perigee) / (apogee + perigee);

        const heoPoints = [];


        // We orbit 1.5 times (Orbit raising maneuvers)

        // Equation: r = a(1-e^2) / (1 + e*cos(theta))

        // We start theta at PI/2 because that's where our LEO segment ended

        for(let i=0; i<=150; i++) {

            const theta = (Math.PI/2) + (i/100) * (Math.PI * 2); // 1.5 loops

            const r = (semiMajor * (1 - eccentricity**2)) / (1 + eccentricity * Math.cos(theta - Math.PI/2)); // Phase shift to align perigee

            

            heoPoints.push(new THREE.Vector3(

                Math.cos(theta) * r,

                Math.sin(theta) * r * 0.2, // Slight inclination

                Math.sin(theta) * r

            ));

        }


        // D. TLI (Tangent Burn to Moon)

        // Start from end of HEO. Velocity is tangent there.

        const tliStart = heoPoints[heoPoints.length - 1];

        

        // We use a Cubic Bezier to ensure the first control point aligns with the HEO velocity

        // HEO velocity at that point is roughly (-1, 0, 0) direction

        const tliCurve = new THREE.CubicBezierCurve3(

            tliStart,

            new THREE.Vector3(tliStart.x - 20, tliStart.y, tliStart.z + 10), // Tangent extension

            new THREE.Vector3(80, 20, 40), // Mid-course

            new THREE.Vector3(MOON_DISTANCE - 10, 5, 10) // Near Moon

        );

        const tliPoints = tliCurve.getPoints(50);


        // E. LUNAR FLYBY

        const flybyCurve = new THREE.CatmullRomCurve3([

            new THREE.Vector3(MOON_DISTANCE - 10, 5, 10),

            new THREE.Vector3(MOON_DISTANCE + 8, 0, 0), // Behind Moon

            new THREE.Vector3(MOON_DISTANCE - 5, -5, -10) // Sling out

        ]);

        const flybyPoints = flybyCurve.getPoints(40);


        // F. RETURN (Shallow Re-entry)

        // Start from flyby end

        const returnStart = flybyPoints[flybyPoints.length - 1];

        

        // Calculate Splashdown point (Pacific)

        const splashdown = getLatLon(32, -117, EARTH_RADIUS);

        

        // To make it shallow, we create a "pre-entry" point just above the atmosphere

        // The vector from Pre-Entry -> Splashdown should be roughly tangent to the surface

        // We cheat visually by placing the control point "skimming" the atmosphere

        const returnCurve = new THREE.CubicBezierCurve3(

            returnStart,

            new THREE.Vector3(80, -20, -20), // Mid-return

            new THREE.Vector3(splashdown.x + 10, splashdown.y + 5, splashdown.z), // Shallow approach vector

            splashdown

        );

        const returnPoints = returnCurve.getPoints(60);


        // --- 5. MERGING & COLORING ---

        const allPoints = [

            ...launchPoints,

            ...leoPoints,

            ...heoPoints,

            ...tliPoints,

            ...flybyPoints,

            ...returnPoints

        ];


        const geometry = new THREE.BufferGeometry().setFromPoints(allPoints);

        const colors = [];


        // Helper to push colors

        function addColors(r, g, b, count) {

            for(let k=0; k<count; k++) colors.push(r, g, b);

        }


        addColors(0, 1, 0, launchPoints.length);     // Green (Launch)

        addColors(0, 1, 1, leoPoints.length);        // Cyan (LEO)

        addColors(0.7, 0, 1, heoPoints.length);      // Purple (HEO)

        addColors(1, 0.8, 0, tliPoints.length);      // Gold (TLI)

        addColors(1, 0.3, 0, flybyPoints.length);    // Orange (Flyby)

        addColors(1, 1, 1, returnPoints.length);     // White (Return)


        geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));

        const material = new THREE.LineBasicMaterial({ vertexColors: true, linewidth: 2 });

        const trajectoryLine = new THREE.Line(geometry, material);

        scene.add(trajectoryLine);



        // --- 6. ANIMATION LOOP ---

        function animate() {

            requestAnimationFrame(animate);

            controls.update();


            // Rotate Earth and Moon

            earth.rotation.y += 0.0005;

            moon.rotation.y += 0.001;


            renderer.render(scene, camera);

        }


        window.addEventListener('resize', () => {

            camera.aspect = window.innerWidth / window.innerHeight;

            camera.updateProjectionMatrix();

            renderer.setSize(window.innerWidth, window.innerHeight);

        });


        animate();

    </script>

</body>

</html>