Script: Solar System Simulation STEM

Solar System Simulation STEM picture
Type
Typescript logo indicatortypescript
Date Created
Mar 9, 2025, 9:21:44 AM
Last Edit Date
Sep 25, 2026, 5:53:27 AM

Project Information

We've made a solar system simulation in collaboration with Artificial Intelligence

View Full Project

Script Code

// main.ts
const scene = bitbybit.babylon.scene.getScene();
const engine = scene.getEngine();

// Setup point light with shadow generator
const ptLight = new Bit.Inputs.BabylonScene.PointLightDto();
ptLight.intensity = 50000;
ptLight.position = [0, 0, 0];
ptLight.shadowDarkness = 0;
ptLight.radius = 0;
ptLight.shadowMaxZ = 3000;
ptLight.shadowMinZ = 0;
const light = bitbybit.babylon.scene.drawPointLight(ptLight);

// GUI Setup
const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
const hoverText = new BABYLON.GUI.TextBlock();
hoverText.text = "";
hoverText.color = "white";
hoverText.fontSize = 36;
hoverText.fontFamily = "Arial";
hoverText.paddingTop = "15px";
hoverText.paddingBottom = "15px";
hoverText.paddingLeft = "20px";
hoverText.paddingRight = "20px";
hoverText.isVisible = false;
advancedTexture.addControl(hoverText);

const speedSlider = new BABYLON.GUI.Slider();
speedSlider.minimum = 0.05;
speedSlider.maximum = 1.0;
speedSlider.value = 0.05;
speedSlider.step = 0.01;
speedSlider.height = "30px";
speedSlider.width = "300px";
speedSlider.left = "30px";
speedSlider.top = "30px";
speedSlider.color = "#f0cebb";
speedSlider.background = "rgba(255, 255, 255, 0.2)";
speedSlider.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
speedSlider.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
advancedTexture.addControl(speedSlider);

const sliderLabel = new BABYLON.GUI.TextBlock();
sliderLabel.text = "Animation Speed: " + speedSlider.value.toFixed(2) + "x";
sliderLabel.color = "white";
sliderLabel.fontSize = 24;
sliderLabel.left = "30px";
sliderLabel.top = "70px";
sliderLabel.textHorizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
sliderLabel.textVerticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
advancedTexture.addControl(sliderLabel);


// Language selection buttons
const languagePanel = new BABYLON.GUI.StackPanel();
languagePanel.isVertical = true;
languagePanel.width = "150px";
languagePanel.left = "30px";
languagePanel.top = "110px";
languagePanel.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
languagePanel.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
advancedTexture.addControl(languagePanel);

let currentLanguage = "en";
const languages = [
    { name: "English", code: "en" },
    { name: "Lietuvių", code: "lt" },
    { name: "Polski", code: "pl" },
    { name: "Deutsch", code: "de" },
    { name: "Español", code: "es" },
    { name: "中文", code: "zh" }
];

const languageButtons = languages.map(lang => {
    const button = BABYLON.GUI.Button.CreateSimpleButton(`lang_${lang.code}`, lang.name);
    button.width = "150px";
    button.height = "30px";
    button.color = "white";
    button.background = "rgba(255, 255, 255, 0.2)";
    button.paddingBottom = "5px";
    button.onPointerUpObservable.add(() => {
        currentLanguage = lang.code;
        // Update button visuals to show selection
        languageButtons.forEach(btn => {
            btn.background = "rgba(255, 255, 255, 0.2)";
            btn.color = "#ffffff";
        });
        button.background = "#f0cebb"; // Highlight selected language
        button.color = "#000000"; // Highlight selected language
    });
    if (lang.code === "en") button.background = "#f0cebb55"; // Default to English
    languagePanel.addControl(button);
    return button;
});

createLogo();

speedSlider.onValueChangedObservable.add((value) => {
    sliderLabel.text = "Animation Speed: " + value.toFixed(2) + "x";
});

// Language translations
const translations = {
    "en": {
        "Sun": "Sun", "Mercury": "Mercury", "Venus": "Venus", "Earth": "Earth",
        "Moon": "Moon", "Mars": "Mars", "Phobos": "Phobos", "Deimos": "Deimos",
        "Jupiter": "Jupiter", "Io": "Io", "Europa": "Europa", "Ganymede": "Ganymede",
        "Callisto": "Callisto", "Saturn": "Saturn", "Mimas": "Mimas", "Enceladus": "Enceladus",
        "Tethys": "Tethys", "Dione": "Dione", "Rhea": "Rhea", "Titan": "Titan",
        "Iapetus": "Iapetus", "Uranus": "Uranus", "Miranda": "Miranda", "Ariel": "Ariel",
        "Umbriel": "Umbriel", "Titania": "Titania", "Oberon": "Oberon", "Neptune": "Neptune",
        "Triton": "Triton", "Nereid": "Nereid"
    },
    "lt": {
        "Sun": "Saulė", "Mercury": "Merkurijus", "Venus": "Venera", "Earth": "Žemė",
        "Moon": "Mėnulis", "Mars": "Marsas", "Phobos": "Fobas", "Deimos": "Deimas",
        "Jupiter": "Jupiteris", "Io": "Io", "Europa": "Europa", "Ganymede": "Ganimedas",
        "Callisto": "Kalista", "Saturn": "Saturnas", "Mimas": "Mimas", "Enceladus": "Enceladas",
        "Tethys": "Tetija", "Dione": "Dionė", "Rhea": "Rėja", "Titan": "Titanas",
        "Iapetus": "Iapetas", "Uranus": "Uranas", "Miranda": "Miranda", "Ariel": "Arielė",
        "Umbriel": "Umbrielis", "Titania": "Titanija", "Oberon": "Oberonas", "Neptune": "Neptūnas",
        "Triton": "Tritonas", "Nereid": "Nereidė"
    },
    "pl": {
        "Sun": "Słońce", "Mercury": "Merkury", "Venus": "Wenus", "Earth": "Ziemia",
        "Moon": "Księżyc", "Mars": "Mars", "Phobos": "Fobos", "Deimos": "Deimos",
        "Jupiter": "Jowisz", "Io": "Io", "Europa": "Europa", "Ganymede": "Ganimedes",
        "Callisto": "Kallisto", "Saturn": "Saturn", "Mimas": "Mimas", "Enceladus": "Enceladus",
        "Tethys": "Tetyda", "Dione": "Dione", "Rhea": "Rea", "Titan": "Tytan",
        "Iapetus": "Japetus", "Uranus": "Uran", "Miranda": "Miranda", "Ariel": "Ariel",
        "Umbriel": "Umbriel", "Titania": "Tytania", "Oberon": "Oberon", "Neptune": "Neptun",
        "Triton": "Tryton", "Nereid": "Nereida"
    },
    "de": {
        "Sun": "Sonne", "Mercury": "Merkur", "Venus": "Venus", "Earth": "Erde",
        "Moon": "Mond", "Mars": "Mars", "Phobos": "Phobos", "Deimos": "Deimos",
        "Jupiter": "Jupiter", "Io": "Io", "Europa": "Europa", "Ganymede": "Ganymed",
        "Callisto": "Kallisto", "Saturn": "Saturn", "Mimas": "Mimas", "Enceladus": "Enceladus",
        "Tethys": "Tethys", "Dione": "Dione", "Rhea": "Rhea", "Titan": "Titan",
        "Iapetus": "Iapetus", "Uranus": "Uranus", "Miranda": "Miranda", "Ariel": "Ariel",
        "Umbriel": "Umbriel", "Titania": "Titania", "Oberon": "Oberon", "Neptune": "Neptun",
        "Triton": "Triton", "Nereid": "Nereid"
    },
    "es": {
        "Sun": "Sol", "Mercury": "Mercurio", "Venus": "Venus", "Earth": "Tierra",
        "Moon": "Luna", "Mars": "Marte", "Phobos": "Fobos", "Deimos": "Deimos",
        "Jupiter": "Júpiter", "Io": "Ío", "Europa": "Europa", "Ganymede": "Ganímedes",
        "Callisto": "Calisto", "Saturn": "Saturno", "Mimas": "Mimas", "Enceladus": "Encélado",
        "Tethys": "Tetis", "Dione": "Dione", "Rhea": "Rea", "Titan": "Titán",
        "Iapetus": "Jápeto", "Uranus": "Urano", "Miranda": "Miranda", "Ariel": "Ariel",
        "Umbriel": "Umbriel", "Titania": "Titania", "Oberon": "Oberón", "Neptune": "Neptuno",
        "Triton": "Tritón", "Nereid": "Nereida"
    },
    "zh": {
        "Sun": "太阳", "Mercury": "水星", "Venus": "金星", "Earth": "地球",
        "Moon": "月球", "Mars": "火星", "Phobos": "火卫一", "Deimos": "火卫二",
        "Jupiter": "木星", "Io": "木卫一", "Europa": "木卫二", "Ganymede": "木卫三",
        "Callisto": "木卫四", "Saturn": "土星", "Mimas": "土卫一", "Enceladus": "土卫二",
        "Tethys": "土卫三", "Dione": "土卫四", "Rhea": "土卫五", "Titan": "土卫六",
        "Iapetus": "土卫八", "Uranus": "天王星", "Miranda": "天卫五", "Ariel": "天卫一",
        "Umbriel": "天卫二", "Titania": "天卫三", "Oberon": "天卫四", "Neptune": "海王星",
        "Triton": "海卫一", "Nereid": "海卫二"
    }
};
// Sun Vertex Shader
BABYLON.Effect.ShadersStore["sunVertexShader"] = `
    precision highp float;
    attribute vec3 position;
    attribute vec3 normal;
    uniform mat4 world;
    uniform mat4 worldViewProjection;
    varying vec3 vPosition;
    varying vec3 vNormal;
    varying vec3 vWorldPosition;
    void main() {
        gl_Position = worldViewProjection * vec4(position, 1.0);
        vPosition = position;
        vWorldPosition = (world * vec4(position, 1.0)).xyz;
        vNormal = normalize((world * vec4(normal, 0.0)).xyz);
    }
    `;

// Sun Fragment Shader
BABYLON.Effect.ShadersStore["sunFragmentShader"] = `
    precision highp float;
    varying vec3 vPosition;
    varying vec3 vNormal;
    varying vec3 vWorldPosition;
    uniform float time;
    uniform vec3 cameraPosition;
    float hash(vec3 p) { return fract(sin(dot(p, vec3(127.1, 311.7, 74.7))) * 43758.5453); }
    float noise(vec3 p) {
        vec3 i = floor(p);
        vec3 f = fract(p);
        vec3 u = f * f * (3.0 - 2.0 * f);
        return mix(mix(mix(hash(i + vec3(0.0,0.0,0.0)), hash(i + vec3(1.0,0.0,0.0)), u.x),
                      mix(hash(i + vec3(0.0,1.0,0.0)), hash(i + vec3(1.0,1.0,0.0)), u.x), u.y),
                  mix(mix(hash(i + vec3(0.0,0.0,1.0)), hash(i + vec3(1.0,0.0,1.0)), u.x),
                      mix(hash(i + vec3(0.0,1.0,1.0)), hash(i + vec3(1.0,1.0,1.0)), u.x), u.y), u.z);
    }
    float fbm(vec3 p) {
        float v = 0.0;
        float a = 0.5;
        vec3 shift = vec3(100.0);
        for (int i = 0; i < 4; ++i) {
            v += a * noise(p);
            p = p * 2.0 + shift;
            a *= 0.5;
        }
        return v;
    }
    void main() {
        vec3 pos = normalize(vPosition);
        vec2 sphericalUV = vec2(atan(pos.z, pos.x), asin(pos.y));
        sphericalUV.x = sphericalUV.x * 0.159154943 + 0.5;
        sphericalUV.y = sphericalUV.y * 0.318309886 + 0.5;
        
        vec3 baseColor = mix(vec3(1.0, 0.9, 0.4), vec3(1.0, 0.5, 0.1), length(sphericalUV - 0.5));
        float spots = fbm(pos * 8.0 + time * 0.1);
        spots = pow(spots, 3.0);
        vec3 spotColor = vec3(0.8, 0.4, 0.1) * spots;
        float detail = fbm(pos * 20.0 + time * 0.05);
        vec3 detailColor = vec3(0.2, 0.1, 0.0) * detail;
        vec3 viewDir = normalize(cameraPosition - vWorldPosition);
        float rim = 1.0 - max(dot(vNormal, viewDir), 0.0);
        
        vec3 finalColor = baseColor;
        finalColor = mix(finalColor, spotColor, spots * 0.8);
        finalColor += detailColor;
        finalColor += vec3(1.0, 0.8, 0.2) * pow(rim, 1.5) * 0.4;
        float pulse = sin(time * 1.5) * 0.03 + 0.97;
        finalColor *= pulse;
        
        gl_FragColor = vec4(finalColor, 1.0);
    }
    `;

// Space Vertex Shader
BABYLON.Effect.ShadersStore["spaceVertexShader"] = `
    precision highp float;
    attribute vec3 position;
    attribute vec3 normal;
    uniform mat4 world;
    uniform mat4 view;
    uniform mat4 projection;
    varying vec3 vPosition;
    varying vec3 vNormal;
    void main() {
        vPosition = position;
        vNormal = normal;
        gl_Position = projection * view * world * vec4(position, 1.0);
    }
    `;

// Space Fragment Shader
BABYLON.Effect.ShadersStore["spaceFragmentShader"] = `
    precision highp float;
    varying vec3 vPosition;
    uniform float time;
    
    float hash(vec3 p) {
        p = fract(p * 0.3183099 + 0.1);
        return fract(sin(dot(p, vec3(127.1, 311.7, 74.7))) * 43758.5453);
    }
    
    float noise(vec3 x) {
        vec3 i = floor(x);
        vec3 f = fract(x);
        f = f * f * (3.0 - 2.0 * f);
        return mix(mix(mix(hash(i + vec3(0.0, 0.0, 0.0)), hash(i + vec3(1.0, 0.0, 0.0)), f.x),
                    mix(hash(i + vec3(0.0, 1.0, 0.0)), hash(i + vec3(1.0, 1.0, 0.0)), f.x), f.y),
                mix(mix(hash(i + vec3(0.0, 0.0, 1.0)), hash(i + vec3(1.0, 0.0, 1.0)), f.x),
                    mix(hash(i + vec3(0.0, 1.0, 1.0)), hash(i + vec3(1.0, 1.0, 1.0)), f.x), f.y), f.z);
    }
    
    float fbm(vec3 p) {
        float v = 0.0;
        float a = 0.5;
        vec3 shift = vec3(100.0);
        for (int i = 0; i < 2; ++i) {
            v += a * noise(p);
            p = p * 2.0 + shift;
            a *= 0.5;
        }
        return v;
    }
    
    void main() {
        vec3 pos = normalize(vPosition) * 10.0 + vec3(time * 0.01);
        float stars = noise(pos * 100.0);
        stars = pow(stars, 40.0);
        float nebula = fbm(pos * 0.5);
        vec3 nebulaColor = vec3(0.3, 0.2, 0.7) * nebula * 0.8;
        vec3 color = vec3(0.0);
        color += vec3(0.8, 0.8, 0.9) * stars;
        color += nebulaColor;
        color = mix(vec3(0.0, 0.0, 0.05), color, clamp(color.r + color.g + color.b, 0.0, 1.0));
        gl_FragColor = vec4(color, 1.0);
    }
    `;

// Space background
const shaderMaterialSpace = new BABYLON.ShaderMaterial("spaceShader", scene, {
    vertex: "space",
    fragment: "space",
}, {
    attributes: ["position", "normal"],
    uniforms: ["world", "view", "projection", "time"]
});
const box = BABYLON.MeshBuilder.CreateBox("box", { size: 10000 }, scene);
box.material = shaderMaterialSpace;
box.flipFaces();

// Scaling factors
const AU = 30;
const planetScale = 1;
const moonScale = 1;

// Sun setup
const sun = BABYLON.MeshBuilder.CreateSphere("sun", { diameter: 5 * planetScale, segments: 128 }, scene);
const sunMaterial = new BABYLON.ShaderMaterial("sunShader", scene, {
    vertex: "sun",
    fragment: "sun",
}, {
    attributes: ["position", "normal"],
    uniforms: ["world", "worldViewProjection", "time", "cameraPosition"]
});
sunMaterial.setVector3("cameraPosition", scene.activeCamera.position);
sun.material = sunMaterial;

const sgs = scene.metadata.shadowGenerators;
// sgs.forEach(shadowGenerator => {
//     shadowGenerator.addShadowCaster(sun);
// });

// Celestial body definitions
const celestialData = [
    {
        name: "Mercury", diameter: 0.8, orbit: 0.4, speed: 2.0, color: [0.7, 0.7, 0.7],
        metallic: 0.1, roughness: 0.8, rotationSpeed: 0.06, moons: []
    },
    {
        name: "Venus", diameter: 1.8, orbit: 0.7, speed: 0.8, color: [0.9, 0.6, 0.3],
        metallic: 0.05, roughness: 0.6, rotationSpeed: 0.04, moons: []
    },
    {
        name: "Earth", diameter: 1.8, orbit: 1, speed: 0.5, color: [0.0, 0.6, 0.8],
        metallic: 0.0, roughness: 0.5, rotationSpeed: 0.05,
        moons: [{ name: "Moon", diameter: 0.5, orbit: 2, speed: 4, color: [0.8, 0.8, 0.8], metallic: 0.1, roughness: 0.9, rotationSpeed: 0.02 }]
    },
    {
        name: "Mars", diameter: 1.5, orbit: 1.5, speed: 0.4, color: [0.8, 0.4, 0.2],
        metallic: 0.1, roughness: 0.7, rotationSpeed: 0.03,
        moons: [
            { name: "Phobos", diameter: 0.3, orbit: 1, speed: 3, color: [0.6, 0.5, 0.5], metallic: 0.1, roughness: 0.9, rotationSpeed: 0.04 },
            { name: "Deimos", diameter: 0.2, orbit: 1.5, speed: 2.5, color: [0.7, 0.6, 0.6], metallic: 0.1, roughness: 0.9, rotationSpeed: 0.03 }
        ]
    },
    {
        name: "Jupiter", diameter: 4, orbit: 5, speed: 0.2, color: [0.9, 0.7, 0.5],
        metallic: 0.0, roughness: 0.4, rotationSpeed: 0.02,
        moons: [
            { name: "Io", diameter: 0.7, orbit: 2, speed: 2.5, color: [1.0, 0.8, 0.3], metallic: 0.1, roughness: 0.7, rotationSpeed: 0.03 },
            { name: "Europa", diameter: 0.6, orbit: 3, speed: 2, color: [0.9, 0.9, 0.9], metallic: 0.0, roughness: 0.3, rotationSpeed: 0.025 },
            { name: "Ganymede", diameter: 1.0, orbit: 4, speed: 1.5, color: [0.7, 0.7, 0.7], metallic: 0.1, roughness: 0.8, rotationSpeed: 0.02 },
            { name: "Callisto", diameter: 0.9, orbit: 5, speed: 1, color: [0.6, 0.6, 0.6], metallic: 0.1, roughness: 0.9, rotationSpeed: 0.015 }
        ]
    },
    {
        name: "Saturn", diameter: 3.5, orbit: 9.5, speed: 0.15, color: [0.8, 0.7, 0.4],
        metallic: 0.0, roughness: 0.4, rotationSpeed: 0.015,
        rings: { radius: 5, color: [0.7, 0.6, 0.5], metallic: 0.0, roughness: 0.6 },
        moons: [
            { name: "Mimas", diameter: 0.3, orbit: 1, speed: 3, color: [0.8, 0.8, 0.8], metallic: 0.1, roughness: 0.9, rotationSpeed: 0.04 },
            { name: "Enceladus", diameter: 0.4, orbit: 1.5, speed: 2.5, color: [0.9, 0.9, 0.9], metallic: 0.0, roughness: 0.3, rotationSpeed: 0.035 },
            { name: "Tethys", diameter: 0.5, orbit: 2, speed: 2, color: [0.8, 0.8, 0.8], metallic: 0.1, roughness: 0.8, rotationSpeed: 0.03 },
            { name: "Dione", diameter: 0.6, orbit: 2.5, speed: 1.8, color: [0.7, 0.7, 0.7], metallic: 0.1, roughness: 0.8, rotationSpeed: 0.025 },
            { name: "Rhea", diameter: 0.7, orbit: 3, speed: 1.5, color: [0.8, 0.8, 0.8], metallic: 0.1, roughness: 0.8, rotationSpeed: 0.02 },
            { name: "Titan", diameter: 1.0, orbit: 4, speed: 1, color: [0.9, 0.6, 0.3], metallic: 0.0, roughness: 0.5, rotationSpeed: 0.015 },
            { name: "Iapetus", diameter: 0.8, orbit: 5, speed: 0.8, color: [0.5, 0.5, 0.5], metallic: 0.1, roughness: 0.9, rotationSpeed: 0.01 }
        ]
    },
    {
        name: "Uranus", diameter: 3, orbit: 19, speed: 0.1, color: [0.5, 0.8, 0.8],
        metallic: 0.0, roughness: 0.4, rotationSpeed: 0.012,
        moons: [
            { name: "Miranda", diameter: 0.3, orbit: 1, speed: 3, color: [0.7, 0.7, 0.7], metallic: 0.1, roughness: 0.9, rotationSpeed: 0.04 },
            { name: "Ariel", diameter: 0.5, orbit: 1.5, speed: 2.5, color: [0.8, 0.8, 0.8], metallic: 0.1, roughness: 0.8, rotationSpeed: 0.035 },
            { name: "Umbriel", diameter: 0.6, orbit: 2, speed: 2, color: [0.6, 0.6, 0.6], metallic: 0.1, roughness: 0.9, rotationSpeed: 0.03 },
            { name: "Titania", diameter: 0.8, orbit: 3, speed: 1.5, color: [0.7, 0.7, 0.7], metallic: 0.1, roughness: 0.8, rotationSpeed: 0.02 },
            { name: "Oberon", diameter: 0.7, orbit: 4, speed: 1, color: [0.6, 0.6, 0.6], metallic: 0.1, roughness: 0.9, rotationSpeed: 0.015 }
        ]
    },
    {
        name: "Neptune", diameter: 3, orbit: 30, speed: 0.08, color: [0.2, 0.4, 0.8],
        metallic: 0.0, roughness: 0.4, rotationSpeed: 0.01,
        moons: [
            { name: "Triton", diameter: 0.9, orbit: 3, speed: 1.5, color: [0.7, 0.7, 0.8], metallic: 0.1, roughness: 0.8, rotationSpeed: 0.02 },
            { name: "Nereid", diameter: 0.3, orbit: 5, speed: 0.5, color: [0.6, 0.6, 0.7], metallic: 0.1, roughness: 0.9, rotationSpeed: 0.01 }
        ]
    }
];

// Utility functions
const createOrbitPath = (radius, parent = null, segments = 128) => {
    const path = [];

    for (let i = 0; i <= segments; i++) {
        const angle = (i / segments) * Math.PI * 2;
        path.push(new BABYLON.Vector3(Math.cos(angle) * radius, 0, Math.sin(angle) * radius));
    }
    const orbit = BABYLON.MeshBuilder.CreateLines(`orbit_${radius}`, { points: path }, scene);
    orbit.color = new BABYLON.Color3(0.5, 0.5, 0.5);
    orbit.alpha = 0.5;
    orbit.visibility = 0.1;

    if (parent) orbit.parent = parent;
    return orbit;
};

const createBody = (name, diameter, color, metallic, roughness, isMoon = false) => {
    const mesh = BABYLON.MeshBuilder.CreateSphere(name, {
        diameter: (isMoon ? moonScale : planetScale) * diameter,
        segments: 32
    }, scene);
    const mat = new BABYLON.PBRMetallicRoughnessMaterial(`${name}Mat`, scene);
    mat.baseColor = new BABYLON.Color3(...color);
    mat.metallic = metallic;
    mat.roughness = roughness;
    mat.backFaceCulling = false;
    mesh.material = mat;
    mesh.receiveShadows = true;
    // sgs.forEach(shadowGenerator => {
    //     shadowGenerator.addShadowCaster(mesh);
    // });
    return mesh;
};

// Create celestial bodies
const celestialBodies = [{ mesh: sun, name: "Sun" }];
const planets = celestialData.map(planet => {
    const mesh = createBody(planet.name, planet.diameter, planet.color, planet.metallic, planet.roughness);
    mesh.position.x = AU * planet.orbit;
    createOrbitPath(AU * planet.orbit);

    if (planet.rings) {
        const ringMat = new BABYLON.PBRMetallicRoughnessMaterial("ringMat", scene);
        ringMat.baseColor = new BABYLON.Color3(...planet.rings.color);
        ringMat.metallic = planet.rings.metallic;
        ringMat.roughness = planet.rings.roughness;
        ringMat.backFaceCulling = true;
        const ring = BABYLON.MeshBuilder.CreateDisc("ring", { radius: planet.rings.radius * planetScale, tessellation: 64 }, scene);
        ring.rotation.x = Math.PI / 2;
        ring.parent = mesh;
        ring.material = ringMat;
        ring.receiveShadows = true;
    }

    const moons = planet.moons.map(moon => {
        const moonMesh = createBody(moon.name, moon.diameter, moon.color, moon.metallic, moon.roughness, true);
        moonMesh.position.x = AU * planet.orbit + moon.orbit;
        createOrbitPath(moon.orbit, mesh);
        return { mesh: moonMesh, data: moon };
    });

    celestialBodies.push({ mesh, name: planet.name });
    moons.forEach(moon => celestialBodies.push({ mesh: moon.mesh, name: moon.data.name }));

    return { mesh, data: planet, moons };
});

// Setup pointer events with language support
const updateHoverText = (body, language) => {
    hoverText.text = translations[language][body.name] || body.name;
};
// Setup pointer events
celestialBodies.forEach(body => {
    body.mesh.actionManager = new BABYLON.ActionManager(scene);
    body.mesh.actionManager.registerAction(
        new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPointerOverTrigger, () => {
            updateHoverText(body, currentLanguage);
            hoverText.isVisible = true;
        })
    );
    body.mesh.actionManager.registerAction(
        new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPointerOutTrigger, () => {
            hoverText.isVisible = false;
        })
    );
});

const canvas = engine.getRenderingCanvas();
const scalingFactor = 1 / engine.getHardwareScalingLevel();
scene.onPointerObservable.add((pointerInfo) => {
    if (hoverText.isVisible) {
        const rect = canvas.getBoundingClientRect();
        const x = (pointerInfo.event.x - rect.width / 2) * scalingFactor;
        const y = (pointerInfo.event.y - rect.height / 2) * scalingFactor;
        hoverText.left = x + 60 + "px";
        hoverText.top = y - 60 + "px";
    }
}, BABYLON.PointerEventTypes.POINTERMOVE);

// Animation
let time = 0;
let twinkleTime = 0;
bitbybit.time.registerRenderFunction(() => {
    const speedFactor = speedSlider.value;
    time += engine.getDeltaTime() * 0.001 * speedFactor;
    twinkleTime += 0.001;
    sunMaterial.setFloat("time", twinkleTime * 40);
    sunMaterial.setVector3("cameraPosition", scene.activeCamera.position);
    shaderMaterialSpace.setFloat("time", twinkleTime);
    sun.rotation.y += 0.01 * speedFactor;

    planets.forEach(planet => {
        const p = planet.data;
        planet.mesh.position.x = Math.cos(time * p.speed) * AU * p.orbit;
        planet.mesh.position.z = Math.sin(time * p.speed) * AU * p.orbit;
        planet.mesh.rotation.y += p.rotationSpeed * speedFactor;

        planet.moons.forEach(moon => {
            const m = moon.data;
            moon.mesh.position.x = planet.mesh.position.x + Math.cos(time * m.speed) * m.orbit;
            moon.mesh.position.z = planet.mesh.position.z + Math.sin(time * m.speed) * m.orbit;
            moon.mesh.rotation.y += m.rotationSpeed * speedFactor;
        });
    });
});

// Add HDR Glow Effect
const glowLayer = new BABYLON.GlowLayer("glow", scene, {
    // mainTextureFixedSize: 1024,
    mainTextureRatio: 1, // Adjust for performance vs quality
    blurKernelSize: 32,    // Larger kernel for softer glow
});
glowLayer.intensity = 0.22;
glowLayer.addExcludedMesh(box); // Exclude the background box from glowing
glowLayer.referenceMeshToUseItsOwnMaterial(sun);




function createLogo() {
    const gui = bitbybit.babylon.gui;
    const textOpt = new Bit.Inputs.BabylonGui.CreateFullScreenUIDto();
    const fullScreenUI = gui.advancedDynamicTexture.createFullScreenUI(textOpt);
    const stackPanelOpt = new Bit.Inputs.BabylonGui.CreateStackPanelDto();
    stackPanelOpt.background = "#00000000";
    const stackPanel = gui.stackPanel.createStackPanel(stackPanelOpt);
    const stackPanelOpt2 = new Bit.Inputs.BabylonGui.CreateStackPanelDto();
    stackPanelOpt2.background = "#00000000";
    const stackPanel2 = gui.stackPanel.createStackPanel(stackPanelOpt2);
    stackPanel2.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM;
    fullScreenUI.addControl(stackPanel2);
    stackPanel.paddingTopInPixels = 10;
    stackPanel2.addControl(stackPanel);

    const imageOpt = new Bit.Inputs.BabylonGui.CreateImageDto();
    imageOpt.url = "assets/logo-gold-small.png";
    const image = gui.image.createImage(imageOpt);
    const padding = 30;
    image.paddingTopInPixels = padding;
    image.paddingBottomInPixels = padding;
    image.paddingLeftInPixels = padding;
    image.paddingRightInPixels = padding;

    image.onPointerClickObservable.add(() => {
        window.open("https://bitbybit.dev", '_blank').focus();
    });
    const txtBlockOptions = new Bit.Inputs.BabylonGui.CreateTextBlockDto();
    txtBlockOptions.text = "BITBYBIT.DEV";
    const txtBlock = gui.textBlock.createTextBlock(txtBlockOptions);
    txtBlock.height = "60px";
    txtBlock.paddingBottomInPixels = 30;

    stackPanel2.addControl(image);
    stackPanel2.addControl(txtBlock);
}


// tata.ts
export const x = 10;

Plans & Pricing

Choose Your Plan

Editor plans for 3D development, API keys for server-side CAD algorithms

B2B

ENTERPRISE

Custom pricing

Custom software development, dedicated servers & CAD automation at scale.

CAD Automation & Software
  • Custom software development
  • Cloud CAD automation pipelines
  • 3D configurators (STEP & GLTF)
  • Batch export jobs
  • Custom algorithms & deployment
Infrastructure & Support
  • Custom compute allocation
  • Dedicated / VPS server tenants
  • Long-running computation jobs
  • Custom upload limits & overage
  • SLA & premium support