fuzzyworld

tower / files / README.md

README.md

40.5 KB · history · blame

Tower

Live map — https://apps.fuzzyworld.net/tower/ · Source

Companion piece to a novel set inside Tower — a fictional smart cylinder orbiting Earth, spun for 1 g, with an inner surface the size of Wisconsin, lit by 54 TW of sunlight piped down its axis and scattered by mirrors that make its days and nights. Its wall is a kilometre of sealed hull: no windows along all 540 km, and no view of the Earth it orbits. Both end caps are windows, though — 100 km of glass each, and the only places in the world with a horizon that is not Tower. Nobody aboard can see the sun either: the 244 km collector sits between Tower and it, 79 times its diameter, so the sun cap looks out at a black disc and the stars around it — black except at its edge, where the structure holding it flat catches the sun side-on and traces the whole 244 km in a thin sun-coloured ring.

Explore Tower from outside, pick a spot on the inner surface, and stand there — with the ground curving up on both sides and the far side of the world hanging 100 km overhead, clearer than the ground at your feet. Turn its sun up to Earth clear-sky noon, down to permanent dusk, or shut the beam off entirely and watch the sky come out: through the far cap the stars wheel once every 7 min 29 s about a single motionless star on the axis. Nothing inside Tower rotates, because you and the ground and the air all turn together — so that window is the only place the spin is visible at all.

Tower flies all 78 billion mirrors of its own sunlight, individually, because nothing passive would stay in the beam past mid-afternoon. It is a person.

Status

All three views are built — map, exterior and interior — over a world that generates itself live, in the browser, from a file of authored features.

Built: the unrolled surface map, Tower from outside, standing inside it and flying over it, a detail card for every place, Tower's published weather, a sun that crosses the world each day on Pisa's clock and a moon by night with Earth's phases, two railways, a scenic tour that flies the world's paragliders, aircraft, airships, trains and spacecraft inside and out, permalinks, and the sightline probe.

The app is for looking; the world is changed in the repository. The author writes alongside Tower rather than in it, and changes the world by talking it through with Claude, who edits content/world.json. That file is the one authoritative copy — there is no editor in the browser, no local draft, and nothing to import or export (decisions.md D-072).

In progress: world-generation.md. Phases 1 to 5 are built — the terrain is no longer baked into images by a build step; every mountain, lake, sea, river, desert and forest is a feature the browser turns into ground on demand, in web workers, from a metre underfoot to the whole world. Mountain ranges are summits joined by ridges and cut by water into valleys; lakes, seas and rivers are water with waves, flow and waterfalls; Tower publishes a weather plan, and ships sail the ring seas by it. The Dry Reach has mesas, dune fields, dry washes and salt pans, and Greatwood is three billion individual trees with meadows through it and a wood of 100 m giants near the Capital. Phases 7–8 add settlements and roads.

Both are series-bible material: coherence outranks spectacle, and the prose is downstream of them.

On a phone the sidebar is a drawer rather than a column: below 720 px the world gets the whole screen and the panel slides in over it, one tap away and one tap gone. Picking a place closes it, because in every view selecting a place is how you travel there — see decisions.md D-043.

Screenshots

Every shot on one sheet

npm run screenshots drives the real application in a headless browser — clicking the view buttons, picking places out of the list, dragging to orbit and to look up — and writes docs/screenshots/. Taking them through the UI is the point: a shot taken this way fails when the UI fails, so a black canvas ends up in the picture instead of hiding behind a passing unit test.

A scene the tour photographs is held at one moment with the water's clock stopped too, so the sea in a shot is the same sea every run and a divergence means a real change. --only <ids> retakes a few shots and leaves the sheet alone.

The whole tour takes about three minutes, and waits on the world being generated rather than on fixed delays: a shot is taken once the terrain has compiled, the map is drawn, and every tile of ground the view wants has arrived. It is kept light on the machine: the world is compiled once for the whole tour and every shot starts from that cache, and each page runs two terrain workers rather than a full pool — four pages at once each compiling the world with six workers was a laptop running hot. It once took six and a half minutes, nearly all of them spent rendering Tower's haze integral on the CPU — the default headless browser has no GPU. It now asks for the full Chrome build, which reaches the real one, and photographs four shots at a time, since a shot is mostly spent waiting. The cost is that the committed images are tied to the GPU that drew them: another machine will show a large one-off divergence rather than a regression.

Desktop — 1440×900
map the unrolled inner surface, with a place selected
map-sightline shift-click two points to measure a sightline through the air
exterior x-ray hull — the inner surface projected out, with the caps and the collector
exterior-true true hull — bare skin, and the land visible through the far cap window
interior standing at The Narrows, the ground curving up on both sides
tour-falls scenic tour: a helicopter circling the Long Water's 680 m fall
tour-falls-glide scenic tour: a paraglider past the same fall
tour-ship scenic tour: following a ship round the Sunward Sea
tour-squall scenic tour: a ship caught out by a gale Tower gave no warning of
tour-summit scenic tour: an airship off Snowcrown, 4,300 m
tour-ridge scenic tour: a paraglider ridge-soaring on a summit's flank
tour-thermal scenic tour: a glider climbing in a thermal over the Dry Reach
tour-mesas scenic tour: past the mesas of the Dry Reach, strata lining up across all of them
tour-giants scenic tour: under the giants of the Tall Wood, 115 m of them
tour-canopy scenic tour: low over Greatwood, closed canopy and the meadows left open in it
tour-deep scenic tour: a seaplane out from the Capital over The Deep
tour-girdle scenic tour: an airliner over the Girdle, antispinward and lighter for it
tour-climb scenic tour: a giant airship climbing out of the Capital, the world closing overhead
tour-sun-circuit scenic tour: a giant airship round the sun, outside the beam
tour-far-cap scenic tour: toward the far cap by night
tour-moonlight scenic tour: over The Deep by the light of Tower's moon
tour-train-narrows scenic tour: a train on the Axial Line through The Narrows
tour-train-ring scenic tour: a train on the Uplands Ring
tour-grand scenic tour: outside: Tower, its collector and the sun in one frame
tour-docking scenic tour: outside: a spacecraft docking on the shell
tour-far-cap-peek scenic tour: outside: looking in through the far cap
tour-hull-skim scenic tour: outside: skimming the hull as it turns
interior-overhead looking up: the far side 100 km overhead is clearer than ground 100 km away
interior-morning 06:30 — the sun just out from the sun cap and coming, the rod lit only behind it
detail a place selected: its detail card, with what the world made of it
Mobile — 390×844
map the world with the whole screen, the panel one tap away
exterior the spin readout dropped clear of the panel button
interior the standing readout at a size that fits 390 px
panel the sidebar as a drawer, opened over the world

Looking before committing

overview.png is a contact sheet of every shot. It exists to be looked at, once, before committing — one image that answers "is the application still there?". Regenerate, glance at it, then commit.

--check puts a number on the same question. Every shot is compared against the committed one and the run fails if any of them moved too far:

npm run screenshots -- --check              # fail past 3% divergence on any shot
npm run screenshots -- --threshold 8        # report only, looser bar
npm run screenshots -- --url http://localhost:5173   # use a dev server already up

The threshold is measured at both ends, not guessed. The 2D shots come out byte-identical between runs — nothing in Tower is stochastic, the exterior spin is switched off, and every shot gets a fresh browser context so no camera leaks into the next. The WebGL shots do not, because the tour draws on the real GPU and Metal does not schedule floating-point work identically twice; they drift by 0.1% to 0.9%. Against that, hiding both 3D canvases scored 7% to 31%, and a view going entirely black scores 12% to 39%.

3% is three times the worst noise and less than half the mildest real failure. It is a smoke alarm, not a verdict: when it fires, go and look at the sheet. Note that a view which never worked scores 0% when it breaks further — this catches regressions, not things that were already broken.

Photographs

A view worth keeping — things lined up, at a particular time — is saved as numbers and rendered again whenever it is wanted, so an illustration can always be remade from the latest world and the latest renderer (D-099).

  1. npm run dev, open the exterior or the interior, and frame the shot: the camera, the day and time, the Light, the hull.
  2. Press P, or Save this shot under View, and give it a name. The shot goes into content/photos.json. Saving under a name already in the list re-frames that shot. The button and the key exist only on a dev server, and it takes a shot only from the machine it runs on; the published site has neither.
  3. npm run photos renders every shot to photos/<name>.png.

To go back to a shot, pick it from Saved shots, under the button: the app opens its view, puts the camera where the shot has it, and stops the clock at its moment (and, outside, the spin), and carries on from there. Adjust it and save under the same name — the name is filled in — to re-frame it. The list is read from the file each time it is opened, so a shot typed by hand is in it too.

npm run photos                              # every shot in content/photos.json
npm run photos -- --only far-cap            # just the shots whose names start so
npm run photos -- --long-edge 5760          # bigger; the default is 3840 (4K)
npm run photos -- --url http://localhost:5173   # use a dev server already up

A render is the view alone — no panel, no readouts, no gauge, no labels — at the shape of the window the shot was framed in, 3840 px along its long edge. The file name never changes, so rendering again replaces the picture with the newest version of itself. photos/ is not committed: the list is what is kept, and the pictures are made from it.

An entry is plain numbers, and is meant to be edited by hand as well:

id the file's name: lower-case letters, digits, hyphens
note anything worth remembering; kept when the shot is re-framed
view exterior or interior
hours the world clock, hours since day 0 began (day 2, 06:30 is 54.5)
dial the Light: dark, twilight, temperate, full
aspect width over height of the frame
interior: theta, z, eyeM where the observer stands: radians round, metres from the sun cap, eye height in metres
interior: yaw, pitch, fovDeg heading in radians from deepward (0 faces the far cap, 3.14159 the sun cap), elevation in radians, field of view in degrees
interior: spin how far the sky through the far cap has wheeled, radians
exterior: position, target the camera and the point it looks at, in kilometres
exterior: phase, hull how far the hull has turned, radians; and the hull reading
exterior: fovDeg field of view in degrees. The view's own is 42 and it has no zoom, so a saved shot says 42; type a smaller number to frame it tighter

A render holds still: the hull does not turn, the sky through the far cap does not wheel, and the water is held at one moment, so the same entry gives the same file every time. A shot cannot be saved while a scenic tour is running — its flyers belong to the tour — so stop the tour first.

The list holds the two caps as seen from 300 m over the Capital at 08:45, and tower-from-the-far-end, the blog illustration of 2026-08-19 worked back from its JPEG: the camera and the field of view fitted to where the far cap, the collector and the sun fall in it, the day from the stars and the hour from the lit rod. How far the hull had turned could only be told to a sixth of a turn, so the rock is not lump for lump the same.

Development

npm install
npm run dev      # http://localhost:5173, plus a LAN URL and a QR code for it
npm test         # 279 tests; canon figures are pinned to design.md
npm run build
npm run screenshots  # drive the app and rephotograph docs/screenshots/
npm run screenshots -- --only tour-grand   # just those shots, for working on one view
npm run photos       # render the saved shots in content/photos.json to photos/

npm run dev binds to every interface (vite --host) and prints a scannable QR code of the network URL, so the touch interactions can be tried on a phone on the same Wi-Fi without typing an address. The server is reachable by anyone on that network while it runs; drop the --host if that is not wanted.

Vite + TypeScript, deployed to GitLab Pages by .gitlab-ci.yml on every push to the default branch. Three.js is loaded only when a 3D view is opened, so a reader who stays on the map never downloads it. There is no terrain build step: the world is generated in the browser from world.json, which the build makes from content/world.json (world-generation.md §5).

Every branch is on Pages too. The default branch is at the site root and every other branch at /tower/<branch>/ — forest at https://apps.fuzzyworld.net/tower/forest/ — so a branch can be looked at without a dev server. When the site holds more than one branch, a branch picker in the panel header switches between them, keeping the view and place in the URL. tools/build-pages.sh builds them all from the default branch's pipeline, and a push to any other branch triggers that pipeline, so a preview is a few minutes behind its branch. A branch that fails to build is left out rather than taking the site down. All of them share one origin, so they share browser storage: the remembered view, camera and label setting follow you between branches.

Assets are referenced relatively, so the same build works whether Pages serves it from https://apps.fuzzyworld.net/tower/ or from a generated unique domain at a root. Set a BASE CI variable to force an absolute base if that is ever needed.

When the interior view looks wrong

The interior keeps a flight recorder — the last quarter-minute of camera, draw calls and frame colour — because the rendering faults worth catching there have all been intermittent (decisions.md D-057, D-058). While the fault is still on screen, open the console and call:

towerDump()   // logs the whole state and copies it to the clipboard

The first line is the answer most of the time. It draws each surface alone and measures how colourful it is:

[tower] alone in frame — ground 31.32, sunCap 19, farCap 31.3, bore 19, beam 19  (19 = nothing drawn)

19 is the clear colour, so it means that surface put nothing in the middle of the view — expected for anything currently off screen. The ground reads about 30 when it is carrying land. A ground near 19 while you are looking at the ground is the diagnosis: the ground's tiles are missing or its shader is failing. The dump's terrain entry says which: the world generation the view is drawing, how many tiles are on screen, whether every tile it wants has arrived, and how busy the worker pool is. The rest carries the camera and the per-frame trace, with the tile count in every frame, so the heading the view changed at can be read off afterwards. window.tower is the view itself, and window.towerTerrain the terrain service, for poking at directly.

This is on in the built site as well as in dev, deliberately: the fault has only ever turned up in ordinary use, and it costs two properties on window that do nothing until they are called.

Geography

content/world.json is the world: every feature — mountains, lakes, seas, rivers, desert, forest, settlements and plain markers — with its shape in canon coordinates (θ, z) and its parameters beside it, plus the author's notes. The browser generates the terrain from it live (world-generation.md, decisions.md D-062); there is no build step and there are no terrain images. It is the only copy: what the app loads is world.json, made from it by vite.config.ts — served by the dev server, written into the build — with every note removed and any feature marked "public": false left out. It is never committed, so it cannot drift from the file it comes from. Save content/world.json with npm run dev running and the open page reloads with the change.

Generation is deterministic. The seeds are in the file, so every reader sees the same world the author does, to the tree.

The compiled world is kept in the browser's IndexedDB, keyed by the world and the build that compiled it, so a returning visit to an unchanged world skips compiling.

When the world loads, and after any edit that changes the ground, it is compiled in a worker — rivers given their long profiles, lake levels found, summits measured. If that takes longer than 400 ms a dialog says what Tower is making, one step at a time. A rename, a blurb or a note changes nothing on the ground and regenerates nothing.

The world was ported from v1's content/geography.json by tools/port-world.mjs, kept for reading; there is no backwards compatibility with v1 files.

Reading

The app only reads the world. Select a place — in the list, on the map, or in the interior — to see its detail card: its name, its blurb, where it is, and what the world made of it — a range's named summits, the sea running on a lake or sea now by the clock, how many trees a forest holds and how far apart, what a desert's landforms came to. Shift-click two points on the map to measure a sightline (Esc clears it), and F fits the map. Show labels in the View section — or L, in any view — hides or shows every label at once: the map's place names and captions, and the captions over the exterior and interior. The choice is remembered across reloads.

Changes to the world — a new place, a moved summit, a storm in the weather plan — are made in content/world.json, not in the browser (D-072).

Any selection updates the URL, so a link is always shareable:

#place=the-narrows select and centre a place
#at=0.03,170000 drop a sightline endpoint at (θ, z)

Views

Map is the unrolled inner surface. Exterior is Tower from outside — a kilometre of hull, a window at each cap, the real night sky, the 244 km collector flying ahead and the beam converging into the sun cap. Each piece is captioned.

The stars are Earth's — every naked-eye star in the Yale Bright Star Catalogue, about 9,100 of them to magnitude 6.5, at their true positions, brightnesses and colours. The same sky is seen through the cap windows from inside. Tower's axis points at the sun, so the far cap looks at the point opposite it, and the sky behind Tower turns once a year with the clock's date; from outside, ecliptic north is up. node tools/bright-stars.mjs rebuilds the catalogue file (src/data/bright-stars.json) from CDS.

The hull reads five ways and the Hull switch picks one; it opens on True and remembers whichever you last chose. True is the outer skin: bare structure, and both caps real windows — look in through either and the land is actually there, hazed exactly as the interior view hazes it and receding 540 km down the tube. It is the only line of sight into Tower that is not a diagram. X-ray wraps the terrain onto the outside instead, which is a diagram of what is inside rather than a view of it, and useful precisely because the wall is opaque. Rock and Piping are experiments, not canon. Rock dresses the hull as an asteroid: a cratered, lumpy shell of rock a few kilometres thick laid over the skin, with the windows left clear. Piping dresses it as industrial plant: panelled plating, a band with hoop pipes every ~36 km, bundles of pipes 0.6–2.2 km across running between them, and blocks of plant. Vents open at random, each on its own clock: grilles flare hot and fall back to an ember, and exhaust shoots out and fades. Near each end are thruster pods — what holds Tower's attitude — and every so often one fires a long flame that fans out into space and lights the plating round it. All of it wears a layer of dust, thickest on whatever faces outward. Rock and piping puts the two together: the plant half buried under banks of rock heaped on as shielding, bare plating and plant rooms in the gaps, the bands and pipe runs going under the rock and out again, and the rock dug clear round each thruster pod. The active view is remembered and travels in the permalink, so #view=exterior&place=the-narrows opens where you left off. Drag to orbit, scroll to zoom, click the hull to drop a point. Scenic tour in the exterior's panel flies spacecraft instead: skimming the hull while it turns under them at 700 m/s, docking on it — ships dock anywhere on the shell, and hang from it at 1.02 g — looking in through the far cap, over the collector's rim, down the outside of the beam, and Tower, the collector and the sun in one frame; the spin runs at 1x to 1200x real time, and a point picked off the turning hull still comes back in canon coordinates.

Interior is standing inside. The ground is the real cylinder, built from generated tiles that get finer around you — half a metre between vertices underfoot, half a kilometre on the far side of the world — so it curves up on both sides and closes overhead. Haze is integrated through Tower's rotational air column for every pixel, which reproduces the strangest fact about the place: the land 100 km straight up is 78% clear while the ground 100 km away is 31% — distant geography here is best seen by looking up.

One finger looks and two fingers move (D-059). Dragging with two takes hold of the ground under them and keeps it under them, so the distance covered comes out right by itself and the tilt of your head is the gearing: level, a screen of drag walks you 1.9 km, and tipped 23° down it steps 26 m. On a trackpad the two-finger swipe moves you too, and so does a mouse wheel: a screen's swipe walks about 70 m from standing and some 40 km from a kilometre up, the ground following your fingers. A mouse has only ever one pointer, so shift-drag or the middle button stands in for the second finger. There is no zoom: the field of view is fixed at 60° (D-083). Selecting a place — in the list or by its caption — still walks you there, which is the only way to cross the world in one move: most of it is beyond the haze horizon from any given spot, so travelling is more use than turning.

The forest is trees. Greatwood is about three billion of them, so only the ones you could see as trees exist at any moment: meshes within a couple of hundred metres, then cards turned to face you, then clumps — one card for every thirty metres of wood — out to nearly three kilometres, over a canopy that closes the ground behind them, with the meadows showing through as grass. Which trees stand where is a rule rather than a list, so they are the same trees for everyone and they are still there when you walk back. The Tall Wood is 52 km² of giants near the Capital — 90 to 115 m, about as tall as a tree can be at 1 g — placed once from the world's seed and then left where it fell.

A settlement clears the trees it stands on, so the Capital is a 20 km opening in Greatwood rather than a city in a wood.

The desert is a desert. The Dry Reach rings the world with tiers of rock standing over dune fields, hills, dry washes routed the way water would have routed them, and salt pans in its lowest ground with the shorelines of lakes that never stood stepped around them. None of it is a remnant: Tower had seen deserts on Earth and built one.

The water is water. Lakes, seas and rivers are surfaces at their own levels, with waves sized from each body's wind and fetch, rivers running downstream, and rapids white. A river that cannot slope falls: the Long Water drops 680 m off the range into a gorge, and the falling water drifts antispinward as it goes — the spin, shown by what falls.

The weather is Tower's, and it is published. Waves follow Tower's weather plan: a storm builds the sea over a few hours, whitecaps spread with the wind, and the sea keeps running after the wind drops. Ships sail both ring seas, each on its own lane round the world, riding the waves drawn under it with its mainsail set to the wind. When a gale or storm has been published for their sea in time, they stay in harbour — even if Tower has since called it off, because people act on what they were told — and a squall announced too late catches them at sea. Set the Day under Time, or run the clock, to move through the plan.

Or take the scenic tour. Scenic tour in the view panel hands you from one of the world's flyers to the next, every twelve to eighteen seconds, in an order dealt at random: a paraglider on Snowcrown's flank, a glider circling up in a thermal over the Dry Reach, a helicopter round the great waterfall, a seaplane across The Deep, an airliner round the Girdle — flying antispinward, and so weighing a third of what it would at rest — a giant airship climbing out of the Capital until the world closes overhead, another circling the sun, outside the beam as every aircraft must be, trains on the two railways, and ships in fair weather and in a squall. The camera rides in the craft or chases it, banks with it, and turns to whatever can be seen from there — never at something the haze has eaten. The slow legs are time-lapses and the caption says so. The caption's border fills in clockwise from its top-left corner as the leg runs, and the next leg comes when it closes. N skips ahead; Esc, a drag or a flight key stops it and leaves you where it was.

Or fly. W A S D or the arrow keys move you, E climbs and Q descends, and shift goes five times faster. Speed follows your height above the ground: a brisk walk at standing height, and a sea crossed in seconds from ten kilometres up, with nothing to set in between.

The caps have more than one name. The sun cap is the end the beam comes in at. The far cap is also the star cap, since it is the one that shows the stars, and the night cap, since the night starts there: the sun goes out at it, and the moon sets out from it. More names get added as they come into use.

The far cap is a window — 100 km of it, looking into deep anti-sun space. By day it is simply a disc of blue, because 540 km of air in front of it scatters more light than anything behind it sends; the stars are there at noon and unseeable, which is a fact about eyes rather than about glass. At night they come out. The sun cap is glazed too: it faces the collector, not the sun, so it has nothing to manage the glare of (design.md §1.3.0).

The one part of the far cap that is not glass is a 3.2 km mirror on the axis. A quarter of the beam survives all 540 km and arrives collimated, so it lands as 1.7 MW/m² — 1,200 suns — on a spot a thousandth of the cap's area; the mirror sends it back up the column for a second pass, which lifts the beam's utilisation from 76% to 94%. The rod reaches it at every hour: by day the sun takes part of the beam and the rest runs on past it, so the beam is one line of light from cap to cap with the sun moving along it, and the mirror is a lit disc where the rod ends.

Both caps' windows are framed by mullions in a lattice of identical equilateral triangles, 8.3 km on a side, six meeting at the axis. That is the pitch of the checker the caps once had, so the frame is still the only object in the world with a known size and the only rule anyone has for judging distance, read against sky.

The far end of the world is cold. The far cap's glass is single, and glass does not let heat out as light: it soaks it up and radiates it to space from its outer face, 1–2 TW over the whole cap. So the window is a cold wall, with a cold wind running down it onto the Deepward Sea, and Tower keeps that end dim and lets it freeze: open water at freezing, then pack ice, then fast ice, dusk by day and dark by night — and against the window ice mountains, the Cap Range, 2 to 3 km high: rock Tower raised at the cap's foot for the ice to stand on, since ice alone spreads out before it gets higher than a few hundred metres. The glass frosts too, and Tower clears it one pane per turn of the world, in an order reshuffled every 35.1-hour loop, so close to the window is white with a scatter of clear, starry triangles — from inside and from outside. Tower can do this because it controls how much heat the hull loses where, up to about 5 TW (design.md §1.9.4, §1.9.6; D-090). The sun cap is double-glazed and does none of this: the Sunward Sea is a temperate one.

The farms keep their own days. Nine farms round the world — on the Uplands, in clearings cut out of Greatwood, and before the far end where the railway ends — share 250 km² of farmland — tulips, lavender, sunflowers, rapeseed, poppies, flax, maize, potatoes, tomatoes, wheat and more, most of it in bloom — is lit by Tower as each crop wants: as at noon from sunrise for twelve to eighteen hours, long-day crops on into the night and short-day ones dimmed early, and every one of them given some darkness, which flowering plants need. After sunset the fields blaze in a dark world and go out one crop at a time (design.md §1.9.7; D-095).

Tower has a sun, and it crosses the world once a day. The mirrorlets that fly in the beam gather into one shoal and throw the beam's light out sideways there, which makes a single blazing sun at one point on the beam. It lights at the sun cap at sunrise, moves at a steady pace down the whole length of the world, and reaches the far cap at sunset, where it goes out: that is nightfall. Through the night the beam is banked to a thousandth, and the next morning the sun lights at the sun cap again. So Tower's sun moves from one end of the world to the other, every day.

Tower keeps Pisa's days. Its clock is Pisa's — Italian time, daylight saving included — and its sun comes on at Pisa's sunrise and goes out at Pisa's sunset, so the days lengthen and shorten with Pisa's seasons: about 44 km/h at the equinoxes, when day 0 falls, 61 km/h at midwinter and 35 km/h at midsummer. The city and the date of day 0 are the calendar in content/world.json. (Until D-089 it kept Sydney's.)

Every place has its own noon. Tower aims the swarm so the sun is as bright seen from anywhere as seen from under it, so the ground is lit by how high the sun stands, as it is under Earth's. From The Capital, halfway along, the morning sun is low in the sunward sky, it passes overhead at midday, and it sinks away deepward in the afternoon; it never sets, since 50 km up and 540 km away it is still 5° high. The beam glows from cap to cap at every hour, a little dimmer past the sun, which takes part of it and lets the rest run on to the far cap's mirror (D-079). Inside and out it is the same sun: the exterior looks in through the windows at the one the interior stands under.

By night Tower has a moon. A second, smaller gathering of the swarm lights at the far cap as the sun goes out there, and crosses the world the other way through the night, reaching the sun cap by sunrise. It is as lit as Earth's Moon is that night — full, gibbous, a crescent lit toward the far cap while it waxes and toward the sun cap while it wanes, or nothing at new moon — and it lights the ground by it: a full-moon night is twice as bright as a moonless one, with a path of light across the water toward it. The Time section says where it is and how lit, and the map draws a pale line where it is overhead.

The clock opens at the time in Pisa now, and runs. It starts from Pisa's current date and time and goes forward at whatever speed it was last run at — 900x until you choose another, and 1x keeps it in step with Pisa. Add ?clock=<hours> to the address to hold it at a moment instead, stopped: ?clock=12 is noon on day 0. That is how the screenshot tour gets the same sky every run.

Time, in the panel, works in every view: the Day (with its date in Pisa), the Time of day, Run the clock and its rate, and the Light — how bright Tower runs its day. It says when the sun rises and sets and where it is now, and the map marks it. Dark shuts the 54 TW beam down entirely and is the only setting that is genuinely black — no sun, no airlight, no rod, and nothing left in the world but the sky. Twilight, Temperate and Full set how bright the day is; night comes by itself, with the clock.

Eye height is a gauge up the right-hand side of the view, from 1.7 m to the beam, 48.4 km up, on a log scale: drag it, or click it and use the arrow keys. It is marked with things of known height — an adult, a two-storey house, the Eiffel Tower, Everest, an airliner cruising, a weather balloon, and at the top the beam itself — which light up as you pass them, and the readout by the thumb gives the height, the local gravity, and what it compares with ("≈ the Eiffel Tower", "2.0× the Burj Khalifa"). On a phone that readout fades once the height has been still for two seconds, and comes back as soon as it changes or you touch the gauge. The Where you stand readout in the bottom-left corner folds down to its title with a click, and stays as you left it; on a phone it starts folded.

Nothing inside rotates, because you, the ground and the air all turn together. The exception is the window: the sky out there does not co-rotate, and wheels once every 7 min 29 s about the one motionless star on the axis. It is the one sign of the spin anywhere in the view, and it is only available at night, at the deepward end, looking the one direction that has ever had anything in it but Tower.

What the world file says

Each feature in content/world.json has a kind, a shape — a point, an open line (a river runs source first), an outline, or a band ringing the world — and its kind's parameters beside it. Changing any of them is a conversation and an edit to the file; the ground regenerates on the next load. This is what the parameters mean.

A mountain range has named summits, each held at exactly its elevation, and parameters for how high its unnamed summits stand and how many there are, how rugged it is, how deeply water cuts it, and its snowline. A change regenerates the range — a few seconds for the Girdle, under the status dialog.

A lake or sea has a wind: the direction it blows toward and its speed. That is its usual wind, which blows whenever the weather plan has nothing scheduled. The detail card says what sea is running there now, by the clock — a 10 m/s wind over The Deep makes waves under a metre; the same wind round a ring sea, which never runs out of water to blow over, makes 2 m, and 20 m/s makes 8.6. A sea also has a number of ships.

Weather is Tower's plan: events over a lake or sea, each published at a moment and revisable later with a reason — the storm eased because someone foolish went sailing — and a number of days the plan takes to repeat. The panel's Weather section shows what is blowing now and the next fortnight, as far as it has been published, with any revision listed under the event it changed and the original struck through. None of it regenerates the ground.

A settlement has a size — hamlet, village, town, city or station — and how far it reaches. It is a point with an extent, not a traced outline: Tower lays the streets out inside it. The Capital is 20 km across, centred on the axial midpoint of the world, which is just wide enough to put its spinward edge on The Deep's shore.

A forest has what Tower planted there: stems per hectare, how much of it is conifer, how much of the ground is left open as meadows, the treeline, and whether it is a wood of giants. The detail card says what that comes to — how many trees, over how much ground, how far apart, and how high the canopy stands.

A desert has its landforms: how high its dunes stand, how far apart, and which way Tower blows the sand; how much of it is rocky hills; how tall its plateaus are, how much of the ground they cover, and how many cliff bands they are cut into; and how much past water Tower quotes there — dry washes, how many salt pans, and whether they are ringed by the shorelines of lakes that never stood. The detail card says what was actually made: "24% standing rock, 37% dune field, 35% cut by washes, 4 salt pans."

A railway is a line with a line speed. Its track keeps a grade of its own over the ground rather than cutting it — the highest ground within a kilometre either side, eased — so it stands on piers much of the way and crosses the gorges on viaducts. There are two: the Axial Line, from Sisters Station through The Narrows and past the Capital to the Deepward Sea, and the Uplands Ring, round the world at 140 km, whose trains weigh 31% more running spinward and 27% less running antispinward.

A region is a label, and it can also be ground Tower raised: give it an uplift and everything inside it is lifted to that height above the open ground, wherever that is higher than what is there. The Uplands are one.

Every feature also has a blurb, shown to readers; notes, which are the author's and never reach the app — though the repository is public, so they are not secret; public, false for a feature not ready to exist in the app at all; and a seed, written once, so it generates the same forever.

Canon is 0 star slats — the hull is sealed, the inner surface is one unbroken 169,646 km², and the only views out are at the end caps. The runtime control for this is disabled and hidden (decisions.md D-033): the world is generated as one unbroken surface, so any other count draws bands over land that has none.

Source
1# Tower
2
3**Live map — <https://apps.fuzzyworld.net/tower/>** · [Source](https://code.fuzzyworld.net/tower/)
4
5Companion piece to a novel set inside **Tower** — a fictional smart cylinder orbiting Earth,
6spun for 1 g, with an inner surface the size of Wisconsin, lit by 54 TW of sunlight
7piped down its axis and scattered by mirrors that make its days and nights. Its wall
8is a kilometre of sealed hull: no windows along all 540 km, and no view of the Earth
9it orbits. Both end caps are windows, though — 100 km of glass each, and the only
10places in the world with a horizon that is not Tower. Nobody aboard can see the sun
11either: the 244 km collector sits between Tower and it, 79 times its diameter, so
12the sun cap looks out at a black disc and the stars around it — black except at its
13edge, where the structure holding it flat catches the sun side-on and traces the
14whole 244 km in a thin sun-coloured ring.
15
16Explore Tower from outside, pick a spot on the inner surface, and stand there — with
17the ground curving up on both sides and the far side of the world hanging 100 km
18overhead, clearer than the ground at your feet. Turn its sun up to Earth clear-sky
19noon, down to permanent dusk, or shut the beam off entirely and watch the sky come
20out: through the far cap the stars wheel once every 7 min 29 s about a single
21motionless star on the axis. Nothing inside Tower rotates, because you and the
22ground and the air all turn together — so that window is the only place the spin is
23visible at all.
24
25Tower flies all 78 billion mirrors of its own sunlight, individually, because
26nothing passive would stay in the beam past mid-afternoon. It is a person.
27
28## Status
29
30**All three views are built** — map, exterior and interior — over a world that
31**generates itself live, in the browser**, from a file of authored features.
32
33Built: the unrolled surface map, Tower from outside, standing inside it and flying
34over it, a detail card for every place, Tower's published weather, a sun that crosses
35the world each day on Pisa's clock and a moon by night with Earth's phases, two railways, a scenic tour that flies the world's
36paragliders, aircraft, airships, trains and spacecraft inside and out, permalinks, and the
37sightline probe.
38
39**The app is for looking; the world is changed in the repository.** The author writes
40alongside Tower rather than in it, and changes the world by talking it through with
41Claude, who edits [`content/world.json`](content/world.json). That file is the one
42authoritative copy — there is no editor in the browser, no local draft, and nothing to
43import or export (decisions.md D-072).
44
45**In progress: [world-generation.md](world-generation.md).** Phases 1 to 5 are built —
46the terrain is no longer baked into images by a build step; every mountain, lake,
47sea, river, desert and forest is a feature the browser turns into ground on demand,
48in web workers, from a metre underfoot to the whole world. Mountain ranges are summits
49joined by ridges and cut by water into valleys; lakes, seas and rivers are water with
50waves, flow and waterfalls; Tower publishes a weather plan, and ships sail the ring seas
51by it. The Dry Reach has mesas, dune fields, dry washes and salt pans, and Greatwood is
52three billion individual trees with meadows through it and a wood of 100 m giants near the
53Capital. Phases 7–8 add settlements and roads.
54
55- [design.md](design.md) — canon, physics and application architecture
56- [world-generation.md](world-generation.md) — how the world is generated, and the plan
57- [decisions.md](decisions.md) — choices made and why
58
59Both are series-bible material: coherence outranks spectacle, and the prose is
60downstream of them.
61
62On a phone the sidebar is a **drawer** rather than a column: below 720 px the world
63gets the whole screen and the panel slides in over it, one tap away and one tap
64gone. Picking a place closes it, because in every view selecting a place is how you
65travel there — see [decisions.md](decisions.md) D-043.
66
67## Screenshots
68
69[![Every shot on one sheet](docs/screenshots/overview.png)](docs/screenshots/overview.png)
70
71`npm run screenshots` drives the real application in a headless browser — clicking
72the view buttons, picking places out of the list, dragging to orbit and to look up —
73and writes [`docs/screenshots/`](docs/screenshots/). Taking them *through the UI* is
74the point: a shot taken this way fails when the UI fails, so a black canvas ends up
75in the picture instead of hiding behind a passing unit test.
76
77A scene the tour photographs is held at one moment with the water's clock stopped too, so
78the sea in a shot is the same sea every run and a divergence means a real change.
79`--only <ids>` retakes a few shots and leaves the sheet alone.
80
81The whole tour takes about **three minutes**, and waits on the world being
82generated rather than on fixed delays: a shot is taken once the terrain has compiled, the
83map is drawn, and every tile of ground the view wants has arrived. It is kept light on the
84machine: the world is **compiled once** for the whole tour and every shot starts from that
85cache, and each page runs **two** terrain workers rather than a full pool — four pages at
86once each compiling the world with six workers was a laptop running hot. It once took six and a
87half minutes, nearly all of them spent rendering Tower's haze integral on the CPU —
88the default headless browser has no GPU. It now asks for the full Chrome build, which reaches
89the real one, and photographs four shots at a time, since a shot is mostly spent
90waiting. The cost is that the committed images are tied to the GPU that drew them:
91another machine will show a large one-off divergence rather than a regression.
92
93| Desktop — 1440×900 | |
94|---|---|
95| [map](docs/screenshots/desktop-map.png) | the unrolled inner surface, with a place selected |
96| [map-sightline](docs/screenshots/desktop-map-sightline.png) | shift-click two points to measure a sightline through the air |
97| [exterior](docs/screenshots/desktop-exterior.png) | x-ray hull — the inner surface projected out, with the caps and the collector |
98| [exterior-true](docs/screenshots/desktop-exterior-true.png) | true hull — bare skin, and the land visible through the far cap window |
99| [interior](docs/screenshots/desktop-interior.png) | standing at The Narrows, the ground curving up on both sides |
100| [tour-falls](docs/screenshots/desktop-tour-falls.png) | scenic tour: a helicopter circling the Long Water's 680 m fall |
101| [tour-falls-glide](docs/screenshots/desktop-tour-falls-glide.png) | scenic tour: a paraglider past the same fall |
102| [tour-ship](docs/screenshots/desktop-tour-ship.png) | scenic tour: following a ship round the Sunward Sea |
103| [tour-squall](docs/screenshots/desktop-tour-squall.png) | scenic tour: a ship caught out by a gale Tower gave no warning of |
104| [tour-summit](docs/screenshots/desktop-tour-summit.png) | scenic tour: an airship off Snowcrown, 4,300 m |
105| [tour-ridge](docs/screenshots/desktop-tour-ridge.png) | scenic tour: a paraglider ridge-soaring on a summit's flank |
106| [tour-thermal](docs/screenshots/desktop-tour-thermal.png) | scenic tour: a glider climbing in a thermal over the Dry Reach |
107| [tour-mesas](docs/screenshots/desktop-tour-mesas.png) | scenic tour: past the mesas of the Dry Reach, strata lining up across all of them |
108| [tour-giants](docs/screenshots/desktop-tour-giants.png) | scenic tour: under the giants of the Tall Wood, 115 m of them |
109| [tour-canopy](docs/screenshots/desktop-tour-canopy.png) | scenic tour: low over Greatwood, closed canopy and the meadows left open in it |
110| [tour-deep](docs/screenshots/desktop-tour-deep.png) | scenic tour: a seaplane out from the Capital over The Deep |
111| [tour-girdle](docs/screenshots/desktop-tour-girdle.png) | scenic tour: an airliner over the Girdle, antispinward and lighter for it |
112| [tour-climb](docs/screenshots/desktop-tour-climb.png) | scenic tour: a giant airship climbing out of the Capital, the world closing overhead |
113| [tour-sun-circuit](docs/screenshots/desktop-tour-sun-circuit.png) | scenic tour: a giant airship round the sun, outside the beam |
114| [tour-far-cap](docs/screenshots/desktop-tour-far-cap.png) | scenic tour: toward the far cap by night |
115| [tour-moonlight](docs/screenshots/desktop-tour-moonlight.png) | scenic tour: over The Deep by the light of Tower's moon |
116| [tour-train-narrows](docs/screenshots/desktop-tour-train-narrows.png) | scenic tour: a train on the Axial Line through The Narrows |
117| [tour-train-ring](docs/screenshots/desktop-tour-train-ring.png) | scenic tour: a train on the Uplands Ring |
118| [tour-grand](docs/screenshots/desktop-tour-grand.png) | scenic tour: outside: Tower, its collector and the sun in one frame |
119| [tour-docking](docs/screenshots/desktop-tour-docking.png) | scenic tour: outside: a spacecraft docking on the shell |
120| [tour-far-cap-peek](docs/screenshots/desktop-tour-far-cap-peek.png) | scenic tour: outside: looking in through the far cap |
121| [tour-hull-skim](docs/screenshots/desktop-tour-hull-skim.png) | scenic tour: outside: skimming the hull as it turns |
122| [interior-overhead](docs/screenshots/desktop-interior-overhead.png) | looking up: the far side 100 km overhead is clearer than ground 100 km away |
123| [interior-morning](docs/screenshots/desktop-interior-morning.png) | 06:30 — the sun just out from the sun cap and coming, the rod lit only behind it |
124| [detail](docs/screenshots/desktop-detail.png) | a place selected: its detail card, with what the world made of it |
125
126| Mobile — 390×844 | |
127|---|---|
128| [map](docs/screenshots/mobile-map.png) | the world with the whole screen, the panel one tap away |
129| [exterior](docs/screenshots/mobile-exterior.png) | the spin readout dropped clear of the panel button |
130| [interior](docs/screenshots/mobile-interior.png) | the standing readout at a size that fits 390 px |
131| [panel](docs/screenshots/mobile-panel.png) | the sidebar as a drawer, opened over the world |
132
133### Looking before committing
134
135[`overview.png`](docs/screenshots/overview.png) is a contact sheet of every shot. It
136exists to be **looked at, once, before committing** — one image that answers "is the
137application still there?". Regenerate, glance at it, then commit.
138
139`--check` puts a number on the same question. Every shot is compared against the
140committed one and the run fails if any of them moved too far:
141
142```
143npm run screenshots -- --check # fail past 3% divergence on any shot
144npm run screenshots -- --threshold 8 # report only, looser bar
145npm run screenshots -- --url http://localhost:5173 # use a dev server already up
146```
147
148The threshold is measured at both ends, not guessed. The 2D shots come out
149**byte-identical** between runs — nothing in Tower is stochastic, the exterior spin
150is switched off, and every shot gets a fresh browser context so no camera leaks into
151the next. **The WebGL shots do not**, because the tour draws on the real GPU and
152Metal does not schedule floating-point work identically twice; they drift by 0.1% to
153**0.9%**. Against that, hiding both 3D canvases scored **7% to 31%**, and a view
154going entirely black scores 12% to 39%.
155
156**3% is three times the worst noise and less than half the mildest real failure.**
157It is a smoke alarm, not a verdict: when it fires, go and look at the sheet. Note
158that a view which never worked scores 0% when it breaks further — this catches
159regressions, not things that were already broken.
160
161## Photographs
162
163A view worth keeping — things lined up, at a particular time — is saved as numbers and
164rendered again whenever it is wanted, so an illustration can always be remade from the
165latest world and the latest renderer (D-099).
166
1671. `npm run dev`, open the **exterior** or the **interior**, and frame the shot: the camera,
168 the day and time, the Light, the hull.
1692. Press **P**, or **Save this shot** under View, and give it a name. The shot goes into
170 [`content/photos.json`](content/photos.json). Saving under a name already in the list
171 re-frames that shot. The button and the key exist only on a dev server, and it takes a
172 shot only from the machine it runs on; the published site has neither.
1733. `npm run photos` renders every shot to `photos/<name>.png`.
174
175To go back to a shot, pick it from **Saved shots**, under the button: the app opens its
176view, puts the camera where the shot has it, and stops the clock at its moment (and,
177outside, the spin), and carries on from there. Adjust it and save under the same name —
178the name is filled in — to re-frame it. The list is read from the file each time it is
179opened, so a shot typed by hand is in it too.
180
181```
182npm run photos # every shot in content/photos.json
183npm run photos -- --only far-cap # just the shots whose names start so
184npm run photos -- --long-edge 5760 # bigger; the default is 3840 (4K)
185npm run photos -- --url http://localhost:5173 # use a dev server already up
186```
187
188A render is **the view alone** — no panel, no readouts, no gauge, no labels — at the shape
189of the window the shot was framed in, 3840 px along its long edge. The file name never
190changes, so rendering again replaces the picture with the newest version of itself.
191`photos/` is not committed: the list is what is kept, and the pictures are made from it.
192
193An entry is plain numbers, and is meant to be edited by hand as well:
194
195| | |
196|---|---|
197| `id` | the file's name: lower-case letters, digits, hyphens |
198| `note` | anything worth remembering; kept when the shot is re-framed |
199| `view` | `exterior` or `interior` |
200| `hours` | the world clock, hours since day 0 began (day 2, 06:30 is `54.5`) |
201| `dial` | the Light: `dark`, `twilight`, `temperate`, `full` |
202| `aspect` | width over height of the frame |
203| interior: `theta`, `z`, `eyeM` | where the observer stands: radians round, metres from the sun cap, eye height in metres |
204| interior: `yaw`, `pitch`, `fovDeg` | heading in radians from deepward (`0` faces the far cap, `3.14159` the sun cap), elevation in radians, field of view in degrees |
205| interior: `spin` | how far the sky through the far cap has wheeled, radians |
206| exterior: `position`, `target` | the camera and the point it looks at, in kilometres |
207| exterior: `phase`, `hull` | how far the hull has turned, radians; and the hull reading |
208| exterior: `fovDeg` | field of view in degrees. The view's own is `42` and it has no zoom, so a saved shot says `42`; type a smaller number to frame it tighter |
209
210A render holds still: the hull does not turn, the sky through the far cap does not wheel,
211and the water is held at one moment, so the same entry gives the same file every time. A
212shot cannot be saved while a scenic tour is running — its flyers belong to the tour — so
213stop the tour first.
214
215The list holds the two caps as seen from 300 m over the Capital at 08:45, and
216`tower-from-the-far-end`, the blog illustration of 2026-08-19 worked back from its JPEG:
217the camera and the field of view fitted to where the far cap, the collector and the sun
218fall in it, the day from the stars and the hour from the lit rod. How far the hull had
219turned could only be told to a sixth of a turn, so the rock is not lump for lump the same.
220
221## Development
222
223```
224npm install
225npm run dev # http://localhost:5173, plus a LAN URL and a QR code for it
226npm test # 279 tests; canon figures are pinned to design.md
227npm run build
228npm run screenshots # drive the app and rephotograph docs/screenshots/
229npm run screenshots -- --only tour-grand # just those shots, for working on one view
230npm run photos # render the saved shots in content/photos.json to photos/
231```
232
233`npm run dev` binds to every interface (`vite --host`) and prints a scannable QR
234code of the network URL, so the touch interactions can be tried on a phone on the
235same Wi-Fi without typing an address. The server is reachable by anyone on that
236network while it runs; drop the `--host` if that is not wanted.
237
238Vite + TypeScript, deployed to GitLab Pages by `.gitlab-ci.yml` on every push to the
239default branch. Three.js is loaded only when a 3D view is opened, so a reader who
240stays on the map never downloads it. There is no terrain build step: the world is
241generated in the browser from `world.json`, which the build makes from
242`content/world.json` (world-generation.md §5).
243
244**Every branch is on Pages too.** The default branch is at the site root and every other
245branch at `/tower/<branch>/` — `forest` at <https://apps.fuzzyworld.net/tower/forest/> —
246so a branch can be looked at without a dev server. When the site holds more than one
247branch, a **branch picker** in the panel header switches between them, keeping the view and
248place in the URL. [`tools/build-pages.sh`](tools/build-pages.sh) builds them all from the
249default branch's pipeline, and a push to any other branch triggers that pipeline, so a
250preview is a few minutes behind its branch. A branch that fails to build is left out rather
251than taking the site down. All of them share one origin, so they share browser storage: the
252remembered view, camera and label setting follow you between branches.
253
254Assets are referenced **relatively**, so the same build works whether Pages serves
255it from `https://apps.fuzzyworld.net/tower/` or from a generated unique domain
256at a root. Set a `BASE` CI variable to force an absolute base if that is ever
257needed.
258
259### When the interior view looks wrong
260
261The interior keeps a flight recorder — the last quarter-minute of camera, draw calls
262and frame colour — because the rendering faults worth catching there have all been
263intermittent (decisions.md D-057, D-058). While the fault is **still on screen**, open
264the console and call:
265
266```js
267towerDump() // logs the whole state and copies it to the clipboard
268```
269
270The first line is the answer most of the time. It draws each surface alone and
271measures how colourful it is:
272
273```
274[tower] alone in frame — ground 31.32, sunCap 19, farCap 31.3, bore 19, beam 19 (19 = nothing drawn)
275```
276
277`19` is the clear colour, so it means that surface put nothing in the middle of the
278view — expected for anything currently off screen. The ground reads about `30` when it
279is carrying land. **A ground near `19` while you are looking at the ground is the
280diagnosis**: the ground's tiles are missing or its shader is failing. The dump's
281`terrain` entry says which: the world generation the view is drawing, how many tiles are
282on screen, whether every tile it wants has arrived, and how busy the worker pool is. The
283rest carries the camera and the per-frame trace, with the tile count in every frame, so
284the heading the view changed at can be read off afterwards. `window.tower` is the view
285itself, and `window.towerTerrain` the terrain service, for poking at directly.
286
287This is on in the built site as well as in dev, deliberately: the fault has only ever
288turned up in ordinary use, and it costs two properties on `window` that do nothing
289until they are called.
290
291## Geography
292
293[`content/world.json`](content/world.json) is the world: every feature — mountains,
294lakes, seas, rivers, desert, forest, settlements and plain markers — with its shape in
295canon coordinates (θ, z) and its parameters beside it, plus the author's notes. The
296browser generates the terrain from it live (world-generation.md, decisions.md D-062);
297there is no build step and there are no terrain images.
298It is the **only copy**: what the app loads is `world.json`, made from it by
299[`vite.config.ts`](vite.config.ts) — served by the dev server, written into the build —
300with every note removed and any feature marked `"public": false` left out. It is never
301committed, so it cannot drift from the file it comes from. Save `content/world.json`
302with `npm run dev` running and the open page reloads with the change.
303
304Generation is deterministic. The seeds are in the file, so every reader sees the same
305world the author does, to the tree.
306
307The compiled world is kept in the browser's IndexedDB, keyed by the world and the build
308that compiled it, so a returning visit to an unchanged world skips compiling.
309
310When the world loads, and after any edit that changes the ground, it is compiled in a
311worker — rivers given their long profiles, lake levels found, summits measured. If that
312takes longer than 400 ms a dialog says what Tower is making, one step at a time. A
313rename, a blurb or a note changes nothing on the ground and regenerates nothing.
314
315The world was ported from v1's `content/geography.json` by
316[`tools/port-world.mjs`](tools/port-world.mjs), kept for reading; there is no
317backwards compatibility with v1 files.
318
319## Reading
320
321The app only reads the world. Select a place — in the list, on the map, or in the
322interior — to see its detail card: its name, its blurb, where it is, and what the world
323made of it — a range's named summits, the sea running on a lake or sea *now* by the
324clock, how many trees a forest holds and how far apart, what a desert's landforms came
325to. **Shift-click two points** on the map to measure a sightline (Esc clears it), and
326**F** fits the map. **Show labels** in the View section — or **L**, in any view — hides
327or shows every label at once: the map's place names and captions, and the captions over
328the exterior and interior. The choice is remembered across reloads.
329
330Changes to the world — a new place, a moved summit, a storm in the weather plan — are
331made in `content/world.json`, not in the browser (D-072).
332
333Any selection updates the URL, so a link is always shareable:
334
335| | |
336|---|---|
337| `#place=the-narrows` | select and centre a place |
338| `#at=0.03,170000` | drop a sightline endpoint at (θ, z) |
339
340## Views
341
342**Map** is the unrolled inner surface. **Exterior** is Tower from outside — a
343kilometre of hull, a window at each cap, the real night sky, the 244 km collector
344flying ahead and the beam converging into the sun cap. Each piece is captioned.
345
346**The stars are Earth's** — every naked-eye star in the Yale Bright Star Catalogue, about
3479,100 of them to magnitude 6.5, at their true positions, brightnesses and colours. The same
348sky is seen through the cap windows from inside. Tower's axis points at the sun, so the far
349cap looks at the point opposite it, and the sky behind Tower turns once a year with the
350clock's date; from outside, ecliptic north is up. `node tools/bright-stars.mjs` rebuilds
351the catalogue file (`src/data/bright-stars.json`) from CDS.
352
353The hull reads five ways and the **Hull** switch picks one; it opens on True and
354remembers whichever you last chose. **True** is the outer
355skin: bare structure, and both caps real windows — look in through either and the
356land is actually there, hazed exactly as the interior view hazes it and receding
357540 km down the tube. It is the only line
358of sight into Tower that is not a diagram. **X-ray** wraps the terrain onto the
359outside instead, which is a diagram of what is inside rather than a view of it, and
360useful precisely because the wall is opaque. **Rock** and **Piping** are experiments, not
361canon. Rock dresses the hull as an asteroid: a cratered, lumpy shell of rock a few
362kilometres thick laid over the skin, with the windows left clear. Piping dresses it as
363industrial plant: panelled plating, a band with hoop pipes every ~36 km, bundles of pipes
3640.6–2.2 km across running between them, and blocks of plant. Vents open at random, each
365on its own clock: grilles flare hot and fall back to an ember, and exhaust shoots out and
366fades. Near each end are thruster pods — what holds Tower's attitude — and every so often
367one fires a long flame that fans out into space and lights the plating round it. All of it
368wears a layer of dust, thickest on whatever faces outward. **Rock and piping** puts the
369two together: the plant half buried under banks of rock heaped on as shielding, bare
370plating and plant rooms in the gaps, the bands and pipe runs going under the rock and out
371again, and the rock dug clear round each thruster pod. The active view is remembered and travels in the permalink, so
372`#view=exterior&place=the-narrows` opens where you left off. Drag to orbit, scroll to zoom, click the hull to drop a point.
373**Scenic tour** in the exterior's panel flies spacecraft instead: skimming the hull while it
374turns under them at 700 m/s, docking on it — ships dock anywhere on the shell, and hang from
375it at 1.02 g — looking in through the far cap, over the collector's rim, down the outside of
376the beam, and Tower, the collector and the sun in one frame; the spin runs at
3771x to 1200x real time, and a point picked off the turning hull still comes back in
378canon coordinates.
379
380**Interior** is standing inside. The ground is the real cylinder, built from
381generated tiles that get finer around you — half a metre between vertices underfoot,
382half a kilometre on the far side of the world — so it curves up on both sides and
383closes overhead. Haze is integrated through Tower's rotational air column for
384every pixel, which reproduces the strangest fact about the place: the land 100 km
385straight up is **78%** clear while the ground 100 km away is **31%** — distant
386geography here is best seen by looking up.
387
388**One finger looks and two fingers move** (D-059). Dragging with two takes hold of
389the ground under them and keeps it under them, so the distance covered comes out
390right by itself and the tilt of your head is the gearing: level, a screen of drag
391walks you 1.9 km, and tipped 23° down it steps 26 m. On a trackpad the two-finger
392swipe moves you too, and so does a mouse wheel: a screen's swipe walks about 70 m from
393standing and some 40 km from a kilometre up, the ground following your fingers. A
394mouse has only ever one pointer, so shift-drag or the middle button stands in for the
395second finger. There is no zoom: the field of view is fixed at 60° (D-083). Selecting a place — in the list or by its
396caption — still **walks you there**, which is the only way to cross the world in
397one move: most of it is beyond the haze horizon from any given spot, so travelling
398is more use than turning.
399
400**The forest is trees.** Greatwood is about three billion of them, so only the ones you
401could see as trees exist at any moment: meshes within a couple of hundred metres, then
402cards turned to face you, then clumps — one card for every thirty metres of wood — out to
403nearly three kilometres, over a canopy that closes the ground behind them, with the meadows
404showing through as grass. Which trees stand where is a rule rather than a list, so they are the
405same trees for everyone and they are still there when you walk back. **The Tall Wood** is
40652 km² of giants near the Capital — 90 to 115 m, about as tall as a tree can be at 1 g —
407placed once from the world's seed and then left where it fell.
408
409A settlement clears the trees it stands on, so the Capital is a 20 km opening in Greatwood
410rather than a city in a wood.
411
412**The desert is a desert.** The Dry Reach rings the world with tiers of rock standing over
413dune fields, hills, dry washes routed the way water would have routed them, and salt pans
414in its lowest ground with the shorelines of lakes that never stood stepped around them.
415None of it is a remnant: Tower had seen deserts on Earth and built one.
416
417**The water is water.** Lakes, seas and rivers are surfaces at their own levels, with
418waves sized from each body's wind and fetch, rivers running downstream, and rapids white.
419A river that cannot slope falls: the Long Water drops 680 m off the range into a gorge,
420and the falling water drifts antispinward as it goes — the spin, shown by what falls.
421
422**The weather is Tower's, and it is published.** Waves follow Tower's weather plan: a
423storm builds the sea over a few hours, whitecaps spread with the wind, and the sea keeps
424running after the wind drops. **Ships** sail both ring seas, each on its own lane round the
425world, riding the waves drawn under it with its mainsail set to the wind. When a gale or
426storm has been published for their sea in time, they stay in harbour — even if Tower has
427since called it off, because people act on what they were told — and a squall announced
428too late catches them at sea. Set the **Day** under **Time**, or run the clock, to move
429through the plan.
430
431**Or take the scenic tour.** *Scenic tour* in the view panel hands you from one of the
432world's flyers to the next, every twelve to eighteen seconds, in an order dealt at random:
433a paraglider on Snowcrown's flank, a glider circling up in a thermal over the Dry Reach, a
434helicopter round the great waterfall, a seaplane across The Deep, an airliner round the
435Girdle — flying antispinward, and so weighing a third of what it would at rest — a giant
436airship climbing out of the Capital until the world closes overhead, another circling the
437sun, outside the beam as every aircraft must be, trains on the two railways, and ships in
438fair weather and in a squall. The camera rides in the craft or chases it, banks with it,
439and turns to whatever can be seen from there — never at something the haze has eaten. The
440slow legs are time-lapses and the caption says so. The caption's border fills in clockwise
441from its top-left corner as the leg runs, and the next leg comes when it closes. **N** skips ahead; **Esc**, a drag or a
442flight key stops it and leaves you where it was.
443
444**Or fly.** W A S D or the arrow keys move you, E climbs and Q descends, and shift
445goes five times faster. Speed follows your height above the ground: a brisk walk
446at standing height, and a sea crossed in seconds from ten kilometres up, with nothing
447to set in between.
448
449**The caps have more than one name.** The **sun cap** is the end the beam comes in at. The
450**far cap** is also the **star cap**, since it is the one that shows the stars, and the **night
451cap**, since the night starts there: the sun goes out at it, and the moon sets out from it. More
452names get added as they come into use.
453
454**The far cap is a window** — 100 km of it, looking into deep anti-sun space. By day
455it is simply a disc of blue, because 540 km of air in front of it scatters more
456light than anything behind it sends; the stars are there at noon and unseeable,
457which is a fact about eyes rather than about glass. At night they
458come out. The sun cap is glazed too: it faces the collector, not the sun, so it has
459nothing to manage the glare of (design.md §1.3.0).
460
461The one part of the far cap that is not glass is a **3.2 km mirror** on the axis.
462A quarter of the beam survives all 540 km and arrives collimated, so it lands as
4631.7 MW/m² — 1,200 suns — on a spot a thousandth of the cap's area; the mirror sends
464it back up the column for a second pass, which lifts the beam's utilisation from 76%
465to 94%. The rod reaches it at every hour: by day the sun takes part of the beam and the
466rest runs on past it, so the beam is one line of light from cap to cap with the sun
467moving along it, and the mirror is a lit disc where the rod ends.
468
469Both caps' windows are framed by **mullions** in a lattice of identical equilateral
470triangles, 8.3 km on a side, six meeting at the axis. That is the pitch of the checker the
471caps once had, so the frame is still the only object in the world with a known size and
472the only rule anyone has for judging distance, read against sky.
473
474**The far end of the world is cold.** The far cap's glass is single, and glass does not let
475heat out as light: it soaks it up and radiates it to space from its outer face, 1–2 TW over
476the whole cap. So the window is a cold wall, with a cold wind running down it onto the
477Deepward Sea, and Tower keeps that end dim and lets it freeze: open water at freezing, then
478pack ice, then fast ice, dusk by day and dark by night — and against the window **ice
479mountains**, the Cap Range, 2 to 3 km high: rock Tower raised at the cap's foot for the ice
480to stand on, since ice alone spreads out before it gets higher than a few hundred metres. The
481glass frosts too, and Tower clears it one pane per turn of the world, in an order reshuffled
482every 35.1-hour loop, so close to the window is white with a scatter of clear, starry
483triangles — from inside and from outside. Tower can do this because it controls how much heat
484the hull loses where, up to about 5 TW (design.md §1.9.4, §1.9.6; D-090). The sun cap is
485double-glazed and does none of this: the Sunward Sea is a temperate one.
486
487**The farms keep their own days.** Nine farms round the world — on the Uplands, in clearings
488cut out of Greatwood, and before the far end where the railway ends — share 250 km² of
489farmland — tulips, lavender, sunflowers, rapeseed, poppies, flax, maize, potatoes, tomatoes,
490wheat and more, most of it in bloom — is lit by Tower as each crop wants: as at noon from
491sunrise for twelve to eighteen hours, long-day crops on into the night and short-day ones
492dimmed early, and every one of them given some darkness, which flowering plants need. After
493sunset the fields blaze in a dark world and go out one crop at a time (design.md §1.9.7;
494D-095).
495
496**Tower has a sun, and it crosses the world once a day.** The mirrorlets that fly in the
497beam gather into one shoal and throw the beam's light out sideways there, which makes a
498single blazing sun at one point on the beam. It lights at the **sun cap** at sunrise, moves
499at a steady pace down the whole length of the world, and reaches the **far cap** at sunset,
500where it goes out: that is nightfall. Through the night the beam is banked to a thousandth,
501and the next morning the sun lights at the sun cap again. So Tower's sun moves from one end
502of the world to the other, every day.
503
504**Tower keeps Pisa's days.** Its clock is Pisa's — Italian time, daylight saving included —
505and its sun comes on at Pisa's sunrise and goes out at Pisa's sunset, so the days lengthen and
506shorten with Pisa's seasons: about 44 km/h at the equinoxes, when day 0 falls, 61 km/h at
507midwinter and 35 km/h at midsummer. The city and the date of day 0 are the `calendar` in
508`content/world.json`. (Until D-089 it kept Sydney's.)
509
510**Every place has its own noon.** Tower aims the swarm so the sun is as bright seen from
511anywhere as seen from under it, so the ground is lit by how high the sun stands, as it is
512under Earth's. From The Capital, halfway along, the morning sun is low in the sunward sky,
513it passes overhead at midday, and it sinks away deepward in the afternoon; it never sets,
514since 50 km up and 540 km away it is still 5° high. The **beam** glows from cap to cap at
515every hour, a little dimmer past the sun, which takes part of it and lets the rest run on to
516the far cap's mirror (D-079). Inside and out it is the same sun: the exterior looks in through
517the windows at the one the interior stands under.
518
519**By night Tower has a moon.** A second, smaller gathering of the swarm lights at the far cap
520as the sun goes out there, and crosses the world the other way through the night, reaching the
521sun cap by sunrise. It is as lit as Earth's Moon is that night — full, gibbous, a crescent lit
522toward the far cap while it waxes and toward the sun cap while it wanes, or nothing at new moon
523— and it lights the ground by it: a full-moon night is twice as bright as a moonless one, with
524a path of light across the water toward it. The Time section says where it is and how lit, and
525the map draws a pale line where it is overhead.
526
527**The clock opens at the time in Pisa now, and runs.** It starts from Pisa's current
528date and time and goes forward at whatever speed it was last run at — 900x until you choose
529another, and 1x keeps it in step with Pisa. Add **`?clock=<hours>`** to the address to
530hold it at a moment instead, stopped: `?clock=12` is noon on day 0. That is how the
531screenshot tour gets the same sky every run.
532
533**Time**, in the panel, works in every view: the **Day** (with its date in Pisa), the
534**Time** of day, **Run the clock** and its rate, and the **Light** — how bright Tower runs
535its day. It says when the sun rises and sets and where it is now, and the map marks it.
536**Dark** shuts the 54 TW beam down entirely and is the only setting that is genuinely black —
537no sun, no airlight, no rod, and nothing left in the world but the sky. Twilight, Temperate
538and Full set how bright the day is; night comes by itself, with the clock.
539
540**Eye height** is a gauge up the right-hand side of the view, from 1.7 m to the beam, 48.4 km up, on a
541log scale: drag it, or click it and use the arrow keys. It is marked with things of known
542height — an adult, a two-storey house, the Eiffel Tower, Everest, an airliner cruising, a
543weather balloon, and at the top the beam itself — which light up as you pass them, and the readout by the thumb gives the
544height, the local gravity, and what it compares with ("≈ the Eiffel Tower", "2.0× the
545Burj Khalifa"). On a phone that readout fades once the height has been still for two
546seconds, and comes back as soon as it changes or you touch the gauge. The **Where you stand** readout in the bottom-left corner folds down to its
547title with a click, and stays as you left it; on a phone it starts folded.
548
549Nothing *inside* rotates, because you, the ground and the air all turn together. The
550exception is the window: the sky out there does not co-rotate, and wheels once every 7 min 29 s about the one motionless star on the
551axis. It is the one sign of the spin anywhere in the view, and
552it is only available at night, at the deepward end, looking the one direction that
553has ever had anything in it but Tower.
554
555## What the world file says
556
557Each feature in `content/world.json` has a kind, a shape — a point, an open line (a
558river runs source first), an outline, or a band ringing the world — and its kind's
559parameters beside it. Changing any of them is a conversation and an edit to the file;
560the ground regenerates on the next load. This is what the parameters mean.
561
562A **mountain range** has named **summits**, each held at exactly its elevation, and
563parameters for how high its unnamed summits stand and how many there are, how rugged it
564is, how deeply water cuts it, and its snowline. A change regenerates the range — a few
565seconds for the Girdle, under the status dialog.
566
567A **lake or sea** has a **wind**: the direction it blows toward and its speed. That is
568its usual wind, which blows whenever the weather plan has nothing scheduled. The detail
569card says what sea is running there *now*, by the clock — a 10 m/s wind over The Deep
570makes waves under a metre; the same wind round a ring sea, which never runs out of water
571to blow over, makes 2 m, and 20 m/s makes 8.6. A sea also has a number of ships.
572
573**Weather** is Tower's plan: events over a lake or sea, each published at a moment and
574revisable later with a reason — the storm eased because someone foolish went sailing —
575and a number of days the plan takes to repeat. The panel's **Weather** section shows what
576is blowing now and the next fortnight, as far as it has been published, with any revision
577listed under the event it changed and the original struck through. None of it
578regenerates the ground.
579
580A **settlement** has a size — hamlet, village, town, city or station — and how far it
581reaches. It is a point with an extent, not a traced outline: Tower lays the streets out
582inside it. The Capital is 20 km across, centred on the axial midpoint of the world, which
583is just wide enough to put its spinward edge on The Deep's shore.
584
585A **forest** has what Tower planted there: stems per hectare, how much of it is conifer,
586how much of the ground is left open as meadows, the treeline, and whether it is a wood of
587giants. The detail card says what that comes to — how many trees, over how much ground,
588how far apart, and how high the canopy stands.
589
590A **desert** has its landforms: how high its dunes stand, how far apart, and which way
591Tower blows the sand; how much of it is rocky hills; how tall its plateaus are, how much
592of the ground they cover, and how many cliff bands they are cut into; and how much past
593water Tower quotes there — dry washes, how many salt pans, and whether they are ringed by
594the shorelines of lakes that never stood. The detail card says what was actually made:
595"24% standing rock, 37% dune field, 35% cut by washes, 4 salt pans."
596
597A **railway** is a line with a line speed. Its track keeps a grade of its own over the
598ground rather than cutting it — the highest ground within a kilometre either side, eased —
599so it stands on piers much of the way and crosses the gorges on viaducts. There are two:
600the **Axial Line**, from Sisters Station through The Narrows and past the Capital to the
601Deepward Sea, and the **Uplands Ring**, round the world at 140 km, whose trains weigh 31%
602more running spinward and 27% less running antispinward.
603
604A **region** is a label, and it can also be ground Tower raised: give it an uplift and
605everything inside it is lifted to that height above the open ground, wherever that is
606higher than what is there. The Uplands are one.
607
608Every feature also has a **blurb**, shown to readers; **notes**, which are the author's
609and never reach the app — though the repository is public, so they are not secret; **`public`**, false for a feature not ready to exist in the app
610at all; and a **seed**, written once, so it generates the same forever.
611
612Canon is **0 star slats** — the hull is sealed, the inner surface is one unbroken
613169,646 km², and the only views out are at the end caps. The runtime control for
614this is disabled and hidden (decisions.md D-033): the world is generated as one
615unbroken surface, so any other count draws bands over land that has none.