Rocket Ascent

One continuous shot from the pad to vacuum. A rocket lifts off, climbs through the cloud deck, and keeps going until the air runs out and the stars come through — with the camera holding station off its flank the whole way.

It exists because nothing else in this repo ever crosses more than one medium. b3d-water contributes an underwater band, b3d-clouds a whiteout, and b3d-skybox a fade to space; each is tested on its own and the seams between them are not. A unit test cannot tell you that leaving a cloud at 900 m and entering vacuum at 2 km reads as one continuous world rather than three effects taking turns. Watching it can.

Demo

import { b3d, rocketAscent, slider3d, label3d } from 'tosijs-3d'
import { tosi } from 'tosijs'

// The panel is the `scenePanel` hook, which renders BOTH as the flat gear
// overlay and as a floating panel inside VR — so the demo is tweakable in a
// headset, where there is no console and no keyboard.
const { flight } = tosi({ flight: { timeOfDay: 14 } })

preview.append(
  b3d(
    {
      style: 'width:100%;height:100%',
      scenePanel: () => [
        // `text`, not `value` — label3d is the one widget here keyed that way,
        // and getting it wrong does not produce a blank row, it takes the WHOLE
        // PANEL down: the undefined string reaches measureTextWidth and throws
        // before anything renders. "The scene panel button has appeared but it
        // literally does nothing." Doc examples are not type-checked, which is
        // exactly why this shipped.
        label3d({ text: 'Ascent' }),
        // NO PAUSE ROW. `<tosi-b3d>` already has pause as a first-class feature
        // — `pause()`/`resume()`, `startPaused`, and `pauseWhenHidden` on by
        // default — and it stops the SIMULATION, not just the render, which a
        // hand-rolled flag in this demo's own loop could never do for the rest
        // of the scene.
        slider3d({
          label: 'time of day',
          value: flight.timeOfDay,
          min: 0,
          max: 24,
          step: 0.5,
        }),
      ],
    },
    ...rocketAscent({ timeOfDay: flight.timeOfDay })
  )
)
.preview { height: 100%; }

What you are looking at

The whole ascent is ONE number — altitude — read by four things that never speak to each other:

altitude what changes who owns it
0 m lit by the sun, blue sky b3d-sun, b3d-skybox
~140 m whiteout, then out the top b3d-clouds
500 m → 2.4 km scattering falls away, sky darkens b3d-skybox spaceStart/spaceFull
2.4 km vacuum: stars, no haze the starfield, and the fog layer going to nothing

None of that is sequenced. There is no timeline and no state machine — every layer is a function of where the camera is, so flying back DOWN runs it all in reverse for free, which is the property that would be lost by scripting it.

No glow layer, deliberately

The first version of this demo set glowLayerIntensity: 0.6 and it was a mistake twice over. A GlowLayer hunts for emissive materials, and both the starfield and the clouds' self-illumination are emissive: the stars bloomed into each other until the whole frame went white, and the clouds turned into glowing white lozenges that read as UFOs rather than weather.

The stars are now excluded from glow layers inside b3d-skybox — that was a real bug and any adopter turning the attribute on would have met it. The clouds are not, because there is nothing to fix: bloom belongs to bright things IN the world, a muzzle flash or a corona, and a cloud deck is not one.

The rocket is Kenney's, and it is a KIT

The Space Kit does not ship a rocket — it ships five stackable parts (base, sides, fuel, fins, nose, each in an A and a B variant), so the rocket here is assembled rather than loaded. That is the right way round for this demo anyway: the point is the sky, and a kit-built rocket reads as a toy, which is exactly the promise we want to make. Fidelity is a promise, and a beautifully modelled booster would be promising a flight model this does not have.

There is no submarine anywhere in Kenney's 3D packs — the only sub hits are a sandwich and a subway train — so the eventual underwater launch will need a model from somewhere else, or a silhouette made of primitives. It barely matters: in that shot the camera is on the missile.

Attributes

rocketAscent(options) returns scene children to spread, like playground — so you can drop pieces or add your own.

Option Default Description
cloudAltitude 140 Centre of the cloud deck (m)
spaceStart 500 Where the sky begins to fade (m)
spaceFull 2400 Full vacuum (m)
apogee 3200 Where it stops and resets (m)
accel 9 Net acceleration (m/s²) — thrust already minus gravity
holdSeconds 2.5 Pause on the pad, and again at apogee
starfield 2500 Background stars (see b3d-skybox)
nebulae 0 Sprite nebulae, OFF — superseded by baking the galaxy
rocketScale 4 Uniform scale on the Kenney parts
timeOfDay 14 Broad daylight — so the stars appear because the AIR ran out, not because night fell