b3d-skybox

Procedural sky with sun/moon cycle driven by time of day. Automatically controls a b3dSun sibling's direction, intensity, and color.

Demo

import { b3d, b3dSun, b3dSkybox, b3dGround, b3dBox, b3dSphere, label3d, slider3d } from 'tosijs-3d'
import { orbitCam } from 'tosijs-3d/demo-utils'
import { tosi } from 'tosijs'

const { sky } = tosi({ sky: { timeOfDay: 17 } })

const scene = b3d(
  {
    scenePanel: () => [
      label3d({ text: 'Sky' }),
      slider3d({ label: 'time of day', value: sky.timeOfDay, min: 0, max: 24, step: 0.5 }),
    ],
    sceneCreated(el, BABYLON) {
      orbitCam(el, { alpha: -Math.PI / 2, beta: Math.PI / 3, radius: 15, target: [0, 0, 0] })
    },
  },
  b3dSun(),
  b3dSkybox({ timeOfDay: sky.timeOfDay, realtimeScale: 0, latitude: 40 }),
  // A checkered ground (receives shadows) + a few casters — scrub the time of
  // day and watch the shadows swing long at dawn/dusk and short at noon.
  b3dGround({ width: 20, height: 20, texture: 'checker', textureTiles: 10 }),
  b3dBox({ meshName: 'pillar', size: 1.5, x: -3, y: 0.75, z: 1, color: '#c85a3a' }),
  b3dBox({ meshName: 'crate', size: 1, x: 2, y: 0.5, z: 3, color: '#5aa0c8' }),
  b3dSphere({ meshName: 'ball', diameter: 2, x: 3, y: 1, z: -2, color: '#c8a83a' }),
)
preview.append(scene)

Demo — the encoded sky

A baked sky is a raster of a thing that is almost entirely empty, and the stars are the expensive part. The PAIR that bakeSkyPair() emits splits the sky the way the measurements argued for: nebulae (low-frequency) in a small smooth cube, stars and distant galaxies (points) in a DATA cube the shader decodes — so stars stay points at any zoom instead of being a smear baked at one resolution. Zoom into the band and watch them stay sharp.

import { b3d, b3dSkybox, b3dGround, label3d, slider3d } from 'tosijs-3d'
import { orbitCam } from 'tosijs-3d/demo-utils'
import { tosi } from 'tosijs'

const { sky } = tosi({ sky: { timeOfDay: 23.5 } })

const scene = b3d(
  {
    scenePanel: () => [
      label3d({ text: 'Encoded sky' }),
      slider3d({ label: 'time of day', value: sky.timeOfDay, min: 0, max: 24, step: 0.5 }),
    ],
    sceneCreated(el, BABYLON) {
      orbitCam(el, { alpha: -Math.PI / 2, beta: Math.PI / 3, radius: 15, target: [0, 0, 0] })
    },
  },
  b3dSkybox({
    timeOfDay: sky.timeOfDay,
    realtimeScale: 0,
    starfieldCube: '/sky/nebula',
    starfieldData: '/sky/stars',
    starfieldTilt: '12,25,58',
  }),
  b3dGround({ width: 20, height: 20, texture: 'checker', textureTiles: 10 }),
)
preview.append(scene)

Pin the shipped sky in a document

/sky/stars + /sky/nebula are latest: what the demos load, and a rebake changes them. A document that should keep the sky it was authored against points at a versioned pair instead, which is never rewritten:

b3dSkybox({
  starfieldCube: 'https://3d.tosijs.net/sky/0.8.4/nebula',
  starfieldData: 'https://3d.tosijs.net/sky/0.8.4/stars',
  starfieldDataSize: 1024, // from the manifest — it must match the data
  starfieldTilt: '12,25,58',
})

Each version folder carries a manifest.json with the decode parameters (starfieldDataSize, starfieldTilt) and the recipe it was baked from, so a consumer can read them from beside the data rather than hard-coding them. Versions so far: 0.8.3 (the generateGalaxy sky) and 0.8.4 (the voxel galaxy — far more stars). tosijs-3d#90.

The starfield attributes (starfield*, nebula*) are live: changing one on an existing sky rebuilds the starfield, so applying a document to a sky that is already up works. skyboxSize is the one that is still read once.

Attributes

Attribute Default Description
timeOfDay 6.5 0-24 hours
realtimeScale 10 Realtime speed multiplier
latitude 40 Geographic latitude in DEGREES (affects the sun's arc)
azimuth 0 Ignored — the sun is placed by latitude and timeOfDay, and the sky material accepts this and discards it. Kept so old markup doesn't break; not in skyboxSchema() (tosijs-3d#86)
luminance 1 Sky brightness
turbidity 10 Atmospheric haze
rayleigh 2 Rayleigh scattering
spaceStart 0 Altitude (m) where the fade to space BEGINS
spaceFull 0 Altitude (m) of full vacuum. Feature is off unless this exceeds spaceStart
atmosphere 1 How much air this WORLD has: 1 Earth, 0 the Moon (black sky at noon, stars out, no haze, a hard sun). Deliberately steep — only the last stretch toward 0 thins the sky (vacuum is (1 − atmosphere)⁴) — and it multiplies with the space band
dust 0 Suspended dust, 0…1: bright, coloured haze that is never blue. Independent of atmosphere, so Mars is almost no air and lots of dust, and the Moon is neither
zenithTint '#ffffff' The sky's colour overhead — the scattered light's own brightness in this hue, by tintStrength. Stars and moon are behind the air and untinted
horizonTint '#ffffff' The same at the horizon. zenithTint: '#c8a070', horizonTint: '#e0b080', tintStrength: 1 is a butterscotch Mars
tintStrength 0 How much the sky takes the tints, 0 (Earth, untouched) … 1
starfieldCube '' Root path of a baked cube (<root>_px.png …). Replaces starfield
starfieldData '' Root path of a DATA cube (<root>_px.png …) encoded by starfield-codec. Not a picture of a starfield — a table of stars the shader decodes into points that stay sharp at any zoom. Composes with starfieldCube rather than replacing it
starfieldDataSize 1024 Texels per face of starfieldData. Must match what encoded it. 1024 is the size to ship — at 512 a packed texel reads as a lattice through the dense band
starfieldSharpness 3 How sharp a decoded point is — higher is tighter. 3 tucks the gaussian tail in so a star reads as a point
starfieldGain 0.9 How bright the decoded stars are — the intensity cap on the whole point sky
starfieldTwinkle 0.35 Scintillation strength. Scaled by the gas (none in vacuum), strongest at the horizon
starfieldFloor 0.4 The faint mass's brightness — most stars sit on it; starfieldGain only moves the bright few above it
starfieldSizeScale 3 How much bigger a full-size object (a distant galaxy) is than a star
starfieldTilt '0,0,0' Degrees rx,ry,rz rotating the sampling direction — both cubes — where a galactic tilt belongs
starfield 0 How many background stars to build. 0 = none
nebulae 0 Soft emission clouds behind the stars. 0 = none
nebulaBrightness 1 Nebula brightness 0…1
nebulaSize 0.045 Nebula size as a fraction of the sky radius
nebulaTexture '' Black-backed image stamped per nebula; empty = a plain procedural falloff
spaceColor '#05070f' What is behind the stars in vacuum. Just north of black, so a black hole still has somewhere darker to go
starfieldSeed 12345 Seed for the starfield — same seed, same constellations
starDistance 0 Park a <tosi-b3d-star> child this far along the sun vector. 0 = leave it alone
sunColor '#eeeeff' Midday sun color
duskColor '#ffaa22' Dawn/dusk sun color
moonColor '#6688cc' Night light color
moonIntensity 0.15 Night light intensity
sunSize 1 The sun's apparent size, 1 = as seen from Earth. Mars 0.66, Venus 1.39, Io 0.19, Titan 0.11 (it goes as 1/distance from the star)
sunBrightness 1 Multiplies the sun's light. A distant world gets less light, but the eye adapts, so set it by how it looks rather than by the inverse square
applyFog false Whether scene fog affects the skybox