logo

Babylon.js Market

NebulaSky

world · space-combat-sim

NebulaSky

2
Unlock

Install with the CLI:

bjs download NebulaSky

NebulaSky

A procedural deep-space backdrop: nebula clouds, stars, and a scattering of galaxies.

What it does

NebulaSky: {} on the world entity turns an empty clear colour into a sky. The System generates six cube faces once at startup and hands them to its engine plugin, which wraps them in a cube texture and hangs it on a camera-locked box.

The whole sky is a function of direction. Every texel of every face is turned back into a unit vector and fed to 3D fractal-Brownian-motion noise, so two texels either side of a face boundary map to nearly the same direction and get nearly the same colour — there is no edge to see where two faces meet. Generate a sky as six independent 2D images and those edges are the first thing you notice.

Two noise fields do the work:

  • Density, 5 octaves, thresholded then squared. The threshold is why most of the sky stays black — a nebula everywhere reads as fog, not as space. Squaring what survives makes patches fall off softly instead of ending at a line.
  • Colour, 3 octaves at a lower frequency and a different offset, indexing a cyclic purple/magenta/rose palette. A separate, coarser field is what makes one region read as a different nebula rather than the same cloud tinted twice.

Stars are ^4.5-distributed, so the field is overwhelmingly faint with a handful of bright ones — like a real sky. A uniform roll gives a flat field of equal dots.

Setup

The engine work ships with the component. Register it once at bootstrap, before the scene loads:

TypeScript
import { registerNebulaSkyExtension } from '@babylonjsmarket/…/NebulaSky/adapter/register';

const adapter = new BabylonAdapter();
registerNebulaSkyExtension(adapter);
const game = new ArcadeGame(adapter, { … });

Without it the System draws no sky and warns once — which is the right outcome headlessly and in tests.

Use it in a scene

A scene is just data — a list of entities, each with its components. At startup the SceneLoader turns this JSON into a live world; edit the file and reload to rebuild it.

Build it from scratch with the bjs CLI:

  1. 1Scaffold a project
    npm create @babylonjsmarket/arcade@latest my-game

    World, renderer, and dev server — ready to run.

  2. 2Install dependencies
    cd my-game && npm install
  3. 3Add NebulaSky
    bjs download NebulaSky

    Copies its source into src/ so the scene resolves.

    First time? Run bjs login once.

  4. 4Paste the scene into src/scenes/arcade-room.ts and run
    npm run dev

    SceneLoader builds the world from the JSON; reload to rebuild.

JSON
{
  "World": {
    "tags": ["world"],
    "components": {
      "SpaceDust": {},
      "NebulaSky": { "size": 256, "starCount": 1800, "galaxyCount": 18 }
    }
  }
}

Props

  • size (number, default 256) — face resolution in texels. 512 is crisper and four times the work.
  • seed (number, default 0xbeef) — seeds the nebula noise fields.
  • starCount (number, default 1800) / starSeed (default 0xdeadbeef).
  • galaxyCount (number, default 18) / galaxySeed (default 0xfee1dead).
  • nebulaScale (number, default 1.6) — density-field frequency. Higher means smaller, busier clouds.
  • densityThreshold (number, default 0.46) — density below this reads as empty space. Raise it for a sparser sky.
  • intensity (number, default 0.85) — peak nebula brightness.
  • skyboxSize (number, default 160000) — world size of the cube.
  • environmentIntensity (number, default 0.18) — above 0, the sky also lights the scene, so hulls pick up a faint violet fill on their dark side. 0 disables it.

Events

None either way.

Dependencies

None.

Notes

  • The cube must fit inside the camera's far plane or it gets frustum-clipped despite being camera-locked. The default 160000 sits inside the 200000 far plane the space scenes use.
  • Depth writes are off. The sky is the background and must never occlude anything: with depth writes on, a distant asteroid z-fights the skybox at the limit of float precision and loses, so rocks appear to pop into existence only once you're close enough for their depth to resolve away from 1.0.
  • Generation costs roughly 6 · size² noise samples and happens once. It is never per-frame work — the sky rides with the camera in the engine, not in ECS.
  • Faces are uploaded as raw pixel buffers rather than encoded images, so generation needs no canvas and works headlessly.
  • Everything is seeded, so a given config always produces the same sky.

More like this

Asteroid
AsteroidField
ChaseCamera6DOF
ChaseCameraTarget
FlightIntent
FreighterCar
FreighterChain
FreighterHead
GameConfig
LensFlare
OilBlob
PlayerFlightInput
ShipDamageFX
ShipFlight
Skybox
SpaceDust
SpaceShooterBullet
SpaceShooterFX
SpaceShooterHUD
SpaceShooterHealth
SpaceShooterScore
WaveDirector
Waypoint
WaypointTrack
WorldOriginAnchor

Was this page helpful?

We read every note — tell us what's working and what isn't.

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search