- 3D scene: Threlte/Three.js with starfield, orbit lines, planet meshes, sun glow, OrbitControls (orbit/zoom/pan), point lighting - 2D velocity tails: gradient lines showing planet velocity direction/magnitude - New WASM API: get_body_velocities_at_epoch(), get_orbit_points() - Orbit ellipses computed in Rust, rendered in both 2D and 3D views - Ecliptic-to-Three.js coordinate mapping (Y-up convention) - View toggle now switches between working 2D and 3D renderers Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
68 lines
1.8 KiB
Svelte
68 lines
1.8 KiB
Svelte
<script lang="ts">
|
|
import { onMount, onDestroy } from 'svelte';
|
|
import { SolarSystem2DRenderer } from '$lib/render/canvas2d/SolarSystem2D';
|
|
import { simulation } from '$lib/stores/simulation.svelte';
|
|
import { getBodyPositions, getBodyVelocities, getBodyInfos, getOrbitPoints } from '$lib/wasm/bridge';
|
|
|
|
let canvas: HTMLCanvasElement;
|
|
let renderer: SolarSystem2DRenderer;
|
|
let animFrameId: number;
|
|
let orbitsComputed = false;
|
|
|
|
function computeOrbits() {
|
|
const bodyCount = simulation.bodyInfos.length;
|
|
for (let i = 1; i < bodyCount; i++) {
|
|
const points = getOrbitPoints(i, simulation.currentJD, 360);
|
|
if (points.length > 0) {
|
|
renderer.updateOrbit(i, points);
|
|
}
|
|
}
|
|
orbitsComputed = true;
|
|
}
|
|
|
|
onMount(() => {
|
|
renderer = new SolarSystem2DRenderer(canvas);
|
|
|
|
if (simulation.wasmReady) {
|
|
simulation.bodyInfos = getBodyInfos();
|
|
}
|
|
|
|
let lastTime = performance.now();
|
|
let frameCount = 0;
|
|
|
|
function mainLoop() {
|
|
const now = performance.now();
|
|
const dt = (now - lastTime) / 1000;
|
|
lastTime = now;
|
|
simulation.advanceTime(dt);
|
|
|
|
if (simulation.wasmReady) {
|
|
simulation.bodyPositions = getBodyPositions(simulation.currentJD);
|
|
const velocities = getBodyVelocities(simulation.currentJD);
|
|
renderer.updateBodies(simulation.bodyInfos, simulation.bodyPositions, velocities);
|
|
|
|
// Compute orbits on first frame and refresh every 600 frames (~10s)
|
|
if (!orbitsComputed || frameCount % 600 === 0) {
|
|
computeOrbits();
|
|
}
|
|
}
|
|
renderer.render();
|
|
frameCount++;
|
|
animFrameId = requestAnimationFrame(mainLoop);
|
|
}
|
|
|
|
mainLoop();
|
|
});
|
|
|
|
onDestroy(() => {
|
|
if (animFrameId) cancelAnimationFrame(animFrameId);
|
|
renderer?.destroy();
|
|
});
|
|
</script>
|
|
|
|
<canvas
|
|
bind:this={canvas}
|
|
class="w-full h-full block"
|
|
style="cursor: grab;"
|
|
></canvas>
|