@johnmorrisdotca/uchusen-rockets 0.4.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 +15 -0
- package/NOTICE.md +2 -0
- package/README.md +78 -3
- 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/build/glb.js +15 -7
- package/dist/build/index.d.ts +5 -0
- package/dist/build/index.js +16 -3
- package/dist/data/flights.d.ts +7 -0
- package/dist/data/flights.js +160 -13
- package/dist/data/propellants.d.ts +59 -0
- package/dist/data/propellants.js +43 -0
- package/dist/data/sources.d.ts +70 -0
- package/dist/data/sources.js +9 -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.js +30 -5
- package/dist/element.js +3 -2
- package/dist/flight.d.ts +2 -0
- package/dist/flight.js +8 -1
- package/dist/flightbar.js +1 -1
- 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/starship.d.ts +6 -3
- package/dist/model/starship.js +12 -7
- package/dist/react.d.ts +2 -2
- package/package.json +18 -3
package/dist/element/plumes.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// Flames for the 3D view, made here and loaded only with it. One shape, one material and one instanced draw for every engine of a part, however many burn, so lighting and dousing engines changes numbers, never what the graphics card holds. The look of a flame (its shock diamonds, its length, its glow) is a picture, not a measurement.
|
|
2
1
|
import { AdditiveBlending, BufferGeometry, Color, DoubleSide, DynamicDrawUsage, Float32BufferAttribute, Group, InstancedMesh, Matrix4, PointLight, Quaternion, ShaderMaterial, Vector3 } from "three";
|
|
3
2
|
import { PLUME_DIAMONDS, plumeLength } from "../engines.js";
|
|
4
3
|
const STEPS = 28;
|
|
@@ -100,9 +99,14 @@ function glowShape() {
|
|
|
100
99
|
geometry.setIndex([0, 1, 2, 0, 2, 3]);
|
|
101
100
|
return geometry;
|
|
102
101
|
}
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
/** What a flame is drawn in: the kind of flame its engine's propellant gives (`src/data/propellants.ts`), and a neutral grey-white where no page read says. A picture, not a measurement. */
|
|
103
|
+
const FLAME_TONES = {
|
|
105
104
|
kerosene: { hot: "#fff4d2", cool: "#ff7a1a" },
|
|
105
|
+
methane: { hot: "#fff1e6", cool: "#6f7dff" },
|
|
106
|
+
hydrogen: { hot: "#ffffff", cool: "#6fa8ff" },
|
|
107
|
+
solid: { hot: "#fff1c4", cool: "#ff4a12" },
|
|
108
|
+
hypergolic: { hot: "#ffffff", cool: "#b8c4ee" },
|
|
109
|
+
neutral: { hot: "#ffffff", cool: "#9aa3b2" },
|
|
106
110
|
};
|
|
107
111
|
const place = new Matrix4();
|
|
108
112
|
const still = new Quaternion();
|
|
@@ -115,11 +119,11 @@ export class PartPlumes {
|
|
|
115
119
|
flames;
|
|
116
120
|
glows;
|
|
117
121
|
key = "";
|
|
118
|
-
constructor(kit, bells) {
|
|
122
|
+
constructor(kit, bells, kind) {
|
|
119
123
|
this.bells = bells;
|
|
120
124
|
this.group.name = "plumes";
|
|
121
|
-
this.flames = new InstancedMesh(kit.shape, kit.
|
|
122
|
-
this.glows = new InstancedMesh(kit.quad, kit.
|
|
125
|
+
this.flames = new InstancedMesh(kit.shape, kit.flameFor(kind), bells.length);
|
|
126
|
+
this.glows = new InstancedMesh(kit.quad, kit.glowFor(kind), bells.length);
|
|
123
127
|
for (const mesh of [this.flames, this.glows]) {
|
|
124
128
|
mesh.instanceMatrix.setUsage(DynamicDrawUsage);
|
|
125
129
|
mesh.frustumCulled = false;
|
|
@@ -149,12 +153,10 @@ export class PartPlumes {
|
|
|
149
153
|
this.glows.dispose();
|
|
150
154
|
}
|
|
151
155
|
}
|
|
152
|
-
/** One set of everything a flame needs, for one viewer. */
|
|
156
|
+
/** One set of everything a flame needs, for one viewer. The materials of each kind of flame share one program and one set of clocks; only the two colours differ. */
|
|
153
157
|
export class PlumeKit {
|
|
154
158
|
shape = flameShape();
|
|
155
159
|
quad = glowShape();
|
|
156
|
-
flame;
|
|
157
|
-
glow;
|
|
158
160
|
/** The hull's own glow in the painted look. Always in the scene, at no strength when no engine burns, so lighting engines never makes the materials build again. */
|
|
159
161
|
light = new PointLight("#ffb56b", 0, 0, 1.6);
|
|
160
162
|
uniforms = {
|
|
@@ -164,21 +166,31 @@ export class PlumeKit {
|
|
|
164
166
|
uLine: { value: 1 },
|
|
165
167
|
uFloor: { value: -1e6 },
|
|
166
168
|
uGlow: { value: 0.75 },
|
|
167
|
-
uHot: { value: new Color(FUEL_COLOURS.kerosene.hot) },
|
|
168
|
-
uCool: { value: new Color(FUEL_COLOURS.kerosene.cool) },
|
|
169
169
|
};
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
170
|
+
kinds = new Map();
|
|
171
|
+
kind(kind) {
|
|
172
|
+
const known = this.kinds.get(kind);
|
|
173
|
+
if (known)
|
|
174
|
+
return known;
|
|
175
|
+
const tone = FLAME_TONES[kind];
|
|
176
|
+
const uniforms = { ...this.uniforms, uHot: { value: new Color(tone.hot) }, uCool: { value: new Color(tone.cool) } };
|
|
177
|
+
const common = { transparent: true, depthWrite: false, blending: AdditiveBlending, toneMapped: false, uniforms };
|
|
178
|
+
const made = {
|
|
179
|
+
flame: new ShaderMaterial({ ...common, vertexShader: FLAME_VERTEX, fragmentShader: FLAME_FRAGMENT, side: DoubleSide }),
|
|
180
|
+
glow: new ShaderMaterial({ ...common, vertexShader: GLOW_VERTEX, fragmentShader: GLOW_FRAGMENT }),
|
|
181
|
+
};
|
|
182
|
+
this.kinds.set(kind, made);
|
|
183
|
+
return made;
|
|
184
|
+
}
|
|
185
|
+
flameFor(kind) {
|
|
186
|
+
return this.kind(kind).flame;
|
|
187
|
+
}
|
|
188
|
+
glowFor(kind) {
|
|
189
|
+
return this.kind(kind).glow;
|
|
174
190
|
}
|
|
175
191
|
setLook(painted) {
|
|
176
192
|
this.uniforms.uLine.value = painted ? 0 : 1;
|
|
177
193
|
}
|
|
178
|
-
setFuel(fuel) {
|
|
179
|
-
this.uniforms.uHot.value.set(FUEL_COLOURS[fuel].hot);
|
|
180
|
-
this.uniforms.uCool.value.set(FUEL_COLOURS[fuel].cool);
|
|
181
|
-
}
|
|
182
194
|
/** 0 near the ground, 1 high up where a flame fans out. */
|
|
183
195
|
setAir(air) {
|
|
184
196
|
this.uniforms.uAir.value = air;
|
|
@@ -200,8 +212,11 @@ export class PlumeKit {
|
|
|
200
212
|
dispose() {
|
|
201
213
|
this.shape.dispose();
|
|
202
214
|
this.quad.dispose();
|
|
203
|
-
this.
|
|
204
|
-
|
|
215
|
+
for (const { flame, glow } of this.kinds.values()) {
|
|
216
|
+
flame.dispose();
|
|
217
|
+
glow.dispose();
|
|
218
|
+
}
|
|
219
|
+
this.kinds.clear();
|
|
205
220
|
this.light.dispose();
|
|
206
221
|
this.light.removeFromParent();
|
|
207
222
|
}
|
package/dist/element/scene.js
CHANGED
|
@@ -77,8 +77,6 @@ void main() {
|
|
|
77
77
|
/** The materials of an engine's bell, in this package's own meshes. */
|
|
78
78
|
const NOZZLE_MATERIALS = new Set(["bell", "bell-inside", "engine-metal"]);
|
|
79
79
|
const asVec = (v) => [v.x, v.y, v.z];
|
|
80
|
-
/** A flame's colours, a picture: Raptor burns methane, Merlin kerosene. */
|
|
81
|
-
const fuelOf = (built) => (built.report.parts.some(({ part }) => part.rocket === "starship") ? "methane" : "kerosene");
|
|
82
80
|
/** The pictures a licensed model's material may hold (the shared sky it reflects is not one of them). */
|
|
83
81
|
const MODEL_PICTURES = ["map", "normalMap", "roughnessMap", "metalnessMap", "aoMap", "emissiveMap"];
|
|
84
82
|
export class RocketViewer {
|
|
@@ -242,8 +240,20 @@ export class RocketViewer {
|
|
|
242
240
|
to: [0, 0, 0],
|
|
243
241
|
hideAtEnd: false,
|
|
244
242
|
plumes: null,
|
|
243
|
+
moves: [],
|
|
245
244
|
};
|
|
246
245
|
this.takeMeshes(source, code, view);
|
|
246
|
+
for (const node of source.children.slice(1)) {
|
|
247
|
+
const axis = node.userData.axis;
|
|
248
|
+
if (!axis)
|
|
249
|
+
continue;
|
|
250
|
+
const group = new Group();
|
|
251
|
+
group.name = node.name;
|
|
252
|
+
group.position.copy(node.position);
|
|
253
|
+
code.add(group);
|
|
254
|
+
this.takeMeshes(node, group, view);
|
|
255
|
+
view.moves.push({ name: String(node.userData.group), group, axis: new Vector3(axis[0], axis[1], axis[2]).normalize(), angle: 0 });
|
|
256
|
+
}
|
|
247
257
|
const place = places.find((p) => p.slot === part.slot);
|
|
248
258
|
holder.position.set(...(place?.at ?? [0, 0, 0]));
|
|
249
259
|
holder.visible = place?.shown ?? false;
|
|
@@ -252,7 +262,6 @@ export class RocketViewer {
|
|
|
252
262
|
}
|
|
253
263
|
this.addGlow();
|
|
254
264
|
this.setLook(look);
|
|
255
|
-
this.plumes.setFuel(fuelOf(built));
|
|
256
265
|
this.frameTo(angle ?? this.currentAngle(), false);
|
|
257
266
|
if (this.clockNow) {
|
|
258
267
|
this.flightKey = "";
|
|
@@ -455,10 +464,11 @@ export class RocketViewer {
|
|
|
455
464
|
for (const view of this.parts) {
|
|
456
465
|
const count = counts.get(view.slot) ?? 0;
|
|
457
466
|
if (count > 0 && !view.plumes) {
|
|
458
|
-
const
|
|
467
|
+
const built = this.built.parts.find((part) => part.slot === view.slot);
|
|
468
|
+
const bells = bellsOf(built?.pieces ?? []);
|
|
459
469
|
if (bells.length === 0)
|
|
460
470
|
continue;
|
|
461
|
-
view.plumes = new PartPlumes(this.plumes, bells);
|
|
471
|
+
view.plumes = new PartPlumes(this.plumes, bells, built?.flame ?? "neutral");
|
|
462
472
|
view.holder.add(view.plumes.group);
|
|
463
473
|
}
|
|
464
474
|
if (!view.plumes)
|
|
@@ -507,7 +517,12 @@ export class RocketViewer {
|
|
|
507
517
|
part.holder.position.set(...(place?.at ?? [0, 0, 0]));
|
|
508
518
|
part.holder.rotation.set(0, 0, 0);
|
|
509
519
|
part.holder.visible = place?.shown ?? false;
|
|
520
|
+
for (const move of part.moves) {
|
|
521
|
+
move.angle = 0;
|
|
522
|
+
move.group.quaternion.identity();
|
|
523
|
+
}
|
|
510
524
|
}
|
|
525
|
+
this.canvas.dataset.turned = "";
|
|
511
526
|
this.plumes.setAir(0);
|
|
512
527
|
this.plumes.setFloor(-1e6);
|
|
513
528
|
this.reframe();
|
|
@@ -583,10 +598,20 @@ export class RocketViewer {
|
|
|
583
598
|
continue;
|
|
584
599
|
const turn = MathUtils.degToRad(pose.pitch);
|
|
585
600
|
const middle = (parts.find((one) => one.slot === part.slot)?.height ?? 0) / 2;
|
|
601
|
+
for (const move of part.moves) {
|
|
602
|
+
const angle = pose.moves[move.name] ?? 0;
|
|
603
|
+
if (angle === move.angle)
|
|
604
|
+
continue;
|
|
605
|
+
move.angle = angle;
|
|
606
|
+
move.group.quaternion.setFromAxisAngle(move.axis, MathUtils.degToRad(angle));
|
|
607
|
+
}
|
|
586
608
|
part.holder.visible = !pose.gone;
|
|
587
609
|
part.holder.rotation.set(0, 0, turn);
|
|
588
610
|
part.holder.position.set(place.at[0] + pose.dx + Math.sin(turn) * middle, place.at[1] + pose.dy + middle - Math.cos(turn) * middle, place.at[2]);
|
|
589
611
|
}
|
|
612
|
+
const turned = this.parts.flatMap((part) => part.moves.filter((move) => move.angle !== 0).map((move) => `${part.slot}:${move.group.name.split("~").slice(1).join("~")}=${Math.round(move.angle)}`)).join(" ");
|
|
613
|
+
if (turned !== this.canvas.dataset.turned)
|
|
614
|
+
this.canvas.dataset.turned = turned;
|
|
590
615
|
this.plumes.setAir(frame.air);
|
|
591
616
|
this.plumes.setFloor(frame.groundY);
|
|
592
617
|
this.ground?.set(frame.groundY, this.options.reducedMotion ? 0 : frame.smoke, performance.now() / 1000);
|
package/dist/element.js
CHANGED
|
@@ -503,11 +503,12 @@ export class UchusenRocket extends HTMLBase {
|
|
|
503
503
|
const from = this.driven ? turnedBy(angle, this.driven.yaw, this.driven.tilt) : (this.viewer?.currentAngle() ?? angle);
|
|
504
504
|
const label = this.getAttribute("label") ?? this.builtNow.report.label;
|
|
505
505
|
const lit = flying ? (media("(prefers-reduced-motion: reduce)") ? false : flying.burns) : this.engineLights();
|
|
506
|
-
const
|
|
506
|
+
const moves = flying ? Object.fromEntries(Object.entries(flying.phase.pose).flatMap(([slot, pose]) => (pose.moves ? [[slot, pose.moves]] : []))) : undefined;
|
|
507
|
+
const key = `${this.key}|${look}|${show}|${from.az.toFixed(2)}|${from.el.toFixed(2)}|${label}|${flying ? flying.index : ""}|${JSON.stringify(lit)}|${JSON.stringify(moves ?? {})}`;
|
|
507
508
|
let node = this.drawing.firstElementChild;
|
|
508
509
|
if (key !== this.drawn.key || !node) {
|
|
509
510
|
const template = document.createElement("template");
|
|
510
|
-
template.innerHTML = this.builtNow.svg({ look, show, view: from, engines: lit });
|
|
511
|
+
template.innerHTML = this.builtNow.svg({ look, show, view: from, engines: lit, ...(moves ? { moves } : {}) });
|
|
511
512
|
node = template.content.firstElementChild;
|
|
512
513
|
if (!node)
|
|
513
514
|
return;
|
package/dist/flight.d.ts
CHANGED
|
@@ -93,6 +93,8 @@ export interface PoseNow {
|
|
|
93
93
|
dy: number;
|
|
94
94
|
pitch: number;
|
|
95
95
|
gone: boolean;
|
|
96
|
+
/** Degrees each moving group is turned, by name. */
|
|
97
|
+
moves: Readonly<Record<string, number>>;
|
|
96
98
|
}
|
|
97
99
|
/**
|
|
98
100
|
* Everything the picture needs at one place on the timeline: the phase, how each part stands, which engines burn, how far the ground has fallen, and how much smoke stands on the pad.
|
package/dist/flight.js
CHANGED
|
@@ -103,7 +103,14 @@ const poseIn = (pose, part, height) => ({
|
|
|
103
103
|
dy: pose?.rest ? -part.baseY : (pose?.dy ?? 0) * height,
|
|
104
104
|
pitch: pose?.pitch ?? 0,
|
|
105
105
|
gone: pose?.gone ?? false,
|
|
106
|
+
moves: pose?.moves ?? {},
|
|
106
107
|
});
|
|
108
|
+
const mixMoves = (from, to, t) => {
|
|
109
|
+
const out = {};
|
|
110
|
+
for (const name of new Set([...Object.keys(from), ...Object.keys(to)]))
|
|
111
|
+
out[name] = mix(from[name] ?? 0, to[name] ?? 0, t);
|
|
112
|
+
return out;
|
|
113
|
+
};
|
|
107
114
|
/**
|
|
108
115
|
* Everything the picture needs at a place on the timeline, for a vehicle `height` metres tall.
|
|
109
116
|
*
|
|
@@ -129,7 +136,7 @@ export function frameAt(flight, position, parts, height) {
|
|
|
129
136
|
for (const part of parts) {
|
|
130
137
|
const from = poseIn(phase.pose[part.slot], part, height);
|
|
131
138
|
const to = poseIn(next.pose[part.slot], part, height);
|
|
132
|
-
const now = { dx: mix(from.dx, to.dx, t), dy: mix(from.dy, to.dy, t), pitch: mix(from.pitch, to.pitch, t), gone: from.gone };
|
|
139
|
+
const now = { dx: mix(from.dx, to.dx, t), dy: mix(from.dy, to.dy, t), pitch: mix(from.pitch, to.pitch, t), gone: from.gone, moves: mixMoves(from.moves, to.moves, t) };
|
|
133
140
|
poses[part.slot] = now;
|
|
134
141
|
if (now.dx !== 0 || now.dy !== 0)
|
|
135
142
|
separated = true;
|
package/dist/flightbar.js
CHANGED
|
@@ -167,7 +167,7 @@ export class UchusenFlight extends HTMLBase {
|
|
|
167
167
|
parts.leave.disabled = !state.active;
|
|
168
168
|
parts.range.value = String(state.position);
|
|
169
169
|
parts.range.setAttribute("aria-valuetext", `${clockWords(phase.at)}, ${phase.name}`);
|
|
170
|
-
parts.now.textContent = `${clockWords(phase.at)}, ${phase.name}${phase.altitude?.value ? `, ${phase.altitude.value}` : ""}`;
|
|
170
|
+
parts.now.textContent = `${clockWords(phase.at)}, ${phase.name}${phase.altitude?.value ? `, ${phase.altitude.value}` : ""}${phase.speed?.value ? `, ${phase.speed.value}` : ""}`;
|
|
171
171
|
parts.what.textContent = phase.what;
|
|
172
172
|
const chartKey = `${flight.id}/${index}/${state.active}`;
|
|
173
173
|
if (chartKey !== this.chartKey) {
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,9 @@ export { MAKERS } from "./data/makers.ts";
|
|
|
6
6
|
export type { MakerId } from "./data/makers.ts";
|
|
7
7
|
export { FLIGHT_LOG, flightLogOf } from "./data/flight-log.ts";
|
|
8
8
|
export type { LoggedFlight } from "./data/flight-log.ts";
|
|
9
|
+
export { moved, movingGroupsOf } from "./model/moves.ts";
|
|
10
|
+
export { PROPELLANTS, propellantOf } from "./data/propellants.ts";
|
|
11
|
+
export type { EnginePropellant, FlameKind } from "./data/propellants.ts";
|
|
9
12
|
export { SOURCES } from "./data/sources.ts";
|
|
10
13
|
export type { Source, SourceId } from "./data/sources.ts";
|
|
11
14
|
export { creditLine, MODEL_CREDITS } from "./data/credits.ts";
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,8 @@ export { PLANNED_ROCKETS, ROCKETS, partIdOf, SLOT_NAMES, variantOf } from "./roc
|
|
|
3
3
|
export { blank, figureWords } from "./data/types.js";
|
|
4
4
|
export { MAKERS } from "./data/makers.js";
|
|
5
5
|
export { FLIGHT_LOG, flightLogOf } from "./data/flight-log.js";
|
|
6
|
+
export { moved, movingGroupsOf } from "./model/moves.js";
|
|
7
|
+
export { PROPELLANTS, propellantOf } from "./data/propellants.js";
|
|
6
8
|
export { SOURCES } from "./data/sources.js";
|
|
7
9
|
export { creditLine, MODEL_CREDITS } from "./data/credits.js";
|
|
8
10
|
export { PART_ENTRIES, partEntry } from "./model/registry.js";
|
package/dist/model/falcon.js
CHANGED
|
@@ -56,11 +56,11 @@ function firstStage(d, withTop) {
|
|
|
56
56
|
if (d.legs)
|
|
57
57
|
for (const az of [45, 135, 225, 315]) {
|
|
58
58
|
const frame = radial(deg(az));
|
|
59
|
-
pieces.push({ kind: "plate", material: "black", frame, outline: [[r - 0.05, 0.8], [r + 0.5, 0.8], [r + 0.55, 3], [r + 0.15, 10.5], [r - 0.05, 11]], thickness: 1.2 });
|
|
59
|
+
pieces.push({ kind: "plate", material: "black", frame, outline: [[r - 0.05, 0.8], [r + 0.5, 0.8], [r + 0.55, 3], [r + 0.15, 10.5], [r - 0.05, 11]], thickness: 1.2, move: { name: "legs", pivot: pointOf(frame, r + 0.2, 0.8), axis: frame.w } });
|
|
60
60
|
}
|
|
61
61
|
if (d.fins)
|
|
62
62
|
for (const az of [45, 135, 225, 315])
|
|
63
|
-
pieces.push(...gridFin(az, tank + 0.1, r, r + 1.4, 1.5, 0.3, false));
|
|
63
|
+
pieces.push(...gridFin(az, tank + 0.1, r, r + 1.4, 1.5, 0.3, false, { name: "grid-fins", about: "tangent" }));
|
|
64
64
|
return pieces;
|
|
65
65
|
}
|
|
66
66
|
function secondStage(d) {
|
|
@@ -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/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
72
|
title?: string | undefined | undefined;
|
|
72
73
|
"aria-label"?: 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;
|