Background pass — bg_hue, bg_bright, bg_vignette, the ramp and the band
An audio-tintable gradient + vignette backdrop drawn before the scene, engine-
wide. bg_bright = 0 (the default) is a black backdrop; raise it to reveal the
gradient. bg_hue picks the tint out of the preset’s palette; bg_vignette (0..1)
darkens the corners.
bg_hue is a coordinate in your [palette]
(ADR-0086). The pass samples
the same baked LUT every scene samples, so an ember preset gets an ember sky and a custom gradient
tints its own backdrop — and saturation / palette_mix move the backdrop with the figure, so an
A/B crossfade carries the whole frame. It is cyclic, with the same wrap trap color_center has:
-0.1 and 0.9 are the same place, and on a stop-list palette that seam is the sharpest transition
in the gradient. With no [palette] declared the gradient is spectrum, and the twenty-row swatch
table in
Colour and palettes
is that ramp — so bg_hue 0.30 is cornflower blue, 0.45 aqua, 0.85 amber until you declare
stops of your own, at which point read the value off your own gradient instead. A bg_hue copied
from another preset arrives at whatever colour your gradient holds there, not the colour it was in
the preset you took it from. Visible wherever the scene leaves the frame unpainted: behind
the sparse scenes (lines, swarm, attractor) where the gaps show through, and in
the reaction-diffusion field’s voids (both composite over the backdrop instead
of presenting opaque). The fragment field
is the one full-screen scene that still draws opaquely, so bg_* has no visible
effect there — including the whole ramp and the band below. A dusk ground
under a fragment_field preset is not a dim ground, it is an absent one.
The directional ramp — bg_angle, bg_hue_span, bg_shade, bg_shade_end, bg_ramp_gamma
Five params turn that single tint into a gradient across the frame
(ADR-0094). The pass sweeps a
segment of your [palette] along one axis instead of taking one point of it, with a brightness
ramp on the same axis and one exponent shaping both.
| Param | Default | What it does |
|---|---|---|
bg_angle | 0.0 | The ramp’s direction, in radians. 0 runs bottom-to-top — the same zero-is-up convention launch_angle uses. 1.5708 (π/2) runs left-to-right, 3.1416 (π) top-to-bottom. |
bg_hue_span | 0.0 | How far the palette coordinate travels from the ramp’s start to its end. bg_hue keeps its meaning as the coordinate at the start. 0 sweeps nowhere, which is the old one-sample behaviour. |
bg_shade | 0.72 | Brightness factor at the ramp’s start. |
bg_shade_end | 1.0 | Brightness factor at its end. |
bg_ramp_gamma | 1.0 | The ramp’s response exponent — eases where things sit along the axis, applied ahead of both the colour and the brightness. Clamped to 0.05 .. 20. |
Every default is an arithmetic identity with the picture the engine drew before the ramp existed, not an approximation of it, so a preset that binds none of them renders byte-for-byte unchanged. All five are ordinary bindable params, so a breathing horizon costs nothing extra.
Placement is authored by your [palette] stops’ own at positions. There is deliberately no
bg_ramp_center or bg_ramp_width: positions already live in the palette, and a second placement
mechanism could disagree with it. Where the horizon sits in the frame is where its colour sits in
your gradient. The worked dusk ground:
[palette]stops = [ { at = 0.00, color = "#060b24" }, # near-black zenith { at = 0.25, color = "#1b2a5e" }, # deep blue { at = 0.50, color = "#c74b1d" }, # the ember band { at = 0.75, color = "#ff7a1f" }, { at = 1.00, color = "#ffd06e" }, # the hot horizon]
[params]bg_bright = "0.6"bg_hue = "1.0" # the ramp STARTS at the palette's hot end...bg_hue_span = "-1.0" # ...and travels backwards to its near-black endbg_angle = "0" # bottom-to-top, so hot at the bottom of the framebg_shade = "1.0" # full brightness at the horizon...bg_shade_end = "0.25" # ...a quarter of it at the topbg_ramp_gamma = "2.0" # hold the horizon, then fall awayMove the at = 0.50 stop down and the ember band moves down the frame with it. Raise
bg_ramp_gamma and the band holds longer before fading; drop it below 1 and the ramp falls away
fast and leaves a long dim tail.
A wide smooth ramp is safe, and the dark tail is not the risky end. A gradient this broad
would otherwise band — visibly, on a real display — worst exactly where this control is most
useful. The reason is worth carrying: a band is a run of pixels sharing one 8-bit value, so it is
widest where the ramp is flattest, and sRGB’s near-black slope makes the dim tail the flattest
part of any ramp that reaches toward black. Undithered on the dusk ground at 1080p,
bg_ramp_gamma = 0.4 spends 7.5 pixels on each level and holds one value for 58 pixels in its
tail. (The intuition that steep is dangerous is backwards — two pixels per level is the healthy
state.)
The tonemap dithers its output by one encoded level (ADR-0096), always, for every gradient in the engine at once — the same frame then spends 2.1 pixels per level and its widest plateau is 20. So author the ramp you want: a long dim tail, a low exponent, a near-black sky under a bright horizon are all ordinary requests, and none of them needs a stop added to break up a step. Nothing to switch on and no param to bind.
Why the exponent exists when stop placement can already shape the colour. Your [palette] is
shared with the scene (and with the [layer], under
ADR-0090), so re-spacing stops to shape
the sky’s falloff re-maps the figure’s colours too. bg_ramp_gamma shapes the backdrop’s mapping
onto its axis and touches nothing else. It is also the only shape control the brightness ramp
has at all — bg_shade -> bg_shade_end is a straight line and no stop can bend it. It applies to
the position rather than to either channel, so colour and brightness always reach their midpoints
at the same height: it is one ramp, not two that can drift apart.
The segment wraps if it leaves [0, 1]. [bg_hue, bg_hue + bg_hue_span] is repeat-addressed
like every other palette coordinate in the engine, so a span that runs off either end comes back
around the other side. bg_hue = 0.8 with bg_hue_span = 0.5 sweeps 0.8 -> 1.3, which paints
0.8 -> 1.0 and then 0.0 -> 0.3 — putting the palette’s hot end at both ends of the sky with
a hard seam where it wraps. That is occasionally what you want and usually a surprise; if the ramp
has a bright band you did not author, check whether the span left the range. It is not clamped, and
deliberately: two shipped presets already drive bg_hue outside [0, 1] and depend on the wrap.
The old fixed brightness tilt is gone. The pass used to multiply its tint by a hardcoded
0.72 -> 1.0 gradient welded to the vertical, always brighter at the top and unexplained by any
param. bg_shade / bg_shade_end are where it went — those two numbers are its constants, which
is why leaving them alone changes nothing. A backdrop can now be brighter at the bottom, which
it never could be.
The backdrop is invisible to every behavioral gate, and the ramp makes that matter more.
sanity measures coverage against the scene with the backdrop suppressed
(ADR-0067), and the animation
gate strips bg_* bindings before scoring motion
(ADR-0091).
So a world whose ground is painted here earns exactly nothing at either gate: the figure and any
[layer] carry the whole burden. This is correct — it is what stops a more capable backdrop being
used to game the gates — but it means a frame that looks full to you can still read as sparse to
sanity. Give the figure enough to stand on its own before reaching for the ramp to fill the frame.
The backdrop composites correctly under every scene, so a lit bg_bright is
worth revisiting on anything in the swarm_* and line families. Additive scenes
emit premultiplied alpha
(ADR-0056), so a
sprite’s falloff is carried by its alpha rather than by its colour alone. Without
that, every sprite punches four black rectangular notches beside itself and every
stroke draws itself a black rim — invisible at bg_bright = 0, and worse the
fatter the stroke. Several presets in these families still sit at a near-black
floor tuned under the older behaviour, and their values were never re-tuned.
bg_bright has a ceiling, and it is a choice rather than a property of the
engine. A scene that draws into
the chain occludes the backdrop by its coverage, whatever light it emits: the
frame resolves c * g + bg * (1 - g), so a fragment darkens the backdrop
wherever its own light c is dimmer than the backdrop bg. Raise bg_bright
past the dimmest emitted luminance in the figure and the dim parts stop
fading out and start reading as dark speckle: on the swarm, the depth-parallaxed
far particles go first; on a line scene, a stroke dimmed by glow or by a
low-amplitude band. Rendered at bg_bright = 0.35, a swarm at
brightness = 0.02 is black specks on a lit field. The working limit is the
darkest part of the figure you still want visible, not a fixed number — sweep it
and look, do not assume.
The one knob for it is occlude, below. It
is what decides whether that limit binds at all.
None of this is worse than before: pre-fix the whole sprite quad held the backdrop out, so every value is brighter now than it was.
The curved band — bg_band_amount, bg_band_angle, bg_band_pos, bg_band_width, bg_band_curve, bg_band_hue, bg_band_hue_span
Seven params paint one soft band of light across the sky, over the ground the ramp paints and under everything else (ADR-0095). It was written for a Milky Way arc standing over a dusk horizon: a swell of light along a bowed diagonal, with the scene’s own stars sitting in front of it.
| Param | Default | What it does |
|---|---|---|
bg_band_amount | 0.0 | The band’s intensity. 0 draws no band at all. Everything else here is inert until you raise it. |
bg_band_angle | 0.0 | The direction across the band, in radians — the same axis convention bg_angle uses, so 0 runs the band horizontally and 1.5708 (π/2) runs it vertically. |
bg_band_pos | 0.5 | Where the centreline sits along that across-axis, in the same normalized 0..1 the ramp uses. At bg_band_angle = 0 that axis runs bottom-to-top, so 0 is the bottom of the frame and 1 the top. |
bg_band_width | 0.15 | The 1/e half-width — see below. Clamped to 0.001 .. 100. |
bg_band_curve | 0.0 | The arc: how far the centreline bows, in across-axis units, at the middle of the band. 0 is exactly straight. |
bg_band_hue | 0.0 | The band’s own coordinate in the same [palette] — an absolute coordinate, not an offset from the ground’s. |
bg_band_hue_span | 0.0 | How far that coordinate travels along the band, so one end can brighten toward a galactic core. |
Every default is an arithmetic identity with the picture that shipped before the band existed, so a preset that binds none of them renders byte-for-byte unchanged. All seven are ordinary bindable params.
bg_band_width is a 1/e half-width, not a full width and not an edge. The envelope is a
gaussian: it is at full strength on the centreline and has fallen to 1/e (about 37 %) exactly
bg_band_width either side of it, still faintly visible for two or three times that. So the
visible band is several times wider than the number you type. At 0.15 on a 1080-row frame with
bg_band_angle = 0, the 1/e line sits about 160 px from the centre and the band reads roughly a
third of the frame tall. Halve it for a tight ribbon; 0.4 is a wash across the whole sky.
The worked Milky Way arc, over the same dusk palette the ramp’s example uses:
[params]bg_bright = "0.0" # a near-black sky: the band does not need a groundbg_band_amount = "0.5"bg_band_angle = "1.2" # the across-axis tilted, so the band runs diagonallybg_band_pos = "0.55" # a little above centrebg_band_width = "0.12"bg_band_curve = "0.18" # bowed — the silhouette that reads as a galaxybg_band_hue = "0.30" # the palette's cool blue-white...bg_band_hue_span = "0.25" # ...warming toward one endTwo levers make it operable: move bg_band_pos and the arc rides up or down the frame; raise
bg_band_curve and it bows further. Turn the whole thing with bg_band_angle, remembering that
angle names the direction across the band rather than along it — so the band itself runs
perpendicular to the number you write.
bg_band_amount > 0 is now enough on its own. The backdrop pass used to skip drawing entirely
below a visible bg_bright; it no longer does. A band over a bg_bright = 0 sky paints, which is
the near-black configuration this look actually wants — the reference photograph’s sky is almost
black away from the horizon. You do not need a lit ground to hang a galaxy on.
The band is additive over the ground and under the scene. It adds light rather than replacing
it, which is what unresolved starlight is — so it brightens whatever the ramp already painted rather
than covering it, and the scene then draws over both. A fullscreen or opaque scene therefore hides
the band exactly as it hides the ramp, and fragment_field hides it completely. A galaxy under
a fragment-field preset is not a dim galaxy, it is an absent one.
The band shares your [palette] with the ground and the scene and any [layer], and that is
the one real authoring constraint this creates. There is no second palette to reach for —
palette_mix already owns the A/B pair for preset crossfade, so pinning the band to B would fight
every dissolve. A sky with both a horizon ramp and a galaxy needs stops that hold both sets of
colours: the dusk palette in the ramp’s example is fully spent on the horizon, and adding an arc to
it means finding room for the band’s colours in the same list. Plan for that before tuning, not
after. Because bg_band_hue is absolute, the band keeps one colour along its whole length
whatever the ramp underneath it is doing — which is what makes a pale arc over a warm horizon
authorable at all.
The band’s coordinate wraps exactly as the ramp’s does: [bg_band_hue, bg_band_hue + bg_band_hue_span] is repeat-addressed, not clamped, so a segment running off either end comes back
around the other side with a hard seam where it wraps. If the arc has a colour break you did not
author, check whether the span left [0, 1].
And the backdrop is still invisible to every behavioral gate. This bears restating here rather
than only under the ramp, because a more capable backdrop makes the temptation to lean on it
stronger. sanity measures coverage against the scene with the backdrop suppressed
(ADR-0067) and animation
strips bg_* bindings before scoring motion
(ADR-0091),
so a galaxy earns a preset nothing at either. The figure and any [layer] carry both floors, no
matter how much of the frame the sky fills.
Built from a8ce055 at version 0.115.0. This site tracks main and is not versioned per release.