@johnmorrisdotca/uchusen-rockets 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -92,6 +92,8 @@ export declare class RocketViewer {
92
92
  private settled;
93
93
  private marks;
94
94
  private markHost;
95
+ /** The words that say what stands beside the craft: its name and length, under its foot. */
96
+ private besideEl;
95
97
  private focusing;
96
98
  private nearSaid;
97
99
  private nearAt;
@@ -189,6 +191,9 @@ export declare class RocketViewer {
189
191
  private wake;
190
192
  /** Labels on the parts: each follows its part as the model turns, hides with its part, and gives way to a label drawn before it that it would cover. Null takes them away. */
191
193
  setMarks(marks: readonly ViewerMark[] | null): void;
194
+ private hostOfMarks;
195
+ /** What stands beside the craft is named: a caption under its foot, kept inside the picture. */
196
+ private placeBeside;
192
197
  /** Put the labels where their parts are now. */
193
198
  private placeMarks;
194
199
  /** Show only some slots and fly to look at them: an inset. Null puts the ship back as it was. */
@@ -14,6 +14,7 @@ import { pixelRatioFor } from "../pixels.js";
14
14
  import { MATERIALS } from "../model/materials.js";
15
15
  import { paintGlow, paintSky, paintSteel, paintTiles } from "./paint.js";
16
16
  import { flightBounds, frameAt } from "../flight.js";
17
+ import { besideLabel } from "../beside.js";
17
18
  import { GroundKit } from "./ground.js";
18
19
  import { PartPlumes, PlumeKit } from "./plumes.js";
19
20
  const IDLE_STOP_MS = 90_000;
@@ -142,6 +143,8 @@ export class RocketViewer {
142
143
  settled = Promise.resolve();
143
144
  marks = [];
144
145
  markHost = null;
146
+ /** The words that say what stands beside the craft: its name and length, under its foot. */
147
+ besideEl = null;
145
148
  focusing = false;
146
149
  nearSaid = false;
147
150
  nearAt = 0;
@@ -237,7 +240,7 @@ export class RocketViewer {
237
240
  this.renderer.shadowMap.enabled = this.shadows;
238
241
  this.sun.castShadow = this.shadows;
239
242
  const places = built.placesOf(show);
240
- for (const part of built.parts) {
243
+ for (const part of [...built.parts, ...built.beside]) {
241
244
  const source = gltf.scene.getObjectByName(part.slot);
242
245
  if (!source)
243
246
  continue;
@@ -247,11 +250,13 @@ export class RocketViewer {
247
250
  holder.add(code);
248
251
  const view = {
249
252
  slot: part.slot,
253
+ beside: built.beside.includes(part),
250
254
  holder,
251
255
  code,
252
256
  model: null,
253
- modelFile: part.record.painted?.file ?? null,
254
- ownNozzle: Boolean(part.record.painted?.ownNozzle),
257
+ // the stack beside it is this package's own paint in every look: a licensed model shows only with its credit, which is the craft's
258
+ modelFile: built.beside.includes(part) ? null : (part.record.painted?.file ?? null),
259
+ ownNozzle: !built.beside.includes(part) && Boolean(part.record.painted?.ownNozzle),
255
260
  modelState: "none",
256
261
  nozzleShown: false,
257
262
  faces: [],
@@ -292,7 +297,8 @@ export class RocketViewer {
292
297
  this.setFlight(this.clockNow);
293
298
  }
294
299
  this.canvas.dataset.ready = "true";
295
- this.canvas.dataset.parts = this.parts.map((part) => part.slot).join(" ");
300
+ this.canvas.dataset.parts = this.parts.filter((part) => !part.beside).map((part) => part.slot).join(" ");
301
+ this.canvas.dataset.beside = built.beside.length ? "on" : "off";
296
302
  this.drivenDirty = this.driven !== null;
297
303
  this.wake();
298
304
  await this.settled;
@@ -606,6 +612,9 @@ export class RocketViewer {
606
612
  this.ground = new GroundKit();
607
613
  this.scene.add(this.ground.group);
608
614
  }
615
+ for (const part of this.parts)
616
+ if (part.beside)
617
+ part.holder.visible = false;
609
618
  const { min, max } = this.boundsNow();
610
619
  this.ground.fit(this.built.boundsOf("together").max[0] * 2.4 + 4, Math.max(Math.abs(min[0]), Math.abs(max[0])));
611
620
  this.ground.group.visible = true;
@@ -707,7 +716,7 @@ export class RocketViewer {
707
716
  this.options.onPainted("");
708
717
  return;
709
718
  }
710
- const states = this.parts.map((part) => (part.modelFile ? part.modelState : "code"));
719
+ const states = this.parts.filter((part) => !part.beside).map((part) => (part.modelFile ? part.modelState : "code"));
711
720
  const state = states.some((s) => s === "loading" || s === "none") ? "loading" : states.every((s) => s === "ready") ? "model" : states.includes("ready") ? "mixed" : "code";
712
721
  this.canvas.dataset.painted = state;
713
722
  this.options.onPainted(state);
@@ -1106,18 +1115,13 @@ export class RocketViewer {
1106
1115
  el.remove();
1107
1116
  this.marks = [];
1108
1117
  if (!marks || marks.length === 0) {
1109
- this.markHost?.remove();
1110
- this.markHost = null;
1118
+ if (!this.besideEl) {
1119
+ this.markHost?.remove();
1120
+ this.markHost = null;
1121
+ }
1111
1122
  return;
1112
1123
  }
1113
- if (!this.markHost) {
1114
- const host = document.createElement("div");
1115
- host.className = "marks";
1116
- host.setAttribute("aria-hidden", "true");
1117
- host.style.cssText = "position:absolute;inset:0;overflow:hidden;pointer-events:none;font:11px/1.2 system-ui,sans-serif";
1118
- this.holder.appendChild(host);
1119
- this.markHost = host;
1120
- }
1124
+ this.hostOfMarks();
1121
1125
  for (const mark of marks) {
1122
1126
  const el = document.createElement("span");
1123
1127
  el.dataset.mark = mark.id;
@@ -1125,11 +1129,52 @@ export class RocketViewer {
1125
1129
  el.style.cssText = mark.numbered
1126
1130
  ? "position:absolute;left:0;top:0;width:22px;height:22px;margin:-11px 0 0 -11px;border-radius:50%;background:#f2c14e;color:#0b111b;font-weight:700;text-align:center;line-height:22px;will-change:transform;display:none"
1127
1131
  : "position:absolute;left:0;top:0;padding:1px 5px;border-left:2px solid #f2c14e;color:#e6edf6;background:rgba(11,17,27,0.72);white-space:nowrap;will-change:transform;display:none";
1128
- this.markHost.appendChild(el);
1132
+ this.hostOfMarks().appendChild(el);
1129
1133
  this.marks.push({ mark, el });
1130
1134
  }
1131
1135
  this.wake();
1132
1136
  }
1137
+ hostOfMarks() {
1138
+ if (!this.markHost) {
1139
+ const host = document.createElement("div");
1140
+ host.className = "marks";
1141
+ host.setAttribute("aria-hidden", "true");
1142
+ host.style.cssText = "position:absolute;inset:0;overflow:hidden;pointer-events:none;font:11px/1.2 system-ui,sans-serif";
1143
+ this.holder.appendChild(host);
1144
+ this.markHost = host;
1145
+ }
1146
+ return this.markHost;
1147
+ }
1148
+ /** What stands beside the craft is named: a caption under its foot, kept inside the picture. */
1149
+ placeBeside() {
1150
+ const view = this.parts.find((part) => part.beside);
1151
+ if (!view) {
1152
+ this.besideEl?.remove();
1153
+ this.besideEl = null;
1154
+ return;
1155
+ }
1156
+ if (!this.besideEl) {
1157
+ const el = document.createElement("span");
1158
+ el.dataset.besideLabel = "";
1159
+ el.textContent = besideLabel();
1160
+ el.style.cssText = "position:absolute;left:0;top:0;padding:1px 5px;color:#e6edf6;background:rgba(11,17,27,0.72);white-space:nowrap;will-change:transform;display:none";
1161
+ this.hostOfMarks().appendChild(el);
1162
+ this.besideEl = el;
1163
+ }
1164
+ const el = this.besideEl;
1165
+ if (!view.holder.visible || this.clockNow) {
1166
+ el.style.display = "none";
1167
+ return;
1168
+ }
1169
+ const width = this.canvas.clientWidth;
1170
+ const height = this.canvas.clientHeight;
1171
+ const point = new Vector3(view.holder.position.x, view.holder.position.y, view.holder.position.z).project(this.camera);
1172
+ const w = besideLabel().length * 6.2 + 12;
1173
+ const x = Math.min(Math.max(((point.x + 1) / 2) * width - w / 2, 4), Math.max(4, width - w - 4));
1174
+ const y = Math.min(((1 - point.y) / 2) * height + 6, height - 20);
1175
+ el.style.display = point.z < 1 ? "block" : "none";
1176
+ el.style.transform = `translate(${Math.round(x)}px,${Math.round(y)}px)`;
1177
+ }
1133
1178
  /** Put the labels where their parts are now. */
1134
1179
  placeMarks() {
1135
1180
  if (this.marks.length === 0)
@@ -1282,6 +1327,7 @@ export class RocketViewer {
1282
1327
  this.syncSizes();
1283
1328
  this.renderer.render(this.scene, this.camera);
1284
1329
  this.placeMarks();
1330
+ this.placeBeside();
1285
1331
  if (this.options.onNear && !this.nearSaid && this.nearAt > 0 && this.camera.position.distanceTo(this.controls.target) < this.nearAt) {
1286
1332
  this.nearSaid = true;
1287
1333
  this.options.onNear();
package/dist/element.d.ts CHANGED
@@ -144,6 +144,8 @@ export declare class UchusenRocket extends HTMLBase {
144
144
  private flightStep;
145
145
  /** Tells the page where the timeline is: at once for a new phase or a stop, otherwise at most 8 times a second. */
146
146
  private noteFlight;
147
+ /** Whether Starship stands beside it: `beside="on"`, and never beside Starship itself. */
148
+ private besideOn;
147
149
  /** Whether the engines are lit: `engines="on"`, and never for a reader who asked for reduced motion. */
148
150
  private engineLights;
149
151
  /** Hands the 3D view what the attributes say about the engines, and its reader's motion setting. */
package/dist/element.js CHANGED
@@ -9,6 +9,7 @@ import { defineUchusenFlight, UchusenFlight } from "./flightbar.js";
9
9
  import { lineupSvg } from "./build/lineup.js";
10
10
  import { CROSSFADE_MS, REDUCED_FADE_MS, revealDelay } from "./crossfade.js";
11
11
  import { cleanView, turnedBy, VIEWS } from "./framing.js";
12
+ import { canBeside } from "./beside.js";
12
13
  import { cleanShow } from "./layout.js";
13
14
  import { cleanLook } from "./looks.js";
14
15
  import { ROCKETS, SLOT_NAMES } from "./rockets.js";
@@ -123,7 +124,7 @@ function whyNot(mode) {
123
124
  * ```
124
125
  */
125
126
  export class UchusenRocket extends HTMLBase {
126
- static observedAttributes = ["rocket", "variant", "show", "look", "view", "build", "mode", "assets", "spin", "way", "label", "engines", "phase", "labels", "inspector"];
127
+ static observedAttributes = ["rocket", "variant", "show", "look", "view", "build", "mode", "assets", "spin", "way", "label", "engines", "phase", "labels", "inspector", "beside"];
127
128
  descriptionValue = null;
128
129
  picture = null;
129
130
  holder = null;
@@ -440,6 +441,10 @@ export class UchusenRocket extends HTMLBase {
440
441
  this.dataset.phase = this.flightState.active ? this.flightState.phase : "";
441
442
  this.emit("uchusen-flight", this.flightState);
442
443
  }
444
+ /** Whether Starship stands beside it: `beside="on"`, and never beside Starship itself. */
445
+ besideOn(description) {
446
+ return this.getAttribute("beside") === "on" && canBeside(description.rocket);
447
+ }
443
448
  /** Whether the engines are lit: `engines="on"`, and never for a reader who asked for reduced motion. */
444
449
  engineLights() {
445
450
  return enginesWanted(this.getAttribute("engines"), media("(prefers-reduced-motion: reduce)"));
@@ -451,11 +456,11 @@ export class UchusenRocket extends HTMLBase {
451
456
  }
452
457
  update() {
453
458
  const description = this.descriptionNow();
454
- const key = JSON.stringify(description);
459
+ const key = `${JSON.stringify(description)}|${this.besideOn(description)}`;
455
460
  if (key !== this.key || !this.builtNow) {
456
461
  this.key = key;
457
462
  try {
458
- this.builtNow = build(description, { detail: this.detailFor(description) });
463
+ this.builtNow = build(description, { detail: this.detailFor(description), beside: this.besideOn(description) });
459
464
  }
460
465
  catch (error) {
461
466
  this.builtNow = null;
@@ -557,6 +562,7 @@ export class UchusenRocket extends HTMLBase {
557
562
  const { look, show, viewName } = this.settings(this.builtNow);
558
563
  this.dataset.look = look;
559
564
  this.dataset.engines = this.engineLights() ? "on" : "off";
565
+ this.dataset.beside = this.builtNow.beside.length ? "on" : "off";
560
566
  this.dataset.flight = this.flight?.id ?? "";
561
567
  this.dataset.show = show;
562
568
  this.dataset.viewAngle = viewName;
@@ -604,7 +610,7 @@ export class UchusenRocket extends HTMLBase {
604
610
  return;
605
611
  this.fine = true;
606
612
  try {
607
- this.builtNow = build(description, { detail: "full" });
613
+ this.builtNow = build(description, { detail: "full", beside: this.besideOn(description) });
608
614
  }
609
615
  catch {
610
616
  return;
@@ -871,7 +877,7 @@ svg { display: block; }
871
877
  * ```
872
878
  */
873
879
  export class UchusenLineup extends HTMLBase {
874
- static observedAttributes = ["items", "unit", "look", "view", "show", "ruler", "labels", "filter", "fit"];
880
+ static observedAttributes = ["items", "unit", "look", "view", "show", "ruler", "labels", "filter", "fit", "real"];
875
881
  connectedCallback() {
876
882
  if (!this.shadowRoot)
877
883
  adopt(this.attachShadow({ mode: "open" }), LINEUP_CSS, lineupSheet);
@@ -888,7 +894,8 @@ export class UchusenLineup extends HTMLBase {
888
894
  const raw = Number.parseFloat(this.getAttribute("unit") ?? "3");
889
895
  const unit = Number.isFinite(raw) && raw > 0 && raw <= 100 ? raw : 3;
890
896
  const items = (this.getAttribute("items") ?? "").split(",").map((item) => item.trim()).filter(Boolean);
891
- const { svg, items: shown, unit: drawnUnit } = lineupSvg({
897
+ const { svg, items: shown, real: shownReal, unit: drawnUnit } = lineupSvg({
898
+ real: this.getAttribute("real") === "on",
892
899
  items,
893
900
  unit,
894
901
  look: cleanLook(this.getAttribute("look")),
@@ -909,6 +916,7 @@ export class UchusenLineup extends HTMLBase {
909
916
  child.remove();
910
917
  root.appendChild(node);
911
918
  this.dataset.count = String(shown.length);
919
+ this.dataset.real = String(shownReal.length);
912
920
  }
913
921
  }
914
922
  /**
package/dist/index.d.ts CHANGED
@@ -22,6 +22,7 @@ export type { Angle, Framing, Vec3, ViewChoice, ViewName } from "./framing.ts";
22
22
  export { cleanLook, DEFAULT_LOOK, LOOK_NAMES, LOOKS } from "./looks.ts";
23
23
  export type { Look, LookName } from "./looks.ts";
24
24
  export { cleanShow, placesFor, showsOf } from "./layout.ts";
25
+ export { BESIDE_ROCKET, besideBounds, besideLabel, besideLayout, canBeside } from "./beside.ts";
25
26
  export type { Place, ShowName } from "./layout.ts";
26
27
  export { CROSSFADE_MS, DRAWING_HOLD_MS, REDUCED_FADE_MS, revealDelay } from "./crossfade.ts";
27
28
  export { MAX_PIXELS, MAX_RATIO, MAX_SIDE, pixelRatioFor } from "./pixels.ts";
package/dist/index.js CHANGED
@@ -12,6 +12,7 @@ export { check } from "./fit.js";
12
12
  export { axesOf, cleanView, DEFAULT_VIEW, directionOf, FOV_DEG, frameFor, PICTURE_H, PICTURE_W, turnedBy, VIEW_NAMES, VIEWS } from "./framing.js";
13
13
  export { cleanLook, DEFAULT_LOOK, LOOK_NAMES, LOOKS } from "./looks.js";
14
14
  export { cleanShow, placesFor, showsOf } from "./layout.js";
15
+ export { BESIDE_ROCKET, besideBounds, besideLabel, besideLayout, canBeside } from "./beside.js";
15
16
  export { CROSSFADE_MS, DRAWING_HOLD_MS, REDUCED_FADE_MS, revealDelay } from "./crossfade.js";
16
17
  export { MAX_PIXELS, MAX_RATIO, MAX_SIDE, pixelRatioFor } from "./pixels.js";
17
18
  export { tiltMode, tiltTurn } from "./tilt.js";
@@ -0,0 +1,47 @@
1
+ /**
2
+ * A place a trip can start or end at: the Earth, the Moon or a planet, with what the arithmetic needs.
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * import type { Stop } from "@johnmorrisdotca/uchusen-rockets/journey";
7
+ *
8
+ * const mars: Stop = { id: "mars", name: { en: "Mars", ja: "火星" }, kind: "planet", radiusKm: 3396.19, colour: "#c76a3f" };
9
+ * console.log(mars.name.en);
10
+ * ```
11
+ */
12
+ export interface Stop {
13
+ id: string;
14
+ name: {
15
+ en: string;
16
+ ja: string;
17
+ };
18
+ kind: "star" | "planet" | "dwarf-planet" | "moon";
19
+ /** The planet a moon goes round. */
20
+ parent?: string;
21
+ /** The equatorial radius, km. */
22
+ radiusKm: number;
23
+ /** The gravitational parameter, km^3/s^2. Left out, the journey's own table (`GM_KM3_S2`) is used. */
24
+ muKm3s2?: number;
25
+ /** The sidereal orbital period, days. Left out, the journey's own table (`PERIOD_DAYS`) is used. */
26
+ periodDays?: number;
27
+ /** The body's mean colour, `#rrggbb`. */
28
+ colour: string;
29
+ }
30
+ /**
31
+ * Where the stops are, and what they are. The journey's core takes one of these and imports nothing.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * import type { BodySource } from "@johnmorrisdotca/uchusen-rockets/journey";
36
+ *
37
+ * const empty: BodySource = { stops: [], positionAu: () => [0, 0, 0], offsetKm: () => [0, 0, 0] };
38
+ * console.log(empty.stops.length);
39
+ * ```
40
+ */
41
+ export interface BodySource {
42
+ stops: readonly Stop[];
43
+ /** A planet's position round the Sun (ecliptic, astronomical units) at a time in milliseconds since 1970. */
44
+ positionAu(id: string, ms: number): readonly [number, number, number];
45
+ /** A moon's position from its planet's centre (ecliptic, kilometres) at a time. */
46
+ offsetKm(id: string, ms: number): readonly [number, number, number];
47
+ }
@@ -0,0 +1,2 @@
1
+ // What the journey needs to know about a place, and where it is. The package depends on no ephemeris: a page hands it a `BodySource`, and `demo/journey-bodies.ts` makes one from wakusei-planets. Pure types.
2
+ export {};
@@ -0,0 +1,115 @@
1
+ /**
2
+ * The speed of light, metres a second (exact, by definition of the metre).
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * import { C } from "@johnmorrisdotca/uchusen-rockets/journey";
7
+ *
8
+ * console.log(C);
9
+ * ```
10
+ */
11
+ export declare const C = 299792458;
12
+ /**
13
+ * One standard gravity, metres a second squared (exact, by definition).
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { G0 } from "@johnmorrisdotca/uchusen-rockets/journey";
18
+ *
19
+ * console.log(G0);
20
+ * ```
21
+ */
22
+ export declare const G0 = 9.80665;
23
+ /**
24
+ * One astronomical unit, metres (exact, IAU 2012).
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * import { AU_M } from "@johnmorrisdotca/uchusen-rockets/journey";
29
+ *
30
+ * console.log(AU_M);
31
+ * ```
32
+ */
33
+ export declare const AU_M = 149597870700;
34
+ /**
35
+ * One astronomical unit, kilometres.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * import { AU_KM } from "@johnmorrisdotca/uchusen-rockets/journey";
40
+ *
41
+ * console.log(AU_KM);
42
+ * ```
43
+ */
44
+ export declare const AU_KM: number;
45
+ /**
46
+ * A day, seconds.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * import { DAY_S } from "@johnmorrisdotca/uchusen-rockets/journey";
51
+ *
52
+ * console.log(DAY_S);
53
+ * ```
54
+ */
55
+ export declare const DAY_S = 86400;
56
+ /**
57
+ * A Julian year, seconds.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * import { YEAR_S } from "@johnmorrisdotca/uchusen-rockets/journey";
62
+ *
63
+ * console.log(YEAR_S);
64
+ * ```
65
+ */
66
+ export declare const YEAR_S = 31557600;
67
+ /**
68
+ * A light year, metres.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * import { LY_M } from "@johnmorrisdotca/uchusen-rockets/journey";
73
+ *
74
+ * console.log(LY_M);
75
+ * ```
76
+ */
77
+ export declare const LY_M: number;
78
+ /**
79
+ * Gravitational parameters (GM), cubic kilometres a second squared. NASA/JPL: "Planetary Satellite Physical Parameters" and "Planetary Physical Parameters"
80
+ * (https://ssd.jpl.nasa.gov/), read 2026-11-04. The Sun's is the IAU 2015 nominal value.
81
+ *
82
+ * @example
83
+ * ```ts
84
+ * import { GM_KM3_S2 } from "@johnmorrisdotca/uchusen-rockets/journey";
85
+ *
86
+ * console.log(GM_KM3_S2.earth, GM_KM3_S2.moon);
87
+ * ```
88
+ */
89
+ export declare const GM_KM3_S2: Readonly<Record<string, number>>;
90
+ /**
91
+ * Sidereal orbital periods, days (NASA's planetary fact sheets, https://nssdc.gsfc.nasa.gov/planetary/factsheet/).
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * import { PERIOD_DAYS } from "@johnmorrisdotca/uchusen-rockets/journey";
96
+ *
97
+ * console.log(PERIOD_DAYS.mars);
98
+ * ```
99
+ */
100
+ export declare const PERIOD_DAYS: Readonly<Record<string, number>>;
101
+ /**
102
+ * The height of the circular parking orbit round each kind of body, kilometres: 185 km above the Earth (Apollo's), 100 km above the Moon (Apollo's), 200 km above any other body.
103
+ *
104
+ * @example
105
+ * ```ts
106
+ * import { PARKING_ALTITUDE_KM } from "@johnmorrisdotca/uchusen-rockets/journey";
107
+ *
108
+ * console.log(PARKING_ALTITUDE_KM.earth);
109
+ * ```
110
+ */
111
+ export declare const PARKING_ALTITUDE_KM: {
112
+ readonly earth: 185;
113
+ readonly moon: 100;
114
+ readonly other: 200;
115
+ };
@@ -0,0 +1,134 @@
1
+ // The constants a trip needs, each with where it is from. Metres and seconds unless the name says otherwise. Pure.
2
+ /**
3
+ * The speed of light, metres a second (exact, by definition of the metre).
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { C } from "@johnmorrisdotca/uchusen-rockets/journey";
8
+ *
9
+ * console.log(C);
10
+ * ```
11
+ */
12
+ export const C = 299_792_458;
13
+ /**
14
+ * One standard gravity, metres a second squared (exact, by definition).
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { G0 } from "@johnmorrisdotca/uchusen-rockets/journey";
19
+ *
20
+ * console.log(G0);
21
+ * ```
22
+ */
23
+ export const G0 = 9.80665;
24
+ /**
25
+ * One astronomical unit, metres (exact, IAU 2012).
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { AU_M } from "@johnmorrisdotca/uchusen-rockets/journey";
30
+ *
31
+ * console.log(AU_M);
32
+ * ```
33
+ */
34
+ export const AU_M = 149_597_870_700;
35
+ /**
36
+ * One astronomical unit, kilometres.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * import { AU_KM } from "@johnmorrisdotca/uchusen-rockets/journey";
41
+ *
42
+ * console.log(AU_KM);
43
+ * ```
44
+ */
45
+ export const AU_KM = AU_M / 1000;
46
+ /**
47
+ * A day, seconds.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * import { DAY_S } from "@johnmorrisdotca/uchusen-rockets/journey";
52
+ *
53
+ * console.log(DAY_S);
54
+ * ```
55
+ */
56
+ export const DAY_S = 86_400;
57
+ /**
58
+ * A Julian year, seconds.
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * import { YEAR_S } from "@johnmorrisdotca/uchusen-rockets/journey";
63
+ *
64
+ * console.log(YEAR_S);
65
+ * ```
66
+ */
67
+ export const YEAR_S = 31_557_600;
68
+ /**
69
+ * A light year, metres.
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * import { LY_M } from "@johnmorrisdotca/uchusen-rockets/journey";
74
+ *
75
+ * console.log(LY_M);
76
+ * ```
77
+ */
78
+ export const LY_M = C * YEAR_S;
79
+ /**
80
+ * Gravitational parameters (GM), cubic kilometres a second squared. NASA/JPL: "Planetary Satellite Physical Parameters" and "Planetary Physical Parameters"
81
+ * (https://ssd.jpl.nasa.gov/), read 2026-11-04. The Sun's is the IAU 2015 nominal value.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * import { GM_KM3_S2 } from "@johnmorrisdotca/uchusen-rockets/journey";
86
+ *
87
+ * console.log(GM_KM3_S2.earth, GM_KM3_S2.moon);
88
+ * ```
89
+ */
90
+ export const GM_KM3_S2 = {
91
+ sun: 132_712_440_018,
92
+ mercury: 22_031.868,
93
+ venus: 324_858.592,
94
+ earth: 398_600.4418,
95
+ moon: 4_902.800,
96
+ mars: 42_828.375,
97
+ jupiter: 126_686_534,
98
+ saturn: 37_931_187,
99
+ uranus: 5_793_939,
100
+ neptune: 6_836_529,
101
+ pluto: 869.6,
102
+ };
103
+ /**
104
+ * Sidereal orbital periods, days (NASA's planetary fact sheets, https://nssdc.gsfc.nasa.gov/planetary/factsheet/).
105
+ *
106
+ * @example
107
+ * ```ts
108
+ * import { PERIOD_DAYS } from "@johnmorrisdotca/uchusen-rockets/journey";
109
+ *
110
+ * console.log(PERIOD_DAYS.mars);
111
+ * ```
112
+ */
113
+ export const PERIOD_DAYS = {
114
+ mercury: 87.969,
115
+ venus: 224.701,
116
+ earth: 365.256,
117
+ mars: 686.98,
118
+ jupiter: 4332.589,
119
+ saturn: 10759.22,
120
+ uranus: 30685.4,
121
+ neptune: 60189,
122
+ pluto: 90560,
123
+ };
124
+ /**
125
+ * The height of the circular parking orbit round each kind of body, kilometres: 185 km above the Earth (Apollo's), 100 km above the Moon (Apollo's), 200 km above any other body.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * import { PARKING_ALTITUDE_KM } from "@johnmorrisdotca/uchusen-rockets/journey";
130
+ *
131
+ * console.log(PARKING_ALTITUDE_KM.earth);
132
+ * ```
133
+ */
134
+ export const PARKING_ALTITUDE_KM = { earth: 185, moon: 100, other: 200 };
@@ -0,0 +1,49 @@
1
+ import type { Trip } from "./trip.ts";
2
+ /**
3
+ * The engine preheat bar before ignition: ten segments and a percent. It fills from 13 seconds before lift-off to 3 seconds before, and is full after.
4
+ * @param missionS Mission seconds from lift-off (negative before).
5
+ * @returns The percent (0 to 100), how many of the ten segments are full, and how full the next one is (0 to 1).
6
+ * @example
7
+ * ```ts
8
+ * import { preheat } from "@johnmorrisdotca/uchusen-rockets/journey";
9
+ *
10
+ * console.log(preheat(-8.5));
11
+ * ```
12
+ */
13
+ export declare function preheat(missionS: number): {
14
+ percent: number;
15
+ full: number;
16
+ partial: number;
17
+ };
18
+ /**
19
+ * The ignition count: IGNITION IN 3, 2, 1, then 0 from lift-off, with how far round the ring dial has gone.
20
+ * @param missionS Mission seconds from lift-off (negative before).
21
+ * @returns The number to show (3, 2, 1 or 0) and the ring's sweep (0 to 1).
22
+ * @example
23
+ * ```ts
24
+ * import { ignition } from "@johnmorrisdotca/uchusen-rockets/journey";
25
+ *
26
+ * console.log(ignition(-2.2), ignition(0));
27
+ * ```
28
+ */
29
+ export declare function ignition(missionS: number): {
30
+ count: number;
31
+ ring: number;
32
+ };
33
+ /**
34
+ * The timer before and during the braking burn: DECELERATION BURN IN until it starts, DECELERATION COMPLETE IN while it runs, nothing after.
35
+ * @param trip A planned trip.
36
+ * @param missionS Mission seconds from lift-off.
37
+ * @returns Which timer, and its seconds; or null when there is none to show.
38
+ * @example
39
+ * ```ts no-run
40
+ * import { burnTimer, type Trip } from "@johnmorrisdotca/uchusen-rockets/journey";
41
+ *
42
+ * declare const trip: Trip;
43
+ * console.log(burnTimer(trip, 10));
44
+ * ```
45
+ */
46
+ export declare function burnTimer(trip: Trip, missionS: number): {
47
+ kind: "burn-in" | "complete-in";
48
+ seconds: number;
49
+ } | null;