Drawing the Real Night Sky in a BrowserSection 6 of 10
Depth Rules and the Bugs Behind Them
The sky is painted as a post-processing pass keyed on depth, so every depth decision shows up on screen. The bugs that appeared, and the rules they left behind.
Most of the rendering rules in Asterarium were derived backwards, from bugs that actually appeared on screen. The reason comes down to one fact: here the sky is not a background object drawn first, but a post-processing — A full-screen pass applied to the image after the scene has been drawn. Fitting brightness to what a display can show, and adjusting colour, both happen at this stage. In this article the sky itself is drawn as one of these passes. that runs after the scene is drawn and reads the GPU memory that records, for every pixel, the distance to whatever is currently drawn there. It is what lets a near object hide a far one. What it holds is not the distance itself but a normalised depth, mapped onto 0 to 1, with 1.0 meaning nothing nearer than the far limit.. That single fact very nearly dictates how stars, the Moon and the planets must treat In rendering, the distance from the camera to whatever is seen at a given pixel. Comparing these values is how a renderer works out what hides what.. Everything here is about In this article, the name for the night-sky scene that opens on the site's front page. It draws the stars, constellation lines, the Milky Way, the Sun, Moon and planets through atmospheric scattering, seen from an observer standing on the ground. The name is there to tell it apart from the eight standalone 3D pages, separate pages such as the Moon globe and the projector which share no 3D code with it or with each other. — the night-sky scene that opens at the top of the site, called that throughout this article to keep it apart from the eight standalone 3D page — In Asterarium, a 3D page that shares no scene code with the main sky or with the other such pages, and there are eight of them: the Moon globe, the moonwalk, the Mars globe, the deep field, the orrery, the interstellar flight, the eclipse viewer and the projector. Each one ships as its own bundle of code, so a visitor downloads only the page they opened.. The standalone 3D pages, such as the Moon globe, run under rules of their own, and they are covered at the end of this page, under "The Standalone Pages Follow Different Rules".
The Sky Paints Every Pixel Left at Far Depth
The mechanism underneath is this. The atmosphere, drawn by the atmospheric scattering — Sunlight bouncing off the molecules and particles of the air and spreading in every direction. Blue light scatters most, which is why the daytime sky is blue, and a low Sun, whose light crosses far more air, turns red. library @takram/three-atmosphere, is a single post-processing pass that reads the depth buffer One of the small squares a screen is divided into; a picture is the whole array of them. Colour is decided one pixel at a time, so the cost of drawing follows roughly from how many of them have to be filled. by pixel. A pixel still at the far depth is taken to be infinitely distant and its colour is replaced outright by the The physical measure of how much light leaves a surface in a given direction. It is what a camera or an eye actually receives, so physically based rendering computes it. It has no ceiling: a daytime sky runs far above the 0-to-1 range a display is given. of the sky. That is a replacement, not an addition: whatever had been drawn there is gone. Every other pixel is dimmed by the air between the camera and the point at that depth, and has the light scattered into that stretch added to it. The top of the atmosphere is fixed at 60 km above the surface, and a point beyond it saturates at the value for the top, so pushing it further out barely changes the result. That is why the Sun, the Moon and the planets, parked about 2,000 km away, receive very nearly the scattered light that the sky beside them is painted with.
The bar for "still at the far value" sits right at the end of the depth scale: only pixels whose The camera distance mapped onto the range 0 to 1, which is what a depth buffer, the GPU memory holding a distance per pixel, actually stores. The near clipping plane sits at 0 and the far limit at 1.0. is at or above 1.0 - 1e-8 get repainted as sky. One part in a hundred million is finer than a single step of the depth buffer, so the test effectively means "pixels whose depth is still exactly 1.0". For compositing scattered light that is a reasonable rule; for the additive blending — A blending mode that adds the new colour onto what is already on screen. Real light also adds up where it overlaps, which suits stars and atmospheric glow. objects drawn in front of it, it is a hard constraint.
The rule that follows comes in a pair. A celestial object must write depth, and any nearly transparent One pixel-sized candidate produced while the GPU breaks a shape into pixels. Only those that survive the checks for whether something nearer is already there end up as colour on screen. whose contribution is negligible must be thrown away with a A small program that runs on the GPU, the chip built for rendering, to compute where a vertex goes or what colour a pixel takes. It runs once for every vertex or every pixel it is handed. An instruction in a shader, the small program running on the GPU, that throws the current pixel away so nothing is written for it. It writes neither a colour nor the per-pixel distance a renderer keeps to work out what hides what, so a pixel that would have contributed nothing leaves whatever is behind it visible.. One without the other does not work. Skip the depth write and the sky simply overwrites those pixels. In practice, that is exactly what happened once: the whole star field vanished. Write depth without discarding the near-transparent fragments and you get the opposite: depth is written where nothing was drawn, so the sky is never composited there and a black rectangle is left in the daytime sky. It stays black because the pixel is never repainted as sky, and because at a radius of 1,000 — about a kilometre, one sixtieth of the 60 km top of the atmosphere — the atmosphere library reads it as a point with almost no air in front of it and adds almost no scattered light. On this page, that symptom is called a dark box.
float alpha = psf * vAlpha * uVisibility;
// …
if (alpha < 0.003) discard;The excerpt comes from near the end of the star shader. psf is the value of the The function describing how a point source of light is smeared out by an optical system. It is why a star looks like a small blur rather than a mathematical point., vAlpha is the The opacity value carried alongside a colour: 0 is fully transparent, 1 fully opaque. derived from that star's brightness, and uVisibility is the In Asterarium, a number from 0 to 1 saying how far into night the sky has gone: 0 with the Sun on the horizon, 1 once it is 18 degrees below and the sky is fully dark. It fades the stars, the constellation lines, the Milky Way and the deep-sky markers together. The Moon stays an opaque disc, but its brightness follows this number squeezed into the range 0.25 to 1, so it shows faintly by day, while the planets come out on a separate threshold in solar altitude of their own.. Why, then, does a depth-writing star not itself leave a dark hole in daylight? Because by day its alpha is zero: the discard above throws it away and no depth is written. The star shader multiplies its final alpha by the night factor, which is 0 whenever the Sun is at or above the horizon. By day every star therefore falls below the threshold, and the sky paints those pixels normally. Constellation lines and the Milky Way share the same night factor. There is one exception: the view from space with the atmosphere off, where the night factor is pinned to 1 whatever the The angle of an object above the observer's horizon: 0 degrees at the horizon, 90 degrees straight overhead, negative when the object is below it. of the Sun. The name says space, but it is only a display toggle that stops the air from being drawn; the observer never moves.
The standard advice in 3D is that additively blended transparent objects should not write depth, because doing so unfairly rejects other transparent objects drawn later. Here that advice is deliberately broken. Between stars it is safe: the sprite — A point that the GPU, the chip built for rendering, draws as a square of a size given in pixels. Throwing away everything outside a circle turns it into a round star, which is the cheap way to draw a whole sky of point-like objects. This article uses the word in three senses: that point, the three.js panel that carries an image and always faces the camera (used for labels), and a sprite sheet, an image packing many small pictures into one (used for the deep-field galaxies). that make up the bulk of the field and the billboard — A four-cornered flat mesh turned so that it always faces the camera. Because it sets its own size it can spread wider than a point drawn by the GPU, which is what a broad glow needs. used for the thirty or so brightest stars are all placed on the same sphere of radius 1,000, and they blend additively, so which of the two draws first cannot change the result. The The comparison that throws away a new pixel when what is already drawn there is nearer, so objects sort correctly whatever order they are drawn in. By default in three.js, the standard 3D library, a pixel at exactly the same distance still passes. also keeps its default comparison, so stars sharing a depth never reject one another. Between objects at different radii, that unfair rejection does occur. The draw order of the Sun's The spill of brightness around a very bright source, caused by light scattering inside an eye or a lens. It spreads wider than the source itself., the planets and the stars is therefore pinned by hand with renderOrder, the number that tells The standard JavaScript library layered over WebGL, the browser 3D interface. It expresses a picture as scenes, cameras, geometries and materials instead of raw draw calls. when to draw an object.
The discard threshold differs per object. Most of them look at alpha directly. The Milky Way looks at the luminance of its colour — brightness as the eye weights the colour components — multiplied by the night factor. That colour has already been dimmed for light pollution, the glow of town lights that washes out faint objects. The horizon glow in the table below, the band those same lights lay faintly along the horizon, is judged on the brightness of that band itself. None of the numbers in the table came from theory: each was settled on screen, as the lowest value that left no holes and no flicker.
Three things can still be drawn by day: the planets, the horizon glow and the ground disc. That none of them leaves a dark box follows from the same rules. (The Moon sits outside the atmosphere, and is covered under the next heading.) The planets have visibility 0 while the Sun is more than 2° above the horizon, so not one pixel of them is drawn. The planets' own visibility curve, which is not the night factor the stars use, runs from +2° down to −10° — more permissive than the stars' night-factor threshold, which is what lets Venus hold up against a bright The stretch of time when the Sun is below the horizon but the sky is still lit. It deepens as the Sun sinks, so an evening runs civil twilight, down to 6 degrees below the horizon, then nautical to 12, then astronomical to 18. A morning takes the same stages in reverse, from astronomical through nautical and civil to sunrise. sky. The horizon glow takes its strength from the amount of light pollution times the night factor, so by day it too is 0 and every fragment falls under the threshold. Of the three, only the ground disc actually puts pixels on screen by day, and it is opaque geometry inside the atmosphere — a disc of radius 2,000, sunk by 3 units below the horizontal plane. It is never a pixel to be repainted as sky but one that gets the dimming and the scattered light of the air in front of it, which is why it takes on the colour of the sky at sunset.
| Object | Depth write | Discard when |
|---|---|---|
| Stars (point sprites and billboards) | yes | alpha < 0.003 |
| Planets | yes | outside the disc, or alpha < 0.003 |
| Sun glare | yes | outside the disc, or alpha < 0.004 |
| Moon | yes | never (opaque disc) |
| Milky Way | yes | luminance * night factor < 0.0015 |
| Constellation lines | yes | alpha < 0.003 |
| Deep-sky objects | yes | alpha < 0.01 |
| Horizon glow | yes | band brightness < 0.004 |
| Labels | no | never (handled separately) |
Bodies Above the Atmosphere, and a Near Plane of 2
The next bug was that the Sun, the Moon and the planets appeared as dark holes against a bright daytime sky — the Moon a dark disc, Venus a dark dot. The cause is that the atmosphere library derives the length of the path through the air from each pixel's depth. At the time the Sun, the Moon and the planets sat on the same sphere as the stars, radius 1,000, about a kilometre out. A kilometre against 60 km of atmosphere is almost no air at all, so almost no scattered light is applied to those pixels. The surrounding sky, at far depth, gets the full depth of the air and turns bright; the pixels of the body do not.
The fix was to move the bodies above the atmosphere. One unit in this scene stands for one metre, and they were moved from radius 1,000 out to 2,000,000. The pixels of a body are then treated as a point outside the air, and receive very nearly the scattered light the surrounding sky receives. The distance went up by a factor of 2,000 and each body is drawn 2,000 times larger to match, so its size on screen is unchanged. The camera is the eye of the observer, and it sits at the origin. Ordered by distance from it, with the clipping planes and the objects listed together, the scene now runs as follows.
- The The near clipping distance of a camera: nothing closer is drawn. The nearer it is placed, the less precision is left for distant objects, so its position decides how reliably far things sort.: 2, about two metres. Nothing closer is drawn
- The ground disc: 3 units, about three metres, measured when you look straight down (a disc of radius 2,000, sunk by 3 units below the horizontal plane)
- The label sprites: radius 990. The constellation lines and the deep-sky object — A collective name for the diffuse things beyond the solar system that are not single stars: nebulae, star clusters and galaxies. Most of them need binoculars or a telescope.: radius 995
- The In astronomy, an imaginary sphere centred on the observer, used to describe the direction in which something appears. It carries no distance at all: it keeps the direction to an object and discards how far away it really is. In this article the word also names the container of 3D objects standing in for it, and since one scene unit is about a metre, the stars sit on a sphere of 1000 units, a kilometre in radius. carrying the stars and the Milky Way: radius 1,000, about a kilometre
- The top of the atmosphere: 60km above the surface
- The Sun, the Moon and the planets: 2,000,000, about 2,000km, more than thirty times further out than the top of the atmosphere
- The The far clipping distance of a camera: nothing beyond it is drawn. Its ratio to the near clipping distance decides how finely distant objects can be told apart in depth, so it is set as tight as the scene allows.: 1e7 units, ten million units, about 10,000km
One distance is missing from that list: the real distance to the Moon, about 384,000 km. It falls far outside the far plane, so it cannot be used, and pushing the plane out that far would only make depth precision worse. The price of the fix is that the bodies now lie outside the sphere the stars sit on, so in depth order the stars are in front. At night, faint stars bleed across the disc of the Moon, which is about 0.5° across. That was judged negligible next to compositing daytime and twilight correctly, and accepted at first. It was solved later, without depth, by a geometric test, described under "Not Every Overlap Is a Depth Problem" later on this page.
That distance of 2,000,000 then caused a bug of its own. Zoomed to a 2° field of view, the Moon showed black gaps across its face, flickering whenever the camera moved. The gaps were triangular because a GPU draws a surface as a mesh of triangles, and the repainting happened one triangle at a time. The cause was depth Rounding a continuous value onto a ladder of fixed steps. Anything finer than one step is lost, so two values that differed can come out equal, or even swap order, once rounded., and the fix was to raise the camera near plane from 0.1 to 2. That was all. Where those two numbers come from is the rest of this story.
The far plane sits far beyond the near plane, so the normalised depth of a point at camera distance z is well approximated by 1 − near/z. The near plane was then 0.1, and at z = 2,000,000 that makes near/z equal to 5e-8. But the smallest step a 24-bit depth buffer can represent is about 5.96e-8, which is one part in 2^24. The gap between the depth of the lunar surface and the far value of 1.0 was smaller than a single step, so it rounded to 1.0 exactly — and the sky test, reading that as infinity, repainted the lunar surface. With the near plane at 2, near/z becomes 1e-6, about seventeen times that smallest step: a comfortable margin.
dpr={[1, 2]}
gl={{ antialias: true, powerPreference: 'high-performance' }}
// …
camera={{ fov: 60, near: 2, far: 1e7 }}What the rule states is not that computed factor of seventeen but the round lower bound of 1e-6. The two textbook remedies for depth precision are a logarithmic depth buffer and reversed-Z, and neither was available here. A logarithmic depth buffer — storing depth on a logarithmic scale to even out steps that otherwise coarsen with distance — has the The GPU program that computes the colour of each individual pixel. Its cost grows with the screen area a shape covers, so large shapes are expensive. rewrite the depth value itself. The pass that paints the sky reads that value back and turns it into a distance, so on a rewritten scale neither the length of the path through the air nor the test for sky comes out right. And reversed-Z — swapping the far value to 0 and the near value to 1 so that the fine steps of floating point land far away — is not supported by the The web standard that lets a page draw 3D graphics with the GPU, the chip built for rendering, straight from the browser. No plugin is involved. build of the atmosphere library. What remains is a one-line rule: any depth-writing distant body must keep near/z at or above 1e-6. A near plane of 2 also means that nothing within two metres of the camera is drawn. That costs nothing here, because the closest object is the ground disc that hides stars below the horizon, and it is sunk by 3 units, deliberately deeper than the near plane, so looking straight down never opens a hole in it.
Not Every Overlap Is a Depth Problem
Pushing the bodies outside the sphere of the stars meant stars showed through the lunar disc at night. Solving that with depth would conflict with the placement rule just established. So it is solved without depth, by a geometric test inside the shader. frame — One image of a moving picture. Smooth motion needs roughly 60 of them a second, which leaves about 16 milliseconds to build each one. A coordinate frame is a different use of the same word. the direction and the The apparent size of a body expressed as an angle: the angle subtended by the radius of its disc. The Sun and the Moon both measure about 0.25 degrees in radius, half a degree across, so the two are very nearly equal. The Moon-Earth distance varies, so the lunar figure drifts up and down: an eclipse with the Moon at its larger sizes is total, one with the Moon smaller leaves a ring of Sun showing and is annular. of the Moon and of the Sun are handed to the The GPU program that decides where each vertex of a shape lands on screen. It runs once per vertex.; if the A calculation that turns two vectors into a single number. When both have length 1 it measures how nearly they point the same way: 1 for the same direction, 0 at a right angle, −1 for opposite directions. of a star's world direction with that of the body exceeds the cosine of that radius, the star lies inside the disc and its alpha is set to 0. The decision is made in the vertex shader, the disappearance happens in the fragment shader: an alpha of 0 is passed straight through and the final threshold test discards it, writing neither colour nor depth. Every direction is passed as a A vector whose length is exactly 1, so that it carries a direction and nothing else. It is the natural way to hold a quantity like where a star appears, which is a direction without a distance. by convention, so a dot product can be compared directly against a cosine. When no direction for the Moon or the Sun is available, the convention is to pass a zero vector, and dot(uMoonDir, uMoonDir) > 0.5 — the dot product of the vector with itself — is the test for whether one was supplied: 1 for a unit vector, 0 for a zero vector, with 0.5 as a threshold placed between them. Doing that check and the comparison against the star for each of the two bodies costs at most four dot products per star. The field holds about 38,000 of them — the whole slice taken from the catalogue, everything brighter than A number for how bright an object looks: smaller is brighter, and a difference of one magnitude is a factor of about 2.512 in brightness. Under a dark sky the naked eye reaches roughly 6 to 6.5. 8 — so that comes to at most about 150,000 dot products per frame.
if (dot(uMoonDir, uMoonDir) > 0.5 && dot(worldDir, uMoonDir) > uMoonCosR) {
alpha = 0.0;
}
if (dot(uSunDir, uSunDir) > 0.5 && dot(worldDir, uSunDir) > uSunCosR) {
alpha = 0.0;
}The apparent radius is padded by a factor of 1.15. A star is not drawn as a mathematical point but as a small image spread by its point spread function, so one just outside the limb, the edge of the disc, would still smear its wings onto the disc. The 1.15, like the thresholds in the table, was settled by eye on screen. Inside the Sun's glare, stars are not hidden but dimmed, by a separate expression: the closer a star lies to the centre of the glare the more smoothly it fades, scaled by how bright the glare currently is, so on a glare-free night the star field is untouched. That reproduces how the eye sees a bright bloom swallow its neighbours, and it also hides a mismatch. A star at a distance of 1,000 and the glare at a distance of 2,000,000 receive their atmospheric correction separately, so the star would otherwise sit inside the glare as a hard, badly matched dot.
The first dark box was the one under the previous heading: the Sun, the Moon and the planets left dark against a bright daytime sky. The second appeared around Venus. Planets are drawn as square point sprites. The wings of the point spread fall off as a A shape in which a quantity falls off as some power of distance. It does not vanish as abruptly as an exponential, so it keeps a long tail, which is how the spill of light around a bright source behaves., so for a point as extreme as Venus — magnitude −4.5 at its brightest — the alpha stays above the 0.003 threshold all the way to the corners of the square. Those corners then write depth and the sky cannot composite there. The fix clips the square sprite to a circle — cutting off what falls outside it — with a discard at the top of the fragment shader for anything beyond the unit disc.
The third was not a dark box but a missing glare: inside the rectangle of a star's sprite, the Sun's glare dropped out. It shows up in the two situations where stars and glare share the screen. One is the view from space with the atmosphere off, described earlier: turning the air off does not stop the glare billboard from being drawn — in that view the same billboard also draws the solar disc itself — and the night factor is pinned to 1, so both are always on screen. The other is twilight, and that window is narrow: stars only appear once the Sun is below the horizon, and the strength of the glare reaches exactly zero at an altitude of −1°. So it is the one degree between 0° and −1° during which the wings of the bloom, reaching above the horizon, share the screen with stars. The glare is a single billboard placed at the position of the Sun, spreading out to eight times the apparent solar radius, roughly 2°.
The cause was sorting. three.js sorts transparent objects by the distance from the camera to the centre of each A sphere that encloses a 3D object entirely, kept as nothing more than a centre and a radius. It stands in for the detailed shape in cheap tests, such as whether the object is off screen or how far it sits from the camera.. But the stars sit on a sphere centred on the observer, and the camera sits at that centre, so the distance is zero and the order becomes arbitrary. When a star draws first, its square writes depth — and the brightest stars are drawn as billboards whose alpha stays above the discard threshold across much of the rectangle, so the area that writes depth is that much wider. Inside that area the far more distant glare failed the depth test. The fix was to state the order explicitly with renderOrder: lower values draw first, so the glare is at −2, the planets at −1, the stars at the default 0. The planets come after the glare because a planet near the Sun sits at the same radius of 2,000,000 as the glare does. Equal depths pass the depth test, but the same radius does not give exactly the same depth along the line of sight — the surface of a sphere is not a plane, so equal radius is not equal distance along a given ray — and which of the two comes out in front depends on where the camera is looking. Laying the glare down first and adding the planet on top removes any chance that a planet's depth write rejects the glare behind it.
Labels Moved to a Scene of Their Own
The labels that name stars and constellations reached their present form after two separate symptoms. In the first, constellation names floating in empty sky appeared while star names pinned to bright stars did not. Labels then sat on the same sphere as the stars, radius 1,000, with the depth test still on. A label therefore landed at all but the same depth as the depth-writing star beneath it, failed the test and vanished; in empty sky no depth had been written, so the constellation names came through. The code now carries two measures against that. The label radius is pulled in to 990, 0.99 of the star sphere, so labels are unambiguously in front; and the depth test on the label sprites is switched off altogether, because a label is an on-screen annotation rather than a celestial object and should always composite in front. Which of the two came first is not recorded. The one part of occlusion that still matters — hiding anchors below the horizon — is an explicit per-frame visibility check rather than anything to do with depth.
Labels do not write depth either: the sprite textures have transparent margins, and depth written there would punch holes in the sky. That, however, produced the second round of symptoms — in daylight, every label vanished. It is a direct consequence of the first rule of this section: a pixel left at far depth is painted over with sky. With no depth written, the label pixels stay at the far value and the atmosphere pass replaces them with sky radiance, and because it replaces rather than adds, the text drawn there is gone. At night the overwrite went unnoticed, since what it paints is a very nearly black sky; only against a bright daytime sky did the labels visibly disappear.
The final fix was to take the labels out of the post-effect chain altogether. The sprites live in a scene of their own, drawn with the same camera after the atmosphere has been composited. For that draw, autoClear — the three.js default of wiping both the colour and the depth buffer before every render — is switched off, and only the depth buffer is cleared. Clearing colour as well would erase the sky that had just been composited. The labels themselves neither read nor write depth, so they always land on top of what is already there. One side effect: the labels are no longer children of the In Asterarium's 3D scene, the three.js Group, a container that moves its children as one, standing in for the celestial sphere. The stars, the constellation lines, the Milky Way and the deep-sky markers are its children, so overwriting the matrix that holds its orientation turns all of them together., so they cannot inherit the rotation A rectangular array of numbers. In 3D it holds a coordinate transform, a rotation or a displacement, as one object, and multiplying transforms together collapses a whole chain of them into a single matrix. that stands in for the Earth's spin. They therefore copy the world matrix of the celestial group — the matrix that gives its final position and orientation once every parent has been applied — onto themselves each frame, and so turn with the stars from inside a separate scene.
The Standalone Pages Follow Different Rules
All of the above applies only to the night-sky scene. The same site hosts standalone 3D pages — such as a Moon globe, a deep-field viewer, an A mechanical model that shows the planets circling the Sun. Asterarium borrows the name for a standalone page that looks down on the planetary orbits and where each planet is now., an eclipse view — that run under their own rules. What separates them is whether the scene receives High dynamic range: keeping brightness as real ratios instead of clamping it into a 0-to-1 range, so values many powers of ten apart can coexist in one image. input. The sky scene takes raw radiance from the atmosphere library, so it needs a post-processing chain, and its depth rules follow from that. The Moon globe page has no atmosphere and no HDR light source; its shader applies exposure itself — scaling the light it has to a brightness the display can show — and writes display-ready colour. A near plane of 2, or bodies parked at 2,000 km, mean nothing to a scene holding a single sphere of radius 1.
The deep-field page is the instructive contrast. Its sprites are already baked to display-ready colour at build time, so The step that maps the wide range of brightness held in real ratios into the narrow range a display can actually show. The shape of the curve decides how colour and highlights read. at render time would be a second pass over the same pixels. Tone mapping is therefore switched off on the renderer, the part of three.js that actually issues the draw calls. The sky scene switches the renderer's tone mapping off as well, and for the opposite reason: there the One of the curves used to fit brightness into what a display can show. It lets highlights lose their colour gradually, giving a roll-off closer to photographic film than the curves used before it. curve is applied once at the end of the post-processing chain, so the renderer must not apply one of its own; here it has been applied already. What decides the convention is not the setting but the question behind it: what range of brightness does this scene take as input? Each bug described above, with its symptom, its cause and the alternatives that were rejected, is written down in the source, beside the constant that caused it. Why that is done is in the section "Design Principles, in Summary".