Flight Systems Documentation
How we grew a planet
out of arithmetic.
This is the mission-control walkthrough of the ORBITAL-7 site. No textures were downloaded, no assets shipped. Everything you saw โ continents, atmosphere, ring, stars โ is generated at load time from noise functions and color ramps. Copy anything. That is what this document is for.
01 ยท The Concept
ORBITAL-7 is a fictional deep-space probe, launched 2031, arriving now at the exoplanet Meridian-4b. The site is its mission page, written as if a real flight team maintained it โ live telemetry, an instrument roster with personalities, a timeline that spans three crews.
The aesthetic is NASA-JPL modernism crossed with science-fiction interface design: true black, one blue (ion exhaust, #5da9ff), one orange (signal warning, #ff8a3d), thin hairline rules, and monospace numerals for anything that claims to be data. Space Grotesk carries the display voice; JetBrains Mono carries the instruments. Two typefaces, five working colors, no exceptions granted.
02 ยท The Techniques
T-01The procedural planet: noise-displaced icosahedron
The planet starts as THREE.IcosahedronGeometry(1, 6) โ about 41,000 vertices,
evenly distributed, no pole pinching. For each vertex we sample seeded 3D simplex noise in
several octaves (fBm) using the vertex's unit direction as the coordinate, so the terrain
wraps seamlessly. Anything above sea level is pushed outward along its normal; ocean stays
on the unit sphere, which is why coastlines read as crisp silhouettes against the limb.
// continents + coastline detail + ridge chains, per vertex
const cont = fbm(dx, dy, dz, 5, 1.15);
const det = fbm(dx + 3.7, dy - 1.2, dz + 2.4, 4, 4.2) * 0.35;
const ridge = 1 - Math.abs(noise(dx*2.6, dy*2.6, dz*2.6)); // fold |n| for crests
const land = (cont + det * 0.6) - SEA;
if (land > 0) disp = land * 0.12
+ Math.pow(Math.max(ridge - 0.55, 0) / 0.45, 1.6) * land * 0.14;
pos.setXYZ(i, dx * (1 + disp), dy * (1 + disp), dz * (1 + disp));
The 1 - |noise| fold is the whole mountain trick: absolute value creases the
smooth field into sharp ridgelines, and gating it by land keeps ranges off the
seafloor. After displacement, computeVertexNormals() rebuilds lighting.
T-02The color ramp: elevation as paint
No texture maps โ each vertex gets a color from a five-stop ramp (shore sand โ lowland green โ olive upland โ rock โ snow) indexed by its elevation, with ocean depth darkening toward the abyss on a power curve. Latitude plus altitude feeds a smoothstep that lerps everything toward ice, which is why the poles and the mountain summits frost over with the same three lines of code. A final low-amplitude noise multiplies brightness by ยฑ10% to kill the banding that flat ramps always produce.
T-03The atmosphere: an inside-out additive shell
The glow is a slightly larger sphere drawn with side: THREE.BackSide โ you
are looking at its inside. Faces behind the planet fail the depth test, so only a rim
annulus survives, and a view-space fresnel curve brightens exactly at the limb. Additive
blending makes it read as scattered light instead of paint.
// fragment shader โ vN is the view-space normal
float rim = clamp(0.62 - dot(vN, vec3(0.0, 0.0, 1.0)), 0.0, 1.0);
gl_FragColor = vec4(uColor, 1.0) * pow(rim, 3.2) * 0.95;
// material: side: BackSide, blending: AdditiveBlending, depthWrite: false
T-04The keyframed camera: scroll as trajectory
Scroll position maps to a 0โ1 mission progress value, which interpolates through four
camera stations โ approach, flyby, orbit, surface scan โ each a spherical coordinate
(distance, polar, azimuth) plus a look-target offset that parks the planet on whichever
side of the screen the copy isn't. Smoothstep eases between stations; a framerate-independent
damp (1 - pow(0.0015, dt)) chases the target so fast scrolling feels like
thruster authority, not a slideshow.
const KEYS = [
{ p: 0.00, dist: 8.4, phi: 1.35, theta: -0.55, tx: -1.55 }, // approach
{ p: 0.30, dist: 5.0, phi: 1.20, theta: 0.45, tx: 1.00 }, // flyby
{ p: 0.58, dist: 3.2, phi: 0.95, theta: 1.35, tx: -0.62 }, // orbit
{ p: 0.92, dist: 2.1, phi: 1.60, theta: 2.45, tx: 0.00 } // surface scan
];
T-05Telemetry that ticks believably
The counters are arithmetic from a launch epoch, not random flicker: range to target
falls at the displayed velocity, distance from Earth climbs by the same amount, propellant
drains at an ion thruster's real ~5 mg/s. Everything renders in JetBrains Mono with
font-variant-numeric: tabular-nums so digits change without the layout
breathing. The lesson: fake data earns trust through consistency, not precision.
T-06Fail-safe engineering
Pixel ratio is capped at 2 so 4K displays don't melt. The render loop cancels on
visibilitychange and resumes on return. If WebGL is unavailable โ or the CDN
never answers โ the page defaults to a CSS-gradient planet with a box-shadow glow and a
radial-gradient starfield; the webgl-on body class only appears after the
renderer actually constructs. Touch devices skip pointer parallax; reduced-motion users get
a still planet, instant camera settles, and no blinking anywhere.
03 ยท How It Was Made
This site was built by Claude (Fable 5) writing vanilla HTML, CSS, and JavaScript by hand โ no frameworks, no build step, no asset pipeline. The only external dependencies are the three.js module from a CDN and two font families. It is one of twenty-five sites in the Fable Showcase, a collection built to prove that one model can hold twenty-five entirely different design languages in its head at once. Every planet, probe, and person named on the mission page is fiction.
04 ยท Steal This
- Fold your noise.
1 - Math.abs(noise(p))turns any smooth noise field into ridgelines. It is the cheapest mountain range in computer graphics โ use it for terrain, lightning, cracks, veins. - BackSide + additive = atmosphere. A second sphere at 1.2ร radius, rendered inside-out with additive blending and a fresnel falloff, gives you planetary glow in ~15 lines. Works for force fields and neon halos too.
- Keyframe cameras in spherical coordinates. Distance, polar, azimuth interpolate cleanly where XYZ paths swing through the subject. Add a look-target offset to compose the subject against your copy instead of behind it.
- Make counters do arithmetic, not theater. Derive every fake number from one clock and keep them mutually consistent โ range falls exactly as fast as velocity says it should. Viewers can't check your facts, but they can feel your inconsistencies.
- Default to the fallback. Ship the CSS version visible and let successful WebGL hide it, never the reverse. Then a dead CDN, an old GPU, or a blocked script still leaves a designed page instead of a black void.