@johnmorrisdotca/uchusen-rockets 0.4.0 → 0.6.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 +25 -0
- package/NOTICE.md +2 -0
- package/README.md +80 -5
- 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.0-dragon-apart.painted.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon-apart.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon-apart.thick.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon-capsule.glb +0 -0
- package/dist/assets/falcon-9-v1.0-dragon-capsule.painted.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon-capsule.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon-capsule.thick.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon-first-stage.glb +0 -0
- package/dist/assets/falcon-9-v1.0-dragon-first-stage.painted.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon-first-stage.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon-first-stage.thick.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon-second-stage.glb +0 -0
- package/dist/assets/falcon-9-v1.0-dragon-second-stage.painted.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon-second-stage.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon-second-stage.thick.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon-trunk.glb +0 -0
- package/dist/assets/falcon-9-v1.0-dragon-trunk.painted.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon-trunk.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon-trunk.thick.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon.glb +0 -0
- package/dist/assets/falcon-9-v1.0-dragon.painted.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon.svg +1 -0
- package/dist/assets/falcon-9-v1.0-dragon.thick.svg +1 -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/build/glb.js +15 -7
- package/dist/build/index.d.ts +5 -0
- package/dist/build/index.js +16 -3
- package/dist/data/falcon.js +18 -0
- package/dist/data/flights.d.ts +7 -0
- package/dist/data/flights.js +204 -13
- package/dist/data/propellants.d.ts +59 -0
- package/dist/data/propellants.js +43 -0
- package/dist/data/sources.d.ts +92 -0
- package/dist/data/sources.js +12 -0
- 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.d.ts +6 -1
- package/dist/element/scene.js +71 -7
- package/dist/element.d.ts +1 -0
- package/dist/element.js +18 -6
- package/dist/flight.d.ts +2 -0
- package/dist/flight.js +8 -1
- package/dist/flightbar.d.ts +30 -0
- package/dist/flightbar.js +46 -9
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/model/falcon.js +2 -2
- 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.js +2 -2
- package/dist/model/starship.d.ts +6 -3
- package/dist/model/starship.js +12 -7
- package/dist/react.d.ts +3 -3
- package/package.json +18 -3
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Piece, Vec3 } from "./pieces.ts";
|
|
2
|
+
/** A direction turned by `degrees` right-handed about `axis` (Rodrigues' rotation). */
|
|
3
|
+
export declare function turnedVector(v: Vec3, axis: Vec3, degrees: number): Vec3;
|
|
4
|
+
/** A point turned about a pivot. */
|
|
5
|
+
export declare function turnedPoint(p: Vec3, pivot: Vec3, axis: Vec3, degrees: number): Vec3;
|
|
6
|
+
/**
|
|
7
|
+
* The pieces with each moving group turned by the angle its name has in `angles` (degrees, 0 where it has none). A turned piece no longer carries its `move`: it is drawn where it stands. A body of revolution cannot turn, and is left as it is.
|
|
8
|
+
*
|
|
9
|
+
* @param pieces The pieces of a part.
|
|
10
|
+
* @param angles Degrees by the name of a moving group, such as `grid-fins`.
|
|
11
|
+
* @returns The pieces, with the moving groups turned.
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { build } from "@johnmorrisdotca/uchusen-rockets/build";
|
|
15
|
+
* import { movingGroupsOf } from "@johnmorrisdotca/uchusen-rockets";
|
|
16
|
+
*
|
|
17
|
+
* const booster = build({ rocket: "starship", variant: "v3" }).parts[0];
|
|
18
|
+
* console.log(booster ? movingGroupsOf(booster.pieces) : []);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function moved(pieces: readonly Piece[], angles: Readonly<Record<string, number>>): readonly Piece[];
|
|
22
|
+
/**
|
|
23
|
+
* The names of the groups a part has that a flight can turn.
|
|
24
|
+
*
|
|
25
|
+
* @param pieces The pieces of a part.
|
|
26
|
+
* @returns The distinct names, in the order they come.
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { build } from "@johnmorrisdotca/uchusen-rockets/build";
|
|
30
|
+
* import { movingGroupsOf } from "@johnmorrisdotca/uchusen-rockets";
|
|
31
|
+
*
|
|
32
|
+
* const stage = build({ rocket: "falcon-9", variant: "block-5" }).parts[0];
|
|
33
|
+
* console.log(stage ? movingGroupsOf(stage.pieces) : []);
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function movingGroupsOf(pieces: readonly Piece[]): string[];
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const unit = (v) => {
|
|
2
|
+
const length = Math.hypot(...v) || 1;
|
|
3
|
+
return [v[0] / length, v[1] / length, v[2] / length];
|
|
4
|
+
};
|
|
5
|
+
/** A direction turned by `degrees` right-handed about `axis` (Rodrigues' rotation). */
|
|
6
|
+
export function turnedVector(v, axis, degrees) {
|
|
7
|
+
const k = unit(axis);
|
|
8
|
+
const a = (degrees * Math.PI) / 180;
|
|
9
|
+
const cos = Math.cos(a);
|
|
10
|
+
const sin = Math.sin(a);
|
|
11
|
+
const dot = k[0] * v[0] + k[1] * v[1] + k[2] * v[2];
|
|
12
|
+
const cross = [k[1] * v[2] - k[2] * v[1], k[2] * v[0] - k[0] * v[2], k[0] * v[1] - k[1] * v[0]];
|
|
13
|
+
return [v[0] * cos + cross[0] * sin + k[0] * dot * (1 - cos), v[1] * cos + cross[1] * sin + k[1] * dot * (1 - cos), v[2] * cos + cross[2] * sin + k[2] * dot * (1 - cos)];
|
|
14
|
+
}
|
|
15
|
+
/** A point turned about a pivot. */
|
|
16
|
+
export function turnedPoint(p, pivot, axis, degrees) {
|
|
17
|
+
const d = turnedVector([p[0] - pivot[0], p[1] - pivot[1], p[2] - pivot[2]], axis, degrees);
|
|
18
|
+
return [pivot[0] + d[0], pivot[1] + d[1], pivot[2] + d[2]];
|
|
19
|
+
}
|
|
20
|
+
const turnedFrame = (f, move, degrees) => ({
|
|
21
|
+
o: turnedPoint(f.o, move.pivot, move.axis, degrees),
|
|
22
|
+
u: turnedVector(f.u, move.axis, degrees),
|
|
23
|
+
v: turnedVector(f.v, move.axis, degrees),
|
|
24
|
+
w: turnedVector(f.w, move.axis, degrees),
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* The pieces with each moving group turned by the angle its name has in `angles` (degrees, 0 where it has none). A turned piece no longer carries its `move`: it is drawn where it stands. A body of revolution cannot turn, and is left as it is.
|
|
28
|
+
*
|
|
29
|
+
* @param pieces The pieces of a part.
|
|
30
|
+
* @param angles Degrees by the name of a moving group, such as `grid-fins`.
|
|
31
|
+
* @returns The pieces, with the moving groups turned.
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { build } from "@johnmorrisdotca/uchusen-rockets/build";
|
|
35
|
+
* import { movingGroupsOf } from "@johnmorrisdotca/uchusen-rockets";
|
|
36
|
+
*
|
|
37
|
+
* const booster = build({ rocket: "starship", variant: "v3" }).parts[0];
|
|
38
|
+
* console.log(booster ? movingGroupsOf(booster.pieces) : []);
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function moved(pieces, angles) {
|
|
42
|
+
if (!pieces.some((piece) => piece.move && angles[piece.move.name]))
|
|
43
|
+
return pieces;
|
|
44
|
+
return pieces.map((piece) => {
|
|
45
|
+
const move = piece.move;
|
|
46
|
+
const degrees = move ? (angles[move.name] ?? 0) : 0;
|
|
47
|
+
if (!move || degrees === 0 || piece.kind === "lathe")
|
|
48
|
+
return piece;
|
|
49
|
+
if (piece.kind === "plate")
|
|
50
|
+
return { ...piece, move: undefined, frame: turnedFrame(piece.frame, move, degrees) };
|
|
51
|
+
return { ...piece, move: undefined, paths: piece.paths.map((path) => path.map((p) => turnedPoint(p, move.pivot, move.axis, degrees))) };
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The names of the groups a part has that a flight can turn.
|
|
56
|
+
*
|
|
57
|
+
* @param pieces The pieces of a part.
|
|
58
|
+
* @returns The distinct names, in the order they come.
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* import { build } from "@johnmorrisdotca/uchusen-rockets/build";
|
|
62
|
+
* import { movingGroupsOf } from "@johnmorrisdotca/uchusen-rockets";
|
|
63
|
+
*
|
|
64
|
+
* const stage = build({ rocket: "falcon-9", variant: "block-5" }).parts[0];
|
|
65
|
+
* console.log(stage ? movingGroupsOf(stage.pieces) : []);
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export function movingGroupsOf(pieces) {
|
|
69
|
+
return [...new Set(pieces.flatMap((piece) => (piece.move ? [piece.move.name] : [])))];
|
|
70
|
+
}
|
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.js
CHANGED
|
@@ -112,7 +112,7 @@ for (const id of Object.keys(FALCON_DRAWS)) {
|
|
|
112
112
|
const d = FALCON_DRAWS[id];
|
|
113
113
|
const painted = (slot) => PAINTED[`falcon-9-${id}-${slot}`] ?? null;
|
|
114
114
|
const drawnFrom = id === "block-5" ? FROM_F9 : FROM_CODE;
|
|
115
|
-
entries.push({ record: { id: `falcon-9-${id}-first-stage`, kind: "first-stage", name: `First stage, Falcon 9 ${id}`, rocket: "falcon-9", trueTo: id === "block-5" ? [id, "block-5-dragon-2"] : [id], height: d.first.height, diameter: 3.7, sourced: facts(FALCON_9_VARIANTS, id, "first-stage"), joints: { top: { kind: "stage", y: d.first.height, diameter: 3.7 } }, painted: painted("first-stage"), drawnFrom }, pieces: () => falconFirstStage(id) }, { record: { id: `falcon-9-${id}-second-stage`, kind: "second-stage", name: `Second stage, Falcon 9 ${id}`, rocket: "falcon-9", trueTo: id === "block-5" ? [id, "block-5-dragon-2"] : [id], height: d.second.height, diameter: 3.7, sourced: facts(FALCON_9_VARIANTS, id, "second-stage"), joints: { bottom: { kind: "stage", y: d.second.joint, diameter: 3.7 }, top: { kind: "stage", y: d.second.height, diameter: 3.7 } }, painted: painted("second-stage"), drawnFrom }, pieces: () => falconSecondStage(id) }, { record: { id: `falcon-9-${id}-fairing`, kind: "fairing", name: `Fairing, Falcon 9 ${id}`, rocket: "falcon-9", trueTo: [id], height: d.fairing.height, diameter: d.fairing.radius * 2, sourced: { height: facts(FALCON_9_VARIANTS, id, "fairing").height, diameter: blankFigure }, joints: { bottom: { kind: "stage", y: 0, diameter: 3.7 } }, painted: painted("fairing"), drawnFrom }, pieces: () => falconFairing(id) });
|
|
115
|
+
entries.push({ record: { id: `falcon-9-${id}-first-stage`, kind: "first-stage", name: `First stage, Falcon 9 ${id}`, rocket: "falcon-9", trueTo: id === "block-5" ? [id, "block-5-dragon-2"] : id === "v1.0" ? [id, "v1.0-dragon"] : [id], height: d.first.height, diameter: 3.7, sourced: facts(FALCON_9_VARIANTS, id, "first-stage"), joints: { top: { kind: "stage", y: d.first.height, diameter: 3.7 } }, painted: painted("first-stage"), drawnFrom }, pieces: () => falconFirstStage(id) }, { record: { id: `falcon-9-${id}-second-stage`, kind: "second-stage", name: `Second stage, Falcon 9 ${id}`, rocket: "falcon-9", trueTo: id === "block-5" ? [id, "block-5-dragon-2"] : id === "v1.0" ? [id, "v1.0-dragon"] : [id], height: d.second.height, diameter: 3.7, sourced: facts(FALCON_9_VARIANTS, id, "second-stage"), joints: { bottom: { kind: "stage", y: d.second.joint, diameter: 3.7 }, top: { kind: "stage", y: d.second.height, diameter: 3.7 } }, painted: painted("second-stage"), drawnFrom }, pieces: () => falconSecondStage(id) }, { record: { id: `falcon-9-${id}-fairing`, kind: "fairing", name: `Fairing, Falcon 9 ${id}`, rocket: "falcon-9", trueTo: [id], height: d.fairing.height, diameter: d.fairing.radius * 2, sourced: { height: facts(FALCON_9_VARIANTS, id, "fairing").height, diameter: blankFigure }, joints: { bottom: { kind: "stage", y: 0, diameter: 3.7 } }, painted: painted("fairing"), drawnFrom }, pieces: () => falconFairing(id) });
|
|
116
116
|
}
|
|
117
117
|
const DRAGON_FROM = {
|
|
118
118
|
"dragon-1": "This package's code for the two line looks, proportions taken from ProgressTH's model; ProgressTH's model for the painted look. It shows the original Dragon 1, with solar wings, not Cargo Dragon 2.",
|
|
@@ -123,7 +123,7 @@ for (const variant of DRAGON_VARIANTS) {
|
|
|
123
123
|
const d = DRAGON_DRAWS[variant.id];
|
|
124
124
|
if (!d)
|
|
125
125
|
continue;
|
|
126
|
-
const trueTo = variant.id === "dragon-2" ? [variant.id, "block-5-dragon-2"] : [variant.id];
|
|
126
|
+
const trueTo = variant.id === "dragon-2" ? [variant.id, "block-5-dragon-2"] : variant.id === "dragon-1" ? [variant.id, "v1.0-dragon"] : [variant.id];
|
|
127
127
|
const joint = 3.7;
|
|
128
128
|
entries.push({ record: { id: `dragon-${variant.id}-trunk`, kind: "trunk", name: `Trunk, ${variant.name}`, rocket: "dragon", trueTo, height: d.trunk, diameter: d.trunkRadius * 2, sourced: { height: variant.facts.parts.trunk, diameter: blankFigure }, joints: { bottom: { kind: "stage", y: 0, diameter: joint }, top: { kind: "stage", y: d.trunk, diameter: joint } }, painted: PAINTED[`dragon-${variant.id}-trunk`] ?? null, drawnFrom: DRAGON_FROM[variant.id] }, pieces: () => trunk(d) }, { record: { id: `dragon-${variant.id}-capsule`, kind: "capsule", name: `Capsule, ${variant.name}`, rocket: "dragon", trueTo, height: d.capsule, diameter: d.baseRadius * 2, sourced: { height: variant.facts.parts.capsule, diameter: variant.facts.diameter }, joints: { bottom: { kind: "stage", y: d.nest, diameter: joint } }, painted: PAINTED[`dragon-${variant.id}-capsule`] ?? null, drawnFrom: DRAGON_FROM[variant.id] }, pieces: () => capsule(d) });
|
|
129
129
|
}
|
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/react.d.ts
CHANGED
|
@@ -64,14 +64,14 @@ export declare function UchusenRocket({ build, ...rest }: UchusenRocketProps): i
|
|
|
64
64
|
/** A phase of the rocket's flight, by its id. */
|
|
65
65
|
phase?: string;
|
|
66
66
|
ref?: Ref<HTMLElement>;
|
|
67
|
-
part?: string | undefined | undefined;
|
|
68
67
|
id?: string | undefined | undefined;
|
|
68
|
+
about?: string | undefined | undefined;
|
|
69
|
+
part?: string | undefined | undefined;
|
|
69
70
|
slot?: string | undefined | undefined;
|
|
70
71
|
children?: import("react").ReactNode;
|
|
71
|
-
title?: string | undefined | undefined;
|
|
72
72
|
"aria-label"?: string | undefined | undefined;
|
|
73
|
+
title?: string | undefined | undefined;
|
|
73
74
|
"aria-live"?: "off" | "assertive" | "polite" | undefined | undefined;
|
|
74
|
-
about?: string | undefined | undefined;
|
|
75
75
|
"aria-pressed"?: boolean | "false" | "mixed" | "true" | undefined | undefined;
|
|
76
76
|
"aria-valuetext"?: string | undefined | undefined;
|
|
77
77
|
color?: string | undefined | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnmorrisdotca/uchusen-rockets",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Uchusen Rockets 宇宙船: line drawings and 3D views of rockets, as a web component. Every variant with its own sourced sizes, a typed way to assemble a rocket from parts, stack and separate. No logos. three.js is a peer dependency.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rocket",
|
|
@@ -91,8 +91,11 @@
|
|
|
91
91
|
"prepublishOnly": "pnpm check",
|
|
92
92
|
"site": "pnpm build && node scripts/site.ts",
|
|
93
93
|
"dev": "pnpm site && node scripts/dev.ts",
|
|
94
|
-
"test:demo": "pnpm site && playwright test",
|
|
94
|
+
"test:demo": "pnpm site && node scripts/docs-site.mjs build && playwright test",
|
|
95
95
|
"test:freeze": "pnpm site && playwright test e2e/freeze.demo.ts --project=chromium-desk",
|
|
96
|
+
"test:usage": "pnpm site && node scripts/check-usage.ts",
|
|
97
|
+
"family:readme": "node scripts/family-readme.mjs",
|
|
98
|
+
"check:standard": "node scripts/check-standard.mjs",
|
|
96
99
|
"screenshots": "pnpm site && node scripts/docs-site.mjs build && node scripts/screenshots.ts",
|
|
97
100
|
"models": "node scripts/reduce-models.ts",
|
|
98
101
|
"models:nasa": "node scripts/reduce-nasa.ts",
|
|
@@ -113,6 +116,10 @@
|
|
|
113
116
|
}
|
|
114
117
|
},
|
|
115
118
|
"devDependencies": {
|
|
119
|
+
"@angular/common": "^22.2.4",
|
|
120
|
+
"@angular/compiler": "^22.2.4",
|
|
121
|
+
"@angular/core": "^22.2.4",
|
|
122
|
+
"@angular/platform-browser": "^22.2.4",
|
|
116
123
|
"@eslint/js": "9.39.5",
|
|
117
124
|
"@gltf-transform/core": "4.5.1",
|
|
118
125
|
"@gltf-transform/extensions": "4.5.1",
|
|
@@ -120,10 +127,12 @@
|
|
|
120
127
|
"@johnmorrisdotca/chikyu-earth": "0.10.0",
|
|
121
128
|
"@johnmorrisdotca/kazoku-ui": "^0.12.0",
|
|
122
129
|
"@playwright/test": "1.64.0",
|
|
130
|
+
"@sveltejs/vite-plugin-svelte": "^7.3.1",
|
|
123
131
|
"@types/node": "24.10.1",
|
|
124
132
|
"@types/react": "19.2.7",
|
|
125
133
|
"@types/react-dom": "19.2.3",
|
|
126
134
|
"@types/three": "0.186.0",
|
|
135
|
+
"@vitejs/plugin-vue": "^6.0.10",
|
|
127
136
|
"draco3dgltf": "1.5.7",
|
|
128
137
|
"esbuild": "0.25.12",
|
|
129
138
|
"eslint": "9.39.5",
|
|
@@ -132,9 +141,15 @@
|
|
|
132
141
|
"pagefind": "^1.6.0",
|
|
133
142
|
"react": "19.3.1",
|
|
134
143
|
"react-dom": "19.3.1",
|
|
144
|
+
"rxjs": "^7.8.2",
|
|
145
|
+
"svelte": "^5.57.3",
|
|
135
146
|
"three": "0.186.1",
|
|
136
147
|
"typescript": "5.9.3",
|
|
137
|
-
"typescript-eslint": "8.72.1"
|
|
148
|
+
"typescript-eslint": "8.72.1",
|
|
149
|
+
"vite": "^8.3.5",
|
|
150
|
+
"vue": "^3.5.44",
|
|
151
|
+
"webpack": "^5.112.2",
|
|
152
|
+
"webpack-cli": "^7.3.1"
|
|
138
153
|
},
|
|
139
154
|
"publishConfig": {
|
|
140
155
|
"access": "public"
|