fuzzyworld

tower / files / src / canon / motion.ts

motion.ts

Blame: the commit that last changed each line · file · history

a08492ba 2026-09-07 Pavel Safronov1/**
2 * How things fall in Tower's rotating frame. See design.md §1.9.2.
3 *
4 * Coriolis never pushes surface water sideways (§1.9.1), so the spin is invisible
5 * in every static thing. The hull is sealed, so there are no stars to wheel
6 * overhead either. That leaves what falls as the only evidence in the sky that
7 * Tower turns at all, which makes these two angles load-bearing for the interior
8 * view rather than decoration.
9 *
10 * Constant-g plus Coriolis is the standard approximation and is what these use.
11 * It is exact only for drops small against the radius: gravity is 2% weaker 1 km
12 * up, and the true inertial-frame path is a straight line, not a parabola.
13 */
14import { G0, OMEGA_RAD_S } from './constants.js'
15
16/** Terminal velocity of an ordinary raindrop, m/s. */
17export const RAINDROP_TERMINAL_M_S = 9
18
19/**
20 * Lean of something already falling at a steady speed, in radians, antispinward.
21 *
22 * Coriolis gives 2ωv antispinward against g outward, and at terminal velocity drag
23 * holds both constant — so rain leans by a *fixed* angle rather than curving. That
24 * angle is small: 1.5° for an ordinary raindrop. Rain is a poor compass here.
25 */
26export const steadyFallLeanRad = (speedMS: number): number =>
27 Math.atan((2 * OMEGA_RAD_S * speedMS) / G0)
28
29/** Time for something dropped from `heightM` to reach the floor. */
30export const freeFallTimeS = (heightM: number): number => Math.sqrt((2 * heightM) / G0)
31
32/**
33 * Antispinward drift of something in free fall from `heightM`. Integrating the
34 * Coriolis acceleration 2ω(gt) twice gives ωgt³/3.
35 */
36export const freeFallDriftM = (heightM: number): number =>
37 (OMEGA_RAD_S * G0 * freeFallTimeS(heightM) ** 3) / 3
38
39/**
40 * Lean of the *path* of a free fall from `heightM` — where it lands, against how
41 * far it dropped. This is the tilt of a waterfall's plume seen whole, and it is
42 * the column design.md §1.9.2 tabulates: 7.6° over a kilometre.
43 */
44export const freeFallPathLeanRad = (heightM: number): number =>
45 Math.atan(freeFallDriftM(heightM) / heightM)
46
47/**
48 * Lean of the *velocity* at the bottom of the same fall — the direction a streak
3e898b51 2026-09-28 Pavel Safronov49 * of it is moving as it arrives, and so the angle falling water and spray streak at.
a08492ba 2026-09-07 Pavel Safronov50 *
51 * It reduces to atan(ωt), independent of g, and it is exactly half again the path
52 * lean in tangent: the drift integrates to ωgt³/3 over a drop of gt²/2, giving
53 * (2/3)ωt, while the sideways speed reaches ωgt² against a fall speed of gt.
54 * Both numbers are real and they describe different things, which is why
55 * §1.9.2 says 7.6° for a kilometre drop and the interior view's readout says 11.3°.
56 *
57 * Unlike rain this keeps growing with the drop, so a tall waterfall *is* a compass
58 * where a shower is not.
59 */
60export const freeFallLeanRad = (heightM: number): number =>
61 Math.atan(OMEGA_RAD_S * freeFallTimeS(heightM))
99a2821b 2026-09-29 Pavel Safronov62
63/**
64 * What something moving round the world weighs, m/s², at `radiusM` from the axis and
65 * `aroundMS` along the floor — positive spinward. Its true speed round the axis is the
66 * floor's ωr plus its own, and the floor has to hold it on that circle: (ωr + v)²/r.
67 *
68 * So going spinward adds weight and going antispinward takes it away, and it is not
69 * small: a train at 100 m/s is 31% heavier one way and 27% lighter the other, and
70 * something doing ωr antispinward — 700 m/s at the floor — weighs nothing at all,
71 * because it is standing still while the world turns under it. Moving along the axis
72 * changes nothing. Every circumferential journey in Tower has a handedness (D-085).
73 */
74export const apparentGravity = (radiusM: number, aroundMS: number): number =>
75 (OMEGA_RAD_S * radiusM + aroundMS) ** 2 / radiusM