tower / commit
docs: establish Tower's canon and its decision record
decisions.md | 702 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ design.md | 684 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1386 insertions(+) diff --git a/decisions.md b/decisions.md new file mode 100644 index 0000000..24a0105 --- /dev/null +++ b/decisions.md @@ -0,0 +1,702 @@ +# Tower — Decisions + +Standing record of choices made and why, so they can be revisited deliberately +rather than rediscovered. Newest sections append at the end. + +--- + +## D-001 — Cylinder geometry: r = 50 km, L = 540 km + +**Decided.** Radius 50 km, length 540 km, giving 169,646 km² of inner surface. + +Considered three shapes, all matching Wisconsin's area at 1 g: + +| | radius | length | spin period | character | +|---|---|---|---|---| +| Long & narrow | 8 km | 3,375 km | 3.0 min | ceiling, not sky; absurd aspect ratio | +| **Balanced** | **50 km** | **540 km** | **7.5 min** | far side visible overhead through haze | +| Wide & short | 150 km | 180 km | 13.0 min | a drum; far cap looms as a wall | + +**Why balanced.** It is the only one where the sky reads as *sky*. At 8 km the +roof is 16 km up and oppressive; at 150 km the far side is 300 km away and lost +entirely. At 50 km the opposite land is 100 km overhead — far enough to be pale +and dreamlike, near enough to be unmistakably *land above you*. That image is the +point of the whole project, and this geometry is what produces it. + +The 7.5-minute spin also sits in a good window: fast enough that star motion is +obvious in a few seconds of watching, slow enough not to look like a fairground +ride. + +--- + +## D-002 — Slats sized so land area equals Wisconsin's land area + +**Decided.** 8 slats, 6.80 km wide, leaving 140,268 km² of land. + +The brief specified a Wisconsin-sized inner surface. Wisconsin has two areas — +total 169,635 km² and land 140,268 km². Sizing the slats to consume exactly the +difference makes both true at once: **Tower's total inner surface is Wisconsin's +total area, and Tower's habitable land is Wisconsin's land area. The slats are its +lakes.** + +This is a coincidence discovered while computing, not a constraint imposed. It +costs nothing and it is too good to pass up. + +*Superseded by D-017: there are no slats, so Tower's land is its entire inner +surface, 169,646 km² — Wisconsin's total area. The second coincidence recorded +below no longer applies.* + +**Slat count is left as a tunable constant.** The width follows from the count: + +| slats | each | land strips between | +|---|---|---| +| 6 | 9.07 km | 43.3 km | +| **8** | **6.80 km** | **32.5 km** | +| 12 | 4.53 km | 21.7 km | +| 24 | 2.27 km | 10.8 km | + +8 chosen because 32.5 km strips read as *regions* — a day's travel across, room +for real geography. At 24 the world becomes narrow ribbons where every point is +within 5 km of a wall of stars, which is striking but claustrophobic. Revisit +after seeing the map view; this is cheap to change. + +*"Revisit after seeing the map view" is now literal — D-014 makes the count a +runtime control from 0 to 16, and 8 is the default rather than a fixed value.* + +--- + +## D-003 — Widen the beam to 10 km; the physics now works unbroken + +**Decided.** The beam is 10 km in circumference, carrying 54.3 TW at 5,000× +concentration. No physical law is bent. *This supersedes an earlier version of +D-003 that accepted an étendue violation in order to keep a 1 km beam.* + +**The mistake in the first pass.** I treated the 1 km beam as fixed and concluded +that Earth-like brightness was impossible without an active, physics-breaking +waveguide. That was wrong, because it conflated two independent parameters: + +- **Collector aperture** sets *how much power* is gathered. This was never limited + by anything but engineering scale. +- **Beam cross-section** sets *how hard the light must be concentrated* to fit + through. This is where étendue binds — passive optics cannot exceed the sun's own + surface radiance, ~46,223× at 1 AU, or 62.9 MW/m². + +Holding the beam at 1 km forced 313,000× and broke the second law. Widening the +beam relaxes the concentration requirement quadratically and costs nothing else. + +**Where the number came from.** Targeting 54.3 TW — Earth clear-sky noon at local +midday, see design §1.3 — against candidate concentrations: + +| concentration | beam circumference needed | status | +|---|---|---| +| 46,223× (étendue limit) | 3.29 km | thermodynamically impossible to exceed | +| 10,000× | 7.08 km | beyond current practice | +| **5,000×** | **10.01 km** | **Odeillo solar furnace reaches ~10 MW/m² today** | +| 1,000× | 22.39 km | routine, but a conspicuously fat beam | + +**5,000× chosen.** It lands the beam on a round 10 km, it is *demonstrated* +terrestrial technology rather than an extrapolation, and it sits at 11 % of the +étendue limit — 9.2× of headroom in reserve. Diffuser mirrors at 99.9 % +reflectivity reach thermal equilibrium at 316 °C in that beam, an ordinary +radiator problem rather than an exotic one. + +**Cost to the imagery: none.** At 1,592 m radius seen from 50 km below, the beam is +3.65° wide — about seven sun-widths. It still reads as a luminous rod running the +length of the sky, which is the image the 1 km figure was protecting. + +**The unlocked consequence.** Because Tower now has *surplus* capability rather +than a deficit, brightness becomes a **setting** rather than a fixed value. The +diffusers are software-controlled; illumination can run anywhere from 30 W/m² +permanent dusk to 320 W/m² clear-sky noon. The "embrace the dimness" option +weighed and rejected in the first pass is no longer an alternative to this +decision — it is a position on its slider. The app should expose that control. + +## D-004 — Terminator orbit, actively precessed + +**Decided.** Orbital plane held normal to the Earth–Sun line, precessing 360°/year. + +The brief requires that one cap face the sun permanently. Any orbit whose plane +contains the sun line puts Tower through Earth's shadow once per revolution, which +would interrupt the beam. A terminator orbit never enters shadow. + +The cost is that the plane must be reoriented ~1°/day against the gyroscopic +stiffness of a spinning 540 km cylinder. This is enormous and continuous. Canon +adopts it as a feature: Tower's existence is a permanent act of maintenance, not a +stable configuration. That is more interesting than a free lunch. + +--- + +## D-005 — Vanilla TypeScript, no UI framework + +**Decided.** Vite + TypeScript + Three.js, no React/Vue/Svelte. + +The app is three canvases, a picker and a control panel, sharing one small state +object. A framework would add build weight and a rendering model that fights +Three.js's own loop, in exchange for conveniences this UI does not need. Revisit +only if the control panel grows genuinely complex. + +Canvas 2D rather than Three.js for the map: it is a flat unrolled rectangle with no +projection distortion, and 2D canvas draws that natively. + +--- + +## D-006 — Interior fidelity: real geometry, simple ground + +**Decided.** The shell, curvature, haze, beam, diffusers, slats and stars are all +genuinely modelled and correct. The ground is procedural terrain and texture only — +no scenery meshes, no settlements, no vegetation. + +The illusion of standing inside Tower comes almost entirely from the sky: land +curving up into blue, the lit shaft overhead, stars wheeling past every 7.5 +minutes. Detailed ground scenery adds cost proportional to realism and contributes +little to that illusion. Deferred, not abandoned. + +--- + +## D-007 — All canon derived from four constants + +**Decided.** `canon/constants.ts` exposes radius, length, slat count and target +land area as free parameters. Everything else — spin period, rim speed, Coriolis +parameter, slat width, angular spacing, axis pressure, beam power — is computed. + +The alternative, transcribing the figures in `design.md` as literals, would drift +the moment any parameter is revisited (and D-002 and D-003 both flag likely +revisits). Derivation makes the whole app answer coherently to a changed radius. + +--- + +## D-008 — Diffusers are a 1.2 cm swarm; the beam glows from air, not from them + +**Decided.** 78 billion 1.2 cm mirrorlets, and the beam's visible glow is +atmospheric scattering that does not depend on them. + +**The question.** Would a modest number of large diffusers read as a string of +separate suns rather than a continuous glowing rod? + +**Yes.** At 50 km, naked-eye resolution is 14.5 m; anything larger shows a visible +disc. But shrinking below 14.5 m is not sufficient, which was the non-obvious part. +A flat mirror preserves radiance, so an aimed mirrorlet shows the *sun's own +surface brightness* over a small angle — unresolved but blinding, exactly as stars +are unresolved and plainly visible. Magnitudes: 1 m → −13.6 (brighter than a full +moon), 10 cm → −8.6, **1.2 cm → −4.0**, which finally sits under the daylight +visibility threshold. The binding constraint is flux, not angular size, and it is +two orders of magnitude tighter than the resolution limit implies. + +**The better answer, found while checking.** The beam glows regardless. Rayleigh +scattering of a 6.8 MW/m² beam through 3.18 km of 5.2 kPa axis air gives 779 +W/m²/sr — 26× blue sky, 25,700× below the solar disc. The continuous-glow imagery +is therefore a robust property of beam plus atmosphere, not a consequence of +getting the diffuser design right. Canon leans on this; the swarm sizing is then +only about keeping individual glints out of the sky. + +**Consequences taken.** 11.3 km² of mirror at 1.2 cm is 78 billion units massing +158 tonnes, spaced 3.8 m apart. Optical depth 1.41 leaves 24 % of the light +reaching the far cap, which satisfies the brief's "shines to the far end" without +stipulating it. *The passive drift-and-recirculate mechanism first recorded here is +superseded by D-009 — it does not work.* + +**Story consequence.** 78 billion independently aimable mirrors make illumination a +render target rather than a schedule. Sunsets are compositing, not optics. + +--- + +## D-009 — Tower flies every foil itself, because nothing else works + +**Decided.** All 78 billion foils are under continuous individual control by Tower. +There is no recirculation machinery at either cap. *This supersedes the passive +drift mechanism in D-008.* + +**Origin.** Proposed by the author as characterisation — Tower is an intelligent +being, so it controls each foil directly and moves the swarm partly for its own +enjoyment. Checking the physics turned this from a flourish into a requirement. + +**A passive swarm is impossible.** D-008 assumed the axis was effectively +weightless. It is not. At the beam's edge, 1,592 m out, g = ω²s = **0.312 m/s²**. A +2 mg foil sinks outward at 0.26 m/s and **falls clear of the beam in 1.7 hours**. A +drifting swarm dissolves in an afternoon. Continuous active flight is the only +configuration that holds together at all. + +**They can easily afford it.** Each foil intercepts 979 W; harvesting 0.1 % yields +~1 W on a 2 mg body — 489,600 W/kg, ~50× a jet engine. Flying up-beam at 1.5 m/s +costs 15 µW against 14,400 µW harvestable from ambient world-light: **a 1000× +margin, without touching the beam.** So the foils fly home unaided, no structure is +required at the far cap, and the exterior render is simpler than D-008 implied. + +**The interesting part is the slack.** With 1000× of margin, efficiency is not a +constraint on Tower's behaviour. It can move the swarm in spirals, shoals and +patterns that cost energy for no reason except preference, and nothing about the +world degrades. Play is not a luxury Tower affords despite the physics — it is +budget the physics hands over for free. The weather is therefore not a system +Tower operates but something closer to body language. + +**Falling out of this: aiming is human-scale.** A 1.2 cm mirror is +diffraction-limited to 4.6×10⁻⁵ rad, giving a **2.3 m spot** at 50 km. Tower can +place a glint on one person that a bystander five metres away cannot see. Offered +to the author as a story mechanic; canon records the optics either way. + +**And: mirrorfall.** A failed foil sinks out of the beam, takes ~2 days to descend, +and lands at 0.48 m/s — snowflake speed. A permanent slow glitter falls out of the +sky. + +--- + +## D-010 — The app is a companion to a novel, not a tech demo + +**Decided.** Tower is the setting of a novel the author is writing. The app serves +that purpose first. + +Two consequences, recorded because they change priorities rather than mechanics: + +- **Coherence outranks spectacle.** These documents are series-bible material and + the prose is downstream of them. A number that looks better but contradicts + something is worse than a duller number that holds. This is already how the + physics has been handled; it is now the stated rule. +- **Shareable permalinks to a point move into scope** (phase 4, previously + deferred). "Stand here and look at this" is the entire value of a companion + piece, and a link is how a reader receives it. Named locations from the novel + should be markable on the map for the same reason. + +Not yet decided, and deliberately left open: whether the app should ever surface +narrative content — place names, events, characters — or remain a pure physical +model that the prose refers to from outside. That is the author's call and does not +need answering to proceed. + +--- + +## D-011 — Writer mode: the app is an instrument, and the world file is git + +**Decided.** Two modes over one committed `world.json`. Readers get a finished map; +the author gets editing plus a set of measuring instruments. No backend. + +**Origin.** The author intends to use the app to *write* — placing things and asking +questions like "can the far face be seen from the midpoint?", "where does a central +embassy go?", "can a lake overhang?". That makes measurement, not rendering, the +core feature. D-010 said the app serves the novel; this is what that costs. + +**Why those questions justify the build.** Two of the three had non-obvious answers +that only fell out of computation, and both became canon (§1.8): the far cap is +invisible from the midpoint at 4 % transmission, and — unexpectedly — the far side +of the world overhead is *clearer* than the ground at the same distance (78 % vs +31 % at 100 km), because a sightline across the interior rises through thin axis +air. An author cannot guess these. The instrument earns its place immediately. + +**Static, file-based, no backend.** GitLab Pages serves static files, so: edit in +browser → export → commit → publish. The world lives in git beside the prose, +diffable and versioned, with no service to run or pay for. Drafts sit in +`localStorage` between exports. + +**Coordinates in the file are canon (θ, z), never map pixels,** so the world +survives any change to how the map is drawn. Consistent with D-007. + +**Writer mode is a UI mode, not a security boundary.** `?writer=1` is guessable and +that is fine — an editor with no persistence and no backend can only alter the +visitor's own copy. Recorded explicitly so it is never mistaken for access control +and never load-bearing for privacy. + +**The real privacy risk is the repo, not the flag.** Working notes must not ship to +readers, but anything committed to a public repository is public whatever a +`"public": false` field says. Hence two export files: `world.json` (public entries, +committed) and `world.private.json` (everything, gitignored). Whether private notes +should be version-controlled anyway — private repo, or a second one — is left to +the author and does not block anything. + +**Sequenced early.** The sightline probe lands in phase 6 but should be built first +within it: it is useful the day it exists, and §1.8 is evidence the author is +already asking questions only it can answer. + +--- + +## D-012 — Ids follow the name until pinned by hand + +**Decided.** A place's id is re-derived from its name while it still matches it, +and freezes permanently once the author edits the id field. + +**The tension.** design.md §3.2 makes ids permalink targets, which argues for +never changing them. But places are created from a placeholder name ("New city"), +so a never-changing id produces a world file of `new-city`, `new-city-2`, +`new-city-7` — unreadable in git diffs and unusable for hand-editing, both of which +D-011 counts as reasons for the file-based design in the first place. + +**Resolution.** During world-building, readability wins; after publication, +stability wins; and the author is the only one who knows which phase a place is in. +So the id tracks the name automatically until they say otherwise, and the id field +is shown in the editor so saying otherwise is one edit. `isAutoId()` in +`src/world/schema.ts` is the test, and is unit-tested directly. + +**Found by running it.** The first implementation derived the id once at creation +and never updated it, which the browser check caught immediately — every exported +place was called `new-city`. Two further bugs surfaced the same way: renaming +blanked the editor (the store re-rendered before the selection moved to the new id), +and clicking an existing marker while a creation tool was active dragged the old +place instead of creating a new one. None were visible in the unit tests. + +--- + +## D-013 — The map is bounded, and cut at a slat centre + +**Decided.** The map shows the inner surface once, as a bordered rectangle, rather +than tiling vertically. The cut falls at the centre of the last slat. + +**Why not tile.** The circumference wraps, so tiling is the honest rendering and it +makes places near the seam continuous. But it also makes the world look boundless: +with no edge, the author cannot see the extent of what they are building, and +repeated strip labels read as more strips rather than as repeats. For a map — a +thing whose job is to show where things are relative to the whole — legible extent +beats a hidden seam. + +**Why cut there.** Any bounded map needs an edge, and the edge destroys whatever it +falls on. Land strip 0 is centred on θ = 0, so the obvious cut would slice a whole +strip in half across the top and bottom margins. Cutting at a slat centre instead +leaves every land strip whole and splits only a band of stars, which carries no +geography. This is exactly why Earth's maps are cut at the antimeridian. With zero +slats there is nothing to protect, so the cut returns to θ = 0. + +**Consequences taken.** Panning is clamped so the surface cannot be lost off-screen +— without tiling there is nothing to pan back into. A sightline whose short route +crosses the edge is drawn as two segments, entering and leaving opposite edges, so +the drawn path always matches the measured distance rather than contradicting it. + +--- + +## D-014 — Slat count is a runtime control, 0 to 16 + +**Decided.** `SLAT_COUNT` stops being a compile-time constant. The count lives in +`src/canon/slats.ts`, adjustable from 0 to 16, persisted per browser, with every +slat-derived figure computed from it. + +**Why.** D-002 already called this "the most tunable number in canon" and said to +revisit it after seeing the map. Making it a slider makes that revisiting real +rather than a code edit, and the author is choosing the shape of a world rather +than configuring software. + +**The invariant that makes it safe.** D-002 fixes the *total* slat width from the +land-area target, and that total does not depend on how many slats it is divided +into. So **land area stays exactly Wisconsin's 140,268 km² at every count from 1 to +16** — the coincidence survives the whole range, and only the per-slat width moves +(18.1 km at 3 slats, 3.40 km at 16). + +**Zero is a genuinely different world, and the app says so.** With no slats the +land becomes the entire inner surface, 169,646 km², and nobody in Tower can ever +see a star. That breaks the D-002 coincidence, so the control states it plainly +instead of silently reporting a changed number. Rounding that away would have been +the easy option and the wrong one — it is exactly the kind of quiet inconsistency +the documentation gate exists to catch. + +**Cost.** Slat geometry moved from constants to functions, which rippled through +`geometry.ts`, the map, the instruments and the tests. Worth it: D-007's principle +was always that canon is derived rather than transcribed, and this is that +principle extended one parameter further. + +--- + +## D-015 — Hydrology: shaped terrain, no sideways Coriolis, climate from the slats + +**Decided.** Recorded as canon in design.md §1.9, and it amends §1.4. + +**The provable part.** The floor's tangent plane is spanned by θ̂ and ẑ and the spin +axis is ẑ, so surface flow gets `ẑ × ẑ = 0` axially and a purely radial `ẑ × θ̂ = −ŝ` +circumferentially. The Coriolis force has **no component inside the surface** at any +heading. Tower's rivers do not curve, and Earth's entire rotational repertoire — +hemispheres, Baer's law, gyres, cyclones — is absent. This is not a simplification; +it falls out of the geometry. + +**Where the force goes instead.** Into vertical motion. Waterfalls lean retrograde +as h^1.5 (133 m over a 1 km drop, 377 m over 2 km), and rain hangs at a permanent +1.47° slant that never varies. Rising things lean the opposite way. A world where +every falling thing drifts one way and every rising thing the other is a strong, +cheap, always-visible signature. + +**The absence that matters more.** Potential depends only on radius, so the floor is +one equipotential and a perfect Tower has *no rivers at all*. Every river exists +because the floor was shaped, there is no tectonic uplift, and erosion is therefore +one-way — ~30 Myr to erase a 3 km range. Tower's hydrology is maintenance, which is +D-004's theme arriving from a new direction. + +**An inconsistency found and fixed, not smoothed over.** §1.4 specified a +glass/**diamond** composite slat fill. Diamond conducts ~2,000 W/m·K; such a slat +would radiate 385 W/m² to space, exceeding Tower's entire 320 W/m² mean insolation +and freezing the world. Canon now specifies low-conductivity glass, which loses +~28 W/m² through 5 m. Raised explicitly per the documentation gate rather than +quietly retconned. + +**The gift in that loss.** Tower has no latitude — every point is equidistant from +the light, so there is no natural climate gradient whatsoever, which is a real +worldbuilding hole. The leaking slats fill it: eight cool belts running the full +540 km, parallel to the axis. **Tower's climate bands run lengthwise, not around**, +and the slat count sets the climate as well as the geography — further support for +D-014 making it a control. + +--- + +## D-016 — Slat orientation: axial or rings — OPEN + +**Not decided.** Canon keeps axial strips for now. Rings are a live alternative and +this records what the choice costs, so it can be made deliberately. + +**Why it matters more than it looks.** Slat layout turns out to set three things at +once — the shape of Tower's countries, its entire climate map, and what its people +can see of the universe. It is not a detail of the hull. + +**Geometry.** At equal total area: rings are 11.69 km wide with 55.8 km land bands. +Each land region is then 314 × 55.8 km rather than 32.5 × 540 km — the same area at +aspect 5.6:1 instead of 16.6:1, a country instead of a corridor. Ring bands are also +**closed loops**: you can walk 314 km around your whole region and come home without +crossing a window. Axial strips are ribbons with two dead ends at the caps. + +**Climate.** Axial strips put the cool belts lengthwise, so a 540 km river runs its +whole length through identical country. Rings put them crosswise, giving Tower a +genuine latitude analogue — a long river crosses all eight bands like the Nile. + +**The sky, which is the deep one.** The spin axis is the celestial pole, so stars +move along the celestial equator. Orientation decides whether a window lies across +that motion or along it: + +- *Axial*: 3.90° across the motion — each star crosses in **4.9 s**, but the strip + spans pole to pole so essentially the whole sky passes through, strobing. +- *Rings*: 6.70° along the motion — a star rides the band horizon to horizon over + **3.7 minutes**, but only the 5.8 % of sky within 3.35° of the celestial equator + is *ever* visible. The rest is never seen at all. + +Earth follows the same rule: a five-second flicker under axial slats, a slow bright +traveller under rings. The sun is at the celestial pole and invisible through both. + +**The cost of rings.** Hoop stress dominates the structure — ρv² is 785 MPa in a +composite shell plus ~500 MPa of air pressure — and it runs along θ. Axial slats sit +across that path, so ribs bridge the gap and the glass carries only local pressure. +A ring runs along the path and is continuous in θ, so **the window itself must carry +~1.2 GPa**. Glass cannot; it would need hoop cables through every pane, putting bars +across every view forever. Characterful, but a real price axial slats do not pay. + +**Consequence for the app if rings are chosen.** D-013 cuts the map at a slat centre +because there is an empty θ to cut at. With rings there is not — every θ is land — +so the map seam would have to slice through inhabited country, or the map would need +reorienting. Worth knowing before the choice is made rather than after. + +--- + +## D-017 — The hull is sealed; the only views out are at the caps + +**Decided by the author.** No slats, in any orientation. The cylinder wall is +opaque and unbroken for its full 540 km. Supersedes D-002's slat sizing, D-014's +default, and closes D-016. + +**What it costs.** The wheeling star field was canon's answer to "what is most alien +about standing inside Tower" (§1.2) and the interior view's headline feature. It is +gone. Tower also loses its only passive climate driver and its only natural source +of geographic variation. + +**What it buys, which is more.** + +- **One unbroken surface.** 169,646 km² of continuous land — Wisconsin's *total* + area, the coincidence in §1.1 now standing alone and cleaner. Nothing divides the + world into strips; you can walk anywhere, and a river can circle the whole 314 km + circumference and close on itself. +- **The spin inverts.** With no windows and a co-rotating far side, *nothing in the + sky moves at all*. But rain still hangs at a permanent 1.47° slant and a 1 km + waterfall still lands 133 m off its cliff. **The sky is still and the water is + not** — a stranger signature than wheeling stars, and one that shows up in every + puddle rather than only when you look up. +- **The caps become the only view, and it is a good one.** A cap window looks along + the spin axis — the celestial pole — so stars do not sweep but *rotate about a + fixed centre*, one turn per 7.5 minutes, one motionless star at the middle. The + caps are also walls rather than floors: gravity there is tangent to their surface, + so each is a 50 km cliff at the end of the world with its windows at the base. +- **Nobody can ever see Earth.** The terminator orbit (D-004) puts Earth ~90° off + the axis, out the side, which is now solid hull. A habitat in Earth orbit whose + people have never seen the planet they orbit. + +**The consequence the author accepted explicitly.** With no latitude and no windows, +nothing breaks the thermal uniformity, so there is no passive weather whatsoever. +Every cloud, every rainfall and every jet stream is Tower deliberately aiming light. +This is D-009 reaching its end point: the swarm was already Tower's body language, +and is now its lungs. There is no autonomic layer beneath. **If Tower's attention +lapses, the rain stops.** + +--- + +## D-018 — Rivers are a closed, pumped circulation, and Tower can easily afford it + +**Decided.** Tower's rivers follow the architecture the author proposed: reservoir → +shaped descent → lake → lift back to the reservoir. Source and sink are one system. + +**Why it is the only option.** The floor is an equipotential (D-015) so there is no +natural slope, and the sealed hull (D-017) leaves no natural water cycle. Water in +Tower moves only because something moves it. + +**Why it is not a compromise.** Costed against the 54.3 TW budget: + +| | | | +|---|---|---| +| Earth-like rainfall, 1,000 mm/yr | 12.2 TW | **22.4 %** — Earth spends the same share | +| Recirculating all runoff (1,792 m³/s, a Rhine) against 500 m | 8.8 GW | **0.016 %** | + +Pumping the entire hydrology of the world is a rounding error — 6,000× headroom. +And full Earth-intensity weather is affordable at the same fraction of budget Earth +itself spends. Tower does not have to choose. + +**Canon uses both, because they give different rivers.** A pumped river *begins at a +machine* — walk to its source and find a wall of water leaving a structure. A +rain-fed river begins at a cloud Tower made over the highlands, and looks entirely +natural while being entirely deliberate. Made weather runs the world's general +hydrology; pumps run the watercourses Tower wants under precise control. + +**Two consequences worth keeping.** A closed loop has no net descent, so a river +circling the world must be pumped — which is the same architecture, closed the whole +way round. And since nothing evaporates to space, **Tower's water inventory is +conserved and exactly known, forever.** + +--- + +## D-019 — Geography is authored as data; terrain is generated from it + +**Decided.** `content/geography.json` holds the authored geography. `npm run terrain` +(tools/terrain.mjs) reads it and emits a height map, a colour map, a corridor detail +render, and a seed `world.json` of places. + +**Why data first.** The author asked to work the geography out before returning to +app code. A JSON source plus a generator means the map is re-derivable from one +readable file: move the river by editing eighteen waypoints, not by repainting. +Coordinates are canon (θ, z) throughout, consistent with D-007 and D-011. + +**No dependencies.** Node's `zlib` is enough to write PNGs directly (tools/png.mjs, +~60 lines for 16-bit greyscale and 8-bit RGB), so the tool adds nothing to +`package.json`. Terrain noise is a small value-noise/fBm module. + +**Three bugs the renders caught that no test would have.** + +- *A float hash.* The noise hash multiplied large integers in floating point, + silently losing precision and streaking the whole map with axis-aligned lines. + Fixed with `Math.imul` throughout. +- *A fractional wrap period.* The circumference is not a round multiple of any + useful feature size, so the noise lattice did not close on itself and tore at the + seam. Sample coordinates on the θ axis are now snapped to a whole number of + cells; the resulting few-percent anisotropy is invisible. +- *A discontinuous river.* Valley geometry switched between reaches abruptly, + stepping the valley from 5.4 km wide to 18.2 km in one pixel column and drawing a + visible wall across the map. Reach parameters now blend along the river. A + `--probe` flag prints elevation jumps along a row, which is how it was found. + +**Known gap, deliberately not fixed here.** The seed `world.json` contains +`polyline` geometry (the river, the canyon) and kinds the app does not yet know. +`parseWorld` accepts only points and polygons, so those two places would be dropped +silently on load. App work is paused by request; this is the first thing to fix when +it resumes. *Closed by D-022.* + +--- + +## D-020 — The world is belts, and the desert rings it + +**Decided by the author.** The desert and its three ridges ring the world; the +capital's water becomes a sea running along the axis; both end caps get ring oceans; +the range feeds four parallel rivers. + +**The ring desert is a barrier no Earth desert can be.** 22,000 km², 13% of the +surface — modest against Earth's ~33% — but on a cylinder there is no way *around* a +band. Combined with three ringing ridges it is three concentric walls across Tower's +waist. + +**The drainage was the hard part, and Earth answered it.** Many rivers each cutting +their own canyon would destroy the chokepoint. But on Earth most drainages do not +cut through a rising ridge — they are defeated and diverted, and only an antecedent +river keeps its course. So three of the four rivers are turned by First Ridge, run +along its front gathering each other, and leave with the fourth through the one gap. +**The Narrows carries the entire world's runoff, ~392 m³/s.** The chokepoint is +strengthened by the extra rivers rather than diluted, and the hydrology is more +realistic than a single river would have been. + +**The Deep's orientation is the decision, not its size.** Long down the axis and +narrow around, so it is crossed the *short* way — around θ, where the floor curves +up and the far shore stands 2.6 km above eye level. Lengthwise it would be dead +flat. It also gives Tower back a thermal flywheel: 19× the diurnal heat storage of +bare ground, 5.9 days per kelvin at full power. D-017's "if Tower blinks the rain +stops" becomes "the world has about a week of momentum" — a lapse now has time to +become visible before it becomes fatal. + +**The cap seas were not chosen.** Gravity on an end cap is tangent to its surface, +so water cannot rest there and runs to the rim. Both ring oceans are consequences, +not designs. + +**Skiing came out of §1.9.2 unprompted.** A descending skier has radial velocity and +therefore real Coriolis: a steady antispinward push on axial fall lines, and a +weight change of up to 11% on circumferential ones. A retrograde run gets lighter as +it accelerates; a prograde run grips harder. Every slope in Tower has a handedness, +which is a sport that cannot exist on Earth. + +**Tool work this required:** `ring` footprints, a `flood` op for troughs and bands, +and a `tarn` op that fills from the bowl floor rather than the rim — the first +version took its level from the rim mean, so water spilled downhill and every +mountain lake rendered as a half-moon. + +--- + +## D-021 — The terrain tool reports progress, and got 13× faster doing it + +**Prompted by the author:** `npm run terrain` ran for a long time saying nothing. +Adding progress output meant first working out where the time went, which turned a +logging task into a performance one. + +**86 s → 6.4 s.** Three causes, all found by measuring rather than guessing: + +- **No spatial index on the river carve.** `opCarve` tested all 592 smoothed river + segments against all 2.4 million pixels — ~2.9 billion distance tests across both + renders. Segments are now binned into a 4 km grid and each pixel tests only its + own cell. *86 s → 17.8 s.* +- **Deflate level 9 on the colour maps.** Hillshade noise compresses poorly, so + level 9 spent 4.2 s on one map for a few percent of size. RGB now encodes at + level 6: 8× faster for 10% larger files, which is the right trade for a tool run + on every edit. The 16-bit height map stays at level 9 — smooth terrain under the + Up filter is nearly all zero deltas, and it costs 0.1 s. *17.8 s → 8 s.* +- **Domain warps computed before range checks.** Several ops evaluated two noise + functions per pixel *then* discovered the pixel was nowhere near the footprint. + A conservative unwarped-z rejection now runs first. *8 s → 6.4 s.* + +**The log is a table, not a stream.** One row per relief op with its timing, then +relief/colourise totals per view, then each PNG with its size, then the seed. The +point is to see which feature is expensive when the file grows, not just that +something is happening. `--quiet` collapses per-feature rows. + +**Worth recording as a habit:** the request was for logging, and the logging is what +exposed that the colour PNG cost more than the entire mountain range. Instrumenting +first and optimising second found three real problems in one pass. + +--- + +## D-022 — The app catches up with the decisions + +**Implemented.** Five outstanding decisions, plus two bugs found while doing it. + +**The schema now matches the world** (closes D-019's gap). `polyline` geometry +joins point and polygon — a polygon needs three vertices for an interior, a +polyline only needs two to go somewhere — and the kind list grows from six to +thirteen (`mountain`, `river`, `canyon`, `forest`, `desert`, `tower`, `town`), with +`AREA_KINDS` / `LINE_KINDS` deciding whether a traced shape closes. Before this the +seed silently dropped The Long Water and The Narrows. A test now loads +`public/world.json` and asserts nothing is lost, so the two files cannot drift apart +again unnoticed. + +**The rendered terrain is drawn under the map**, which is what the whole tool was +for. Area regions become outlines rather than fills when it is showing: the raster +already says where the desert is, and a translucent rectangle over it only fights. + +**A desync that would have been baffling.** The app cut the map at θ = 0 with no +slats; `content/geography.json` renders against θ = π. The raster would have landed +**half a world out of register** with its own place markers. Both now use +`MAP_CUT_WITHOUT_SLATS = π` — opposite the capital, which is D-013's antimeridian +principle applied to habitation rather than geology — and a test asserts the two +files agree. + +**Reader and writer modes** (D-011). `?writer=1` reveals the tools, editor, canon +controls and import/export; readers get the map, the place list, a read-only detail +card and the sightline probe. **A bug worth recording:** `renderEditor` un-hid the +editor whenever a place was selected, overriding the mode — so readers were shown +the edit fields *including private notes*. Mode is now decided inside +`renderEditor`, not applied around it. Hiding a panel elsewhere is not the same as +never rendering it. + +**Permalinks** (D-010). `#place=<id>` selects and centres a place; `#at=θ,z` restores +a sightline endpoint. This is why D-012 made ids follow names only until pinned — +a permalink is worthless if the id churns. + +**Labels are placed by priority and skipped on collision.** Settlements outrank +regions; overlapping labels are dropped rather than drawn on top of each other. With +22 seeded places the mountain stations were an unreadable smear. diff --git a/design.md b/design.md new file mode 100644 index 0000000..aee40ed --- /dev/null +++ b/design.md @@ -0,0 +1,684 @@ +# Tower — Design + +**Tower is the setting of a novel.** This app exists to serve that: first as an +instrument for the author to see the place and keep it consistent, and second as a +companion piece readers can explore. Where a choice trades spectacle against +coherence, coherence wins — canon here is series-bible material, and the book is +downstream of it. + +Tower is a smart cylinder in orbit around Earth, spun for 1 g, with an inner +surface the size of Wisconsin, lit by sunlight piped down its axis and scattered by +a swarm of mirrors it flies itself. It is also a person. + +The app has three linked views: + +1. **Exterior** — a 3D render of Tower from outside, with its collector, beam and + orbit. You pick a point on the hull. +2. **Map** — a 2D unrolled map of the inner surface. You pick a point here too; the + two pickers stay in sync. +3. **Interior** — a first-person "streetview" from the picked point, with live + controls for time of day and spin phase. + +--- + +## 1. Canon + +### 1.1 Dimensions + +All numbers derive from two free parameters — radius and length — chosen so the +inner surface matches Wisconsin. + +| Quantity | Value | Notes | +|---|---|---| +| Radius | **50 km** | floor to axis | +| Length | **540 km** | sun cap to far cap | +| Circumference | **314.16 km** | the world's "width" | +| Inner surface area | **169,646 km²** | Wisconsin total area, 169,635 km² | +| Habitable land area | **169,646 km²** | all of it — the hull is sealed (§1.4) | + +Every square metre of the inner surface is land. There are no windows in the wall, +so nothing is subtracted. *An earlier version sized star slats to leave exactly +Wisconsin's land area of 140,268 km²; D-017 removes them and that second +coincidence with it.* + +### 1.2 Spin and gravity + +| Quantity | Value | +|---|---| +| Angular velocity ω | **0.014005 rad/s** | +| Spin period | **448.6 s** = 7 min 29 s | +| Rotation rate | **0.134 rpm** | +| Rim speed | **700.2 m/s** | +| Floor gravity | **1.000 g** by construction | + +Consequences that the app should show or at least respect: + +- **Gravity falls off linearly with height.** g(h) = ω²(R−h). A 1 km peak sits at + 0.98 g; the axis is weightless. Mirrors at the axis float. +- **Coriolis is mild but real.** 2ω = 0.0280 s⁻¹. Walking is unaffected (0.4 % g). + A ball thrown at 30 m/s deflects at 8.6 % g — enough that Tower's sports differ + from Earth's, and enough that thrown objects visibly curve. +- **Nothing in the sky moves.** The hull is sealed (§1.4), so there are no stars to + wheel past — and the far side of the world overhead co-rotates with you, hanging + perfectly still. The spin is invisible *upward*. +- **But everything that falls leans.** Rain hangs at a permanent 1.47° slant, smoke + drifts the other way, and a 1 km waterfall lands 133 m off its own cliff (§1.9.2). + This inversion is the alien fact the interior view must sell: **the sky is still + and the water is not.** + +### 1.3 The sun system + +Sunlight enters through the sun-facing end cap and runs the full 540 km axis. + +- **Collector.** A mirror array flies ahead of Tower, gathering sunlight and + concentrating it into the beam. **46,900 km² of aperture — a disc ~244 km + across**, two and a half times Tower's own diameter. It is the dominant visual + element of the exterior view. +- **Beam.** **10 km in circumference** — 1,592 m radius, 7.96 km² cross-section — + carrying **54.3 TW** at a concentration of **5,000×**, or 6.8 MW/m². It runs the + axis from sun cap to far cap. +- **Diffusers.** Not lamps — a **swarm**. See §1.3.1. +- **The beam is visible, and it glows by itself.** There is real air at the axis + (§1.5), and a 6.8 MW/m² beam Rayleigh-scattering through 3.18 km of it radiates + **779 W/m²/sr** — **26× brighter than clear blue sky, 25,700× dimmer than the + sun's disc.** It is a brilliantly sunlit cloud extruded into a rod, safe to look + at directly. From the floor 50 km below it is **3.65° wide, about seven + sun-widths**, running the whole length of the sky. This glow is a property of the + beam and the air, not of the diffusers — it would be there if the beam were empty. + +#### 1.3.1 The diffuser swarm + +The diffusers must be individually invisible, or the sky becomes a row of separate +suns. Two thresholds govern this, and only the second one binds: + +- **Resolvability.** At 50 km, one arcminute is 14.5 m. Anything larger is a + resolved disc with a visible edge. +- **Visibility.** Being unresolved is not enough — stars are unresolved and we see + them. A mirror *preserves radiance*, so a mirrorlet aimed at an observer shows + the sun's own surface brightness over a tiny angle. A 1 m mirrorlet reads at + magnitude −13.6, brighter than the full moon. Blending into daylight requires + **~1.2 cm**, at magnitude −4.0, just under Venus. + +Diverting 54.3 TW needs 11.3 km² of mirror, so: + +| | | +|---|---| +| Mirrorlet size | **1.2 cm**, ~1.4 cm², 2 mg | +| Count | **78 billion** | +| Total mass | **158 tonnes** — the entire sun system | +| Mean spacing in beam | **3.8 m** — sparse enough to fly through | +| Optical depth over 540 km | 1.41, so **24 % of light reaches the far cap** | + +**The swarm cannot be passive — it must fly, always.** The axis is not weightless. +At the beam's edge gravity is **0.312 m/s²**, enough that a foil sinks outward at +0.26 m/s and **leaves the beam in 1.7 hours**. A drifting swarm dissolves the same +afternoon. Every foil is therefore under continuous individual control. This is not +a flourish on a working system; it is the only configuration that works. + +**They have absurd power to do it with.** Each foil intercepts 979 W of beam. +Harvesting 0.1 % gives it ~1 W on a 2 mg body — **489,600 W/kg**, some fifty times +a jet engine's specific power. + +| | | +|---|---| +| Down-beam, riding radiation pressure | 0.85 m/s, 7.4 days | +| Back up-beam under its own power at 1.5 m/s | 15 µW, 4.2 days | +| Harvestable from ambient world-light | **14,400 µW** — a 1000× margin | + +**So there is no recirculation machinery, at either cap.** The foils fly home on +scavenged daylight. Nothing needs to be built for them, and the 1000× power margin +means Tower can afford to move them *wastefully* — in spirals, shoals and patterns +that cost energy for no reason but preference. + +**Lighting is a render target, not a schedule.** 78 billion independently aimed +mirrors put any intensity on any patch of ground at any time. Dawn, dusk, moving +cloud shadows and seasons are compositing problems, not optical ones. + +**Aiming resolution is human-sized.** A 1.2 cm mirror is diffraction-limited to +4.6×10⁻⁵ rad, so its reflection lands as a **2.3 m spot** on the floor 50 km below. +Tower can put a glint on one person that someone five metres away cannot see. The +privacy is set by the wavelength of light, not by any protocol. + +**Mirrorfall.** A failed foil sinks out of the beam and falls. Terminal velocity at +the floor is 0.48 m/s; the descent takes about two days and it lands like a +snowflake. There is a permanent slow glitter coming down out of Tower's sky. + +#### Illumination is a dial, not a constant + +54.3 TW is Tower's *capability*, not its setting. Spread over the inner surface it +is 320 W/m² mean, which — with roughly half the surface lit at a time and a +sinusoidal day profile — puts **local noon at ~1,000 W/m², Earth clear-sky +daylight**. But the diffusers are software-controlled, so brightness is genuinely +adjustable in-world across the full range: + +| Setting | Mean W/m² | Feels like | +|---|---|---| +| Twilight | 30 | permanent overcast dusk | +| Temperate | 200 | Earth's global mean | +| **Full** | **320** | **Earth clear-sky noon** | + +This should be a control in the app, not a fixed number. It is the most +characterful thing about a world whose sun is a machine. + +#### Headroom + +5,000× is **11 % of the étendue limit** (46,223× at 1 AU). Tower could in principle +push the beam 9.2× further and cook itself; the diffuser network is as much a safety +system as a lighting system. 5,000× was chosen because it is *demonstrated* +technology — the Odeillo solar furnace reaches ~10 MW/m² on Earth today. Nothing in +Tower's sun system requires physics that does not exist. See `decisions.md` D-003. + +### 1.4 Sealed hull, and the cap windows + +**The cylinder wall is opaque and unbroken.** No slats, no windows, no view out +along any of the 540 km. From anywhere on the inner surface, the sky is land, haze +and the beam — nothing else. See D-017. + +The only views out are at the **end caps**, and they are peculiar: + +- **A cap is a wall, not a floor.** Gravity there points radially outward, which is + *tangent* to the cap's surface, so nothing rests on it — you would slide to the + rim. Each cap is a **50 km vertical cliff** standing at the end of the world, and + its windows sit at its base, at eye level for anyone standing on the floor. +- **The sky through them does not sweep — it turns.** A cap window looks along the + spin axis, which is the celestial pole. Stars rotate about a fixed centre, one + full turn every 7.5 minutes, with one motionless star at the middle. **A pinwheel + sky.** It is the only moving sky anyone in Tower ever sees. +- The **far cap** looks into deep anti-sun space. The **sun cap** faces the sun and + the collector, and needs heavy glare management. + +**Nobody aboard can ever see Earth.** Tower holds a terminator orbit (D-004), which +puts Earth roughly 90° off the axis — out the *side* of the cylinder, which is now +solid hull. A habitat in Earth orbit whose inhabitants have never seen the planet +they orbit. + +The caps are therefore the only places in the world with a horizon that is not +Tower. Whatever grows up around them, it will not be ordinary. + +### 1.5 Atmosphere and the look of the sky + +Air co-rotates with the shell. Because g falls linearly to zero at the axis, the +atmosphere is much deeper than Earth's: + +- Pressure at the axis, 50 km up: **5.2 kPa** — thin, but genuinely air. +- A vertical column floor-to-axis is ~10,600 kg/m², about **one Earth atmosphere**. + +So the interior sky behaves like this, and the shader must reproduce it: + +- **Straight up** you look through ~1 atmosphere and see the far side of the world + 100 km away — visible, but washed to pale blue like a very distant mountain range. +- **Along the axis** you look through many atmospheres. The far end cap is not + visible as a wall; it dissolves into blue haze around 100–200 km out. The world + reads as endless in the axial direction and closed in the circumferential one. +- **The ground curves up on both sides** into that same blue, meeting overhead. +- **The beam** is a self-luminous scattering shaft 3.65° wide at 779 W/m²/sr — + render it as a bright sunlit cloud, not as a light source with a halo. With the + hull sealed, it is the only thing in the sky that is not land. + +### 1.6 Orbit and attitude + +- Tower holds a high circular orbit with its **orbital plane kept normal to the + Earth–Sun line** — a terminator orbit. This is why one cap can face the sun + permanently and Tower is never eclipsed. +- The plane precesses 360° per year to track the sun. Tower's angular momentum is + enormous, so this 1°/day reorientation is actively driven, continuously, forever. + Canon treats this as Tower's defining maintenance burden. +- Consequence for the interior view: the star field slowly drifts across the year + while spinning fast every 7.5 minutes. Two nested motions. + +### 1.7 Coordinates + +The canonical surface coordinate is **(θ, z)**: + +- `θ` — angle around the cylinder, 0 to 2π. θ = 0 is the centre of land strip 0. +- `z` — distance from the sun cap, 0 to 540 km. + +The 2D map is the direct unroll: `x = z`, `y = (θ − θ₀) · R`. No projection +distortion — a cylinder unrolls exactly. This is a genuine advantage over mapping a +globe and the map view should lean on it. + +**The map shows the surface once, bounded**, so its extent is readable. That means +it needs an edge, and the edge is placed at **θ₀ = the centre of the last slat**. +Land strip 0 is centred on θ = 0, so cutting there would slice a whole strip in +half across the top and bottom margins; cutting at a slat centre leaves every land +strip whole and splits only a band of stars, which carries no geography. Same +reasoning as putting Earth's map edge at the antimeridian. A sightline whose short +route crosses the edge is drawn as two segments, so the drawn path always matches +the measured distance. + +--- + +### 1.8 Sightlines: Tower has two horizons + +Along the axis the floor is perfectly flat and never falls away, so nothing is ever +hidden by curvature. **Tower's horizon is haze.** Circumferentially the floor curves +*up*, so distant land rises into the sky rather than sinking below a line. The two +directions behave completely differently, and this is one of the most alien facts +about living there. + +Rayleigh transmission from a floor-level observer: + +| Distance | Along the axis | Across the interior (overhead) | +|---|---|---| +| 26 km | 78 % | 77 % | +| 50 km | 56 % | 70 % | +| 100 km | **31 %** | **78 %** | +| 270 km (far cap from midpoint) | **4 %** — a ghost | — | + +Two consequences: + +- **The axial horizon closes at 100–150 km.** From the midpoint you cannot see + either end cap. Everyone can see 100 km, knows there is more beyond, and cannot + resolve it — a different psychology of distance than Earth's 5 km cliff-edge. +- **The far side of the world is clearer than the ground at the same distance,** + because a sightline across the interior rises through thin axis air while one + along the floor grinds through full density. It gets *better* with distance: the + land directly overhead, 100 km away, is the crispest far object in Tower at 78 %. + **Distant geography is best seen by looking up.** People would orient by what is + overhead; the ground is the vague part. This inverts the human default. + +### 1.9 Water + +Tower's hydrology is stranger than its geometry, and most of it follows from one +fact and one absence. + +#### 1.9.1 Coriolis never pushes surface water sideways + +The floor's tangent plane is spanned by θ̂ and ẑ, and the spin axis is ẑ. For any +flow along the surface: + +- **along the axis** — `ẑ × ẑ = 0`, no Coriolis force at all; +- **around the circumference** — `ẑ × θ̂ = −ŝ`, the force is purely radial. + +The Coriolis term never has a component *inside* the surface. So **Tower's rivers +do not curve.** No hemispheres, no Baer's law, no preferred bank erosion, no gyres, +no cyclones. Every large-scale rotational habit of Earth's water and weather is +absent, and a meander in Tower is pure flow dynamics with no thumb on the scale. + +#### 1.9.2 What it does instead: everything vertical leans + +The force goes into the floor rather than across it, so it appears whenever water +moves up or down. Deflection of a free fall goes as h^1.5: + +| Fall | Lands (retrograde) | Lean | +|---|---|---| +| 100 m | 4.2 m | 2.4° | +| 500 m | 47 m | 5.4° | +| **1,000 m** | **133 m** | **7.6°** | +| 2,000 m | 377 m | 10.7° | + +**Rain falls permanently slanted** — a raindrop at terminal velocity sits at a fixed +**1.47° against the spin**, ~51 m of drift over a 2 km fall, never varying, never +reversing. Rising things lean the opposite way: smoke drifts spinward, rain drifts +anti-spinward. Every plume and every shower in Tower tilts, and they tilt against +each other. + +The same applies to anything that descends, not just water — see §1.11 on what it +does to skiing. + +Horizontal flow changes *weight* rather than direction (Eötvös): +0.57 % for a +2 m/s prograde river, negligible hydrologically. It only matters at speed — an +express train at 100 m/s gains 29 %, and anything moving retrograde at the 700 m/s +rim speed is stationary in space and therefore weightless. + +#### 1.9.3 A perfect cylinder has no slope anywhere + +Potential depends only on radius, so **the whole floor is a single equipotential +surface.** Water on it has no preferred direction: a perfect Tower has no rivers at +all, forever. + +**Every river in Tower exists because the floor was shaped.** There are no +tectonics and no uplift, so erosion is strictly one-way — a 3 km range wears flat in +~30 Myr under a wet engineered climate, ~150 Myr under a dry one. Tower's rivers +are steadily destroying its landscape and the highlands must be rebuilt to keep them +running. This is D-004's theme again: Tower's rivers are plumbing it chose to +install and has to keep re-installing. + +Two corollaries: + +- **No river can circumnavigate.** A closed loop has no net descent. +- **Lakes curve upward.** Level means constant radius, so across a 30 km lake the + far shore rides **2.3 km above your tangent plane** — Earth would hide it 18 m + below the horizon. You look *up* at the opposite beach, and water appears to + climb away from you. + +#### 1.9.4 There is no passive climate at all + +**Tower has no latitude** — every point is equidistant from the light — and with the +hull sealed it has no windows either. Nothing breaks the thermal uniformity. A +uniform hull radiates at 274 K everywhere, so left alone the world settles into a +flat calm: no gradient, no wind, no evaporation, no rain, no rivers. + +**So every weather system in Tower is deliberate.** Tower makes climate the only way +left to it — by aiming light. It warms where it wants convection and shades where it +wants condensation; the hull's uniform loss is the sink. Every cloud, every +rainfall, every jet stream is something Tower is doing, continuously, on purpose. + +This is D-009 arriving at its conclusion. The mirrorlet swarm was already Tower's +body language; now it is also its lungs and its weather. There is no autonomic +layer underneath. **If Tower's attention ever lapses, the rain stops.** + +Costs, for scale against a 54.3 TW budget: + +| | | | +|---|---|---| +| Earth-like rainfall, 1,000 mm/yr | **12.2 TW** | **22.4 %** — Earth spends the same fraction | +| Recirculating all runoff (1,792 m³/s) against 500 m | 8.8 GW | 0.016 % | + +#### 1.9.5 Rivers are a closed, pumped circulation + +With no natural cycle and no natural slope, a Tower river is a **loop**: a headwater +reservoir, a shaped descent through the landscape, a lake at the bottom, and a lift +back to the top. Source and sink are the same system. + +Two ways to close the loop, and they give completely different rivers: + +- **The pump outfall.** A river begins at a machine. Walk to the source of any + river and find a wall of water coming out of a structure — not a spring, an + outlet. Costs a rounding error (above). +- **The made cloud.** Tower evaporates the lake with aimed light and condenses it + over the highlands, so rain falls exactly where the river should start. No + machinery: the swarm is the pump. Costs the 22.4 % above, and buys real weather + with it. + +Canon uses **both** — made weather for the world's general hydrology, pumps for +watercourses Tower wants under precise control. + +Two consequences of the sealed hull: + +- **A river can circle the world.** The surface is one unbroken sheet, so a channel + can run the full 314 km circumference and close on itself — a lazy river returning + to its own source. Gravity cannot drive a closed loop, so it is pumped. +- **The water inventory is conserved and exactly known.** Nothing evaporates to + space. Tower knows how much water it has, to the litre, forever. + +Lifting is also slightly cheaper than on Earth, since gravity falls off with height: +1 % cheaper at 1 km, 5 % at 5 km, 25 % at 25 km. + +### 1.10 Slat orientation — RESOLVED: none + +Axial strips versus rings was weighed at length (D-016) and answered by removing +slats entirely (D-017). The comparison is kept in D-016 because it established what +the choice *cost*, and because the reasoning — that slat layout sets the shape of +Tower's countries, its climate map and its astronomy all at once — is what made +"none" a real option rather than an absence. + +### 1.11 The world as built + +Authored geography lives in **`content/geography.json`** — the source of truth — and +`npm run terrain` renders it. Names are provisional. Tower is laid out in **belts +along the axis**, which is the natural grain of an engineered climate (§1.9.4): + +| z | | | +|---|---|---| +| 0–42 km | **The Sunward Sea** | ring ocean at the foot of the sun cap | +| 55–140 km | **the range** | Westwall, The Sisters, **Snowcrown** (4,300 m), Eastwall — a 140 km arc, not a ring | +| 148–218 km | **The Dry Reach** | desert **ringing the world**, 22,000 km², 13% of the surface | +| 176/190/203 km | **three ridges** | ringing, concentric — and **The Narrows** is the only breach in all three | +| 214–430 km | **Greatwood** | forest belt | +| 248–402 km | **The Deep** | 154 × 32 km sea, long down the axis and narrow around | +| 270 km | **The Capital / The Spindle** | axial midpoint, on The Deep's antispinward shore | +| 496–540 km | **The Deepward Sea** | ring ocean at the foot of the far cap | + +#### Why the desert rings + +**On a cylinder you cannot go around a band.** Every desert on Earth can be +circumnavigated; a ringed one cannot. It is an absolute barrier across the world's +waist, and with the three ridges ringing too it becomes three concentric walls. + +#### The drainage, and why it keeps the chokepoint + +Four rivers come off the range — Westwall Water, Sisters Water, Eastwall Water and +The Long Water. On Earth most drainages **do not** cut through a rising ridge; they +are defeated and diverted, and only an *antecedent* river with enough power keeps +its course. So three of the four are turned by First Ridge, run **along its front** +gathering each other, and leave with the fourth through the single gap. + +- **The Narrows carries the entire world's runoff** — ~392 m³/s off a 9,800 km² + range, lifted 1,780 m for 6.9 GW (0.013% of budget). +- The ridge-front reaches are **the only circumferential water in Tower**, and + weigh fractionally more or less for it (§1.9.2). Everything else runs axially, + where Coriolis is exactly zero. +- Whoever holds The Narrows holds the axis of the world. The Capital sits behind it. + +#### The Deep is oriented for the view + +Long down the axis and narrow around it, so you cross it the **short** way — around +θ, where the floor curves up. From the Capital the far shore is 32 km away and +stands **2.6 km above eye level**. Crossing it lengthwise instead would be dead +flat. The orientation is the whole point. + +It is also the world's flywheel: 19× the diurnal heat storage of bare ground, and +5.9 days at full power to move its temperature one kelvin. Tower still supplies +every joule (§1.9.4), but the world now coasts for about a week rather than +stopping the moment attention lapses. + +#### The cap seas are not designed + +Gravity on an end cap points radially outward — *tangent* to the cap. Nothing rests +there; water runs down to the rim and pools. **Both ring oceans exist whether anyone +planned them or not**, each with a 314 km shoreline and a 50 km cliff standing +behind it. The only windows in the world are at their feet (§1.4). + +#### Skiing, because it is a different sport here + +Level motion feels no Coriolis (§1.9.1) but a descending skier has radial velocity, +and that does deflect: + +- **Down the axis:** a steady sideways push, always antispinward — 1.5% of g at + 15 m/s on a 20° slope, 6.4% at 35 m/s on 40°. +- **Around the cylinder:** you get heavier or lighter. 8.6% at 30 m/s, 11.4% at 40. + +So a **retrograde run gets lighter the faster you go**, which is self-reinforcing, +while a prograde run grips harder as it accelerates. Every slope in Tower has a +handedness. No Earth mountain does. Settlements sit at the tarns — Sisters Station, +Hollow Station — around 2,100 m, with the runs above them. + +#### Open questions + +- **The Spindle's height.** 3.2 km is a placeholder; an object dropped from its top + lands ~760 m antispinward of its base. +- **z 430–496 km** is unauthored, as is most of the circumference outside the range. + +## 2. Application architecture + +### 2.1 Stack + +- **Vite** + **TypeScript** (strict), no framework — the app is three canvases and + a control panel, and a framework would not earn its weight. +- **Three.js** for the exterior and interior 3D views. +- **Canvas 2D** for the map view. +- **GitLab CI → GitLab Pages**, publishing `dist/` as `public/`. + +### 2.2 Module layout + +``` +src/ + canon/ + constants.ts single source of truth for every number in §1 + geometry.ts (θ,z) <-> 3D, slat layout, map <-> surface + lighting.ts swarm aiming solution -> sun direction + intensity at + (θ,z,t), scaled by the global brightness setting (§1.3) + views/ + palette.ts one colour per place kind, shared by map, list and editor + world/ + schema.ts world.json types + validation + store.ts places CRUD, localStorage drafts, JSON import/export + instruments.ts sightline, viewshed, lighting probe, travel (§3.3) + state/ + store.ts selected point, time-of-day, spin phase, view mode, writer flag + views/ + exterior.ts Three.js: hull, slats, collector, beam, orbit, point picker + map.ts Canvas 2D: unrolled surface, slats, terminator, point picker + interior.ts Three.js: shell geometry, beam, diffusers, ground + sky.ts the atmospheric shader of §1.5 + ui/ + controls.ts time-of-day slider, brightness slider, spin toggle, view switcher + editor.ts writer-mode place editing panel + readout.ts live figures for the picked point + main.ts +``` + +`canon/constants.ts` is the spine. Every derived figure — period, rim speed, land +area, slat width — is *computed* from radius, length, slat count and target land +area, never hard-coded. Changing the radius changes the whole app coherently. + +### 2.3 State + +One small observable store. Views subscribe; nothing owns anything else. + +```ts +type TowerState = { + point: { theta: number; z: number } | null // the picked location + tod: number // 0..1, position in the diffuser day cycle + brightness: number // W/m^2 mean, 30..320 -- the diffuser output setting + spinPhase: number // 0..2pi, rotation for star motion + spinning: boolean + view: 'exterior' | 'map' | 'interior' + writer: boolean // ?writer=1 -- a UI mode, not a security boundary + probe: { from: SurfacePoint; to: SurfacePoint } | null +} +``` + +The exterior and map pickers both write `point`; the interior view reads it. That +is the entire interaction loop. + +### 2.4 The interior view + +Per the chosen scope: **real geometry, simple ground.** + +Real: the shell curving up on both sides, the far land visible overhead through +haze, the axis beam and its diffusers, correct gravity-gradient and atmospheric +cues. **No stars** — the hull is sealed (§1.4). The sky is land and light. + +Simple: the ground is procedural terrain and texture that varies plausibly with +(θ, z), not modelled scenery. No buildings, no vegetation meshes. Detailed +procedural scenery is a later phase, deliberately deferred. + +The sky is a shader over an inward-facing shell, fed by: view direction, the +atmospheric column integral along that ray, and the diffuser lighting solution. It +is the piece that carries the whole illusion and deserves the most care. + +With the stars gone, the interior view has to sell the spin some other way, and +§1.2 says how: **the sky is still and the water is not.** Slanted rain and a leaning +waterfall now do the work the wheeling stars used to. + +--- + +## 3. Writer mode and the world file + +The app is an instrument for writing the novel as much as a thing to look at. It +must answer questions like *can the far face be seen from the midpoint?*, *where +does a central embassy go?*, *can a lake overhang?* — and let their answers be +placed, named and kept. + +### 3.1 Two modes over one data file + +| | Reader (default) | Writer (`?writer=1`) | +|---|---|---| +| World content | committed `world.json`, read-only | editable, drafts in `localStorage` | +| Instruments (§3.3) | sightline probe only | all | +| Output | permalinks to a point or place | **Export JSON** for the author to commit | +| Panel | read-only detail card | full editor, canon controls, import/export | + +There is no backend — GitLab Pages is static. The loop is: the author edits in the +browser, exports `world.json`, commits it, and the published site serves it. Simple, +versioned in git alongside the prose, and diffable. + +**Writer mode is a UI mode, not a security boundary.** Anyone may set `?writer=1`; +they can only edit their own local copy, which persists nowhere and reaches nobody. +This is fine, and arguably good — a reader who finds it gets a sandbox. It must not +be mistaken for access control. + +### 3.2 The world file + +```jsonc +{ + "version": 1, + "places": [{ + "id": "hallow-crossing", // permalink target; see below + "name": "Hallow Crossing", + "kind": "city|embassy|lake|region|landmark|note", + "geometry": { "type": "point", "theta": 1.9635, "z": 270000 }, + // or { "type": "polygon", "points": [[theta,z], ...] } for lakes, regions + "blurb": "public description, shown to readers", + "notes": "the author's working notes — NEVER shipped", + "public": true // false = not ready to exist publicly + }] +} +``` + +**Two text fields, deliberately separate.** `blurb` is written for readers and +ships; `notes` is the author's working thinking and never leaves the machine except +in a backup. One field with a flag would have made every note a publication +accident waiting to happen. + +**Ids follow the name until pinned.** An id is a permalink target and must be +stable once published, but during world-building names churn constantly and a file +full of `new-city-7` is unreadable. So the id tracks the name while it still +matches it, and editing the id field freezes it for good. The editor shows the id +for exactly this reason. + +Coordinates are canon (θ radians, z metres, §1.7) — never map pixels, so the file +survives any change to how the map is drawn. + +**The `public` flag is a privacy trap worth naming.** Working notes ("embassy here? +check sightline to the cap") must not ship to readers. But a `world.json` committed +to a public repository is public regardless of any flag in it. So export writes two +files: **`world.json`** (public entries only, committed) and +**`world.private.json`** (everything, gitignored by default). Whether private notes +should nonetheless be version-controlled — in a private repo, or a second one — is +the author's call and is deliberately unresolved. + +### 3.3 Instruments + +The measuring tools are the real substance of writer mode. Each answers a question +the novel actually raised: + +- **Sightline probe.** Pick two points; get surface distance, straight-line + distance, optical depth, transmission, and a plain verdict (*crisp / hazy / ghost + / invisible*). This is the tool that answered §1.8. Available to readers too — it + is the single most illustrative thing in the app. +- **Viewshed overlay.** From a selected point, shade the whole map by transmission. + It renders the axis-versus-overhead asymmetry as one picture, which is worth more + than the table in §1.8. +- **Lighting probe.** At a point, illumination across the day cycle at the current + brightness setting (§1.3) — for writing a scene at a specific hour. +- **Travel.** Surface distance and journey time between points at chosen speeds, + including whether the route crosses a slat. +- **Sky-at-a-time.** Star field, beam position and Earth transits for a given point + and moment, so a described sky is a correct sky. + +### 3.4 What readers get + +The public link is the finished map: embassies, towns, lakes, named regions — the +permanent things, behaving like any map application. Plus the exterior view, the +interior view from any point, and permalinks so a reader can be handed a place and +a moment. Reading the world, not editing it. + +## 4. Phases + +1. **Design** — this document and `decisions.md`. ← current +2. **Scaffold** — Vite/TS/Three, CI to Pages, `canon/` implemented and unit-tested. +3. **Exterior** — hull, collector, beam, slats, orbit; hull point picking. +4. **Map** — unrolled surface, slat rendering, picking, sync with exterior. +5. **Interior** — shell geometry, sky shader, beam, stars, time-of-day. +6. **Writer mode** — ✅ *built ahead of 3–5, at the author's request, because the + world needs developing before there is anything to render.* Map view, place + editing for all thirteen kinds, points/polylines/polygons, localStorage + autosave, backup and static exports, import, and the sightline probe. +7. **Content pipeline and reader mode** — ✅ `content/geography.json` + + `npm run terrain` (D-019); the rendered terrain drawn under the map; reader and + writer modes (D-011); permalinks (D-010). +8. **Polish** — transitions, mobile, performance. + +Phases 3 (exterior) and 5 (interior) are still ahead; phase 2's `canon/` landed +with phase 6 since the map could not be drawn without it. + +**Shareable permalinks are implemented** (phase 7) — the app has +readers, and "stand here and look at this" is the whole reason it exists as a +companion piece. Named locations from the novel should be markable on the map for +the same reason. + +Later, explicitly out of scope for now: procedural scenery, settlements, weather +systems.