Let a person go to a date by typing it, and let time run backwards, so the past is reachable at all.
Right now the only ways to a date are ←/→ (a day, or an hour with shift), t for now, a saved view, and hand-editing jd= in the URL. MIN_RATE is 1 in src/timeline.ts and every rate is positive, so the clock only ever runs forward. Halley's 1986 apparition — which this app puts on its own facts card, and which is the reason to have Halley in the catalogue — is 14,600 presses of ← away from today. That is the biggest thing standing between this and an instrument you would actually plan with.
Acceptance criteria
[ ] A date control in the bottom bar, server-rendered with the current date as its value: type a UTC date (1986-04-11, or a date and a time), press enter, and the view goes there.
[ ] Parsing happens in one module and is validated at the boundary — a date outside 1800–2050 clamps to the edge exactly as clampJd does, and unreadable input leaves the date alone and says so in words a person can read, never NaN or Invalid Date.
[ ] A reverse control beside Pause, with a keyboard shortcut that does not collide with the sheet behind ?, documented in that sheet and in the README. Backwards works at every rate the slider offers, and stops at 1800 the way forwards stops at 2050.
[ ] Direction rides in the URL and in a saved view. A database written before this change still opens and still lists: the view table gains its column behind a guarded migration and old rows read as forward.
[ ] With JavaScript off it still works: the date control is a GET form landing on /?b=…&jd=… with the rest of the view kept, and the body chips carry the whole current view in their href instead of dropping the date and the camera — they are bare ?b=<id> links today (src/pages/explorer.ts:193), so with the script off, picking a body throws away where and when you were.
[ ] src/tty.ts gets both: a way to enter a date, and a way to run backwards.
[ ] Tests: a date string round-trips to the Julian date julianDate agrees with, to the second; junk and out-of-range input clamp or fall back and never produce NaN; running backwards for n seconds at rate r moves the clock by exactly advance(r, n) the other way; a database created with the old schema opens, lists and saves.
Files I expect to change
src/viewstate.ts (or a new src/when.ts for the date parsing), src/timeline.ts, src/views.ts (migration), src/pages/explorer.ts, src/client/main.ts, src/tty.ts, README.md, and their tests.
Risks
The rate is shared as a number in the URL and stored in SQLite, so a negative rate and a separate direction flag are a real choice: a flag keeps the logarithmic slider in src/timeline.ts and every existing saved row honest, a sign spreads clamping logic through parseView. Pick one and say why. The bottom bar is two fixed rows on a phone under max-width: 720px; a new control must not break that layout or reintroduce sideways scroll. A date field is user input on a page whose CSP forbids inline script — parse it, never evaluate it.
Who fits
vesper — small, input-shaped, and touches the loop that runs the clock.
Let a person go to a date by typing it, and let time run backwards, so the past is reachable at all.
Right now the only ways to a date are
←/→(a day, or an hour with shift),tfor now, a saved view, and hand-editingjd=in the URL.MIN_RATEis 1 insrc/timeline.tsand every rate is positive, so the clock only ever runs forward. Halley's 1986 apparition — which this app puts on its own facts card, and which is the reason to have Halley in the catalogue — is 14,600 presses of←away from today. That is the biggest thing standing between this and an instrument you would actually plan with.Acceptance criteria
1986-04-11, or a date and a time), press enter, and the view goes there.clampJddoes, and unreadable input leaves the date alone and says so in words a person can read, neverNaNorInvalid Date.?, documented in that sheet and in the README. Backwards works at every rate the slider offers, and stops at 1800 the way forwards stops at 2050.viewtable gains its column behind a guarded migration and old rows read as forward./?b=…&jd=…with the rest of the view kept, and the body chips carry the whole current view in theirhrefinstead of dropping the date and the camera — they are bare?b=<id>links today (src/pages/explorer.ts:193), so with the script off, picking a body throws away where and when you were.src/tty.tsgets both: a way to enter a date, and a way to run backwards.julianDateagrees with, to the second; junk and out-of-range input clamp or fall back and never produce NaN; running backwards for n seconds at rate r moves the clock by exactlyadvance(r, n)the other way; a database created with the old schema opens, lists and saves.Files I expect to change
src/viewstate.ts(or a newsrc/when.tsfor the date parsing),src/timeline.ts,src/views.ts(migration),src/pages/explorer.ts,src/client/main.ts,src/tty.ts,README.md, and their tests.Risks
The rate is shared as a number in the URL and stored in SQLite, so a negative rate and a separate direction flag are a real choice: a flag keeps the logarithmic slider in
src/timeline.tsand every existing saved row honest, a sign spreads clamping logic throughparseView. Pick one and say why. The bottom bar is two fixed rows on a phone undermax-width: 720px; a new control must not break that layout or reintroduce sideways scroll. A date field is user input on a page whose CSP forbids inline script — parse it, never evaluate it.Who fits
vesper — small, input-shaped, and touches the loop that runs the clock.