@johnmorrisdotca/uchusen-rockets 0.3.0 → 0.4.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 +16 -5
- package/README.md +241 -4
- 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 +14 -0
- package/dist/build/index.d.ts +89 -4
- package/dist/build/index.js +55 -4
- 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 +54 -2
- package/dist/data/flights.js +10 -0
- package/dist/data/makers.d.ts +21 -0
- package/dist/data/makers.js +10 -0
- package/dist/data/sources.d.ts +32 -0
- package/dist/data/sources.js +10 -0
- package/dist/data/types.d.ts +81 -1
- package/dist/data/types.js +26 -1
- package/dist/element.d.ts +61 -3
- package/dist/element.js +50 -3
- 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 +134 -9
- package/dist/flight.js +122 -9
- package/dist/flightbar.d.ts +12 -0
- package/dist/flightbar.js +12 -0
- package/dist/framing.d.ts +182 -8
- package/dist/framing.js +127 -6
- 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/materials.d.ts +32 -0
- package/dist/model/materials.js +10 -0
- package/dist/model/registry.d.ts +22 -0
- package/dist/model/registry.js +22 -0
- 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 +24 -0
- 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 +10 -5
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;
|
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>>;
|
package/dist/rockets.js
CHANGED
|
@@ -21,6 +21,16 @@ import { ISS_VARIANTS } from "./data/iss.js";
|
|
|
21
21
|
import { HUBBLE_VARIANTS } from "./data/hubble.js";
|
|
22
22
|
import { STARSHIP_VARIANTS } from "./data/starship.js";
|
|
23
23
|
import { MADE_BY } from "./data/makers.js";
|
|
24
|
+
/**
|
|
25
|
+
* 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.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { ROCKETS } from "@johnmorrisdotca/uchusen-rockets";
|
|
30
|
+
*
|
|
31
|
+
* console.log(Object.keys(ROCKETS).slice(0, 6));
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
24
34
|
export const ROCKETS = {
|
|
25
35
|
starship: { id: "starship", name: "Starship", status: "built", ...MADE_BY["starship"], variants: STARSHIP_VARIANTS, defaultVariant: "v3" },
|
|
26
36
|
"falcon-9": { id: "falcon-9", name: "Falcon 9", status: "built", ...MADE_BY["falcon-9"], variants: FALCON_9_VARIANTS, defaultVariant: "block-5" },
|
|
@@ -47,17 +57,63 @@ export const ROCKETS = {
|
|
|
47
57
|
starbase: { id: "starbase", name: "Starbase", status: "built", ...MADE_BY["starbase"], variants: STARBASE_VARIANTS, defaultVariant: "launch-site" },
|
|
48
58
|
};
|
|
49
59
|
const fig = (value, source) => ({ value, source });
|
|
60
|
+
/**
|
|
61
|
+
* Rockets with sourced facts and no shape yet.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* import { PLANNED_ROCKETS } from "@johnmorrisdotca/uchusen-rockets";
|
|
66
|
+
*
|
|
67
|
+
* console.log(PLANNED_ROCKETS.map((rocket) => rocket.name));
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
50
70
|
export const PLANNED_ROCKETS = [
|
|
51
71
|
{ id: "vulcan-centaur", name: "Vulcan Centaur", status: "planned", height: fig(61.6, "wikipedia-vulcan"), diameter: fig(5.4, "wikipedia-vulcan"), firstFlight: { value: "2024-01-08", source: "wikipedia-vulcan" }, source: "wikipedia-vulcan" },
|
|
52
72
|
{ id: "ariane-6", name: "Ariane 6", status: "planned", height: fig(63, "wikipedia-ariane-6"), diameter: fig(5.4, "wikipedia-ariane-6"), firstFlight: { value: "2024-07-09", source: "wikipedia-ariane-6" }, source: "wikipedia-ariane-6" },
|
|
53
73
|
];
|
|
74
|
+
/**
|
|
75
|
+
* Finds a rocket's variant, with its sourced sizes.
|
|
76
|
+
*
|
|
77
|
+
* @param rocket A rocket's id.
|
|
78
|
+
* @param id A variant's id. Left out, null or undefined: the rocket's default variant.
|
|
79
|
+
* @returns The variant, or undefined when the rocket or the variant is not known.
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* import { variantOf } from "@johnmorrisdotca/uchusen-rockets";
|
|
83
|
+
*
|
|
84
|
+
* const v3 = variantOf("starship", "v3");
|
|
85
|
+
* console.log(v3?.facts.height.value, variantOf("starship", "v99"));
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
54
88
|
export function variantOf(rocket, id) {
|
|
55
89
|
const entry = Object.hasOwn(ROCKETS, rocket) ? ROCKETS[rocket] : undefined;
|
|
56
90
|
return entry?.variants.find((variant) => variant.id === (id ?? entry.defaultVariant));
|
|
57
91
|
}
|
|
58
|
-
/**
|
|
92
|
+
/**
|
|
93
|
+
* A part's name for a rocket's slot in a variant.
|
|
94
|
+
*
|
|
95
|
+
* @param rocket A rocket's id.
|
|
96
|
+
* @param variant A variant's id.
|
|
97
|
+
* @param slot A slot name.
|
|
98
|
+
* @returns The id of the part that stands in that slot.
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* import { partIdOf } from "@johnmorrisdotca/uchusen-rockets";
|
|
102
|
+
*
|
|
103
|
+
* console.log(partIdOf("starship", "v3", "booster"));
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
59
106
|
export const partIdOf = (rocket, variant, slot) => variantOf(rocket, variant)?.partIds?.[slot] ?? `${rocket}-${variant}-${slot}`;
|
|
60
|
-
/**
|
|
107
|
+
/**
|
|
108
|
+
* What to call a slot.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* import { SLOT_NAMES } from "@johnmorrisdotca/uchusen-rockets";
|
|
113
|
+
*
|
|
114
|
+
* console.log(SLOT_NAMES["booster"]);
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
61
117
|
export const SLOT_NAMES = {
|
|
62
118
|
booster: "Super Heavy",
|
|
63
119
|
ship: "Ship",
|
package/dist/spin.d.ts
CHANGED
|
@@ -1,11 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which way a rocket turns: `cw` (clockwise) or `ccw` (counter-clockwise).
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import type { Way } from "@johnmorrisdotca/uchusen-rockets";
|
|
7
|
+
*
|
|
8
|
+
* const way: Way = "ccw";
|
|
9
|
+
* console.log(way);
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
1
12
|
export type Way = "cw" | "ccw";
|
|
13
|
+
/**
|
|
14
|
+
* The slow turn of a rocket: the seconds a full turn takes (0 is none) and which way.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { DEFAULT_SPIN, type Spin } from "@johnmorrisdotca/uchusen-rockets";
|
|
19
|
+
*
|
|
20
|
+
* const spin: Spin = DEFAULT_SPIN;
|
|
21
|
+
* console.log(spin.seconds, spin.way);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
2
24
|
export interface Spin {
|
|
3
25
|
/** Seconds a turn, 0 for not at all. */
|
|
4
26
|
seconds: number;
|
|
5
27
|
way: Way;
|
|
6
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* The spin used when none is asked for: 180 seconds a turn, clockwise.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { DEFAULT_SPIN } from "@johnmorrisdotca/uchusen-rockets";
|
|
35
|
+
*
|
|
36
|
+
* console.log(DEFAULT_SPIN);
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
7
39
|
export declare const DEFAULT_SPIN: Spin;
|
|
8
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* Anything but `ccw` is the default way.
|
|
42
|
+
*
|
|
43
|
+
* @param value Anything.
|
|
44
|
+
* @returns `ccw` for `ccw`, and `cw` for anything else.
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* import { cleanWay } from "@johnmorrisdotca/uchusen-rockets";
|
|
48
|
+
*
|
|
49
|
+
* console.log(cleanWay("ccw"), cleanWay("left"));
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
9
52
|
export declare const cleanWay: (value: unknown) => Way;
|
|
10
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* A spin from the `spin` and `way` attributes: a name, or seconds a turn. A nonsense value is the default, and a negative one is none.
|
|
55
|
+
*
|
|
56
|
+
* @param spin The `spin` attribute: `off`, `slow`, `medium`, `fast`, or seconds a turn. Null when missing.
|
|
57
|
+
* @param way The `way` attribute. Null when missing.
|
|
58
|
+
* @returns The spin to use.
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* import { spinOf } from "@johnmorrisdotca/uchusen-rockets";
|
|
62
|
+
*
|
|
63
|
+
* console.log(spinOf("fast", null), spinOf("30", "ccw"), spinOf("nonsense", null));
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
11
66
|
export declare function spinOf(spin: string | null, way: string | null): Spin;
|
package/dist/spin.js
CHANGED
|
@@ -1,9 +1,42 @@
|
|
|
1
1
|
// How a view turns by itself. `way` is which way round: `cw`, clockwise seen from above, takes the near side to the viewer's left, and `ccw` to the right. Pure.
|
|
2
2
|
const NAMED = { off: 0, slow: 180, medium: 67, fast: 20 };
|
|
3
|
+
/**
|
|
4
|
+
* The spin used when none is asked for: 180 seconds a turn, clockwise.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { DEFAULT_SPIN } from "@johnmorrisdotca/uchusen-rockets";
|
|
9
|
+
*
|
|
10
|
+
* console.log(DEFAULT_SPIN);
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
3
13
|
export const DEFAULT_SPIN = { seconds: 180, way: "cw" };
|
|
4
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Anything but `ccw` is the default way.
|
|
16
|
+
*
|
|
17
|
+
* @param value Anything.
|
|
18
|
+
* @returns `ccw` for `ccw`, and `cw` for anything else.
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { cleanWay } from "@johnmorrisdotca/uchusen-rockets";
|
|
22
|
+
*
|
|
23
|
+
* console.log(cleanWay("ccw"), cleanWay("left"));
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
5
26
|
export const cleanWay = (value) => (value === "ccw" ? "ccw" : "cw");
|
|
6
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* A spin from the `spin` and `way` attributes: a name, or seconds a turn. A nonsense value is the default, and a negative one is none.
|
|
29
|
+
*
|
|
30
|
+
* @param spin The `spin` attribute: `off`, `slow`, `medium`, `fast`, or seconds a turn. Null when missing.
|
|
31
|
+
* @param way The `way` attribute. Null when missing.
|
|
32
|
+
* @returns The spin to use.
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { spinOf } from "@johnmorrisdotca/uchusen-rockets";
|
|
36
|
+
*
|
|
37
|
+
* console.log(spinOf("fast", null), spinOf("30", "ccw"), spinOf("nonsense", null));
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
7
40
|
export function spinOf(spin, way) {
|
|
8
41
|
const raw = spin === null ? NaN : Object.hasOwn(NAMED, spin) ? NAMED[spin] : Number(spin);
|
|
9
42
|
const seconds = spin === null || spin.trim() === "" || !Number.isFinite(raw) ? DEFAULT_SPIN.seconds : Math.max(0, raw);
|
package/dist/tilt.d.ts
CHANGED
|
@@ -1,20 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether tilting a device turns the view: `off`, `ask` (the browser must ask first, as on iOS) or `on`.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import type { TiltMode } from "@johnmorrisdotca/uchusen-rockets";
|
|
7
|
+
*
|
|
8
|
+
* const mode: TiltMode = "ask";
|
|
9
|
+
* console.log(mode);
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
1
12
|
export type TiltMode = "off" | "ask" | "on";
|
|
2
|
-
/**
|
|
3
|
-
* on "Tilt to turn" asks, never the page by itself); else on.
|
|
13
|
+
/**
|
|
14
|
+
* Off under reduced motion, on a computer with a mouse, or where the browser has no orientation events; "ask" where it must ask first (iOS: a tap on "Tilt to turn" asks, never the page by itself); else on.
|
|
15
|
+
*
|
|
16
|
+
* @param env What the page knows: reduced motion, a coarse pointer (touch), whether the browser has orientation events, and whether it must ask permission first.
|
|
17
|
+
* @returns `off`, `ask` or `on`.
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { tiltMode } from "@johnmorrisdotca/uchusen-rockets";
|
|
21
|
+
*
|
|
22
|
+
* console.log(tiltMode({ reducedMotion: false, coarsePointer: true, hasOrientation: true, needsPermission: true }));
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
4
25
|
export declare function tiltMode(env: {
|
|
5
26
|
reducedMotion: boolean;
|
|
6
27
|
coarsePointer: boolean;
|
|
7
28
|
hasOrientation: boolean;
|
|
8
29
|
needsPermission: boolean;
|
|
9
30
|
}): TiltMode;
|
|
31
|
+
/**
|
|
32
|
+
* One reading of a device's orientation: front to back (`beta`, -180 to 180 degrees) and left to right (`gamma`, -90 to 90 degrees). Either is null when the device gives none.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* import type { Reading } from "@johnmorrisdotca/uchusen-rockets";
|
|
37
|
+
*
|
|
38
|
+
* const reading: Reading = { beta: 20, gamma: -5 };
|
|
39
|
+
* console.log(reading);
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
10
42
|
export interface Reading {
|
|
11
43
|
/** Front to back, -180 to 180 degrees. */
|
|
12
44
|
beta: number | null;
|
|
13
45
|
/** Left to right, -90 to 90 degrees. */
|
|
14
46
|
gamma: number | null;
|
|
15
47
|
}
|
|
16
|
-
/**
|
|
17
|
-
* screen's orientation (0, 90, 180 or 270), so leaning a phone held sideways still turns the view the way it looks. Null for an empty reading.
|
|
48
|
+
/**
|
|
49
|
+
* The turn (degrees round, degrees up or down) for a reading, measured from `rest` (how the device was held when tilting began). `angle` is the screen's orientation (0, 90, 180 or 270), so leaning a phone held sideways still turns the view the way it looks. Null for an empty reading.
|
|
50
|
+
*
|
|
51
|
+
* @param reading The current reading.
|
|
52
|
+
* @param rest The reading when tilting began.
|
|
53
|
+
* @param angle The screen's orientation: 0, 90, 180 or 270. Defaults to 0.
|
|
54
|
+
* @returns The turn in degrees round (`azimuth`) and up or down (`polar`), or null for an empty reading.
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* import { tiltTurn } from "@johnmorrisdotca/uchusen-rockets";
|
|
58
|
+
*
|
|
59
|
+
* console.log(tiltTurn({ beta: 30, gamma: 10 }, { beta: 20, gamma: 0 }), tiltTurn({ beta: null, gamma: null }, { beta: 0, gamma: 0 }));
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
18
62
|
export declare function tiltTurn(reading: Reading, rest: Reading, angle?: number): {
|
|
19
63
|
azimuth: number;
|
|
20
64
|
polar: number;
|
package/dist/tilt.js
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
// Tilt to turn: on a phone or tablet, leaning the device turns a 3D view a little. Pure: when it is offered, and how a reading becomes a turn of the view.
|
|
2
|
-
/**
|
|
3
|
-
* on "Tilt to turn" asks, never the page by itself); else on.
|
|
2
|
+
/**
|
|
3
|
+
* Off under reduced motion, on a computer with a mouse, or where the browser has no orientation events; "ask" where it must ask first (iOS: a tap on "Tilt to turn" asks, never the page by itself); else on.
|
|
4
|
+
*
|
|
5
|
+
* @param env What the page knows: reduced motion, a coarse pointer (touch), whether the browser has orientation events, and whether it must ask permission first.
|
|
6
|
+
* @returns `off`, `ask` or `on`.
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { tiltMode } from "@johnmorrisdotca/uchusen-rockets";
|
|
10
|
+
*
|
|
11
|
+
* console.log(tiltMode({ reducedMotion: false, coarsePointer: true, hasOrientation: true, needsPermission: true }));
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
4
14
|
export function tiltMode(env) {
|
|
5
15
|
if (env.reducedMotion || !env.coarsePointer || !env.hasOrientation)
|
|
6
16
|
return "off";
|
|
@@ -10,8 +20,20 @@ const GAIN = 0.6;
|
|
|
10
20
|
const MAX_TURN = 25;
|
|
11
21
|
const MAX_LEAN = 12;
|
|
12
22
|
const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
|
|
13
|
-
/**
|
|
14
|
-
* screen's orientation (0, 90, 180 or 270), so leaning a phone held sideways still turns the view the way it looks. Null for an empty reading.
|
|
23
|
+
/**
|
|
24
|
+
* The turn (degrees round, degrees up or down) for a reading, measured from `rest` (how the device was held when tilting began). `angle` is the screen's orientation (0, 90, 180 or 270), so leaning a phone held sideways still turns the view the way it looks. Null for an empty reading.
|
|
25
|
+
*
|
|
26
|
+
* @param reading The current reading.
|
|
27
|
+
* @param rest The reading when tilting began.
|
|
28
|
+
* @param angle The screen's orientation: 0, 90, 180 or 270. Defaults to 0.
|
|
29
|
+
* @returns The turn in degrees round (`azimuth`) and up or down (`polar`), or null for an empty reading.
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* import { tiltTurn } from "@johnmorrisdotca/uchusen-rockets";
|
|
33
|
+
*
|
|
34
|
+
* console.log(tiltTurn({ beta: 30, gamma: 10 }, { beta: 20, gamma: 0 }), tiltTurn({ beta: null, gamma: null }, { beta: 0, gamma: 0 }));
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
15
37
|
export function tiltTurn(reading, rest, angle = 0) {
|
|
16
38
|
if (reading.beta === null || reading.gamma === null || rest.beta === null || rest.gamma === null)
|
|
17
39
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnmorrisdotca/uchusen-rockets",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.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",
|
|
@@ -93,9 +93,12 @@
|
|
|
93
93
|
"dev": "pnpm site && node scripts/dev.ts",
|
|
94
94
|
"test:demo": "pnpm site && playwright test",
|
|
95
95
|
"test:freeze": "pnpm site && playwright test e2e/freeze.demo.ts --project=chromium-desk",
|
|
96
|
-
"screenshots": "pnpm site && node scripts/screenshots.ts",
|
|
96
|
+
"screenshots": "pnpm site && node scripts/docs-site.mjs build && node scripts/screenshots.ts",
|
|
97
97
|
"models": "node scripts/reduce-models.ts",
|
|
98
|
-
"models:nasa": "node scripts/reduce-nasa.ts"
|
|
98
|
+
"models:nasa": "node scripts/reduce-nasa.ts",
|
|
99
|
+
"docs:site": "pnpm build && node scripts/docs-site.mjs build",
|
|
100
|
+
"docs:check": "pnpm build && node scripts/docs-site.mjs check",
|
|
101
|
+
"size": "node scripts/docs-site.mjs size"
|
|
99
102
|
},
|
|
100
103
|
"peerDependencies": {
|
|
101
104
|
"react": ">=18",
|
|
@@ -114,8 +117,8 @@
|
|
|
114
117
|
"@gltf-transform/core": "4.5.1",
|
|
115
118
|
"@gltf-transform/extensions": "4.5.1",
|
|
116
119
|
"@gltf-transform/functions": "4.5.1",
|
|
117
|
-
"@johnmorrisdotca/chikyu-earth": "0.
|
|
118
|
-
"@johnmorrisdotca/kazoku-ui": "^0.
|
|
120
|
+
"@johnmorrisdotca/chikyu-earth": "0.10.0",
|
|
121
|
+
"@johnmorrisdotca/kazoku-ui": "^0.12.0",
|
|
119
122
|
"@playwright/test": "1.64.0",
|
|
120
123
|
"@types/node": "24.10.1",
|
|
121
124
|
"@types/react": "19.2.7",
|
|
@@ -124,7 +127,9 @@
|
|
|
124
127
|
"draco3dgltf": "1.5.7",
|
|
125
128
|
"esbuild": "0.25.12",
|
|
126
129
|
"eslint": "9.39.5",
|
|
130
|
+
"marked": "^18.1.3",
|
|
127
131
|
"meshoptimizer": "1.3.0",
|
|
132
|
+
"pagefind": "^1.6.0",
|
|
128
133
|
"react": "19.3.1",
|
|
129
134
|
"react-dom": "19.3.1",
|
|
130
135
|
"three": "0.186.1",
|