async function start() {
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);
}
start().catch(console.error);