From 027025e4af3217bd1e026f614f47a1c92fcbd8b9 Mon Sep 17 00:00:00 2001 From: "Somhairle H. Marisol" Date: Mon, 21 Sep 2026 23:52:23 +0800 Subject: feat(viewer): starfield backdrop for deep-space context --- src/SomhairlesDream.Frontend/App.fs | 22 +++++++++++++++++++++- src/SomhairlesDream.Frontend/Bindings.fs | 6 ++++++ 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/SomhairlesDream.Frontend/App.fs b/src/SomhairlesDream.Frontend/App.fs index 72d1be2..2aa78eb 100644 --- a/src/SomhairlesDream.Frontend/App.fs +++ b/src/SomhairlesDream.Frontend/App.fs @@ -210,7 +210,7 @@ let frameObject (view: ViewState) (node: ThreeNode) = camera.position.set(dirX / norm * distance, dirY / norm * distance, dirZ / norm * distance) |> ignore camera.near <- max 1.0 (distance * 0.05) - camera.far <- distance + longest * 3.0 + camera.far <- max 700.0 (distance + longest * 3.0) camera.lookAt(0.0, 0.0, 0.0) camera.updateProjectionMatrix () @@ -277,6 +277,26 @@ let initializeView () = let bounceLight = createHemisphereLight("#3d4a56", "#141a1e", 0.9) scene.add(bounceLight) + // Starfield: gives deep-space context so the vehicle reads as a ship in + // the void instead of a model on a grey stage. + let starCount = 2600 + let starPositions = Array.zeroCreate (starCount * 3) + let starRng = System.Random(4242) + + for index in 0 .. starCount - 1 do + let theta = starRng.NextDouble() * 2.0 * System.Math.PI + let phi = System.Math.Acos(2.0 * starRng.NextDouble() - 1.0) + let radius = 260.0 + starRng.NextDouble() * 90.0 + starPositions.[index * 3] <- radius * System.Math.Sin(phi) * System.Math.Cos(theta) + starPositions.[index * 3 + 1] <- radius * System.Math.Cos(phi) + starPositions.[index * 3 + 2] <- radius * System.Math.Sin(phi) * System.Math.Sin(theta) + + let starGeometry = createBufferGeometry () + starGeometry.setAttribute("position", createFloat32BufferAttribute(starPositions, 3)) |> ignore + let starMaterial = createPointsMaterial "#c9d6e6" 1.7 0.9 + let stars = createPoints starGeometry starMaterial + scene.add(stars) + // Coordinate ground grid so the model reads as anchored in a workspace // instead of floating in a void. let grid = createGridHelper (24.0, 48, "#5a4a2a", "#2a2f33") diff --git a/src/SomhairlesDream.Frontend/Bindings.fs b/src/SomhairlesDream.Frontend/Bindings.fs index 05d8e95..df94777 100644 --- a/src/SomhairlesDream.Frontend/Bindings.fs +++ b/src/SomhairlesDream.Frontend/Bindings.fs @@ -59,6 +59,12 @@ type ServerEvent = type GLTFScene = abstract scene: ThreeNode with get +[] +let createPointsMaterial (color: string) (size: float) (opacity: float) : obj = jsNative + +[] +let createPoints (geometry: obj) (material: obj) : ThreeNode = jsNative + [] let createDRACOLoader () : obj = jsNative -- cgit v1.2.3