@crewlethq/icons 0.15.0 → 0.15.1
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/README.md +7 -3
- package/dist/characters.d.ts +23 -12
- package/dist/characters.js +1 -1
- package/dist/{chunk-7RRFA6BN.js → chunk-X7FKGFKM.js} +377 -108
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -166,11 +166,15 @@ import { CrewletCharacter, CREWLET_CHARACTERS, isCrewletCharacter } from '@crewl
|
|
|
166
166
|
| Prop | Type | Default | Purpose |
|
|
167
167
|
| ---- | ---- | ------- | ------- |
|
|
168
168
|
| `character` | `CrewletCharacterId`, one of `CREWLET_CHARACTERS` | required | Which character to draw. `crewlet`, the first, is the mark itself. |
|
|
169
|
-
| `detail` | `'full' \| 'compact'` | `'full'` | `full` draws the keyline floating off the body and the gap round the visor; `compact` leaves both out and opens the eyes, for a character too small for a hairline gap to read. |
|
|
169
|
+
| `detail` | `'full' \| 'compact'` | `'full'` | `full` draws the keyline floating off the body and the gap round the visor; `compact` leaves both out, with every other cut as fine as them (the page's fold), and opens the eyes, for a character too small for a hairline gap to read. |
|
|
170
170
|
|
|
171
|
-
Every character is cut from the mark's own rules: every corner chamfered at 45 degrees, a keyline at the mark's own proportions, a visor with two upright slits measured from the visor itself, a V notch on a flat crown and block legs under a flat base.
|
|
171
|
+
Every character is cut from the mark's own rules: every corner chamfered at 45 degrees, a keyline at the mark's own proportions, a visor with two upright slits measured from the visor itself, a V notch on a flat crown and block legs under a flat base.
|
|
172
172
|
|
|
173
|
-
|
|
173
|
+
A character is framed square on its optical centre: the point halfway between the middle of its bounding box and the centre of area of its silhouette, in the smallest square round that point that holds everything it draws, the keyline's mitred corners included. A symmetric silhouette is centred geometrically; a heart over thin legs, a speech bubble over its tail or a triangle over its apex moves half the way toward its mass, so it sits in the middle of any box it is given.
|
|
174
|
+
|
|
175
|
+
Its face and holes are cut into its own paths, wound against the outline round them, and never painted or masked. A cut shows whatever the character stands on (a badge's plate, a chart's card, a hovered row) in every colour and theme, and nothing a host stylesheet does to the paths in its zone can fill one. It carries no mask and no id, so any number of copies, rendered together or apart, can share a page.
|
|
176
|
+
|
|
177
|
+
An id is what a configuration stores, so the set is a contract: `CREWLET_CHARACTERS` lists the ids in the order a picker offers them, `CREWLET_CHARACTER_GEOMETRY` gives each one's name and a few words on its shape, and `isCrewletCharacter` tells an id this build draws from anything else read off the wire. The geometry lives in `src/crewletCharacters.ts`, the union and the cuts in `src/region.ts` and the frame and the face in `src/characterDrawing.ts`; the original Crewlet is drawn from `svg/crewlet-icon.svg` itself, which `test/characters.test.mjs` holds. `@crewlethq/ui`'s `Avatar` draws a character on a plate in an agent's hue.
|
|
174
178
|
|
|
175
179
|
## Stylesheets
|
|
176
180
|
|
package/dist/characters.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { SVGProps } from 'react';
|
|
|
12
12
|
* in it. `cut` is that rule as a function.
|
|
13
13
|
* - THE KEYLINE. An outline floats off the body with a transparent gap, as the
|
|
14
14
|
* mark is drawn: a line of KEYLINE_LINE at KEYLINE_GAP, the mark's own
|
|
15
|
-
* proportions. It is drawn at full detail only (see
|
|
15
|
+
* proportions. It is drawn at full detail only (see characterDrawing.ts).
|
|
16
16
|
* - THE VISOR. One band with two upright slits, each slit's size and place
|
|
17
17
|
* measured from the band itself (EYE), so every face matches the mark's at
|
|
18
18
|
* whatever body it sits on.
|
|
@@ -22,14 +22,19 @@ import { SVGProps } from 'react';
|
|
|
22
22
|
* THIS FILE IS THE GEOMETRY'S ONE SOURCE. Nothing regenerates it, so an edit
|
|
23
23
|
* here is the edit. Every outline is a polygon on a stage 100 units wide whose
|
|
24
24
|
* ground is at GROUND, written clockwise with the chamfer each corner takes;
|
|
25
|
-
* the
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* the polygons are computed when the module loads, and everything measured
|
|
26
|
+
* off them (the union, the keyline, the box) the first time it is asked for.
|
|
27
|
+
* The original Crewlet is the exception: it IS the mark, so it is drawn from
|
|
28
|
+
* the mark's own paths (generated from svg/crewlet-icon.svg at build) placed
|
|
29
|
+
* on the same stage.
|
|
28
30
|
*
|
|
29
|
-
* Every outline of one character is drawn as ONE union: the
|
|
30
|
-
*
|
|
31
|
-
* goes round the whole figure rather than round each part.
|
|
31
|
+
* Every outline of one character is drawn as ONE union (see region.ts): the
|
|
32
|
+
* parts overlap, so a leg under a body fills as part of it, and the keyline
|
|
33
|
+
* goes round the whole figure rather than round each part. The face and the
|
|
34
|
+
* holes are cut out of that union as geometry, never painted over it (see
|
|
35
|
+
* characterDrawing.ts).
|
|
32
36
|
*/
|
|
37
|
+
|
|
33
38
|
/** The characters, in the order a picker offers them. The first is the mark. */
|
|
34
39
|
declare const CREWLET_CHARACTERS: readonly ["crewlet", "hexlet", "peaklet", "prismlet", "towerlet", "bricklet", "gemlet", "coglet", "pluslet", "shieldlet", "stacklet", "sparklet", "cloudlet", "foxlet", "rocketlet", "crownlet", "cactlet", "wisplet", "heartlet", "flasklet", "chiplet", "duolet", "chatlet", "pagelet", "archlet", "dashlet", "octlet", "conelet", "hivelet", "folderlet"];
|
|
35
40
|
/** One character's id, which is what a configuration stores. */
|
|
@@ -48,7 +53,7 @@ interface Described {
|
|
|
48
53
|
readonly name: string;
|
|
49
54
|
/** What its outline is, in a few words, for a description: `Hexagon with pointed flanks`. */
|
|
50
55
|
readonly shape: string;
|
|
51
|
-
/** Everything it draws, keyline included, which is what
|
|
56
|
+
/** Everything it draws, keyline included, which is what its frame has to hold. */
|
|
52
57
|
readonly bounds: CharacterBox;
|
|
53
58
|
}
|
|
54
59
|
/** A character drawn from polygons on the stage. */
|
|
@@ -80,10 +85,10 @@ declare const CREWLET_CHARACTER_GEOMETRY: Readonly<Record<CrewletCharacterId, Cr
|
|
|
80
85
|
* How much of a character is drawn.
|
|
81
86
|
*
|
|
82
87
|
* `full` is the mark's own drawing: the keyline floating off the body, and the
|
|
83
|
-
* gap round the visor. `compact` leaves both out
|
|
84
|
-
* for a character drawn too small for a
|
|
85
|
-
* 56px): at that size the keyline turns
|
|
86
|
-
* than a line.
|
|
88
|
+
* gap round the visor. `compact` leaves both out, with every other cut as fine
|
|
89
|
+
* as them, and opens the eyes a little, for a character drawn too small for a
|
|
90
|
+
* hairline gap to read (an avatar under 56px): at that size the keyline turns
|
|
91
|
+
* into a blur round the body rather than a line.
|
|
87
92
|
*/
|
|
88
93
|
type CrewletCharacterDetail = 'full' | 'compact';
|
|
89
94
|
interface CrewletCharacterProps extends Omit<SVGProps<SVGSVGElement>, 'children' | 'viewBox'> {
|
|
@@ -95,6 +100,12 @@ interface CrewletCharacterProps extends Omit<SVGProps<SVGSVGElement>, 'children'
|
|
|
95
100
|
/**
|
|
96
101
|
* One Crewlet character, in the current text colour, centred in a square.
|
|
97
102
|
*
|
|
103
|
+
* It is framed on its optical centre and its face and holes are cut through
|
|
104
|
+
* it (see `characterDrawing.ts`), so it sits in the middle of whatever box a
|
|
105
|
+
* consumer puts it in and shows that box's ground through every cut. It
|
|
106
|
+
* carries no mask and no id, so nothing a host stylesheet paints reaches a
|
|
107
|
+
* hole and any number of copies can share a page.
|
|
108
|
+
*
|
|
98
109
|
* It is a picture and says nothing on its own: it is hidden from assistive
|
|
99
110
|
* technology, and whatever draws it beside a name (an avatar, a picker's
|
|
100
111
|
* option) carries that name. Colour it with CSS `color` on it or any ancestor.
|
package/dist/characters.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { CREWLET_CHARACTERS, CREWLET_CHARACTER_GEOMETRY, CrewletCharacter_default as CrewletCharacter, isCrewletCharacter } from './chunk-
|
|
1
|
+
export { CREWLET_CHARACTERS, CREWLET_CHARACTER_GEOMETRY, CrewletCharacter_default as CrewletCharacter, isCrewletCharacter } from './chunk-X7FKGFKM.js';
|
|
@@ -1,14 +1,264 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
-
|
|
4
|
-
// src/CrewletCharacter.tsx
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
5
2
|
|
|
6
3
|
// src/generated/crewletMark.ts
|
|
7
4
|
var CREWLET_MARK = {
|
|
8
5
|
paths: ["M543.42 868.92 l-34.44 -0.24 0 -58.77 0 -58.77 -28.92 0 -28.80 0 -40.20 -39.61 c-119.78 -118.25 -181.49 -179.97 -204.30 -204.30 -15.87 -16.93 -82.75 -96.74 -92.51 -110.38 l-3.76 -5.17 26.80 -18.46 c14.69 -10.11 34.09 -23.51 43.14 -29.86 55.25 -38.32 70.29 -48.43 71.12 -47.49 0.47 0.47 11.64 13.87 24.69 29.74 13.17 15.87 27.98 33.62 32.80 39.50 4.94 5.88 21.63 26.10 37.15 44.90 15.52 18.81 28.56 34.21 29.15 34.21 0.47 0.12 0.82 -30.44 0.82 -67.83 l0 -68.06 37.26 -34.56 c43.38 -40.20 61.83 -57.13 75.11 -69 l9.52 -8.46 261.78 0 261.90 0 47.14 45.73 c25.98 25.16 52.43 51.02 58.66 57.36 l11.52 11.52 0.24 67.94 0.35 67.83 31.74 -40.79 c17.51 -22.33 34.91 -45.02 38.91 -50.19 15.16 -20.34 44.32 -57.72 45.14 -58.07 0.71 -0.24 104.97 75.82 126.83 92.51 2.23 1.65 4.58 3.41 5.17 3.76 1.65 1.18 -7.99 14.22 -46.08 62.07 -35.38 44.32 -49.84 61.13 -92.39 106.97 -19.28 20.81 -38.91 41.73 -148.70 157.40 l-34.68 36.56 -26.45 0.12 c-19.04 0 -26.92 0.35 -27.98 1.41 -1.06 1.06 -1.41 15.05 -1.41 55.72 l0 54.31 -34.91 0.47 c-19.28 0.24 -53.72 0.24 -76.41 0 l-41.49 -0.47 0 -55.72 0 -55.72 -99.33 0 -99.33 0 -0.24 56.19 -0.35 56.07 -39.97 0 c-21.98 0 -55.48 -0.12 -74.29 -0.35z m94.74 -13.87 l7.17 -0.82 0 -54.89 c0 -49.02 0.24 -55.13 1.88 -55.72 1.06 -0.35 51.84 -0.71 112.85 -0.71 l110.97 0 0 55.84 0 55.84 62.89 0 62.89 0 0 -55.84 0 -55.84 31.50 0 31.50 0 14.69 -14.93 c30.80 -31.50 113.20 -118.49 144.47 -152.58 48.66 -53.01 81.34 -90.28 104.85 -119.43 22.80 -28.45 44.43 -56.42 44.43 -57.48 0 -0.59 -2 -2.47 -4.35 -4.23 -2.47 -1.76 -7.05 -5.17 -10.34 -7.64 -3.17 -2.35 -16.93 -12.34 -30.56 -22.22 -13.52 -9.87 -33.50 -24.57 -44.43 -32.68 -16.34 -12.11 -19.98 -14.34 -21.39 -13.17 -0.94 0.82 -5.88 6.82 -10.81 13.40 -4.94 6.47 -13.99 18.46 -20.10 26.57 -6.23 8.11 -26.57 34.44 -45.37 58.54 -18.81 24.10 -36.56 47.02 -39.50 50.78 -5.29 7.05 -5.29 7.05 -11.40 7.05 l-6.23 0 0 -79.58 0 -79.58 -37.85 -37.03 c-20.92 -20.45 -45.14 -44.08 -53.95 -52.66 l-15.99 -15.63 -256.84 0 -256.73 0 -47.49 44.20 c-26.21 24.33 -51.13 47.49 -55.60 51.37 l-7.88 7.05 0 79.11 0 79.23 -6.35 0 -6.35 0 -48.66 -58.54 c-26.80 -32.09 -55.95 -67.24 -64.89 -78.17 -8.93 -10.81 -16.69 -19.63 -17.16 -19.63 -0.94 0 -8.58 5.17 -34.32 22.92 -34.21 23.74 -46.08 31.86 -62.65 43.26 -10.34 7.05 -19.28 13.28 -19.87 13.87 -0.59 0.47 2.35 5.05 6.47 10.11 13.87 16.93 53.13 63.12 66.77 78.40 21.86 24.57 83.81 87.69 145.41 148.23 31.62 31.03 68.65 67.36 82.28 80.76 l24.69 24.45 33.50 0.24 33.38 0.35 0.35 59.13 0.24 59.01 53.37 0 c29.27 0 56.54 -0.35 60.54 -0.71z", "M535.78 783.81 l-0.35 -59.13 -36.67 0 -36.67 0 -6.82 -6.47 c-48.78 -46.43 -176.91 -173.03 -210.41 -207.82 -24.69 -25.74 -75.70 -81.70 -93.69 -102.85 -3.29 -3.88 -5.29 -7.17 -4.70 -7.76 1.29 -1.06 58.30 -40.32 82.05 -56.42 l16.34 -11.05 3.64 4.47 c11.05 13.87 76.99 92.51 98.98 118.14 l25.74 29.97 15.63 0.35 15.52 0.35 0 -82.87 0 -82.75 50.55 -46.67 c27.86 -25.74 50.55 -47.14 50.55 -47.72 0 -0.59 46.78 -1.06 111.55 -1.06 l111.55 0 15.52 14.81 c15.28 14.58 15.52 14.69 17.98 12.58 1.29 -1.18 8.46 -7.76 15.75 -14.58 l13.40 -12.46 17.75 -0.71 c9.76 -0.47 58.77 -0.82 108.85 -0.82 l90.98 0 14.34 13.75 c7.76 7.64 24.57 23.86 37.15 36.20 12.58 12.34 29.15 28.45 36.67 35.85 l13.87 13.40 0.24 82.87 0.35 82.99 14.22 0.35 14.34 0.35 4.47 -5.64 c2.47 -3.06 11.52 -14.11 19.98 -24.45 8.46 -10.34 30.56 -38.32 49.14 -62.30 43.85 -56.42 46.20 -59.36 48.43 -59.36 2.12 0 4.82 1.88 47.96 33.27 43.02 31.27 45.37 33.03 45.37 34.09 0 0.82 -39.03 46.20 -62.42 72.53 -62.42 70.29 -106.50 117.67 -184.08 197.60 l-50.78 52.43 -13.28 0.71 c-7.29 0.47 -23.98 0.82 -37.03 0.82 l-23.86 0 0 57.01 0 57.01 -49.37 0 -49.37 0 0 -56.42 0 -56.42 -114.37 0 c-63.01 0 -120.13 0.35 -126.95 0.82 l-12.58 0.71 0 55.72 0 55.60 -47.61 0 -47.61 0 -0.24 -59.01z m443.16 -373.22 l-0.35 -119.66 -223.93 0.12 -223.93 0.12 -0.35 119.43 -0.24 119.55 224.52 0 224.52 0 -0.24 -119.55z", "M546.36 516.39 c-0.24 -0.59 -0.47 -4.94 -0.35 -9.76 0 -4.82 0.12 -52.54 0.35 -106.15 l0.24 -97.21 209.59 0.24 209.47 0.35 0.35 106.73 0.24 106.62 -209.71 0 c-115.43 0 -209.94 -0.35 -210.18 -0.82z m121.07 -100.50 l-0.35 -66.18 -34.32 -0.35 -34.44 -0.24 0 66.41 0 66.41 34.68 0 34.68 0 -0.24 -66.06z m260.96 0 l-0.35 -66.18 -34.09 0 -34.09 0 0 10.93 c0 5.88 0.12 35.62 0.35 66.06 l0.24 55.25 34.09 0 34.09 0 -0.24 -66.06z"],
|
|
9
|
-
box: { left: 110.48999999999992, top: 196.30999999999992, right: 1389.0800000000002, bottom: 869.2899999999998 }
|
|
6
|
+
box: { left: 110.48999999999992, top: 196.30999999999992, right: 1389.0800000000002, bottom: 869.2899999999998 },
|
|
7
|
+
centroid: { x: 755.6746766446299, y: 497.3295661269271 }
|
|
10
8
|
};
|
|
11
9
|
|
|
10
|
+
// src/region.ts
|
|
11
|
+
var twiceArea = (ring) => ring.reduce((sum, p, i) => {
|
|
12
|
+
const q = ring[(i + 1) % ring.length];
|
|
13
|
+
return sum + p[0] * q[1] - q[0] * p[1];
|
|
14
|
+
}, 0);
|
|
15
|
+
function collect(rings, add, into) {
|
|
16
|
+
for (const ring of rings) {
|
|
17
|
+
ring.forEach((p, i) => {
|
|
18
|
+
const q = ring[(i + 1) % ring.length];
|
|
19
|
+
if (p[1] === q[1]) return;
|
|
20
|
+
into.push(
|
|
21
|
+
p[1] < q[1] ? { x0: p[0], y0: p[1], x1: q[0], y1: q[1], wind: 1, add } : { x0: q[0], y0: q[1], x1: p[0], y1: p[1], wind: -1, add }
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
var xAt = (e, y) => y === e.y0 ? e.x0 : y === e.y1 ? e.x1 : e.x0 + (y - e.y0) * (e.x1 - e.x0) / (e.y1 - e.y0);
|
|
27
|
+
function heights(edges) {
|
|
28
|
+
const ys = /* @__PURE__ */ new Set();
|
|
29
|
+
for (const e of edges) {
|
|
30
|
+
ys.add(e.y0);
|
|
31
|
+
ys.add(e.y1);
|
|
32
|
+
}
|
|
33
|
+
for (let i = 0; i < edges.length; i += 1) {
|
|
34
|
+
const a = edges[i];
|
|
35
|
+
for (let j = i + 1; j < edges.length && edges[j].y0 < a.y1; j += 1) {
|
|
36
|
+
const b = edges[j];
|
|
37
|
+
const top = Math.max(a.y0, b.y0);
|
|
38
|
+
const bottom = Math.min(a.y1, b.y1);
|
|
39
|
+
if (bottom <= top) continue;
|
|
40
|
+
const above = xAt(a, top) - xAt(b, top);
|
|
41
|
+
const below = xAt(a, bottom) - xAt(b, bottom);
|
|
42
|
+
if (above * below < 0) ys.add(top + (bottom - top) * above / (above - below));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return [...ys].sort((p, q) => p - q);
|
|
46
|
+
}
|
|
47
|
+
var SNAP = 1e-9;
|
|
48
|
+
function snapper() {
|
|
49
|
+
const seen = /* @__PURE__ */ new Map();
|
|
50
|
+
return (y, x) => {
|
|
51
|
+
let xs = seen.get(y);
|
|
52
|
+
if (!xs) seen.set(y, xs = []);
|
|
53
|
+
for (const known of xs) if (Math.abs(known - x) <= SNAP) return known;
|
|
54
|
+
xs.push(x);
|
|
55
|
+
return x;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function spansOf(active, top, bottom, snap) {
|
|
59
|
+
const at = active.map((e) => ({ e, a: snap(top, xAt(e, top)), b: snap(bottom, xAt(e, bottom)) })).sort((p, q) => p.a + p.b - (q.a + q.b));
|
|
60
|
+
const spans = [];
|
|
61
|
+
let added = 0;
|
|
62
|
+
let removed = 0;
|
|
63
|
+
let inside = false;
|
|
64
|
+
let from = [0, 0];
|
|
65
|
+
for (let i = 0; i < at.length; ) {
|
|
66
|
+
const { a, b } = at[i];
|
|
67
|
+
for (; i < at.length && at[i].a === a && at[i].b === b; i += 1) {
|
|
68
|
+
const { e } = at[i];
|
|
69
|
+
if (e.add) added += e.wind;
|
|
70
|
+
else removed += e.wind;
|
|
71
|
+
}
|
|
72
|
+
const now = added !== 0 && removed === 0;
|
|
73
|
+
if (now && !inside) from = [a, b];
|
|
74
|
+
else if (!now && inside) spans.push({ left: from, right: [a, b] });
|
|
75
|
+
inside = now;
|
|
76
|
+
}
|
|
77
|
+
return spans;
|
|
78
|
+
}
|
|
79
|
+
function minus(a, b) {
|
|
80
|
+
const out = [];
|
|
81
|
+
let j = 0;
|
|
82
|
+
for (const [start, end] of a) {
|
|
83
|
+
let from = start;
|
|
84
|
+
while (j < b.length && b[j][1] <= from) j += 1;
|
|
85
|
+
for (let k = j; k < b.length && b[k][0] < end && from < end; k += 1) {
|
|
86
|
+
const [bStart, bEnd] = b[k];
|
|
87
|
+
if (bStart > from) out.push([from, bStart]);
|
|
88
|
+
from = Math.max(from, bEnd);
|
|
89
|
+
}
|
|
90
|
+
if (from < end) out.push([from, end]);
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
function boundaryOf(ys, slabs) {
|
|
95
|
+
const out = [];
|
|
96
|
+
slabs.forEach((spans, k) => {
|
|
97
|
+
const top = ys[k];
|
|
98
|
+
const bottom = ys[k + 1];
|
|
99
|
+
for (const { left, right } of spans) {
|
|
100
|
+
out.push([
|
|
101
|
+
[right[0], top],
|
|
102
|
+
[right[1], bottom]
|
|
103
|
+
]);
|
|
104
|
+
out.push([
|
|
105
|
+
[left[1], bottom],
|
|
106
|
+
[left[0], top]
|
|
107
|
+
]);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
ys.forEach((y, k) => {
|
|
111
|
+
const above = k > 0 ? slabs[k - 1].map(({ left, right }) => [left[1], right[1]]) : [];
|
|
112
|
+
const below = k < slabs.length ? slabs[k].map(({ left, right }) => [left[0], right[0]]) : [];
|
|
113
|
+
for (const [a, b] of minus(below, above)) {
|
|
114
|
+
out.push([
|
|
115
|
+
[a, y],
|
|
116
|
+
[b, y]
|
|
117
|
+
]);
|
|
118
|
+
}
|
|
119
|
+
for (const [a, b] of minus(above, below)) {
|
|
120
|
+
out.push([
|
|
121
|
+
[b, y],
|
|
122
|
+
[a, y]
|
|
123
|
+
]);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
return out.filter(([a, b]) => a[0] !== b[0] || a[1] !== b[1]);
|
|
127
|
+
}
|
|
128
|
+
var EPSILON = 1e-9;
|
|
129
|
+
function simplify(ring) {
|
|
130
|
+
let points = [...ring];
|
|
131
|
+
let changed = true;
|
|
132
|
+
while (changed && points.length >= 3) {
|
|
133
|
+
changed = false;
|
|
134
|
+
const kept = [];
|
|
135
|
+
for (let i = 0; i < points.length; i += 1) {
|
|
136
|
+
const prev = kept.length > 0 ? kept[kept.length - 1] : points[points.length - 1];
|
|
137
|
+
const p = points[i];
|
|
138
|
+
const next = points[(i + 1) % points.length];
|
|
139
|
+
const ux = p[0] - prev[0];
|
|
140
|
+
const uy = p[1] - prev[1];
|
|
141
|
+
const vx = next[0] - p[0];
|
|
142
|
+
const vy = next[1] - p[1];
|
|
143
|
+
const short = Math.hypot(ux, uy) < EPSILON;
|
|
144
|
+
const straight = Math.abs(ux * vy - uy * vx) < EPSILON;
|
|
145
|
+
if (short || straight) {
|
|
146
|
+
changed = true;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
kept.push(p);
|
|
150
|
+
}
|
|
151
|
+
points = kept;
|
|
152
|
+
}
|
|
153
|
+
return points;
|
|
154
|
+
}
|
|
155
|
+
function chain(segments) {
|
|
156
|
+
const key = (p) => `${p[0]} ${p[1]}`;
|
|
157
|
+
const from = /* @__PURE__ */ new Map();
|
|
158
|
+
segments.forEach(([a], i) => {
|
|
159
|
+
const list = from.get(key(a));
|
|
160
|
+
if (list) list.push(i);
|
|
161
|
+
else from.set(key(a), [i]);
|
|
162
|
+
});
|
|
163
|
+
const used = new Uint8Array(segments.length);
|
|
164
|
+
const rings = [];
|
|
165
|
+
segments.forEach((first, i) => {
|
|
166
|
+
if (used[i]) return;
|
|
167
|
+
const ring = [];
|
|
168
|
+
let at = i;
|
|
169
|
+
while (at !== void 0) {
|
|
170
|
+
used[at] = 1;
|
|
171
|
+
const [a, b] = segments[at];
|
|
172
|
+
ring.push(a);
|
|
173
|
+
if (b[0] === first[0][0] && b[1] === first[0][1]) break;
|
|
174
|
+
at = from.get(key(b))?.find((n) => !used[n]);
|
|
175
|
+
}
|
|
176
|
+
rings.push(ring);
|
|
177
|
+
});
|
|
178
|
+
return rings.map(simplify).filter((ring) => ring.length >= 3 && Math.abs(twiceArea(ring)) > EPSILON);
|
|
179
|
+
}
|
|
180
|
+
function region(add, remove = []) {
|
|
181
|
+
const edges = [];
|
|
182
|
+
collect(add, true, edges);
|
|
183
|
+
collect(remove, false, edges);
|
|
184
|
+
edges.sort((p, q) => p.y0 - q.y0);
|
|
185
|
+
const ys = heights(edges);
|
|
186
|
+
const snap = snapper();
|
|
187
|
+
const slabs = [];
|
|
188
|
+
let next = 0;
|
|
189
|
+
let active = [];
|
|
190
|
+
for (let k = 0; k + 1 < ys.length; k += 1) {
|
|
191
|
+
const top = ys[k];
|
|
192
|
+
const bottom = ys[k + 1];
|
|
193
|
+
while (next < edges.length && edges[next].y0 <= top) active.push(edges[next++]);
|
|
194
|
+
active = active.filter((e) => e.y1 > top);
|
|
195
|
+
slabs.push(spansOf(active, top, bottom, snap));
|
|
196
|
+
}
|
|
197
|
+
return chain(boundaryOf(ys, slabs));
|
|
198
|
+
}
|
|
199
|
+
var areaOf = (rings) => rings.reduce((sum, ring) => sum + twiceArea(ring), 0) / 2;
|
|
200
|
+
function centroidOf(rings) {
|
|
201
|
+
let x = 0;
|
|
202
|
+
let y = 0;
|
|
203
|
+
for (const ring of rings) {
|
|
204
|
+
ring.forEach((p, i) => {
|
|
205
|
+
const q = ring[(i + 1) % ring.length];
|
|
206
|
+
const cross = p[0] * q[1] - q[0] * p[1];
|
|
207
|
+
x += (p[0] + q[0]) * cross;
|
|
208
|
+
y += (p[1] + q[1]) * cross;
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
const six = 6 * areaOf(rings);
|
|
212
|
+
return [x / six, y / six];
|
|
213
|
+
}
|
|
214
|
+
var clockwise = (ring) => twiceArea(ring) < 0 ? ring.reverse() : ring;
|
|
215
|
+
function strokeBand(rings, distance, miterLimit = 4) {
|
|
216
|
+
const pieces = [];
|
|
217
|
+
for (const ring of rings) {
|
|
218
|
+
ring.forEach((p, i) => {
|
|
219
|
+
const q = ring[(i + 1) % ring.length];
|
|
220
|
+
const r = ring[(i + 2) % ring.length];
|
|
221
|
+
const length = Math.hypot(q[0] - p[0], q[1] - p[1]);
|
|
222
|
+
const nx = (q[1] - p[1]) / length;
|
|
223
|
+
const ny = -(q[0] - p[0]) / length;
|
|
224
|
+
const onward = Math.hypot(r[0] - q[0], r[1] - q[1]);
|
|
225
|
+
const mx = (r[1] - q[1]) / onward;
|
|
226
|
+
const my = -(r[0] - q[0]) / onward;
|
|
227
|
+
const d = distance;
|
|
228
|
+
pieces.push(
|
|
229
|
+
clockwise([
|
|
230
|
+
[p[0] + nx * d, p[1] + ny * d],
|
|
231
|
+
[q[0] + nx * d, q[1] + ny * d],
|
|
232
|
+
[q[0] - nx * d, q[1] - ny * d],
|
|
233
|
+
[p[0] - nx * d, p[1] - ny * d]
|
|
234
|
+
])
|
|
235
|
+
);
|
|
236
|
+
const turn = (q[0] - p[0]) * (r[1] - q[1]) - (q[1] - p[1]) * (r[0] - q[0]);
|
|
237
|
+
if (turn === 0) return;
|
|
238
|
+
const side = turn > 0 ? 1 : -1;
|
|
239
|
+
const a = [q[0] + side * nx * d, q[1] + side * ny * d];
|
|
240
|
+
const b = [q[0] + side * mx * d, q[1] + side * my * d];
|
|
241
|
+
const sx = nx + mx;
|
|
242
|
+
const sy = ny + my;
|
|
243
|
+
const reach = sx * sx + sy * sy;
|
|
244
|
+
if (reach > 0 && 2 / Math.sqrt(reach) <= miterLimit) {
|
|
245
|
+
const tip = [q[0] + side * sx * 2 * d / reach, q[1] + side * sy * 2 * d / reach];
|
|
246
|
+
pieces.push(clockwise([q, a, tip, b]));
|
|
247
|
+
} else {
|
|
248
|
+
pieces.push(clockwise([q, a, b]));
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
return pieces;
|
|
253
|
+
}
|
|
254
|
+
var round = (n) => Math.round(n * 100) / 100;
|
|
255
|
+
function pathOfRings(rings) {
|
|
256
|
+
return rings.map((ring) => {
|
|
257
|
+
const points = ring.map(([x, y]) => `${round(x)} ${round(y)}`).filter((p, i, all) => p !== all[i - 1]);
|
|
258
|
+
return `M${points.join("L")}Z`;
|
|
259
|
+
}).join("");
|
|
260
|
+
}
|
|
261
|
+
|
|
12
262
|
// src/crewletCharacters.ts
|
|
13
263
|
var CREWLET_CHARACTERS = [
|
|
14
264
|
"crewlet",
|
|
@@ -47,13 +297,14 @@ var GROUND = 96;
|
|
|
47
297
|
var KEYLINE_LINE = 1.35;
|
|
48
298
|
var KEYLINE_GAP = 0.9;
|
|
49
299
|
var VISOR_GAP = 1.3;
|
|
300
|
+
var HAIRLINE = 2;
|
|
50
301
|
var EYE = {
|
|
51
302
|
full: { width: 0.164, height: 0.62 },
|
|
52
303
|
compact: { width: 0.19, height: 0.68 },
|
|
53
304
|
offset: 0.312
|
|
54
305
|
};
|
|
55
306
|
var NOTCH = { half: 3.2, depth: 2.6 };
|
|
56
|
-
var
|
|
307
|
+
var round2 = (n) => Math.round(n * 100) / 100;
|
|
57
308
|
function cut(points, chamfer) {
|
|
58
309
|
const out = [];
|
|
59
310
|
points.forEach((vertex, i) => {
|
|
@@ -72,14 +323,10 @@ function cut(points, chamfer) {
|
|
|
72
323
|
});
|
|
73
324
|
return out;
|
|
74
325
|
}
|
|
75
|
-
var pathOf = (points) => `M${points.map(([x, y]) => `${
|
|
76
|
-
var area = (points) => points.reduce((sum, p, i) => {
|
|
77
|
-
const q = points[(i + 1) % points.length];
|
|
78
|
-
return sum + p[0] * q[1] - q[0] * p[1];
|
|
79
|
-
}, 0);
|
|
326
|
+
var pathOf = (points) => `M${points.map(([x, y]) => `${round2(x)} ${round2(y)}`).join("L")}Z`;
|
|
80
327
|
function poly(points, chamfer = 0) {
|
|
81
328
|
const chamfers = typeof chamfer === "number" ? points.map(() => chamfer) : chamfer;
|
|
82
|
-
return
|
|
329
|
+
return twiceArea(points) < 0 ? cut([...points].reverse(), [...chamfers].reverse()) : cut(points, chamfers);
|
|
83
330
|
}
|
|
84
331
|
var rect = (x, y, width, height, chamfer = 0) => poly(
|
|
85
332
|
[
|
|
@@ -110,45 +357,56 @@ function gear(cx, cy, outer, inner, teeth) {
|
|
|
110
357
|
}
|
|
111
358
|
return poly(points);
|
|
112
359
|
}
|
|
113
|
-
function boxOf(
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
left = Math.min(left, numbers[i]);
|
|
121
|
-
right = Math.max(right, numbers[i]);
|
|
122
|
-
top = Math.min(top, numbers[i + 1]);
|
|
123
|
-
bottom = Math.max(bottom, numbers[i + 1]);
|
|
124
|
-
}
|
|
125
|
-
return { x: left - grow, y: top - grow, width: right - left + 2 * grow, height: bottom - top + 2 * grow };
|
|
360
|
+
function boxOf(rings) {
|
|
361
|
+
const points = rings.flat();
|
|
362
|
+
const xs = points.map(([x]) => x);
|
|
363
|
+
const ys = points.map(([, y]) => y);
|
|
364
|
+
const left = Math.min(...xs);
|
|
365
|
+
const top = Math.min(...ys);
|
|
366
|
+
return { x: left, y: top, width: Math.max(...xs) - left, height: Math.max(...ys) - top };
|
|
126
367
|
}
|
|
127
368
|
var box = ([x, y, width, height]) => ({ x, y, width, height });
|
|
369
|
+
var RINGS = /* @__PURE__ */ new WeakMap();
|
|
128
370
|
function drawn(spec) {
|
|
129
|
-
|
|
371
|
+
const holes = spec.holes ?? [];
|
|
372
|
+
let bounds;
|
|
373
|
+
const geometry = {
|
|
130
374
|
kind: "drawn",
|
|
131
375
|
name: spec.name,
|
|
132
376
|
shape: spec.shape,
|
|
133
|
-
shapes: spec.shapes,
|
|
134
|
-
holes:
|
|
377
|
+
shapes: spec.shapes.map(pathOf),
|
|
378
|
+
holes: holes.map(pathOf),
|
|
135
379
|
visor: box(spec.visor),
|
|
136
380
|
notch: spec.notch === void 0 ? null : [spec.notchX ?? 50, spec.notch],
|
|
137
|
-
//
|
|
138
|
-
bounds
|
|
381
|
+
// It takes the union, so it is measured the first time it is asked for.
|
|
382
|
+
get bounds() {
|
|
383
|
+
return bounds ??= boxOf([...silhouetteOf(geometry), ...keylineReachOf(geometry)]);
|
|
384
|
+
}
|
|
139
385
|
};
|
|
386
|
+
RINGS.set(geometry, { parts: spec.shapes, holes });
|
|
387
|
+
return geometry;
|
|
388
|
+
}
|
|
389
|
+
var ringsOf = (geometry) => RINGS.get(geometry);
|
|
390
|
+
function silhouetteOf(geometry) {
|
|
391
|
+
const rings = ringsOf(geometry);
|
|
392
|
+
return rings.silhouette ??= region(rings.parts);
|
|
393
|
+
}
|
|
394
|
+
function keylineReachOf(geometry) {
|
|
395
|
+
const rings = ringsOf(geometry);
|
|
396
|
+
return rings.reach ??= strokeBand(silhouetteOf(geometry), KEYLINE_GAP + KEYLINE_LINE);
|
|
140
397
|
}
|
|
141
398
|
var MARK_SCALE = 0.095;
|
|
142
399
|
var MARK_CENTRE = 760;
|
|
143
400
|
var MARK_FEET = 869;
|
|
401
|
+
var markOnStage = (x, y) => [
|
|
402
|
+
50 + (x - MARK_CENTRE) * MARK_SCALE,
|
|
403
|
+
GROUND + (y - MARK_FEET) * MARK_SCALE
|
|
404
|
+
];
|
|
405
|
+
var MARK_CENTROID = markOnStage(CREWLET_MARK.centroid.x, CREWLET_MARK.centroid.y);
|
|
144
406
|
function mark() {
|
|
145
407
|
const { paths, box: own } = CREWLET_MARK;
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
GROUND + (y - MARK_FEET) * MARK_SCALE
|
|
149
|
-
];
|
|
150
|
-
const [left, top] = onStage(own.left, own.top);
|
|
151
|
-
const [right, bottom] = onStage(own.right, own.bottom);
|
|
408
|
+
const [left, top] = markOnStage(own.left, own.top);
|
|
409
|
+
const [right, bottom] = markOnStage(own.right, own.bottom);
|
|
152
410
|
return {
|
|
153
411
|
kind: "mark",
|
|
154
412
|
name: "Crewlet",
|
|
@@ -659,89 +917,103 @@ var CREWLET_CHARACTER_GEOMETRY = {
|
|
|
659
917
|
visor: [24, 40, 52, 22]
|
|
660
918
|
})
|
|
661
919
|
};
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
920
|
+
|
|
921
|
+
// src/characterDrawing.ts
|
|
922
|
+
var OPTICAL_PULL = 0.5;
|
|
923
|
+
var rect2 = (x, y, width, height) => [
|
|
924
|
+
[x, y],
|
|
925
|
+
[x + width, y],
|
|
926
|
+
[x + width, y + height],
|
|
927
|
+
[x, y + height]
|
|
928
|
+
];
|
|
929
|
+
function widthOf(ring) {
|
|
930
|
+
let least = Infinity;
|
|
931
|
+
ring.forEach((p, i) => {
|
|
932
|
+
const q = ring[(i + 1) % ring.length];
|
|
933
|
+
const length = Math.hypot(q[0] - p[0], q[1] - p[1]);
|
|
934
|
+
if (length === 0) return;
|
|
935
|
+
const depth = Math.max(
|
|
936
|
+
...ring.map((r) => Math.abs((q[0] - p[0]) * (r[1] - p[1]) - (q[1] - p[1]) * (r[0] - p[0])) / length)
|
|
937
|
+
);
|
|
938
|
+
least = Math.min(least, depth);
|
|
939
|
+
});
|
|
940
|
+
return least;
|
|
666
941
|
}
|
|
667
|
-
function
|
|
668
|
-
const {
|
|
942
|
+
function cutsOf(geometry, detail) {
|
|
943
|
+
const { visor, notch } = geometry;
|
|
669
944
|
const full = detail === "full";
|
|
670
|
-
const d = shapes.join("");
|
|
671
945
|
const eye = full ? EYE.full : EYE.compact;
|
|
672
946
|
const eyeWidth = visor.width * eye.width;
|
|
673
947
|
const eyeHeight = visor.height * eye.height;
|
|
674
948
|
const eyeTop = visor.y + (visor.height - eyeHeight) / 2;
|
|
675
949
|
const middle = visor.x + visor.width / 2;
|
|
676
950
|
const offset = visor.width * EYE.offset;
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
}
|
|
733
|
-
),
|
|
734
|
-
/* @__PURE__ */ jsx("path", { d, mask: `url(#${face})`, fill: "currentColor" })
|
|
735
|
-
] });
|
|
951
|
+
const cuts = [middle - offset, middle + offset].map(
|
|
952
|
+
(centre) => rect2(centre - eyeWidth / 2, eyeTop, eyeWidth, eyeHeight)
|
|
953
|
+
);
|
|
954
|
+
if (notch) {
|
|
955
|
+
cuts.push([
|
|
956
|
+
[notch[0] - NOTCH.half, notch[1] - 1],
|
|
957
|
+
[notch[0] + NOTCH.half, notch[1] - 1],
|
|
958
|
+
[notch[0], notch[1] + NOTCH.depth]
|
|
959
|
+
]);
|
|
960
|
+
}
|
|
961
|
+
for (const hole of ringsOf(geometry).holes) if (full || widthOf(hole) > HAIRLINE) cuts.push(hole);
|
|
962
|
+
if (full) {
|
|
963
|
+
const half = VISOR_GAP / 2;
|
|
964
|
+
cuts.push(rect2(visor.x - half, visor.y - half, visor.width + VISOR_GAP, visor.height + VISOR_GAP));
|
|
965
|
+
cuts.push([...rect2(visor.x + half, visor.y + half, visor.width - VISOR_GAP, visor.height - VISOR_GAP)].reverse());
|
|
966
|
+
}
|
|
967
|
+
return cuts;
|
|
968
|
+
}
|
|
969
|
+
function frameOf(bounds, centroid) {
|
|
970
|
+
const boxX = bounds.x + bounds.width / 2;
|
|
971
|
+
const boxY = bounds.y + bounds.height / 2;
|
|
972
|
+
const x = boxX + OPTICAL_PULL * (centroid[0] - boxX);
|
|
973
|
+
const y = boxY + OPTICAL_PULL * (centroid[1] - boxY);
|
|
974
|
+
const side = Math.max(bounds.width + 2 * Math.abs(x - boxX), bounds.height + 2 * Math.abs(y - boxY));
|
|
975
|
+
return { x: x - side / 2, y: y - side / 2, width: side, height: side };
|
|
976
|
+
}
|
|
977
|
+
function drawnDrawing(geometry) {
|
|
978
|
+
const { parts } = ringsOf(geometry);
|
|
979
|
+
const silhouette = silhouetteOf(geometry);
|
|
980
|
+
const made = {};
|
|
981
|
+
const body = (detail) => pathOfRings(region(parts, cutsOf(geometry, detail)));
|
|
982
|
+
const keyline = () => pathOfRings(
|
|
983
|
+
region([...silhouette, ...keylineReachOf(geometry)], [...silhouette, ...strokeBand(silhouette, KEYLINE_GAP)])
|
|
984
|
+
);
|
|
985
|
+
return {
|
|
986
|
+
frame: frameOf(geometry.bounds, centroidOf(silhouette)),
|
|
987
|
+
paths: (detail) => made[detail] ??= detail === "full" ? [keyline(), body("full")] : [body("compact")]
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
var drawings = /* @__PURE__ */ new Map();
|
|
991
|
+
function drawingOf(character) {
|
|
992
|
+
let drawing = drawings.get(character);
|
|
993
|
+
if (drawing) return drawing;
|
|
994
|
+
const geometry = CREWLET_CHARACTER_GEOMETRY[character];
|
|
995
|
+
if (geometry.kind === "mark") {
|
|
996
|
+
const full = [geometry.keyline, ...geometry.body];
|
|
997
|
+
drawing = {
|
|
998
|
+
frame: frameOf(geometry.bounds, MARK_CENTROID),
|
|
999
|
+
paths: (detail) => detail === "full" ? full : geometry.body
|
|
1000
|
+
};
|
|
1001
|
+
} else {
|
|
1002
|
+
drawing = drawnDrawing(geometry);
|
|
1003
|
+
}
|
|
1004
|
+
drawings.set(character, drawing);
|
|
1005
|
+
return drawing;
|
|
736
1006
|
}
|
|
1007
|
+
var round3 = (n) => Math.round(n * 100) / 100;
|
|
737
1008
|
var CrewletCharacter = ({ character, detail = "full", ...rest }) => {
|
|
738
|
-
const id = `crewlet-character-${useId().replace(/[^A-Za-z0-9_-]/g, "")}`;
|
|
739
1009
|
const geometry = CREWLET_CHARACTER_GEOMETRY[character];
|
|
1010
|
+
const { frame, paths } = drawingOf(character);
|
|
1011
|
+
const drawn2 = paths(detail).map((d) => /* @__PURE__ */ jsx("path", { d }, d));
|
|
740
1012
|
return /* @__PURE__ */ jsx(
|
|
741
1013
|
"svg",
|
|
742
1014
|
{
|
|
743
1015
|
xmlns: "http://www.w3.org/2000/svg",
|
|
744
|
-
viewBox:
|
|
1016
|
+
viewBox: [frame.x, frame.y, frame.width, frame.height].map(round3).join(" "),
|
|
745
1017
|
width: "1em",
|
|
746
1018
|
height: "1em",
|
|
747
1019
|
"aria-hidden": "true",
|
|
@@ -749,10 +1021,7 @@ var CrewletCharacter = ({ character, detail = "full", ...rest }) => {
|
|
|
749
1021
|
"data-character": character,
|
|
750
1022
|
"data-detail": detail,
|
|
751
1023
|
...rest,
|
|
752
|
-
children:
|
|
753
|
-
detail === "full" && /* @__PURE__ */ jsx("path", { d: geometry.keyline }),
|
|
754
|
-
geometry.body.map((d) => /* @__PURE__ */ jsx("path", { d }, d))
|
|
755
|
-
] }) : /* @__PURE__ */ jsx(Drawn, { geometry, detail, id })
|
|
1024
|
+
children: /* @__PURE__ */ jsx("g", { fill: "currentColor", transform: geometry.kind === "mark" ? geometry.transform : void 0, children: drawn2 })
|
|
756
1025
|
}
|
|
757
1026
|
);
|
|
758
1027
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { CREWLET_CHARACTERS, CREWLET_CHARACTER_GEOMETRY, CrewletCharacter_default as CrewletCharacter, isCrewletCharacter } from './chunk-
|
|
1
|
+
export { CREWLET_CHARACTERS, CREWLET_CHARACTER_GEOMETRY, CrewletCharacter_default as CrewletCharacter, isCrewletCharacter } from './chunk-X7FKGFKM.js';
|
|
2
2
|
import { cssLength } from './chunk-TOSJN7HA.js';
|
|
3
3
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
4
|
import './CrewletFigure-4PMMCAFG.css';
|
package/package.json
CHANGED