@johnmorrisdotca/dougu-sports 0.9.0 → 0.11.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.
@@ -0,0 +1,88 @@
1
+ // The lettering of the maker wordmarks: our own alphabet of capitals, drawn as strokes. Each letter is a few polylines on a unit box (x across, y down, 0 to 1); a style sets the weight, how the corners are
2
+ // treated (sharp, rounded or cut), the width, the spacing, the slant and the line ends, so that each maker's wordmark has a lettering of its own from one set of skeletons. It is not a copy of any typeface.
3
+ const BOX = [[0, 0], [1, 0], [1, 1], [0, 1]];
4
+ const SKELETONS = {
5
+ A: { strokes: [[[0, 1], [0.5, 0], [1, 1]], [[0.2, 0.68], [0.8, 0.68]]], wide: 1.1 },
6
+ B: { strokes: [[[0, 0], [0, 1]], [[0, 0], [0.88, 0], [0.88, 0.5], [0, 0.5]], [[0.88, 0.5], [1, 0.5], [1, 1], [0, 1]]] },
7
+ C: { strokes: [[[1, 0], [0, 0], [0, 1], [1, 1]]] },
8
+ D: { strokes: [[[0, 0], [0.62, 0], [1, 0.34], [1, 0.66], [0.62, 1], [0, 1]]], closed: [0] },
9
+ E: { strokes: [[[1, 0], [0, 0], [0, 1], [1, 1]], [[0, 0.5], [0.8, 0.5]]] },
10
+ F: { strokes: [[[1, 0], [0, 0], [0, 1]], [[0, 0.5], [0.8, 0.5]]] },
11
+ G: { strokes: [[[1, 0.16], [1, 0], [0, 0], [0, 1], [1, 1], [1, 0.55], [0.55, 0.55]]] },
12
+ H: { strokes: [[[0, 0], [0, 1]], [[1, 0], [1, 1]], [[0, 0.5], [1, 0.5]]] },
13
+ I: { strokes: [[[0.5, 0], [0.5, 1]]], wide: 0 },
14
+ J: { strokes: [[[1, 0], [1, 0.78], [0.78, 1], [0.22, 1], [0, 0.78]]] },
15
+ K: { strokes: [[[0, 0], [0, 1]], [[1, 0], [0.08, 0.56], [1, 1]]] },
16
+ L: { strokes: [[[0, 0], [0, 1], [1, 1]]] },
17
+ M: { strokes: [[[0, 1], [0, 0], [0.5, 0.62], [1, 0], [1, 1]]], wide: 1.3 },
18
+ N: { strokes: [[[0, 1], [0, 0], [1, 1], [1, 0]]] },
19
+ O: { strokes: [BOX], closed: [0] },
20
+ P: { strokes: [[[0, 1], [0, 0], [1, 0], [1, 0.55], [0, 0.55]]] },
21
+ Q: { strokes: [BOX, [[0.6, 0.62], [1, 1]]], closed: [0] },
22
+ R: { strokes: [[[0, 1], [0, 0], [1, 0], [1, 0.5], [0, 0.5]], [[0.44, 0.5], [1, 1]]] },
23
+ S: { strokes: [[[1, 0], [0, 0], [0, 0.5], [1, 0.5], [1, 1], [0, 1]]] },
24
+ T: { strokes: [[[0, 0], [1, 0]], [[0.5, 0], [0.5, 1]]] },
25
+ U: { strokes: [[[0, 0], [0, 1], [1, 1], [1, 0]]] },
26
+ V: { strokes: [[[0, 0], [0.5, 1], [1, 0]]], wide: 1.1 },
27
+ W: { strokes: [[[0, 0], [0.25, 1], [0.5, 0.3], [0.75, 1], [1, 0]]], wide: 1.5 },
28
+ X: { strokes: [[[0, 0], [1, 1]], [[1, 0], [0, 1]]], wide: 1.05 },
29
+ Y: { strokes: [[[0, 0], [0.5, 0.5], [1, 0]], [[0.5, 0.5], [0.5, 1]]] },
30
+ Z: { strokes: [[[0, 0], [1, 0], [0, 1], [1, 1]]] },
31
+ };
32
+ /** Letters whose right side is open at the top or the bottom, and letters whose sides lean in: a pair of the two is set closer. */
33
+ const OPEN = "LTFPYRVAW";
34
+ const LEAN = "AVWYT";
35
+ /** The letters the alphabet draws. */
36
+ export const LETTERS = Object.freeze(Object.keys(SKELETONS));
37
+ const round1 = (value) => String(Math.round(value * 10) / 10 + 0);
38
+ /** One stroke as a path: corners rounded or cut by `radius`, never by more than half a side. */
39
+ function strokePath(points, closed, style) {
40
+ const n = points.length;
41
+ let d = "";
42
+ for (let i = 0; i < n; i++) {
43
+ const p = points[i];
44
+ const end = !closed && (i === 0 || i === n - 1);
45
+ if (end || style.corner === "sharp" || style.radius <= 0) {
46
+ d += `${i === 0 ? "M" : "L"}${round1(p[0])} ${round1(p[1])}`;
47
+ continue;
48
+ }
49
+ const a = points[(i + n - 1) % n];
50
+ const b = points[(i + 1) % n];
51
+ const l1 = Math.hypot(a[0] - p[0], a[1] - p[1]);
52
+ const l2 = Math.hypot(b[0] - p[0], b[1] - p[1]);
53
+ const t1 = Math.min(style.radius / l1, 0.5);
54
+ const t2 = Math.min(style.radius / l2, 0.5);
55
+ const s = [p[0] + (a[0] - p[0]) * t1, p[1] + (a[1] - p[1]) * t1];
56
+ const e = [p[0] + (b[0] - p[0]) * t2, p[1] + (b[1] - p[1]) * t2];
57
+ d += `${i === 0 ? "M" : "L"}${round1(s[0])} ${round1(s[1])}`;
58
+ d += style.corner === "round" ? `Q${round1(p[0])} ${round1(p[1])} ${round1(e[0])} ${round1(e[1])}` : `L${round1(e[0])} ${round1(e[1])}`;
59
+ }
60
+ return closed ? `${d}Z` : d;
61
+ }
62
+ /** The unit height the lettering is drawn at. */
63
+ export const LETTER_HEIGHT = 100;
64
+ /** A word in capitals, in a style. A letter the alphabet does not have is left out. The box includes the stroke's half weight and the room a lean needs. */
65
+ export function lettering(word, style) {
66
+ const lean = Math.tan((style.slant * Math.PI) / 180);
67
+ const half = style.weight / 2;
68
+ const top = half + (style.cap === "square" ? half : 0);
69
+ const pad = half + (style.cap === "square" ? half * 0.42 : 0) + Math.abs(lean) * (LETTER_HEIGHT / 2);
70
+ let x = pad;
71
+ let before = "";
72
+ const parts = [];
73
+ for (const char of word.toUpperCase()) {
74
+ const skeleton = SKELETONS[char];
75
+ if (skeleton === undefined)
76
+ continue;
77
+ const w = 60 * style.width * (skeleton.wide ?? 1);
78
+ if (before !== "" && OPEN.includes(before) && LEAN.includes(char) && before !== char)
79
+ x -= 0.3 * 60 * style.width;
80
+ before = char;
81
+ skeleton.strokes.forEach((stroke, index) => {
82
+ const points = stroke.map(([u, v]) => [x + u * w + (LETTER_HEIGHT / 2 - v * LETTER_HEIGHT) * lean, top + v * LETTER_HEIGHT]);
83
+ parts.push(strokePath(points, skeleton.closed?.includes(index) === true, style));
84
+ });
85
+ x += w + style.weight + style.gap;
86
+ }
87
+ return { d: parts.join(""), width: x - style.gap - style.weight + pad, height: LETTER_HEIGHT + 2 * top, weight: style.weight };
88
+ }
@@ -0,0 +1,47 @@
1
+ import { type MakerId, type TeamId } from "./brand.data.ts";
2
+ /** What a maker's logo is made of: its mark alone (the default), its wordmark alone, the two side by side or the wordmark under the mark. */
3
+ export type LogoLayout = "mark" | "wordmark" | "horizontal" | "stacked";
4
+ /** The options every logo takes. */
5
+ export interface LogoOptions {
6
+ /** `"full"` (the default) draws the logo in its own colours; `"mono"` draws it in one colour, `ink`. */
7
+ color?: "full" | "mono";
8
+ /** The colours of the logo for a light page (the default) or a dark one. */
9
+ theme?: "light" | "dark";
10
+ /** The one colour of a `"mono"` logo: `#rgb`, `#rrggbb` or `rgb()`. By default `currentColor`, so the logo takes the page's text colour. Ignored by a full-colour logo. */
11
+ ink?: string;
12
+ /** The height in pixels (64 by default); the width follows the layout. The drawing is a vector at any size. */
13
+ size?: number;
14
+ /** The `<title>`: a string writes that title (escaped), `false` drops it and marks the drawing `aria-hidden="true"`. By default the maker's name or the team's name. */
15
+ title?: string | false;
16
+ }
17
+ /** The options of a maker's logo. */
18
+ export interface MakerLogoOptions extends LogoOptions {
19
+ /** Which parts to draw. By default only the mark: the name is optional. */
20
+ layout?: LogoLayout;
21
+ }
22
+ /** Where a logo goes inside another drawing: its top left corner and its height, in that drawing's units. */
23
+ export interface LogoPlace {
24
+ x?: number;
25
+ y?: number;
26
+ /** The height of the logo in the drawing's units (100 by default). */
27
+ size?: number;
28
+ }
29
+ /**
30
+ * A fictional maker's logo as an SVG document: its mark by default, or its wordmark, or both (`layout`). In its own colours for a light or a dark page, or in one colour (`color: "mono"`, `ink`).
31
+ * @example
32
+ * ```ts
33
+ * import { makerLogo } from "@johnmorrisdotca/dougu-sports/brands";
34
+ * const svg = makerLogo("arvane", { size: 48 });
35
+ * console.log(svg.startsWith("<svg"), svg.includes("<title>Arvane</title>"));
36
+ * // true true
37
+ * ```
38
+ */
39
+ export declare function makerLogo(id: MakerId, o?: MakerLogoOptions): string;
40
+ /** A fictional team's logo as an SVG document, in its own colours for a light or a dark page, or in one colour. */
41
+ export declare function teamLogo(id: TeamId, o?: LogoOptions): string;
42
+ /**
43
+ * A maker's logo as a `<g>` to put inside another SVG: a jersey, a cap, a T-shirt, a card. It has no id, no gradient and no `<title>`, so any number of them can sit in one document. `x`, `y` and `size` place it in that drawing's units.
44
+ */
45
+ export declare function makerLogoGroup(id: MakerId, place?: LogoPlace, o?: Omit<MakerLogoOptions, "size" | "title">): string;
46
+ /** A team's logo as a `<g>` to put inside another SVG (see `makerLogoGroup`). */
47
+ export declare function teamLogoGroup(id: TeamId, place?: LogoPlace, o?: Omit<LogoOptions, "size" | "title">): string;
@@ -0,0 +1,106 @@
1
+ // Draws the fictional logos: a maker's mark, its wordmark or both, and a team's logo, as an SVG document or as a group to place inside another drawing. A pure function of its options: the same id and options give the same
2
+ // string, there are no ids, no gradients and no filters, and a colour that is not `#rgb`, `#rrggbb` or `rgb()` is ignored.
3
+ import { escape, hexOf, readColour } from "../emblems/emblem.core.js";
4
+ import { LETTER_HEIGHT, lettering } from "./brand.letters.js";
5
+ import { MAKERS, TEAMS } from "./brand.data.js";
6
+ const MARK = 100;
7
+ const r2 = (value) => Math.round(value * 100) / 100;
8
+ const r4 = (value) => Math.round(value * 10000) / 10000;
9
+ const HORIZONTAL_GAP = 16;
10
+ const WORD_HEIGHT_BESIDE = 34;
11
+ const STACK_GAP = 12;
12
+ const clampSize = (value, fallback) => (typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.min(value, 4096) : fallback);
13
+ /** The colour of a mono logo: a colour that reads, or `currentColor`. */
14
+ function monoInk(ink) {
15
+ const rgb = readColour(ink);
16
+ return rgb === undefined ? "currentColor" : hexOf(rgb);
17
+ }
18
+ const partsMarkup = (parts, colorOf) => parts.map((part) => `<path fill="${colorOf(part)}" fill-rule="evenodd" d="${part.d}"/>`).join("");
19
+ function makerBody(maker, layout, o) {
20
+ const mono = o?.color === "mono";
21
+ const palette = o?.theme === "dark" ? maker.dark : maker.light;
22
+ const ink = monoInk(o?.ink);
23
+ const mark = partsMarkup(maker.parts, (part) => (mono ? ink : part.role === "a" ? palette.a : palette.b));
24
+ const word = lettering(maker.name, maker.lettering);
25
+ const stroke = mono ? ink : palette.ink;
26
+ const join = maker.lettering.corner === "round" ? "round" : "miter";
27
+ const letters = `<path fill="none" stroke="${stroke}" stroke-width="${r2(maker.lettering.weight)}" stroke-linecap="${maker.lettering.cap}" stroke-linejoin="${join}" d="${word.d}"/>`;
28
+ if (layout === "mark")
29
+ return { width: MARK, height: MARK, body: mark };
30
+ if (layout === "wordmark")
31
+ return { width: r2(word.width), height: r2(word.height), body: letters };
32
+ if (layout === "horizontal") {
33
+ const k = WORD_HEIGHT_BESIDE / LETTER_HEIGHT;
34
+ const top = MARK / 2 - (word.height * k) / 2;
35
+ return { width: r2(MARK + HORIZONTAL_GAP + word.width * k), height: MARK, body: `${mark}<g transform="translate(${MARK + HORIZONTAL_GAP} ${r2(top)}) scale(${r4(k)})">${letters}</g>` };
36
+ }
37
+ const k = Math.min(0.32, 96 / word.width);
38
+ const width = Math.max(MARK, word.width * k);
39
+ const x = (width - MARK) / 2;
40
+ const wx = (width - word.width * k) / 2;
41
+ return {
42
+ width: r2(width),
43
+ height: r2(MARK + STACK_GAP + word.height * k),
44
+ body: `<g transform="translate(${r2(x)} 0)">${mark}</g><g transform="translate(${r2(wx)} ${MARK + STACK_GAP}) scale(${r4(k)})">${letters}</g>`,
45
+ };
46
+ }
47
+ function teamBody(team, o) {
48
+ const mono = o?.color === "mono";
49
+ const palette = o?.theme === "dark" ? team.dark : team.light;
50
+ const ink = monoInk(o?.ink);
51
+ return { width: MARK, height: MARK, body: partsMarkup(team.parts, (part) => (mono ? ink : palette[part.role])) };
52
+ }
53
+ function document(built, name, o) {
54
+ const height = clampSize(o?.size, 64);
55
+ const width = r2((height * built.width) / built.height);
56
+ const title = o?.title === false ? undefined : typeof o?.title === "string" ? o.title : name;
57
+ const label = title === undefined ? ' aria-hidden="true"' : ` role="img"`;
58
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${built.width} ${built.height}" width="${width}" height="${r2(height)}"${label}>${title === undefined ? "" : `<title>${escape(title)}</title>`}${built.body}</svg>`;
59
+ }
60
+ function group(built, place) {
61
+ const size = clampSize(place?.size, MARK);
62
+ const k = size / built.height;
63
+ const x = typeof place?.x === "number" && Number.isFinite(place.x) ? place.x : 0;
64
+ const y = typeof place?.y === "number" && Number.isFinite(place.y) ? place.y : 0;
65
+ return `<g transform="translate(${r2(x)} ${r2(y)}) scale(${r4(k)})">${built.body}</g>`;
66
+ }
67
+ const layoutOf = (value) => (value === "wordmark" || value === "horizontal" || value === "stacked" ? value : "mark");
68
+ function maker(id) {
69
+ if (!Object.hasOwn(MAKERS, id))
70
+ throw new Error(`Unknown maker "${String(id).slice(0, 40)}"; see MAKER_IDS.`);
71
+ return MAKERS[id];
72
+ }
73
+ function team(id) {
74
+ if (!Object.hasOwn(TEAMS, id))
75
+ throw new Error(`Unknown team "${String(id).slice(0, 40)}"; see TEAM_IDS.`);
76
+ return TEAMS[id];
77
+ }
78
+ /**
79
+ * A fictional maker's logo as an SVG document: its mark by default, or its wordmark, or both (`layout`). In its own colours for a light or a dark page, or in one colour (`color: "mono"`, `ink`).
80
+ * @example
81
+ * ```ts
82
+ * import { makerLogo } from "@johnmorrisdotca/dougu-sports/brands";
83
+ * const svg = makerLogo("arvane", { size: 48 });
84
+ * console.log(svg.startsWith("<svg"), svg.includes("<title>Arvane</title>"));
85
+ * // true true
86
+ * ```
87
+ */
88
+ export function makerLogo(id, o) {
89
+ const data = maker(id);
90
+ return document(makerBody(data, layoutOf(o?.layout), o), data.name, o);
91
+ }
92
+ /** A fictional team's logo as an SVG document, in its own colours for a light or a dark page, or in one colour. */
93
+ export function teamLogo(id, o) {
94
+ const data = team(id);
95
+ return document(teamBody(data, o), `${data.city} ${data.nickname}`, o);
96
+ }
97
+ /**
98
+ * A maker's logo as a `<g>` to put inside another SVG: a jersey, a cap, a T-shirt, a card. It has no id, no gradient and no `<title>`, so any number of them can sit in one document. `x`, `y` and `size` place it in that drawing's units.
99
+ */
100
+ export function makerLogoGroup(id, place, o) {
101
+ return group(makerBody(maker(id), layoutOf(o?.layout), o), place);
102
+ }
103
+ /** A team's logo as a `<g>` to put inside another SVG (see `makerLogoGroup`). */
104
+ export function teamLogoGroup(id, place, o) {
105
+ return group(teamBody(team(id), o), place);
106
+ }
@@ -0,0 +1,8 @@
1
+ export { MAKERS, MAKER_IDS, TEAMS, TEAM_IDS } from "./brands/brand.data.ts";
2
+ export type { LogoPart, MakerData, MakerId, MakerPalette, PartRole, TeamData, TeamId, TeamPalette } from "./brands/brand.data.ts";
3
+ export { makerLogo, makerLogoGroup, teamLogo, teamLogoGroup } from "./brands/brand.render.ts";
4
+ export type { LogoLayout, LogoOptions, LogoPlace, MakerLogoOptions } from "./brands/brand.render.ts";
5
+ export { makerBall, renderMakerBall } from "./brands/brand.ball.ts";
6
+ export type { MakerBallOptions } from "./brands/brand.ball.ts";
7
+ export { LETTERS, lettering } from "./brands/brand.letters.ts";
8
+ export type { LetterStyle, Lettering } from "./brands/brand.letters.ts";
@@ -0,0 +1,5 @@
1
+ // The brands entry point: twelve fictional maker marks, ten fictional team logos, and the functions that draw them, place them in another drawing or print them on a ball. The set is the data in `MAKERS` and `TEAMS`.
2
+ export { MAKERS, MAKER_IDS, TEAMS, TEAM_IDS } from "./brands/brand.data.js";
3
+ export { makerLogo, makerLogoGroup, teamLogo, teamLogoGroup } from "./brands/brand.render.js";
4
+ export { makerBall, renderMakerBall } from "./brands/brand.ball.js";
5
+ export { LETTERS, lettering } from "./brands/brand.letters.js";
@@ -0,0 +1,2 @@
1
+ /** Ribbon. */
2
+ export declare const AWARD_RIBBON: import("../emblem.core.ts").Emblem<import("../emblem.shapes.ts").FlatModel>;
@@ -0,0 +1,17 @@
1
+ // Ribbon: a banner ribbon, a gold band with two red notched tails hanging behind it, drawn for this package, in metal, line and flat colour. It stands alone (a prize ribbon without a rosette); `trophy:rosette` is the one with ribbons.
2
+ import { defineFlat } from "../emblem.shapes.js";
3
+ /** Ribbon. */
4
+ export const AWARD_RIBBON = /* @__PURE__ */ defineFlat("award:ribbon", "Ribbon", "リボン", "ours", {
5
+ metal: "gold",
6
+ ribbon: "#c0392b",
7
+ front: [
8
+ // The two tails hang from behind the band, each ending in a notch.
9
+ ["r", "M13 34H29V57L21 49L13 57z"],
10
+ ["r", "M35 34H51V57L43 49L35 57z"],
11
+ // The band.
12
+ ["m", "M5 10H59V34H5z"],
13
+ ["e", "M9 14H55V30H9z", "1.6"],
14
+ ["l", "M5 10H59V14H5z"],
15
+ ],
16
+ rim: 2,
17
+ });
@@ -26,7 +26,7 @@ import { BALL_LACROSSE, BALL_RACQUETBALL, BALL_TABLE_TENNIS, BALL_SHOT } from ".
26
26
  import { BALL_SOCCER_26, BALL_SOCCER_18, BALL_SOCCER_14, BALL_SOCCER_12, BALL_SOCCER_6, BALL_SOCCER_26_ORANGE, BALL_SOCCER_18_ORANGE, BALL_SOCCER_14_ORANGE, BALL_SOCCER_12_ORANGE, BALL_SOCCER_6_ORANGE, BALL_SOCCER_26_YELLOW, BALL_SOCCER_18_YELLOW, BALL_SOCCER_14_YELLOW, BALL_SOCCER_12_YELLOW, BALL_SOCCER_6_YELLOW } from "./ball.soccer.panels.js";
27
27
  import { BALL_FUTSAL, BALL_BEACH_SOCCER } from "./ball.soccer.indoor.js";
28
28
  import { BALL_SOCCER_1870_HAND_STITCHED, BALL_SOCCER_1900_LACED, BALL_SOCCER_1930_18_PANEL, BALL_SOCCER_1950_12_PANEL, BALL_SOCCER_1960_32_PANEL_LEATHER } from "./ball.soccer.vintage.js";
29
- import { BALL_SOCCER_1970_BLACK_WHITE, BALL_SOCCER_1978_TRIAD, BALL_SOCCER_1986_DECORATED_TRIAD, BALL_SOCCER_1998_COLOURED_TRIAD, BALL_SOCCER_2002_TRIANGLE_SWEEP, BALL_SOCCER_2006_PROPELLER, BALL_SOCCER_2010_GROOVED, BALL_SOCCER_2014_RIBBON, BALL_SOCCER_2018_PIXEL, BALL_SOCCER_2022_SPEED_SHELL, BALL_SOCCER_TRAINING_HIGH_VIS } from "./ball.soccer.era.js";
29
+ import { BALL_SOCCER_RETRO_PENTAGONS, BALL_SOCCER_RETRO_LEAVES, BALL_SOCCER_RETRO_ROSETTE, BALL_SOCCER_RETRO_STAR, BALL_SOCCER_RETRO_PINWHEEL, BALL_SOCCER_RETRO_KITES, BALL_SOCCER_14_PANEL_DOUBLE_BORDER, BALL_SOCCER_8_PANEL_PLAIN, BALL_SOCCER_6_PANEL_BANDS, BALL_SOCCER_6_PANEL_DIAMONDS, BALL_SOCCER_20_PANEL_DOTS, BALL_SOCCER_TRAINING_HIGH_VIS } from "./ball.soccer.era.js";
30
30
  import { BALL_SOCCER_STARS_BLUE, BALL_SOCCER_STARS_RED, BALL_SOCCER_STARS_NIGHT, BALL_SOCCER_HEXAGONS_CYAN, BALL_SOCCER_HEXAGONS_MAGENTA, BALL_SOCCER_HEXAGONS_LIME, BALL_SOCCER_FLAMES_FIRE, BALL_SOCCER_FLAMES_ICE, BALL_SOCCER_FLAMES_TOXIC, BALL_SOCCER_CHEVRONS_RED, BALL_SOCCER_CHEVRONS_GREEN, BALL_SOCCER_CHEVRONS_BLUE, BALL_SOCCER_SWIRL_BLUE, BALL_SOCCER_SWIRL_RED, BALL_SOCCER_SWIRL_TEAL, BALL_SOCCER_METALLIC_GOLD, BALL_SOCCER_METALLIC_SILVER, BALL_SOCCER_METALLIC_COBALT } from "./ball.soccer.store.js";
31
31
  import { BALL_BASEBALL_LEMON_PEEL, BALL_BASEBALL_RED_BLUE, BALL_BASEBALL_BLACK_RED, BALL_BASEBALL_VINTAGE_LEATHER, BALL_SOFTBALL_11_OPTIC } from "./ball.baseball.vintage.js";
32
32
  import { BALL_VOLLEYBALL_COLOURS, BALL_VOLLEYBALL_BRAZIL, BALL_VOLLEYBALL_JAPAN, BALL_VOLLEYBALL_CANADA, BALL_VOLLEYBALL_USA, BALL_VOLLEYBALL_ITALY, BALL_VOLLEYBALL_POLAND, BALL_VOLLEYBALL_FRANCE, BALL_VOLLEYBALL_SERBIA, BALL_VOLLEYBALL_NETHERLANDS, BALL_VOLLEYBALL_GERMANY } from "./ball.volleyball.flag.js";
@@ -36,7 +36,7 @@ import { BALL_TEQBALL } from "./ball.teqball.js";
36
36
  import { BALL_VOLLEYBALL, BALL_VOLLEYBALL_8, BALL_BEACH_VOLLEYBALL } from "./ball.volleyball.js";
37
37
  import { BALL_WATER_POLO } from "./ball.waterpolo.js";
38
38
  /** Every ball, in the order a gallery shows them. */
39
- export const BALLS = [BALL_SOCCER, BALL_SOCCER_COLOUR, BALL_SOCCER_26, BALL_SOCCER_18, BALL_SOCCER_14, BALL_SOCCER_12, BALL_SOCCER_6, BALL_SOCCER_ORANGE, BALL_SOCCER_26_ORANGE, BALL_SOCCER_18_ORANGE, BALL_SOCCER_14_ORANGE, BALL_SOCCER_12_ORANGE, BALL_SOCCER_6_ORANGE, BALL_SOCCER_YELLOW, BALL_SOCCER_26_YELLOW, BALL_SOCCER_18_YELLOW, BALL_SOCCER_14_YELLOW, BALL_SOCCER_12_YELLOW, BALL_SOCCER_6_YELLOW, BALL_FUTSAL, BALL_BEACH_SOCCER, BALL_SOCCER_1870_HAND_STITCHED, BALL_SOCCER_1900_LACED, BALL_SOCCER_1930_18_PANEL, BALL_SOCCER_1950_12_PANEL, BALL_SOCCER_1960_32_PANEL_LEATHER, BALL_SOCCER_1970_BLACK_WHITE, BALL_SOCCER_1978_TRIAD, BALL_SOCCER_1986_DECORATED_TRIAD, BALL_SOCCER_1998_COLOURED_TRIAD, BALL_SOCCER_2002_TRIANGLE_SWEEP, BALL_SOCCER_2006_PROPELLER, BALL_SOCCER_2010_GROOVED, BALL_SOCCER_2014_RIBBON, BALL_SOCCER_2018_PIXEL, BALL_SOCCER_2022_SPEED_SHELL, BALL_SOCCER_TRAINING_HIGH_VIS, BALL_SOCCER_STARS_BLUE, BALL_SOCCER_STARS_RED, BALL_SOCCER_STARS_NIGHT, BALL_SOCCER_HEXAGONS_CYAN, BALL_SOCCER_HEXAGONS_MAGENTA, BALL_SOCCER_HEXAGONS_LIME, BALL_SOCCER_FLAMES_FIRE, BALL_SOCCER_FLAMES_ICE, BALL_SOCCER_FLAMES_TOXIC, BALL_SOCCER_CHEVRONS_RED, BALL_SOCCER_CHEVRONS_GREEN, BALL_SOCCER_CHEVRONS_BLUE, BALL_SOCCER_SWIRL_BLUE, BALL_SOCCER_SWIRL_RED, BALL_SOCCER_SWIRL_TEAL, BALL_SOCCER_METALLIC_GOLD, BALL_SOCCER_METALLIC_SILVER, BALL_SOCCER_METALLIC_COBALT, BALL_TEQBALL, BALL_BASKETBALL, BALL_BASKETBALL_6, BALL_BASKETBALL_3X3, BALL_BASEBALL, BALL_SOFTBALL, BALL_BASEBALL_LEMON_PEEL, BALL_BASEBALL_RED_BLUE, BALL_BASEBALL_BLACK_RED, BALL_BASEBALL_VINTAGE_LEATHER, BALL_SOFTBALL_11_OPTIC, BALL_TENNIS, BALL_PADEL, BALL_SLIOTAR, BALL_VOLLEYBALL, BALL_VOLLEYBALL_8, BALL_BEACH_VOLLEYBALL, BALL_VOLLEYBALL_COLOURS, BALL_VOLLEYBALL_BRAZIL, BALL_VOLLEYBALL_JAPAN, BALL_VOLLEYBALL_CANADA, BALL_VOLLEYBALL_USA, BALL_VOLLEYBALL_ITALY, BALL_VOLLEYBALL_POLAND, BALL_VOLLEYBALL_FRANCE, BALL_VOLLEYBALL_SERBIA, BALL_VOLLEYBALL_NETHERLANDS, BALL_VOLLEYBALL_GERMANY, BALL_CRICKET_RED, BALL_CRICKET_WHITE, BALL_CRICKET_PINK, BALL_FOOTBALL, BALL_FOOTBALL_CFL, BALL_FOOTBALL_IFAF, BALL_RUGBY, BALL_AFL, BALL_GAELIC_FOOTBALL, BALL_NETBALL, BALL_PICKLEBALL_OUTDOOR, BALL_PICKLEBALL_INDOOR, BALL_SQUASH_DOUBLE_YELLOW, BALL_SQUASH_YELLOW, BALL_SQUASH_GREEN, BALL_SQUASH_RED, BALL_SQUASH_BLUE, BALL_RACQUETBALL, BALL_LACROSSE, BALL_FIELD_HOCKEY, BALL_TABLE_TENNIS, BALL_HANDBALL, BALL_WATER_POLO, BALL_GOLF, BALL_PUCK, BALL_CURLING_STONE, BALL_SHOT, BALL_DISCUS, BALL_HAMMER, BALL_SEPAK_TAKRAW, BALL_ROUNDNET, BALL_SHUTTLECOCK_FEATHER, BALL_SHUTTLECOCK_NYLON];
39
+ export const BALLS = [BALL_SOCCER, BALL_SOCCER_COLOUR, BALL_SOCCER_26, BALL_SOCCER_18, BALL_SOCCER_14, BALL_SOCCER_12, BALL_SOCCER_6, BALL_SOCCER_ORANGE, BALL_SOCCER_26_ORANGE, BALL_SOCCER_18_ORANGE, BALL_SOCCER_14_ORANGE, BALL_SOCCER_12_ORANGE, BALL_SOCCER_6_ORANGE, BALL_SOCCER_YELLOW, BALL_SOCCER_26_YELLOW, BALL_SOCCER_18_YELLOW, BALL_SOCCER_14_YELLOW, BALL_SOCCER_12_YELLOW, BALL_SOCCER_6_YELLOW, BALL_FUTSAL, BALL_BEACH_SOCCER, BALL_SOCCER_1870_HAND_STITCHED, BALL_SOCCER_1900_LACED, BALL_SOCCER_1930_18_PANEL, BALL_SOCCER_1950_12_PANEL, BALL_SOCCER_1960_32_PANEL_LEATHER, BALL_SOCCER_RETRO_PENTAGONS, BALL_SOCCER_RETRO_LEAVES, BALL_SOCCER_RETRO_ROSETTE, BALL_SOCCER_RETRO_STAR, BALL_SOCCER_RETRO_PINWHEEL, BALL_SOCCER_RETRO_KITES, BALL_SOCCER_14_PANEL_DOUBLE_BORDER, BALL_SOCCER_8_PANEL_PLAIN, BALL_SOCCER_6_PANEL_BANDS, BALL_SOCCER_6_PANEL_DIAMONDS, BALL_SOCCER_20_PANEL_DOTS, BALL_SOCCER_TRAINING_HIGH_VIS, BALL_SOCCER_STARS_BLUE, BALL_SOCCER_STARS_RED, BALL_SOCCER_STARS_NIGHT, BALL_SOCCER_HEXAGONS_CYAN, BALL_SOCCER_HEXAGONS_MAGENTA, BALL_SOCCER_HEXAGONS_LIME, BALL_SOCCER_FLAMES_FIRE, BALL_SOCCER_FLAMES_ICE, BALL_SOCCER_FLAMES_TOXIC, BALL_SOCCER_CHEVRONS_RED, BALL_SOCCER_CHEVRONS_GREEN, BALL_SOCCER_CHEVRONS_BLUE, BALL_SOCCER_SWIRL_BLUE, BALL_SOCCER_SWIRL_RED, BALL_SOCCER_SWIRL_TEAL, BALL_SOCCER_METALLIC_GOLD, BALL_SOCCER_METALLIC_SILVER, BALL_SOCCER_METALLIC_COBALT, BALL_TEQBALL, BALL_BASKETBALL, BALL_BASKETBALL_6, BALL_BASKETBALL_3X3, BALL_BASEBALL, BALL_SOFTBALL, BALL_BASEBALL_LEMON_PEEL, BALL_BASEBALL_RED_BLUE, BALL_BASEBALL_BLACK_RED, BALL_BASEBALL_VINTAGE_LEATHER, BALL_SOFTBALL_11_OPTIC, BALL_TENNIS, BALL_PADEL, BALL_SLIOTAR, BALL_VOLLEYBALL, BALL_VOLLEYBALL_8, BALL_BEACH_VOLLEYBALL, BALL_VOLLEYBALL_COLOURS, BALL_VOLLEYBALL_BRAZIL, BALL_VOLLEYBALL_JAPAN, BALL_VOLLEYBALL_CANADA, BALL_VOLLEYBALL_USA, BALL_VOLLEYBALL_ITALY, BALL_VOLLEYBALL_POLAND, BALL_VOLLEYBALL_FRANCE, BALL_VOLLEYBALL_SERBIA, BALL_VOLLEYBALL_NETHERLANDS, BALL_VOLLEYBALL_GERMANY, BALL_CRICKET_RED, BALL_CRICKET_WHITE, BALL_CRICKET_PINK, BALL_FOOTBALL, BALL_FOOTBALL_CFL, BALL_FOOTBALL_IFAF, BALL_RUGBY, BALL_AFL, BALL_GAELIC_FOOTBALL, BALL_NETBALL, BALL_PICKLEBALL_OUTDOOR, BALL_PICKLEBALL_INDOOR, BALL_SQUASH_DOUBLE_YELLOW, BALL_SQUASH_YELLOW, BALL_SQUASH_GREEN, BALL_SQUASH_RED, BALL_SQUASH_BLUE, BALL_RACQUETBALL, BALL_LACROSSE, BALL_FIELD_HOCKEY, BALL_TABLE_TENNIS, BALL_HANDBALL, BALL_WATER_POLO, BALL_GOLF, BALL_PUCK, BALL_CURLING_STONE, BALL_SHOT, BALL_DISCUS, BALL_HAMMER, BALL_SEPAK_TAKRAW, BALL_ROUNDNET, BALL_SHUTTLECOCK_FEATHER, BALL_SHUTTLECOCK_NYLON];
40
40
  /** The id of every ball: `"ball:soccer"`, `"ball:cricket-red"`. */
41
41
  export const BALL_IDS = BALLS.map((b) => b.id);
42
42
  const TABLE = new Map([...BALLS, ...PUCKS].map((b) => [b.id, b]));
@@ -1,23 +1,25 @@
1
1
  import { type BallSpec } from "./ball.engine.ts";
2
- /** The 1970s: twelve black pentagons with a white ring round a small boss, and twenty white hexagons that each hold a pale dished hexagon and a dot. */
3
- export declare const BALL_SOCCER_1970_BLACK_WHITE: import("./ball.core.ts").Piece<BallSpec>;
4
- /** The late 1970s: a pinwheel of three bold curved triangles on each of the twenty hexagons, black on white; their points meet round each of the twelve pentagons. */
5
- export declare const BALL_SOCCER_1978_TRIAD: import("./ball.core.ts").Piece<BallSpec>;
6
- /** The 1980s: the same triads in a warm clay, each blade ornamented with a row of white beads along its spine, and gold-ringed dark pentagons. */
7
- export declare const BALL_SOCCER_1986_DECORATED_TRIAD: import("./ball.core.ts").Piece<BallSpec>;
8
- /** The 1990s: the triads in three colours (blue, red and gold) on a white ground, with deep navy pentagons. */
9
- export declare const BALL_SOCCER_1998_COLOURED_TRIAD: import("./ball.core.ts").Piece<BallSpec>;
10
- /** The early 2000s: long thin triangles that sweep across each hexagon from one side to the next, in graphite and gold, with a red spark, over charcoal pentagons. */
11
- export declare const BALL_SOCCER_2002_TRIANGLE_SWEEP: import("./ball.core.ts").Piece<BallSpec>;
12
- /** The mid 2000s: the 14-panel propeller layout (six propellers and eight triangles), with a fine line following each curved seam inside the panel, and a small ring on each triangle. */
13
- export declare const BALL_SOCCER_2006_PROPELLER: import("./ball.core.ts").Piece<BallSpec>;
14
- /** The early 2010s: the 8-panel layout, an octahedron whose edges are bent into S curves, with deep grooves for seams and contour lines across each panel: white panels with teal lines and teal panels with white ones. */
15
- export declare const BALL_SOCCER_2010_GROOVED: import("./ball.core.ts").Piece<BallSpec>;
16
- /** The mid 2010s: six twisted panels in white, crossed by wide ribbons that swirl round the ball in teal, orange and violet. */
17
- export declare const BALL_SOCCER_2014_RIBBON: import("./ball.core.ts").Piece<BallSpec>;
18
- /** The late 2010s: six panels covered with square pixel blocks, thick where the ball is dark and thinning out toward the lighter side. */
19
- export declare const BALL_SOCCER_2018_PIXEL: import("./ball.core.ts").Piece<BallSpec>;
20
- /** The early 2020s: twenty triangles (an icosahedron) in three warm tones, each carrying a shell of nested edges and a trail of speed lines. */
21
- export declare const BALL_SOCCER_2022_SPEED_SHELL: import("./ball.core.ts").Piece<BallSpec>;
2
+ /** The 1970s: twelve dark slate pentagons and twenty white hexagons that each hold a pale dished hexagon. */
3
+ export declare const BALL_SOCCER_RETRO_PENTAGONS: import("./ball.core.ts").Piece<BallSpec>;
4
+ /** The late 1970s: a trefoil of three straight leaves on each of the twenty hexagons, navy on white, each pointing at a pentagon. */
5
+ export declare const BALL_SOCCER_RETRO_LEAVES: import("./ball.core.ts").Piece<BallSpec>;
6
+ /** The 1980s: a five-petal rosette on each hexagon in a warm clay, each petal ornamented with a row of white beads along its spine, and gold-ringed dark pentagons. */
7
+ export declare const BALL_SOCCER_RETRO_ROSETTE: import("./ball.core.ts").Piece<BallSpec>;
8
+ /** The 1980s, second version: a six-armed star on each hexagon in deep teal with a saffron centre, over cream hexagons, with navy pentagons ringed in cream. */
9
+ export declare const BALL_SOCCER_RETRO_STAR: import("./ball.core.ts").Piece<BallSpec>;
10
+ /** The 1990s: a pinwheel of three curved leaves in three colours (green, amber and plum) on a white ground, turning the other way from the 1970s, a solid deep green circle where the three meet, and deep green pentagons. */
11
+ export declare const BALL_SOCCER_RETRO_PINWHEEL: import("./ball.core.ts").Piece<BallSpec>;
12
+ /** The early 2000s: long kites that sweep across each hexagon, in slate blue and silver, over charcoal pentagons. */
13
+ export declare const BALL_SOCCER_RETRO_KITES: import("./ball.core.ts").Piece<BallSpec>;
14
+ /** The mid 2000s: the 14-panel layout (six propellers and eight triangles) with a double border: two parallel black lines along every seam (a thin gap between them), and two parallel red lines inside each propeller; white propellers, dark triangles with a red dot. */
15
+ export declare const BALL_SOCCER_14_PANEL_DOUBLE_BORDER: import("./ball.core.ts").Piece<BallSpec>;
16
+ /** The early 2010s: the 8-panel layout, an octahedron whose edges are bent into S curves, with plain seams: the white panels are plain, and the slate-blue ones carry three white contour lines. */
17
+ export declare const BALL_SOCCER_8_PANEL_PLAIN: import("./ball.core.ts").Piece<BallSpec>;
18
+ /** The mid 2010s: six twisted panels in white, crossed by straight bands along each panel in blue, amber and magenta, and a series of diamonds at each pole where the seams meet. */
19
+ export declare const BALL_SOCCER_6_PANEL_BANDS: import("./ball.core.ts").Piece<BallSpec>;
20
+ /** The late 2010s: six panels covered with small diamonds, thick on one side and thinning out toward the other, and a series of diamonds at each pole where the seams meet. */
21
+ export declare const BALL_SOCCER_6_PANEL_DIAMONDS: import("./ball.core.ts").Piece<BallSpec>;
22
+ /** The early 2020s: twenty triangles (an icosahedron) in deep blue, cream and sand, each carrying one inner outline and a dot at its middle. */
23
+ export declare const BALL_SOCCER_20_PANEL_DOTS: import("./ball.core.ts").Piece<BallSpec>;
22
24
  /** A modern high-visibility training ball: 32 panels in fluorescent yellow-green, hot pink pentagons ringed in black, and three dark speed marks across each hexagon. */
23
25
  export declare const BALL_SOCCER_TRAINING_HIGH_VIS: import("./ball.core.ts").Piece<BallSpec>;