@johnmorrisdotca/uchusen-rockets 0.3.0 → 0.5.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.
- package/CHANGELOG.md +31 -5
- package/NOTICE.md +2 -0
- package/README.md +316 -4
- package/dist/assets/droneship-asog-landed.glb +0 -0
- package/dist/assets/droneship-asog.glb +0 -0
- package/dist/assets/droneship-jrti-landed.glb +0 -0
- package/dist/assets/droneship-jrti.glb +0 -0
- package/dist/assets/droneship-ocisly-landed.glb +0 -0
- package/dist/assets/droneship-ocisly.glb +0 -0
- package/dist/assets/falcon-9-block-5-dragon-2-first-stage.glb +0 -0
- package/dist/assets/falcon-9-block-5-dragon-2.glb +0 -0
- package/dist/assets/falcon-9-block-5-first-stage.glb +0 -0
- package/dist/assets/falcon-9-block-5.glb +0 -0
- package/dist/assets/falcon-9-ft-first-stage.glb +0 -0
- package/dist/assets/falcon-9-ft.glb +0 -0
- package/dist/assets/falcon-9-v1.1-first-stage.glb +0 -0
- package/dist/assets/falcon-9-v1.1.glb +0 -0
- package/dist/assets/falcon-heavy-falcon-heavy-centre.glb +0 -0
- package/dist/assets/falcon-heavy-falcon-heavy-side-left.glb +0 -0
- package/dist/assets/falcon-heavy-falcon-heavy-side-right.glb +0 -0
- package/dist/assets/falcon-heavy-falcon-heavy.glb +0 -0
- package/dist/assets/landing-zone-lz-1-landed.glb +0 -0
- package/dist/assets/landing-zone-lz-1.glb +0 -0
- package/dist/assets/landing-zone-lz-4-landed.glb +0 -0
- package/dist/assets/landing-zone-lz-4.glb +0 -0
- package/dist/assets/launch-tower-catch-booster.glb +0 -0
- package/dist/assets/launch-tower-catch.glb +0 -0
- package/dist/assets/launch-tower-stack-booster.glb +0 -0
- package/dist/assets/launch-tower-stack-ship.glb +0 -0
- package/dist/assets/launch-tower-stack.glb +0 -0
- package/dist/assets/starship-2019.glb +0 -0
- package/dist/assets/starship-v1-booster.glb +0 -0
- package/dist/assets/starship-v1-flight1-booster.glb +0 -0
- package/dist/assets/starship-v1-flight1-ship.glb +0 -0
- package/dist/assets/starship-v1-flight1.glb +0 -0
- package/dist/assets/starship-v1-ship.glb +0 -0
- package/dist/assets/starship-v1.glb +0 -0
- package/dist/assets/starship-v2-booster.glb +0 -0
- package/dist/assets/starship-v2-ship.glb +0 -0
- package/dist/assets/starship-v2.glb +0 -0
- package/dist/assets/starship-v3-booster.glb +0 -0
- package/dist/assets/starship-v3-ship.glb +0 -0
- package/dist/assets/starship-v3.glb +0 -0
- package/dist/assets/starship-v4-booster.glb +0 -0
- package/dist/assets/starship-v4-ship.glb +0 -0
- package/dist/assets/starship-v4.glb +0 -0
- package/dist/attrs.d.ts +70 -4
- package/dist/attrs.js +59 -4
- package/dist/build/glb.d.ts +25 -0
- package/dist/build/glb.js +29 -7
- package/dist/build/index.d.ts +94 -4
- package/dist/build/index.js +71 -7
- package/dist/build/lineup.d.ts +56 -2
- package/dist/build/lineup.js +23 -2
- package/dist/builder.d.ts +47 -1
- package/dist/builder.js +14 -1
- package/dist/crossfade.d.ts +44 -2
- package/dist/crossfade.js +44 -2
- package/dist/data/credits.d.ts +44 -1
- package/dist/data/credits.js +22 -1
- package/dist/data/flight-log.d.ts +33 -1
- package/dist/data/flight-log.js +22 -1
- package/dist/data/flights.d.ts +61 -2
- package/dist/data/flights.js +160 -3
- package/dist/data/makers.d.ts +21 -0
- package/dist/data/makers.js +10 -0
- package/dist/data/propellants.d.ts +59 -0
- package/dist/data/propellants.js +43 -0
- package/dist/data/sources.d.ts +102 -0
- package/dist/data/sources.js +19 -0
- package/dist/data/types.d.ts +81 -1
- package/dist/data/types.js +26 -1
- package/dist/draw/plume.d.ts +10 -1
- package/dist/draw/plume.js +15 -5
- package/dist/element/plumes.d.ts +7 -8
- package/dist/element/plumes.js +36 -21
- package/dist/element/scene.js +30 -5
- package/dist/element.d.ts +61 -3
- package/dist/element.js +53 -5
- package/dist/embed.d.ts +110 -5
- package/dist/embed.js +88 -5
- package/dist/engines.d.ts +86 -4
- package/dist/engines.js +75 -4
- package/dist/fit.d.ts +68 -0
- package/dist/fit.js +13 -0
- package/dist/flight.d.ts +136 -9
- package/dist/flight.js +130 -10
- package/dist/flightbar.d.ts +12 -0
- package/dist/flightbar.js +13 -1
- package/dist/framing.d.ts +182 -8
- package/dist/framing.js +127 -6
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/layout.d.ts +65 -1
- package/dist/layout.js +43 -1
- package/dist/looks.d.ts +64 -1
- package/dist/looks.js +42 -1
- package/dist/model/falcon.js +2 -2
- package/dist/model/materials.d.ts +32 -0
- package/dist/model/materials.js +10 -0
- package/dist/model/moves.d.ts +36 -0
- package/dist/model/moves.js +70 -0
- package/dist/model/pieces.d.ts +31 -0
- package/dist/model/pieces.js +51 -9
- package/dist/model/registry.d.ts +22 -0
- package/dist/model/registry.js +22 -0
- package/dist/model/starship.d.ts +6 -3
- package/dist/model/starship.js +12 -7
- package/dist/parts.d.ts +33 -1
- package/dist/pixels.d.ts +44 -4
- package/dist/pixels.js +44 -4
- package/dist/react.d.ts +26 -2
- package/dist/react.js +13 -0
- package/dist/rockets.d.ts +91 -3
- package/dist/rockets.js +58 -2
- package/dist/spin.d.ts +57 -2
- package/dist/spin.js +35 -2
- package/dist/tilt.d.ts +48 -4
- package/dist/tilt.js +26 -4
- package/package.json +27 -7
package/dist/model/pieces.d.ts
CHANGED
|
@@ -7,6 +7,15 @@ export interface Frame {
|
|
|
7
7
|
v: Vec3;
|
|
8
8
|
w: Vec3;
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* A piece that a flight can turn: the name of the group it belongs to (every piece with the same name and pivot turns together), the point it turns about and the axis it turns round, in the part's own metres.
|
|
12
|
+
* A positive angle turns it right-handed about the axis. The piece is drawn where its group is at rest, which is the angle 0.
|
|
13
|
+
*/
|
|
14
|
+
export interface Move {
|
|
15
|
+
name: string;
|
|
16
|
+
pivot: Vec3;
|
|
17
|
+
axis: Vec3;
|
|
18
|
+
}
|
|
10
19
|
/** A body of revolution: `profile` is [radius, y] points going up the outside (going the other way faces inward). */
|
|
11
20
|
export interface Lathe {
|
|
12
21
|
kind: "lathe";
|
|
@@ -32,6 +41,7 @@ export interface Lathe {
|
|
|
32
41
|
body?: boolean;
|
|
33
42
|
/** Its outline is drawn in a drawing. */
|
|
34
43
|
outline?: boolean;
|
|
44
|
+
move?: Move;
|
|
35
45
|
}
|
|
36
46
|
/** A flat outline with a thickness, in a frame: `outline` is [u, v] points, going round; it stands from -thickness/2 to +thickness/2 along w. Convex, or it is drawn as its hull. */
|
|
37
47
|
export interface Plate {
|
|
@@ -47,6 +57,7 @@ export interface Plate {
|
|
|
47
57
|
only?: "mesh" | "drawing";
|
|
48
58
|
/** No feature lines of its own. */
|
|
49
59
|
plain?: boolean;
|
|
60
|
+
move?: Move;
|
|
50
61
|
}
|
|
51
62
|
/** Lines only, in the part's own space. */
|
|
52
63
|
export interface Lines {
|
|
@@ -54,6 +65,7 @@ export interface Lines {
|
|
|
54
65
|
weight: "feature" | "weld";
|
|
55
66
|
paths: readonly (readonly Vec3[])[];
|
|
56
67
|
only?: "mesh" | "drawing";
|
|
68
|
+
move?: Move;
|
|
57
69
|
}
|
|
58
70
|
export type Piece = Lathe | Plate | Lines;
|
|
59
71
|
/** A frame standing on the axis: u points outwards at `az` radians, v is up, w is along the circle. */
|
|
@@ -76,15 +88,34 @@ export interface LineBuffers {
|
|
|
76
88
|
positions: number[];
|
|
77
89
|
indices: number[];
|
|
78
90
|
}
|
|
91
|
+
/** The mesh of one moving group, its points relative to its pivot, so the group turns about its own origin. */
|
|
92
|
+
export interface MoveMesh {
|
|
93
|
+
/** The group's name, and a node name of its own: `grid-fins~0`, `grid-fins~1`. */
|
|
94
|
+
name: string;
|
|
95
|
+
id: string;
|
|
96
|
+
pivot: Vec3;
|
|
97
|
+
axis: Vec3;
|
|
98
|
+
mesh: PartMesh;
|
|
99
|
+
}
|
|
79
100
|
export interface PartMesh {
|
|
80
101
|
faces: Map<MaterialName, Buffers>;
|
|
81
102
|
feature: LineBuffers;
|
|
82
103
|
weld: LineBuffers;
|
|
104
|
+
/** What a flight can turn, apart from the rest. Empty for a part with no moving group. */
|
|
105
|
+
moves: MoveMesh[];
|
|
83
106
|
}
|
|
84
107
|
/** A ring just proud of the surface at a height, so it is not lost in it. */
|
|
85
108
|
export declare function ringPath(piece: Lathe, y: number, lift?: number): Vec3[];
|
|
86
109
|
/** The triangles and lines of a part. */
|
|
87
110
|
export declare function meshOf(pieces: readonly Piece[]): PartMesh;
|
|
111
|
+
/** The groups a flight can turn: the pieces with a `move`, by name and pivot, in the order they come, each with a node name of its own. */
|
|
112
|
+
export declare function moveGroups(pieces: readonly Piece[]): {
|
|
113
|
+
name: string;
|
|
114
|
+
id: string;
|
|
115
|
+
pivot: Vec3;
|
|
116
|
+
axis: Vec3;
|
|
117
|
+
pieces: Piece[];
|
|
118
|
+
}[];
|
|
88
119
|
export interface Bounds {
|
|
89
120
|
min: Vec3;
|
|
90
121
|
max: Vec3;
|
package/dist/model/pieces.js
CHANGED
|
@@ -178,7 +178,43 @@ function plateFaces(mesh, piece) {
|
|
|
178
178
|
}
|
|
179
179
|
/** The triangles and lines of a part. */
|
|
180
180
|
export function meshOf(pieces) {
|
|
181
|
-
const mesh =
|
|
181
|
+
const mesh = meshOfFixed(pieces.filter((piece) => !piece.move));
|
|
182
|
+
for (const group of moveGroups(pieces)) {
|
|
183
|
+
const part = meshOfFixed(group.pieces);
|
|
184
|
+
const shift = (positions) => {
|
|
185
|
+
for (let i = 0; i < positions.length; i += 3)
|
|
186
|
+
for (let c = 0; c < 3; c++)
|
|
187
|
+
positions[i + c] -= group.pivot[c];
|
|
188
|
+
};
|
|
189
|
+
for (const buffers of part.faces.values())
|
|
190
|
+
shift(buffers.positions);
|
|
191
|
+
shift(part.feature.positions);
|
|
192
|
+
shift(part.weld.positions);
|
|
193
|
+
mesh.moves.push({ name: group.name, id: group.id, pivot: group.pivot, axis: group.axis, mesh: part });
|
|
194
|
+
}
|
|
195
|
+
return mesh;
|
|
196
|
+
}
|
|
197
|
+
/** The groups a flight can turn: the pieces with a `move`, by name and pivot, in the order they come, each with a node name of its own. */
|
|
198
|
+
export function moveGroups(pieces) {
|
|
199
|
+
const groups = [];
|
|
200
|
+
const counts = new Map();
|
|
201
|
+
for (const piece of pieces) {
|
|
202
|
+
if (!piece.move)
|
|
203
|
+
continue;
|
|
204
|
+
const key = `${piece.move.name}@${piece.move.pivot.join(",")}`;
|
|
205
|
+
let group = groups.find((one) => one.key === key);
|
|
206
|
+
if (!group) {
|
|
207
|
+
const n = counts.get(piece.move.name) ?? 0;
|
|
208
|
+
counts.set(piece.move.name, n + 1);
|
|
209
|
+
group = { name: piece.move.name, id: `${piece.move.name}~${n}`, pivot: piece.move.pivot, axis: piece.move.axis, pieces: [], key };
|
|
210
|
+
groups.push(group);
|
|
211
|
+
}
|
|
212
|
+
group.pieces.push(piece);
|
|
213
|
+
}
|
|
214
|
+
return groups.map((group) => ({ name: group.name, id: group.id, pivot: group.pivot, axis: group.axis, pieces: group.pieces }));
|
|
215
|
+
}
|
|
216
|
+
function meshOfFixed(pieces) {
|
|
217
|
+
const mesh = { faces: new Map(), feature: { positions: [], indices: [] }, weld: { positions: [], indices: [] }, moves: [] };
|
|
182
218
|
for (const piece of pieces) {
|
|
183
219
|
if (piece.only === "drawing")
|
|
184
220
|
continue;
|
|
@@ -211,13 +247,19 @@ export function meshOf(pieces) {
|
|
|
211
247
|
export function boundsOf(mesh) {
|
|
212
248
|
const min = [Infinity, Infinity, Infinity];
|
|
213
249
|
const max = [-Infinity, -Infinity, -Infinity];
|
|
214
|
-
|
|
215
|
-
for (
|
|
216
|
-
for (let
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
250
|
+
const sweep = (from, offset) => {
|
|
251
|
+
for (const b of from.faces.values())
|
|
252
|
+
for (let i = 0; i < b.positions.length; i += 3)
|
|
253
|
+
for (let c = 0; c < 3; c++) {
|
|
254
|
+
const value = b.positions[i + c] + offset[c];
|
|
255
|
+
if (value < min[c])
|
|
256
|
+
min[c] = value;
|
|
257
|
+
if (value > max[c])
|
|
258
|
+
max[c] = value;
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
sweep(mesh, [0, 0, 0]);
|
|
262
|
+
for (const group of mesh.moves)
|
|
263
|
+
sweep(group.mesh, group.pivot);
|
|
222
264
|
return { min, max };
|
|
223
265
|
}
|
package/dist/model/registry.d.ts
CHANGED
|
@@ -4,5 +4,27 @@ export interface PartEntry {
|
|
|
4
4
|
record: PartRecord;
|
|
5
5
|
pieces: () => Piece[];
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Every part of every rocket, each with its record: its real size in metres, the joints it mates at, and where its shape came from.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { PART_ENTRIES } from "@johnmorrisdotca/uchusen-rockets";
|
|
13
|
+
*
|
|
14
|
+
* console.log(PART_ENTRIES.length, PART_ENTRIES[0]?.record.name);
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
7
17
|
export declare const PART_ENTRIES: readonly PartEntry[];
|
|
18
|
+
/**
|
|
19
|
+
* Finds a part by its id.
|
|
20
|
+
*
|
|
21
|
+
* @param id A part's id.
|
|
22
|
+
* @returns The part's entry, or undefined for an id that is not a part.
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { partEntry } from "@johnmorrisdotca/uchusen-rockets";
|
|
26
|
+
*
|
|
27
|
+
* console.log(partEntry("raptor-vacuum")?.record.height, partEntry("nonsense"));
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
8
30
|
export declare const partEntry: (id: string) => PartEntry | undefined;
|
package/dist/model/registry.js
CHANGED
|
@@ -162,6 +162,28 @@ const RAPTOR_LENGTH = { value: 3.1, source: "wikipedia-raptor", note: "The famil
|
|
|
162
162
|
const b3 = STARSHIP_DRAWS.v3;
|
|
163
163
|
const b2 = STARSHIP_DRAWS.v2;
|
|
164
164
|
entries.push(detail("raptor-sea-level", "engine", "Raptor, sea-level", 3.1, 1.24, { height: RAPTOR_LENGTH, diameter: RAPTOR_DIAMETER }, () => raptor([0, 0], 0, "sea")), detail("raptor-vacuum", "engine", "Raptor, vacuum", 4.4, 2.3, { height: blankFigure, diameter: blankFigure }, () => raptor([0, 0], 0, "vacuum")), detail("grid-fin-four", "fin", "Grid fin, Blocks 1 and 2", 0.9, 2.9, { height: blankFigure, diameter: blankFigure }, () => gridFin(90, 0, b2.radius, b2.fins.reach, b2.fins.width, b2.fins.thick, false)), detail("grid-fin-three", "fin", "Grid fin, Block 3", 0.9, 3.4, { height: blankFigure, diameter: blankFigure }, () => gridFin(90, 0, b3.radius, b3.fins.reach, b3.fins.width, b3.fins.thick, true)), detail("flap-aft", "flap", "Aft flap", 11.6, 3.8, { height: blankFigure, diameter: blankFigure }, () => [flap(b3.aft, 1)]), detail("flap-forward", "flap", "Forward flap, Blocks 2 and 3", 8.1, 4.7, { height: blankFigure, diameter: blankFigure }, () => [flap(b3.forward, 1)]), detail("merlin-sea-level", "engine", "Merlin, sea-level", 2, 0.92, { height: blankFigure, diameter: blankFigure }, () => merlin([0, 0], 0, 0.46, 2)));
|
|
165
|
+
/**
|
|
166
|
+
* Every part of every rocket, each with its record: its real size in metres, the joints it mates at, and where its shape came from.
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```ts
|
|
170
|
+
* import { PART_ENTRIES } from "@johnmorrisdotca/uchusen-rockets";
|
|
171
|
+
*
|
|
172
|
+
* console.log(PART_ENTRIES.length, PART_ENTRIES[0]?.record.name);
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
165
175
|
export const PART_ENTRIES = entries;
|
|
166
176
|
const byId = new Map(entries.map((entry) => [entry.record.id, entry]));
|
|
177
|
+
/**
|
|
178
|
+
* Finds a part by its id.
|
|
179
|
+
*
|
|
180
|
+
* @param id A part's id.
|
|
181
|
+
* @returns The part's entry, or undefined for an id that is not a part.
|
|
182
|
+
* @example
|
|
183
|
+
* ```ts
|
|
184
|
+
* import { partEntry } from "@johnmorrisdotca/uchusen-rockets";
|
|
185
|
+
*
|
|
186
|
+
* console.log(partEntry("raptor-vacuum")?.record.height, partEntry("nonsense"));
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
167
189
|
export const partEntry = (id) => byId.get(id);
|
package/dist/model/starship.d.ts
CHANGED
|
@@ -57,10 +57,13 @@ export interface StarshipDraw {
|
|
|
57
57
|
export declare const STARSHIP_DRAWS: Readonly<Record<string, StarshipDraw>>;
|
|
58
58
|
/** One Raptor from its exit up: the bell, its dark inside and the machinery over it. Its origin is the middle of its exit. */
|
|
59
59
|
export declare function raptor(at: readonly [number, number], y: number, type: "sea" | "vacuum"): Piece[];
|
|
60
|
-
/** A grid fin held out flat: a frame and a lattice, u outwards and v along the circle. */
|
|
61
|
-
export declare function gridFin(azDeg: number, y: number, rootRadius: number, reach: number, width: number, thick: number, octagon: boolean
|
|
60
|
+
/** A grid fin held out flat: a frame and a lattice, u outwards and v along the circle. With `turn`, every piece of it is one moving group, hinged at its root: round the fin's own axis out from the hull (`radial`, how it steers) or across it (`tangent`, how it folds in). */
|
|
61
|
+
export declare function gridFin(azDeg: number, y: number, rootRadius: number, reach: number, width: number, thick: number, octagon: boolean, turn?: {
|
|
62
|
+
name: string;
|
|
63
|
+
about: "radial" | "tangent";
|
|
64
|
+
}): Piece[];
|
|
62
65
|
/** A flap's plate, tiled on its windward face. `outline` is [radius, height]. */
|
|
63
|
-
export declare function flap(draw: FlapDraw, side: 1 | -1): Plate;
|
|
66
|
+
export declare function flap(draw: FlapDraw, side: 1 | -1, name?: string): Plate;
|
|
64
67
|
/** Super Heavy: its base on the axis at the bells' exit. */
|
|
65
68
|
export declare function boosterPieces(d: StarshipDraw): Piece[];
|
|
66
69
|
/** The ship: its base on the axis at the bottom of its skirt. */
|
package/dist/model/starship.js
CHANGED
|
@@ -230,8 +230,8 @@ function clip(a, b, outline) {
|
|
|
230
230
|
[a[0] + d[0] * t1, a[1] + d[1] * t1],
|
|
231
231
|
];
|
|
232
232
|
}
|
|
233
|
-
/** A grid fin held out flat: a frame and a lattice, u outwards and v along the circle. */
|
|
234
|
-
export function gridFin(azDeg, y, rootRadius, reach, width, thick, octagon) {
|
|
233
|
+
/** A grid fin held out flat: a frame and a lattice, u outwards and v along the circle. With `turn`, every piece of it is one moving group, hinged at its root: round the fin's own axis out from the hull (`radial`, how it steers) or across it (`tangent`, how it folds in). */
|
|
234
|
+
export function gridFin(azDeg, y, rootRadius, reach, width, thick, octagon, turn) {
|
|
235
235
|
const frame = flat(deg(azDeg), y);
|
|
236
236
|
const r0 = rootRadius + 0.35;
|
|
237
237
|
const hw = width / 2;
|
|
@@ -291,10 +291,14 @@ export function gridFin(azDeg, y, rootRadius, reach, width, thick, octagon) {
|
|
|
291
291
|
});
|
|
292
292
|
// where it meets the hull
|
|
293
293
|
pieces.push(strut("fin", pointOf(frame, rootRadius - 0.1, 0, 0), pointOf(frame, r0 + 0.05, 0, 0), 1, 0.7, { only: "mesh" }));
|
|
294
|
+
if (turn) {
|
|
295
|
+
const move = { name: turn.name, pivot: pointOf(frame, r0, 0, 0), axis: turn.about === "radial" ? frame.u : frame.v };
|
|
296
|
+
return pieces.map((piece) => ({ ...piece, move }));
|
|
297
|
+
}
|
|
294
298
|
return pieces;
|
|
295
299
|
}
|
|
296
300
|
/** A flap's plate, tiled on its windward face. `outline` is [radius, height]. */
|
|
297
|
-
export function flap(draw, side) {
|
|
301
|
+
export function flap(draw, side, name) {
|
|
298
302
|
const az = deg(draw.az) * side;
|
|
299
303
|
const frame = radial(az);
|
|
300
304
|
// w must look windward, so the +w face takes the tiles
|
|
@@ -308,7 +312,8 @@ export function flap(draw, side) {
|
|
|
308
312
|
if (seam)
|
|
309
313
|
ribs.push(seam);
|
|
310
314
|
}
|
|
311
|
-
|
|
315
|
+
const hinge = name ? { name, pivot: pointOf(frame, Math.min(...reach), 0, 0), axis: [0, side, 0] } : undefined;
|
|
316
|
+
return { kind: "plate", material: "steel", top: "tile-plain", frame: windward, outline: draw.outline, thickness: draw.thickness, ribs, ...(hinge ? { move: hinge } : {}) };
|
|
312
317
|
}
|
|
313
318
|
/** A flap's root fairing above it. */
|
|
314
319
|
function fairing(azDeg, y0, y1, surface, proud) {
|
|
@@ -448,7 +453,7 @@ export function boosterPieces(d) {
|
|
|
448
453
|
// the band of vents round the common dome
|
|
449
454
|
pieces.push({ kind: "lathe", material: "engine-pale", segs: 64, only: "mesh", profile: [[r + 0.015, topOfHull * 0.62 - 0.12], [r + 0.015, topOfHull * 0.62 + 0.12]] });
|
|
450
455
|
for (const az of d.fins.az)
|
|
451
|
-
pieces.push(...gridFin(az, d.fins.y, r, d.fins.reach, d.fins.width, d.fins.thick, d.fins.octagon));
|
|
456
|
+
pieces.push(...gridFin(az, d.fins.y, r, d.fins.reach, d.fins.width, d.fins.thick, d.fins.octagon, { name: "grid-fins", about: "radial" }));
|
|
452
457
|
if (d.ring.height > 0)
|
|
453
458
|
pieces.push(...hotStage(d));
|
|
454
459
|
else
|
|
@@ -475,8 +480,8 @@ export function shipPieces(d) {
|
|
|
475
480
|
pieces.push(...engineRings(d.shipEngines, 0.2));
|
|
476
481
|
const surface = (y) => radiusAt(profile, y);
|
|
477
482
|
for (const side of [1, -1]) {
|
|
478
|
-
pieces.push(flap(d.aft, side));
|
|
479
|
-
pieces.push(flap(d.forward, side));
|
|
483
|
+
pieces.push(flap(d.aft, side, "aft-flaps"));
|
|
484
|
+
pieces.push(flap(d.forward, side, "forward-flaps"));
|
|
480
485
|
const aftTop = Math.max(...d.aft.outline.map(([, y]) => y));
|
|
481
486
|
pieces.push(fairing(d.aft.az * side, aftTop - 1, aftTop + 2.8, surface, 0.8));
|
|
482
487
|
const fwdBottom = Math.min(...d.forward.outline.map(([, y]) => y));
|
package/dist/parts.d.ts
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
1
|
import type { CreditId } from "./data/credits.ts";
|
|
2
2
|
import type { Figure } from "./data/types.ts";
|
|
3
|
+
/**
|
|
4
|
+
* What kind of part a record is: a booster, a ship, a stage, a fairing, a capsule, an engine, a fin and so on. A joint only mates a part of a kind that fits it.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { partEntry, type PartKind } from "@johnmorrisdotca/uchusen-rockets";
|
|
9
|
+
*
|
|
10
|
+
* const kind: PartKind | undefined = partEntry("raptor-vacuum")?.record.kind;
|
|
11
|
+
* console.log(kind);
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
3
14
|
export type PartKind = "booster" | "first-stage" | "ship" | "second-stage" | "fairing" | "capsule" | "trunk" | "engine" | "fin" | "flap" | "ring" | "test-vehicle" | "third-stage" | "adapter" | "service-module" | "tower" | "tank" | "solid-booster" | "liquid-booster" | "orbiter" | "deck" | "mount" | "arms" | "site" | "spacecraft";
|
|
4
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Where a part mates. Every part's origin is the middle of its base on its axis, at its lowest point; Y is up and the windward side faces +Z, in metres.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { partEntry, type Joint } from "@johnmorrisdotca/uchusen-rockets";
|
|
21
|
+
*
|
|
22
|
+
* const top: Joint | undefined = partEntry("starship-v3-booster")?.record.joints.top;
|
|
23
|
+
* console.log(top);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
5
26
|
export interface Joint {
|
|
6
27
|
/** What this joint is, so only like meets like: "stage". */
|
|
7
28
|
kind: "stage";
|
|
@@ -10,6 +31,17 @@ export interface Joint {
|
|
|
10
31
|
/** Metres across at the joint. */
|
|
11
32
|
diameter: number;
|
|
12
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* The one record every part has: its id, kind and name, the rocket and variants it is true for, its height and diameter in metres, the sourced figures, its joints, any painted model, and where its shape came from.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* import { partEntry, type PartRecord } from "@johnmorrisdotca/uchusen-rockets";
|
|
40
|
+
*
|
|
41
|
+
* const record: PartRecord | undefined = partEntry("starship-v3-ship")?.record;
|
|
42
|
+
* console.log(record?.name, record?.height, record?.trueTo);
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
13
45
|
export interface PartRecord {
|
|
14
46
|
id: string;
|
|
15
47
|
kind: PartKind;
|
package/dist/pixels.d.ts
CHANGED
|
@@ -1,8 +1,48 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* The most the backing store may hold, in pixels (a 620 x 827 view at a ratio of 2 is 2 million).
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { MAX_PIXELS } from "@johnmorrisdotca/uchusen-rockets";
|
|
7
|
+
*
|
|
8
|
+
* console.log(MAX_PIXELS);
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
2
11
|
export declare const MAX_PIXELS = 6000000;
|
|
3
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* The longest side the backing store may have.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { MAX_SIDE } from "@johnmorrisdotca/uchusen-rockets";
|
|
18
|
+
*
|
|
19
|
+
* console.log(MAX_SIDE);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
4
22
|
export declare const MAX_SIDE = 4096;
|
|
5
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* The sharpest ratio ever used, however dense the screen.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { MAX_RATIO } from "@johnmorrisdotca/uchusen-rockets";
|
|
29
|
+
*
|
|
30
|
+
* console.log(MAX_RATIO);
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
6
33
|
export declare const MAX_RATIO = 2;
|
|
7
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* The device pixel ratio to draw a `width` x `height` view at: the screen's own, held to 2, to 4096 pixels a side and to 6 million in all. At least 0.25, and 1 for a nonsense value.
|
|
36
|
+
*
|
|
37
|
+
* @param width The view's width in CSS pixels.
|
|
38
|
+
* @param height Its height in CSS pixels.
|
|
39
|
+
* @param deviceRatio The screen's own pixel ratio.
|
|
40
|
+
* @returns The ratio to draw at.
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { pixelRatioFor } from "@johnmorrisdotca/uchusen-rockets";
|
|
44
|
+
*
|
|
45
|
+
* console.log(pixelRatioFor(620, 827, 3), pixelRatioFor(3000, 3000, 2));
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
8
48
|
export declare function pixelRatioFor(width: number, height: number, deviceRatio: number): number;
|
package/dist/pixels.js
CHANGED
|
@@ -1,11 +1,51 @@
|
|
|
1
1
|
// How sharp the 3D canvas may be. The backing store is width x height x ratio squared, and a view as big as a 5K screen at a ratio of 2 would ask the graphics card for 15 million pixels, every frame. Pure.
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* The most the backing store may hold, in pixels (a 620 x 827 view at a ratio of 2 is 2 million).
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { MAX_PIXELS } from "@johnmorrisdotca/uchusen-rockets";
|
|
8
|
+
*
|
|
9
|
+
* console.log(MAX_PIXELS);
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
3
12
|
export const MAX_PIXELS = 6_000_000;
|
|
4
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* The longest side the backing store may have.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { MAX_SIDE } from "@johnmorrisdotca/uchusen-rockets";
|
|
19
|
+
*
|
|
20
|
+
* console.log(MAX_SIDE);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
5
23
|
export const MAX_SIDE = 4096;
|
|
6
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* The sharpest ratio ever used, however dense the screen.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { MAX_RATIO } from "@johnmorrisdotca/uchusen-rockets";
|
|
30
|
+
*
|
|
31
|
+
* console.log(MAX_RATIO);
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
7
34
|
export const MAX_RATIO = 2;
|
|
8
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* The device pixel ratio to draw a `width` x `height` view at: the screen's own, held to 2, to 4096 pixels a side and to 6 million in all. At least 0.25, and 1 for a nonsense value.
|
|
37
|
+
*
|
|
38
|
+
* @param width The view's width in CSS pixels.
|
|
39
|
+
* @param height Its height in CSS pixels.
|
|
40
|
+
* @param deviceRatio The screen's own pixel ratio.
|
|
41
|
+
* @returns The ratio to draw at.
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* import { pixelRatioFor } from "@johnmorrisdotca/uchusen-rockets";
|
|
45
|
+
*
|
|
46
|
+
* console.log(pixelRatioFor(620, 827, 3), pixelRatioFor(3000, 3000, 2));
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
9
49
|
export function pixelRatioFor(width, height, deviceRatio) {
|
|
10
50
|
const w = Math.max(1, width);
|
|
11
51
|
const h = Math.max(1, height);
|
package/dist/react.d.ts
CHANGED
|
@@ -2,6 +2,17 @@ import { type HTMLAttributes, type Ref } from "react";
|
|
|
2
2
|
import type { Description } from "./fit.ts";
|
|
3
3
|
import type { ViewName } from "./framing.ts";
|
|
4
4
|
import type { LookName } from "./looks.ts";
|
|
5
|
+
/**
|
|
6
|
+
* The props of the React wrapper: the element's attributes as props (`rocket`, `variant`, `show`, `look`, `view`, `mode`, `assets`, `spin`, `way`, `label`, `engines`, `phase`), `build` as an object, and any other HTML attribute.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import type { UchusenRocketProps } from "@johnmorrisdotca/uchusen-rockets/react";
|
|
11
|
+
*
|
|
12
|
+
* const props: UchusenRocketProps = { rocket: "starship", variant: "v3", look: "thick" };
|
|
13
|
+
* console.log(props);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
5
16
|
export interface UchusenRocketProps extends Omit<HTMLAttributes<HTMLElement>, "style"> {
|
|
6
17
|
rocket?: string;
|
|
7
18
|
variant?: string;
|
|
@@ -22,6 +33,19 @@ export interface UchusenRocketProps extends Omit<HTMLAttributes<HTMLElement>, "s
|
|
|
22
33
|
phase?: string;
|
|
23
34
|
ref?: Ref<HTMLElement>;
|
|
24
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* A thin React wrapper round `<uchusen-rocket>`. It loads the element on first use, so server rendering draws only the tag.
|
|
38
|
+
*
|
|
39
|
+
* @param props The props. `build` is turned into the element's JSON attribute; the rest go through as they are.
|
|
40
|
+
* @returns The `<uchusen-rocket>` element. It is never null or undefined.
|
|
41
|
+
* @example
|
|
42
|
+
* ```tsx no-run
|
|
43
|
+
* import { UchusenRocket } from "@johnmorrisdotca/uchusen-rockets/react";
|
|
44
|
+
*
|
|
45
|
+
* export const Hero = () => <UchusenRocket rocket="falcon-9" variant="block-5" look="painted" />;
|
|
46
|
+
* console.log(typeof UchusenRocket);
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
25
49
|
export declare function UchusenRocket({ build, ...rest }: UchusenRocketProps): import("react").DOMElement<{
|
|
26
50
|
build: string | undefined;
|
|
27
51
|
rocket?: string;
|
|
@@ -40,14 +64,14 @@ export declare function UchusenRocket({ build, ...rest }: UchusenRocketProps): i
|
|
|
40
64
|
/** A phase of the rocket's flight, by its id. */
|
|
41
65
|
phase?: string;
|
|
42
66
|
ref?: Ref<HTMLElement>;
|
|
43
|
-
part?: string | undefined | undefined;
|
|
44
67
|
id?: string | undefined | undefined;
|
|
68
|
+
about?: string | undefined | undefined;
|
|
69
|
+
part?: string | undefined | undefined;
|
|
45
70
|
slot?: string | undefined | undefined;
|
|
46
71
|
children?: import("react").ReactNode;
|
|
47
72
|
title?: string | undefined | undefined;
|
|
48
73
|
"aria-label"?: string | undefined | undefined;
|
|
49
74
|
"aria-live"?: "off" | "assertive" | "polite" | undefined | undefined;
|
|
50
|
-
about?: string | undefined | undefined;
|
|
51
75
|
"aria-pressed"?: boolean | "false" | "mixed" | "true" | undefined | undefined;
|
|
52
76
|
"aria-valuetext"?: string | undefined | undefined;
|
|
53
77
|
color?: string | undefined | undefined;
|
package/dist/react.js
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
// A thin React wrapper round `<uchusen-rocket>`.
|
|
2
2
|
import { createElement, useEffect } from "react";
|
|
3
|
+
/**
|
|
4
|
+
* A thin React wrapper round `<uchusen-rocket>`. It loads the element on first use, so server rendering draws only the tag.
|
|
5
|
+
*
|
|
6
|
+
* @param props The props. `build` is turned into the element's JSON attribute; the rest go through as they are.
|
|
7
|
+
* @returns The `<uchusen-rocket>` element. It is never null or undefined.
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx no-run
|
|
10
|
+
* import { UchusenRocket } from "@johnmorrisdotca/uchusen-rockets/react";
|
|
11
|
+
*
|
|
12
|
+
* export const Hero = () => <UchusenRocket rocket="falcon-9" variant="block-5" look="painted" />;
|
|
13
|
+
* console.log(typeof UchusenRocket);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
3
16
|
export function UchusenRocket({ build, ...rest }) {
|
|
4
17
|
useEffect(() => {
|
|
5
18
|
void import("./element.js");
|
package/dist/rockets.d.ts
CHANGED
|
@@ -1,7 +1,29 @@
|
|
|
1
1
|
import { type MakerId } from "./data/makers.ts";
|
|
2
2
|
import type { Figure, Variant } from "./data/types.ts";
|
|
3
3
|
import type { SourceId } from "./data/sources.ts";
|
|
4
|
+
/**
|
|
5
|
+
* Whether a rocket is `built` (it has a shape) or `planned` (it has facts and no shape yet).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { ROCKETS, type RocketStatus } from "@johnmorrisdotca/uchusen-rockets";
|
|
10
|
+
*
|
|
11
|
+
* const status: RocketStatus | undefined = ROCKETS["starship"]?.status;
|
|
12
|
+
* console.log(status);
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
4
15
|
export type RocketStatus = "built" | "planned";
|
|
16
|
+
/**
|
|
17
|
+
* One rocket: its id and name, its variants, its default variant, the group it is listed under and who made it.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { ROCKETS, type RocketEntry } from "@johnmorrisdotca/uchusen-rockets";
|
|
22
|
+
*
|
|
23
|
+
* const starship: RocketEntry | undefined = ROCKETS["starship"];
|
|
24
|
+
* console.log(starship?.name, starship?.variants.map((variant) => variant.id));
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
5
27
|
export interface RocketEntry {
|
|
6
28
|
id: string;
|
|
7
29
|
name: string;
|
|
@@ -13,7 +35,17 @@ export interface RocketEntry {
|
|
|
13
35
|
/** Whose it is and who built it, as its source says, or a blank. */
|
|
14
36
|
madeBy: Figure<string>;
|
|
15
37
|
}
|
|
16
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* A rocket on the list with no mesh yet: its name and the sourced facts to build it from.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { PLANNED_ROCKETS, type PlannedRocket } from "@johnmorrisdotca/uchusen-rockets";
|
|
44
|
+
*
|
|
45
|
+
* const planned: PlannedRocket | undefined = PLANNED_ROCKETS[0];
|
|
46
|
+
* console.log(planned?.name);
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
17
49
|
export interface PlannedRocket {
|
|
18
50
|
id: string;
|
|
19
51
|
name: string;
|
|
@@ -23,10 +55,66 @@ export interface PlannedRocket {
|
|
|
23
55
|
firstFlight: Figure<string>;
|
|
24
56
|
source: SourceId;
|
|
25
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Every rocket that has a shape, by id, each with its variants. Add a rocket here and the element, the drawing, the fit check and the demo all read it.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* import { ROCKETS } from "@johnmorrisdotca/uchusen-rockets";
|
|
64
|
+
*
|
|
65
|
+
* console.log(Object.keys(ROCKETS).slice(0, 6));
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
26
68
|
export declare const ROCKETS: Readonly<Record<string, RocketEntry>>;
|
|
69
|
+
/**
|
|
70
|
+
* Rockets with sourced facts and no shape yet.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* import { PLANNED_ROCKETS } from "@johnmorrisdotca/uchusen-rockets";
|
|
75
|
+
*
|
|
76
|
+
* console.log(PLANNED_ROCKETS.map((rocket) => rocket.name));
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
27
79
|
export declare const PLANNED_ROCKETS: readonly PlannedRocket[];
|
|
80
|
+
/**
|
|
81
|
+
* Finds a rocket's variant, with its sourced sizes.
|
|
82
|
+
*
|
|
83
|
+
* @param rocket A rocket's id.
|
|
84
|
+
* @param id A variant's id. Left out, null or undefined: the rocket's default variant.
|
|
85
|
+
* @returns The variant, or undefined when the rocket or the variant is not known.
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* import { variantOf } from "@johnmorrisdotca/uchusen-rockets";
|
|
89
|
+
*
|
|
90
|
+
* const v3 = variantOf("starship", "v3");
|
|
91
|
+
* console.log(v3?.facts.height.value, variantOf("starship", "v99"));
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
28
94
|
export declare function variantOf(rocket: string, id?: string | null): Variant | undefined;
|
|
29
|
-
/**
|
|
95
|
+
/**
|
|
96
|
+
* A part's name for a rocket's slot in a variant.
|
|
97
|
+
*
|
|
98
|
+
* @param rocket A rocket's id.
|
|
99
|
+
* @param variant A variant's id.
|
|
100
|
+
* @param slot A slot name.
|
|
101
|
+
* @returns The id of the part that stands in that slot.
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* import { partIdOf } from "@johnmorrisdotca/uchusen-rockets";
|
|
105
|
+
*
|
|
106
|
+
* console.log(partIdOf("starship", "v3", "booster"));
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
30
109
|
export declare const partIdOf: (rocket: string, variant: string, slot: string) => string;
|
|
31
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* What to call a slot.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* import { SLOT_NAMES } from "@johnmorrisdotca/uchusen-rockets";
|
|
116
|
+
*
|
|
117
|
+
* console.log(SLOT_NAMES["booster"]);
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
32
120
|
export declare const SLOT_NAMES: Readonly<Record<string, string>>;
|