@johnmorrisdotca/dougu-sports 0.8.0 → 0.10.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 +27 -0
- package/NOTICE.md +14 -0
- package/README.md +58 -26
- package/dist/brands/brand.ball.d.ts +29 -0
- package/dist/brands/brand.ball.js +23 -0
- package/dist/brands/brand.data.d.ts +47 -0
- package/dist/brands/brand.data.js +308 -0
- package/dist/brands/brand.letters.d.ts +31 -0
- package/dist/brands/brand.letters.js +88 -0
- package/dist/brands/brand.render.d.ts +47 -0
- package/dist/brands/brand.render.js +106 -0
- package/dist/brands-entry.d.ts +8 -0
- package/dist/brands-entry.js +5 -0
- package/dist/emblems/award/ribbon.d.ts +2 -0
- package/dist/emblems/award/ribbon.js +17 -0
- package/dist/emblems/ball/ball.baseball.js +2 -1
- package/dist/emblems/ball/ball.contrast.d.ts +4 -0
- package/dist/emblems/ball/ball.contrast.js +22 -0
- package/dist/emblems/ball/ball.core.d.ts +42 -0
- package/dist/emblems/ball/ball.core.js +34 -1
- package/dist/emblems/ball/ball.engine.d.ts +70 -4
- package/dist/emblems/ball/ball.engine.js +70 -20
- package/dist/emblems/ball/ball.family.seamed.d.ts +4 -0
- package/dist/emblems/ball/ball.family.seamed.js +42 -7
- package/dist/emblems/ball/ball.image.d.ts +8 -0
- package/dist/emblems/ball/ball.image.js +14 -5
- package/dist/emblems/ball/ball.index.js +2 -4
- package/dist/emblems/ball/ball.letters.d.ts +3 -0
- package/dist/emblems/ball/ball.letters.js +51 -0
- package/dist/emblems/ball/ball.print.d.ts +81 -0
- package/dist/emblems/ball/ball.print.js +268 -0
- package/dist/emblems/ball/ball.printable.d.ts +6 -0
- package/dist/emblems/ball/ball.printable.js +13 -0
- package/dist/emblems/ball/ball.region.d.ts +12 -0
- package/dist/emblems/ball/ball.region.js +94 -0
- package/dist/emblems/ball/ball.script.d.ts +15 -0
- package/dist/emblems/ball/ball.script.js +107 -0
- package/dist/emblems/ball/ball.soccer.js +7 -3
- package/dist/emblems/ball/ball.soccer.panels.d.ts +2 -0
- package/dist/emblems/ball/ball.soccer.panels.js +6 -3
- package/dist/emblems/ball/ball.soccer.size.d.ts +2 -0
- package/dist/emblems/ball/ball.soccer.size.js +8 -0
- package/dist/emblems/ball/ball.softball.js +2 -1
- package/dist/emblems/ball/ball.warp.d.ts +48 -0
- package/dist/emblems/ball/ball.warp.js +441 -0
- package/dist/emblems/emblem.core.d.ts +13 -0
- package/dist/emblems/emblem.equipment.js +3 -3
- package/dist/emblems/emblem.ids.d.ts +4 -4
- package/dist/emblems/emblem.ids.js +2 -2
- package/dist/emblems/emblem.registry.js +2 -0
- package/dist/emblems/gear/gear.index.js +2 -1
- package/dist/emblems/gear/gear.nets.d.ts +3 -0
- package/dist/emblems/gear/gear.nets.js +103 -0
- package/dist/emblems-entry.d.ts +1 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +5 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +8 -1
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
// The set: twelve fictional maker marks and ten fictional team logos, as data. Every mark is drawn for this package on a 100 by 100 box in a few flat parts, each part one path and one role (`a` the main colour, `b` the second, `c` a third
|
|
2
|
+
// for a team); the parts never overlap, so the mark is the same drawn in one colour. Nothing here is a real company's or club's mark, name or lettering: each note says what the nearest real one is and how this differs.
|
|
3
|
+
export const MAKER_IDS = ["arvane", "tarsin", "ravelle", "kovreth", "dunmar", "ostrel", "vexlin", "quillan", "tenzar", "marenko", "halvane", "solvik"];
|
|
4
|
+
export const TEAM_IDS = ["saltmere", "greywick", "brightwater", "cinderfell", "valmere", "larkmoor", "ironport", "pinecrest", "redfern", "tarn"];
|
|
5
|
+
const part = (role, d) => ({ role, d });
|
|
6
|
+
export const MAKERS = Object.freeze({
|
|
7
|
+
arvane: {
|
|
8
|
+
id: "arvane",
|
|
9
|
+
name: "Arvane",
|
|
10
|
+
genre: "stripes",
|
|
11
|
+
note: "Nearest: the Adidas performance mark, three slanted stripes that make a triangle. Arvane is one upright triangle cut into three level bands with a notch in the base, in green and amber; there is no slanted stripe at all.",
|
|
12
|
+
parts: [
|
|
13
|
+
part("a", "M49.3 11.3Q50 10 50.7 11.3L62.8 32.7Q63.5 34 62 34L38 34Q36.5 34 37.2 32.7Z"),
|
|
14
|
+
part("b", "M32.3 41.3Q33.1 40 34.6 40L65.4 40Q66.9 40 67.7 41.3L78.6 60.7Q79.3 62 77.8 62L22.2 62Q20.7 62 21.4 60.7Z"),
|
|
15
|
+
part("a", "M16.6 69.3Q17.3 68 18.8 68L81.2 68Q82.7 68 83.4 69.3L93.3 86.7Q94 88 92.5 88L61.5 88Q60 88 58.9 86.9L51.1 79.1Q50 78 48.9 79.1L41.1 86.9Q40 88 38.5 88L7.5 88Q6 88 6.7 86.7Z"),
|
|
16
|
+
],
|
|
17
|
+
light: { a: "#0f5a46", b: "#f2a33a", ink: "#0f2f27" },
|
|
18
|
+
dark: { a: "#3fc59a", b: "#f7b955", ink: "#eaf6f1" },
|
|
19
|
+
lettering: { weight: 11, corner: "sharp", radius: 0, width: 0.8, gap: 14, slant: 0, cap: "butt" },
|
|
20
|
+
},
|
|
21
|
+
tarsin: {
|
|
22
|
+
id: "tarsin",
|
|
23
|
+
name: "Tarsin",
|
|
24
|
+
genre: "animal",
|
|
25
|
+
note: "Nearest: Orca, the triathlon and swim maker whose mark is a whole orca. Tarsin shows only the symmetrical tail fluke over two waterline bars, in indigo and cyan, and no body.",
|
|
26
|
+
parts: [
|
|
27
|
+
part("a", "M50 40C42 33 26 34 6 22C10 46 28 62 46 62L45 80L55 80L54 62C72 62 90 46 94 22C74 34 58 33 50 40Z"),
|
|
28
|
+
part("b", "M6 89Q6 86 9 86L39 86Q42 86 42 89L42 89Q42 92 39 92L9 92Q6 92 6 89Z"),
|
|
29
|
+
part("b", "M58 89Q58 86 61 86L91 86Q94 86 94 89L94 89Q94 92 91 92L61 92Q58 92 58 89Z"),
|
|
30
|
+
],
|
|
31
|
+
light: { a: "#1d2d78", b: "#3fb8cf", ink: "#141d4f" },
|
|
32
|
+
dark: { a: "#8fa2ff", b: "#5fd0e3", ink: "#e8ecff" },
|
|
33
|
+
lettering: { weight: 9, corner: "round", radius: 40, width: 1, gap: 18, slant: 0, cap: "round" },
|
|
34
|
+
},
|
|
35
|
+
ravelle: {
|
|
36
|
+
id: "ravelle",
|
|
37
|
+
name: "Ravelle",
|
|
38
|
+
genre: "motion",
|
|
39
|
+
note: "Nearest: the Nike swoosh, one tapered curve. Ravelle is a ball with two concentric arcs that taper at both ends and wrap the ball like a wake; it has no single wedge and no check shape.",
|
|
40
|
+
parts: [
|
|
41
|
+
part("b", "M49 46A17 17 0 1 0 83 46A17 17 0 1 0 49 46Z"),
|
|
42
|
+
part("a", "M61.1 73.6L59.1 73.7L57 73.5L54.9 73.2L52.9 72.6L50.9 71.9L48.9 71L47.1 69.9L45.2 68.7L43.5 67.4L41.9 65.9L40.4 64.2L39 62.5L37.8 60.6L36.7 58.6L35.8 56.5L35 54.4L34.5 52.2L34 50L33.8 47.7L33.8 45.4L33.9 43.2L34.2 40.9L34.7 38.7L35.4 36.5L36.2 34.4L37.2 32.4L38.3 30.4L39.6 28.6L41.1 26.9L42.6 25.3L44.3 23.9L46.1 22.6L47.9 21.4L49.8 20.4L51.8 19.6L53.8 18.9L55.9 18.5L58 18.2L60 18.1L62.1 18.3L62.1 18.3L60.3 19.2L58.5 20L56.8 21L55.2 22L53.7 23.1L52.2 24.2L50.9 25.5L49.7 26.8L48.5 28.2L47.4 29.6L46.5 31L45.6 32.6L44.9 34.1L44.2 35.7L43.6 37.3L43.2 38.9L42.8 40.6L42.5 42.2L42.3 43.9L42.3 45.6L42.3 47.3L42.4 48.9L42.6 50.6L42.9 52.3L43.3 53.9L43.8 55.5L44.5 57.1L45.2 58.7L46 60.3L46.9 61.8L47.9 63.2L49 64.6L50.2 66L51.5 67.3L52.9 68.5L54.4 69.6L55.9 70.7L57.6 71.7L59.3 72.6L61.1 73.6Z"),
|
|
43
|
+
part("a", "M50.6 84L48.3 83.7L46.1 83.1L43.9 82.4L41.7 81.4L39.6 80.4L37.6 79.1L35.6 77.8L33.7 76.3L31.9 74.7L30.2 73L28.6 71.1L27.2 69.2L25.8 67.1L24.6 65L23.5 62.7L22.5 60.5L21.7 58.1L21.1 55.7L20.6 53.3L20.3 50.8L20.1 48.3L20 45.8L20.2 43.4L20.5 40.9L20.9 38.5L21.5 36.1L22.3 33.7L23.2 31.4L24.2 29.2L25.4 27.1L26.7 25L28.1 23.1L29.7 21.2L31.3 19.5L33.1 17.9L34.9 16.4L36.8 15L38.8 13.8L40.9 12.8L43.1 12L43.1 12L41.7 13.8L40.3 15.6L39 17.3L37.7 19.1L36.6 20.9L35.5 22.7L34.6 24.6L33.7 26.5L33 28.4L32.3 30.3L31.7 32.2L31.2 34.1L30.8 36.1L30.4 38.1L30.2 40L30 42L29.9 43.9L30 45.9L30 47.8L30.2 49.8L30.4 51.7L30.8 53.6L31.2 55.5L31.7 57.4L32.2 59.3L32.9 61.2L33.6 63L34.4 64.8L35.3 66.6L36.3 68.4L37.3 70.1L38.5 71.8L39.7 73.5L41 75.1L42.5 76.7L43.9 78.2L45.5 79.7L47.2 81.1L48.9 82.5L50.6 84Z"),
|
|
44
|
+
],
|
|
45
|
+
light: { a: "#c41e6b", b: "#26262c", ink: "#26262c" },
|
|
46
|
+
dark: { a: "#ff5fa2", b: "#f1f1f4", ink: "#f6f6f8" },
|
|
47
|
+
lettering: { weight: 10, corner: "round", radius: 30, width: 1, gap: 12, slant: 10, cap: "round" },
|
|
48
|
+
},
|
|
49
|
+
kovreth: {
|
|
50
|
+
id: "kovreth",
|
|
51
|
+
name: "Kovreth",
|
|
52
|
+
genre: "monogram",
|
|
53
|
+
note: "Nearest: Fila, a letter in a box. Kovreth is a hexagon with the K cut out of it as negative space (a slit between the stem and the arms), in sunflower; the letter, the shape and the cut are all different.",
|
|
54
|
+
parts: [
|
|
55
|
+
part("a", "M45.7 6.5Q50 4 54.3 6.5L85.5 24.5Q89.8 27 89.8 32L89.8 68Q89.8 73 85.5 75.5L54.3 93.5Q50 96 45.7 93.5L14.5 75.5Q10.2 73 10.2 68L10.2 32Q10.2 27 14.5 24.5ZM30 29Q30 28 31 28L42 28Q43 28 43 29L43 71Q43 72 42 72L31 72Q30 72 30 71ZM47.7 50.8Q47 50 47.7 49.2L65.3 28.8Q66 28 67 28L80 28Q81 28 80.3 28.7L60.7 49.3Q60 50 60.7 50.7L80.3 71.3Q81 72 80 72L67 72Q66 72 65.3 71.2Z"),
|
|
56
|
+
],
|
|
57
|
+
light: { a: "#f2b21b", b: "#f2b21b", ink: "#221c0a" },
|
|
58
|
+
dark: { a: "#f2b21b", b: "#f2b21b", ink: "#fff5d6" },
|
|
59
|
+
lettering: { weight: 18, corner: "sharp", radius: 0, width: 0.7, gap: 5, slant: 0, cap: "butt" },
|
|
60
|
+
},
|
|
61
|
+
dunmar: {
|
|
62
|
+
id: "dunmar",
|
|
63
|
+
name: "Dunmar",
|
|
64
|
+
genre: "shield",
|
|
65
|
+
note: "Nearest: the shield badges that many kit makers and clubs use, with no single owner. Dunmar is a shield split down the middle, the right half set lower, with no letter, stripe or star, in claret and old gold.",
|
|
66
|
+
parts: [
|
|
67
|
+
part("a", "M11 10H48V94C28 84 11 72 11 50Z"),
|
|
68
|
+
part("b", "M52 18H89V50C89 72 72 84 52 94Z"),
|
|
69
|
+
],
|
|
70
|
+
light: { a: "#7a1f33", b: "#c9a24a", ink: "#4a1220" },
|
|
71
|
+
dark: { a: "#d6657d", b: "#e3c26e", ink: "#fbe9ee" },
|
|
72
|
+
lettering: { weight: 12, corner: "cut", radius: 14, width: 0.9, gap: 12, slant: 0, cap: "butt" },
|
|
73
|
+
},
|
|
74
|
+
ostrel: {
|
|
75
|
+
id: "ostrel",
|
|
76
|
+
name: "Ostrel",
|
|
77
|
+
genre: "disc",
|
|
78
|
+
note: "Nearest: The North Face, a half dome cut by curved lines. Ostrel is a whole disc cut by one straight diagonal gap into two offset pieces, in orange and navy.",
|
|
79
|
+
parts: [
|
|
80
|
+
part("a", "M20.1 73.5A42 42 0 1 1 92.2 31.9Z"),
|
|
81
|
+
part("b", "M16.6 81.5A42 42 0 0 0 87 40.9Z"),
|
|
82
|
+
],
|
|
83
|
+
light: { a: "#ee6a2c", b: "#141e3a", ink: "#141e3a" },
|
|
84
|
+
dark: { a: "#ff8a4d", b: "#8fa3d6", ink: "#f6efe9" },
|
|
85
|
+
lettering: { weight: 8, corner: "round", radius: 50, width: 1.1, gap: 22, slant: 0, cap: "round" },
|
|
86
|
+
},
|
|
87
|
+
vexlin: {
|
|
88
|
+
id: "vexlin",
|
|
89
|
+
name: "Vexlin",
|
|
90
|
+
genre: "geometry",
|
|
91
|
+
note: "Nearest: Umbro's double diamond and Hummel's chevrons, marks made of one repeated simple shape. Vexlin is three hexagons in a triangle, one a ring and one in the second colour, in violet and teal.",
|
|
92
|
+
parts: [
|
|
93
|
+
part("a", "M47.4 9.5Q50 8 52.6 9.5L65.6 17Q68.2 18.5 68.2 21.5L68.2 36.5Q68.2 39.5 65.6 41L52.6 48.5Q50 50 47.4 48.5L34.4 41Q31.8 39.5 31.8 36.5L31.8 21.5Q31.8 18.5 34.4 17ZM48.7 20.3Q50 19.5 51.3 20.3L56.9 23.5Q58.2 24.3 58.2 25.8L58.2 32.3Q58.2 33.8 56.9 34.5L51.3 37.8Q50 38.5 48.7 37.8L43.1 34.5Q41.8 33.8 41.8 32.3L41.8 25.8Q41.8 24.3 43.1 23.5Z"),
|
|
94
|
+
part("a", "M26.7 45.3Q29.3 43.8 31.9 45.3L44.9 52.8Q47.5 54.3 47.5 57.3L47.5 72.3Q47.5 75.3 44.9 76.8L31.9 84.3Q29.3 85.8 26.7 84.3L13.7 76.8Q11.1 75.3 11.1 72.3L11.1 57.3Q11.1 54.3 13.7 52.8Z"),
|
|
95
|
+
part("b", "M68.1 45.3Q70.7 43.8 73.3 45.3L86.3 52.8Q88.9 54.3 88.9 57.3L88.9 72.3Q88.9 75.3 86.3 76.8L73.3 84.3Q70.7 85.8 68.1 84.3L55.1 76.8Q52.5 75.3 52.5 72.3L52.5 57.3Q52.5 54.3 55.1 52.8Z"),
|
|
96
|
+
],
|
|
97
|
+
light: { a: "#5b2a86", b: "#19b6a2", ink: "#34195a" },
|
|
98
|
+
dark: { a: "#a77be0", b: "#36d6c0", ink: "#f1e9fb" },
|
|
99
|
+
lettering: { weight: 14, corner: "cut", radius: 18, width: 0.95, gap: 12, slant: 0, cap: "butt" },
|
|
100
|
+
},
|
|
101
|
+
quillan: {
|
|
102
|
+
id: "quillan",
|
|
103
|
+
name: "Quillan",
|
|
104
|
+
genre: "disc",
|
|
105
|
+
note: "Nearest: the BMW roundel, a circle in four quarters (not a sports mark). Quillan has convex quarter-discs set apart by a cross-shaped gap, one quarter smaller, with no ring, in teal and amber.",
|
|
106
|
+
parts: [
|
|
107
|
+
part("a", "M48 48L8 48A40 40 0 0 1 48 8Z"),
|
|
108
|
+
part("b", "M52 48L92 48A40 40 0 0 0 52 8Z"),
|
|
109
|
+
part("b", "M48 52L8 52A40 40 0 0 0 48 92Z"),
|
|
110
|
+
part("a", "M52 52L78 52A26 26 0 0 1 52 78Z"),
|
|
111
|
+
],
|
|
112
|
+
light: { a: "#12857f", b: "#f0b429", ink: "#0d4d49" },
|
|
113
|
+
dark: { a: "#3fc4bd", b: "#ffc94d", ink: "#e6f7f6" },
|
|
114
|
+
lettering: { weight: 10, corner: "round", radius: 20, width: 0.95, gap: 14, slant: 0, cap: "square" },
|
|
115
|
+
},
|
|
116
|
+
tenzar: {
|
|
117
|
+
id: "tenzar",
|
|
118
|
+
name: "Tenzar",
|
|
119
|
+
genre: "monogram",
|
|
120
|
+
note: "Nearest: the three-bar marks such as the Adidas performance logo. Tenzar is a Z of two level bars with bevelled ends joined by one diagonal slab in a second colour; the bars are not parallel and not three of a kind.",
|
|
121
|
+
parts: [
|
|
122
|
+
part("a", "M12 14Q12 12 14 12L86 12Q88 12 87.1 13.8L79.9 28.2Q79 30 77 30L14 30Q12 30 12 28Z"),
|
|
123
|
+
part("b", "M58.3 35.1Q60 34 62 34L86 34Q88 34 86.3 35.1L41.7 64.9Q40 66 38 66L14 66Q12 66 13.7 64.9Z"),
|
|
124
|
+
part("a", "M20.1 71.8Q21 70 23 70L86 70Q88 70 88 72L88 86Q88 88 86 88L14 88Q12 88 12.9 86.2Z"),
|
|
125
|
+
],
|
|
126
|
+
light: { a: "#10151d", b: "#14b7c9", ink: "#10151d" },
|
|
127
|
+
dark: { a: "#e9edf2", b: "#3fd4e4", ink: "#f2f5f8" },
|
|
128
|
+
lettering: { weight: 16, corner: "sharp", radius: 0, width: 1.1, gap: 10, slant: 14, cap: "butt" },
|
|
129
|
+
},
|
|
130
|
+
marenko: {
|
|
131
|
+
id: "marenko",
|
|
132
|
+
name: "Marenko",
|
|
133
|
+
genre: "geometry",
|
|
134
|
+
note: "Nearest: no sports maker that we know; the golden-ratio spiral is a common device in design. Marenko is four tiles, three of them quarter-discs, in gold and green.",
|
|
135
|
+
parts: [
|
|
136
|
+
part("a", "M60.1 77.5L5.1 77.5A55 55 0 0 1 60.1 22.5Z"),
|
|
137
|
+
part("b", "M63.1 54.3L63.1 22.5A31.8 31.8 0 0 1 94.9 54.3Z"),
|
|
138
|
+
part("a", "M74.7 57.3L94.9 57.3A20.2 20.2 0 0 1 74.7 77.5Z"),
|
|
139
|
+
part("b", "M63.1 57.3L71.7 57.3L71.7 77.5L63.1 77.5Z"),
|
|
140
|
+
],
|
|
141
|
+
light: { a: "#e0a100", b: "#1b8a5a", ink: "#3b2c00" },
|
|
142
|
+
dark: { a: "#f5c230", b: "#3fc78a", ink: "#fff4cc" },
|
|
143
|
+
lettering: { weight: 12, corner: "round", radius: 60, width: 0.9, gap: 14, slant: 0, cap: "round" },
|
|
144
|
+
},
|
|
145
|
+
halvane: {
|
|
146
|
+
id: "halvane",
|
|
147
|
+
name: "Halvane",
|
|
148
|
+
genre: "animal",
|
|
149
|
+
note: "Nearest: the Ram Trucks ram head (a vehicle maker, not sport) and clubs that are called Rams. Halvane is two spiral horns and a plain shield face, flat, in violet and yellow.",
|
|
150
|
+
parts: [
|
|
151
|
+
part("a", "M40.1 17.5L36.2 16.2L32.3 15.6L28.4 15.6L24.6 16.1L21 17.2L17.6 18.8L14.6 20.8L12 23.2L9.8 25.9L8 28.9L6.8 32L6 35.2L5.8 38.4L6 41.5L6.6 44.5L7.7 47.3L9.1 49.8L10.9 52.1L12.9 53.9L15.2 55.5L17.5 56.6L20 57.3L22.4 57.7L24.8 57.7L27.1 57.3L29.2 56.6L31.2 55.6L32.8 54.3L34.3 52.9L35.4 51.3L36.3 49.7L36.8 48L37.1 46.3L37.1 44.6L36.8 43.1L36.3 41.7L35.7 41.7L35.8 43L35.6 44.3L35.3 45.5L34.8 46.8L34.2 47.9L33.3 49L32.3 49.9L31.1 50.7L29.9 51.4L28.5 51.8L27.1 52.1L25.6 52.1L24.1 51.9L22.6 51.5L21.2 50.9L19.9 50.1L18.7 49L17.6 47.8L16.8 46.5L16.1 45L15.6 43.4L15.4 41.7L15.4 40L15.6 38.3L16.2 36.6L16.9 35L17.9 33.5L19.1 32.2L20.5 31L22.1 30L23.9 29.2L25.8 28.7L27.7 28.5L29.7 28.5L31.7 28.9L33.7 29.5L36.4 29.9L39.1 29.4L41.5 27.9L43.2 25.8L44 23.3L43.6 20.9L42.2 18.8ZM59.9 17.5L63.8 16.2L67.7 15.6L71.6 15.6L75.4 16.1L79 17.2L82.4 18.8L85.4 20.8L88 23.2L90.2 25.9L92 28.9L93.2 32L94 35.2L94.2 38.4L94 41.5L93.4 44.5L92.3 47.3L90.9 49.8L89.1 52.1L87.1 53.9L84.8 55.5L82.5 56.6L80 57.3L77.6 57.7L75.2 57.7L72.9 57.3L70.8 56.6L68.8 55.6L67.2 54.3L65.7 52.9L64.6 51.3L63.7 49.7L63.2 48L62.9 46.3L62.9 44.6L63.2 43.1L63.7 41.7L64.3 41.7L64.2 43L64.4 44.3L64.7 45.5L65.2 46.8L65.8 47.9L66.7 49L67.7 49.9L68.9 50.7L70.1 51.4L71.5 51.8L72.9 52.1L74.4 52.1L75.9 51.9L77.4 51.5L78.8 50.9L80.1 50.1L81.3 49L82.4 47.8L83.2 46.5L83.9 45L84.4 43.4L84.6 41.7L84.6 40L84.4 38.3L83.8 36.6L83.1 35L82.1 33.5L80.9 32.2L79.5 31L77.9 30L76.1 29.2L74.2 28.7L72.3 28.5L70.3 28.5L68.3 28.9L66.3 29.5L63.6 29.9L60.9 29.4L58.5 27.9L56.8 25.8L56 23.3L56.4 20.9L57.8 18.8Z"),
|
|
152
|
+
part("b", "M42 29Q50 23 58 29L58 54Q57 72 50 86Q43 72 42 54Z"),
|
|
153
|
+
],
|
|
154
|
+
light: { a: "#3a2a8c", b: "#f4b400", ink: "#231a5c" },
|
|
155
|
+
dark: { a: "#8f7df0", b: "#ffcb33", ink: "#efeaff" },
|
|
156
|
+
lettering: { weight: 7, corner: "sharp", radius: 0, width: 1, gap: 20, slant: 0, cap: "butt" },
|
|
157
|
+
},
|
|
158
|
+
solvik: {
|
|
159
|
+
id: "solvik",
|
|
160
|
+
name: "Solvik",
|
|
161
|
+
genre: "ball",
|
|
162
|
+
note: "Nearest: the everyday tennis-ball icon, a disc with two seam curves, which is a generic symbol and not any maker's mark. Solvik is a lime disc with two crescent seams cut out, and nothing else.",
|
|
163
|
+
parts: [
|
|
164
|
+
part("a", "M7 50A43 43 0 1 0 93 50A43 43 0 1 0 7 50ZM26 22C52 38 52 62 26 78C44 62 44 38 26 22ZM74 22C48 38 48 62 74 78C56 62 56 38 74 22Z"),
|
|
165
|
+
],
|
|
166
|
+
light: { a: "#9bc41c", b: "#9bc41c", ink: "#2a3306" },
|
|
167
|
+
dark: { a: "#b6e03a", b: "#b6e03a", ink: "#f3fbd6" },
|
|
168
|
+
lettering: { weight: 13, corner: "round", radius: 16, width: 0.85, gap: 12, slant: 0, cap: "round" },
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
export const TEAMS = Object.freeze({
|
|
172
|
+
saltmere: {
|
|
173
|
+
id: "saltmere",
|
|
174
|
+
city: "Saltmere",
|
|
175
|
+
nickname: "Gulls",
|
|
176
|
+
genre: "roundel",
|
|
177
|
+
note: "Nearest: a club that wears a whole seagull. This one is a roundel: a gull's wings cut out of the sky over a wave line.",
|
|
178
|
+
parts: [
|
|
179
|
+
part("a", "M4 50A46 46 0 1 0 96 50A46 46 0 1 0 4 50ZM9.5 50A40.5 40.5 0 1 0 90.5 50A40.5 40.5 0 1 0 9.5 50Z"),
|
|
180
|
+
part("b", "M17.1 62A35 35 0 1 1 82.9 62C72 55 62 69 50 62C38 55 28 69 17.1 62ZM26 40Q38 22 50 38Q62 22 74 40Q62 33 50 48Q38 33 26 40Z"),
|
|
181
|
+
part("a", "M19.4 67C28 60 38 74 50 67C62 74 72 60 80.6 67A35 35 0 0 1 19.4 67Z"),
|
|
182
|
+
],
|
|
183
|
+
light: { a: "#0e4a6b", b: "#8fd0e8", c: "#ffffff" },
|
|
184
|
+
dark: { a: "#3b9bc4", b: "#a9dff0", c: "#ffffff" },
|
|
185
|
+
},
|
|
186
|
+
greywick: {
|
|
187
|
+
id: "greywick",
|
|
188
|
+
city: "Greywick",
|
|
189
|
+
nickname: "Wardens",
|
|
190
|
+
genre: "crest",
|
|
191
|
+
note: "Nearest: the many castle-on-a-shield crests. This is a plain shield under a red chief with a tower cut out.",
|
|
192
|
+
parts: [
|
|
193
|
+
part("b", "M12 10L88 10L88 25L12 25Z"),
|
|
194
|
+
part("a", "M12 30H88V50C88 72 70 86 50 95C30 86 12 72 12 50ZM34 80L34 46L34 40L40 40L40 46L45 46L45 40L55 40L55 46L60 46L60 40L66 40L66 46L66 80ZM45 80V66Q50 58 55 66V80Z"),
|
|
195
|
+
],
|
|
196
|
+
light: { a: "#4a4f57", b: "#c8372d", c: "#ffffff" },
|
|
197
|
+
dark: { a: "#aeb6c2", b: "#e5594d", c: "#ffffff" },
|
|
198
|
+
},
|
|
199
|
+
brightwater: {
|
|
200
|
+
id: "brightwater",
|
|
201
|
+
city: "Brightwater",
|
|
202
|
+
nickname: "Comets",
|
|
203
|
+
genre: "monogram",
|
|
204
|
+
note: "Nearest: letter-in-a-disc club badges. A B knocked out of a violet disc, with a gold arc for the comet.",
|
|
205
|
+
parts: [
|
|
206
|
+
part("a", "M14 50A36 36 0 1 0 86 50A36 36 0 1 0 14 50ZM34 29Q34 26 37 26L53 26Q56 26 58.7 27.3L65.3 30.7Q68 32 68 35L68 42Q68 45 65.9 47.1L65.1 47.9Q63 50 65.3 52L67.7 54Q70 56 70 59L70 65Q70 68 67.5 69.7L60.5 74.3Q58 76 55 76L37 76Q34 76 34 73ZM44 36.5Q44 35 45.5 35L52.5 35Q54 35 55.2 35.9L56.8 37.1Q58 38 58 39.5L58 41.5Q58 43 56.8 43.9L55.2 45.1Q54 46 52.5 46L45.5 46Q44 46 44 44.5ZM44 56.5Q44 55 45.5 55L53.5 55Q55 55 56.2 55.9L58.8 58.1Q60 59 60 60.5L60 62.5Q60 64 58.8 64.9L56.2 67.1Q55 68 53.5 68L45.5 68Q44 68 44 66.5Z"),
|
|
207
|
+
part("b", "M9.6 35.3L10.3 31.9L11.5 28.7L13 25.5L14.7 22.4L16.8 19.5L19 16.8L21.6 14.3L24.3 11.9L27.3 9.8L30.4 7.9L33.7 6.3L37.1 5L40.6 4L44.3 3.2L47.9 2.8L51.7 2.7L55.4 2.9L59.1 3.4L62.7 4.2L66.2 5.4L69.7 6.8L73 8.5L76.2 10.5L79.1 12.7L81.9 15.2L84.4 17.9L86.8 20.8L88.8 23.8L90.6 27L92.1 30.4L93.3 33.8L94.2 37.3L94.8 40.9L95.1 44.5L95 48L94.7 51.6L94.1 55L93.2 58.4L92 61.6L90.4 64.7L90.4 64.7L90.9 61.3L91.2 58L91.3 54.7L91.2 51.4L90.9 48.2L90.3 45.1L89.5 42L88.5 39L87.3 36.1L85.9 33.3L84.3 30.6L82.5 28.1L80.6 25.7L78.4 23.5L76.2 21.4L73.8 19.5L71.3 17.8L68.7 16.3L66 15L63.2 13.8L60.3 12.9L57.4 12.2L54.4 11.6L51.3 11.3L48.3 11.3L45.3 11.4L42.2 11.7L39.2 12.3L36.2 13.1L33.3 14.1L30.4 15.3L27.6 16.8L24.9 18.4L22.3 20.3L19.8 22.4L17.5 24.6L15.3 27L13.3 29.6L11.4 32.4L9.6 35.3Z"),
|
|
208
|
+
],
|
|
209
|
+
light: { a: "#7a2a8e", b: "#f2b705", c: "#ffffff" },
|
|
210
|
+
dark: { a: "#b46ad0", b: "#ffc933", c: "#ffffff" },
|
|
211
|
+
},
|
|
212
|
+
cinderfell: {
|
|
213
|
+
id: "cinderfell",
|
|
214
|
+
city: "Cinderfell",
|
|
215
|
+
nickname: "Bears",
|
|
216
|
+
genre: "mascot",
|
|
217
|
+
note: "Nearest: the Memphis Grizzlies' bear head. This one is a flat front view built from circles, with an angry brow.",
|
|
218
|
+
parts: [
|
|
219
|
+
part("a", "M11 28A13 13 0 1 0 37 28A13 13 0 1 0 11 28Z"),
|
|
220
|
+
part("a", "M63 28A13 13 0 1 0 89 28A13 13 0 1 0 63 28Z"),
|
|
221
|
+
part("a", "M16 56A34 34 0 1 0 84 56A34 34 0 1 0 16 56ZM30 47Q30 46 30.9 46.4L43.1 51.6Q44 52 43.7 52.9L42.3 57.1Q42 58 41.1 57.7L30.9 54.3Q30 54 30 53ZM70 47Q70 46 69.1 46.4L56.9 51.6Q56 52 56.3 52.9L57.7 57.1Q58 58 58.9 57.7L69.1 54.3Q70 54 70 53ZM31 70Q50 52 69 70Q66 88 50 90Q34 88 31 70Z"),
|
|
222
|
+
part("c", "M35 71Q50 58 65 71Q63 85 50 87Q37 85 35 71ZM43 69Q50 64 57 69Q56 76 50 77Q44 76 43 69Z"),
|
|
223
|
+
],
|
|
224
|
+
light: { a: "#5a3a24", b: "#d9b27c", c: "#d9b27c" },
|
|
225
|
+
dark: { a: "#c08a5c", b: "#f0d4aa", c: "#f0d4aa" },
|
|
226
|
+
},
|
|
227
|
+
valmere: {
|
|
228
|
+
id: "valmere",
|
|
229
|
+
city: "Valmere",
|
|
230
|
+
nickname: "Hawks",
|
|
231
|
+
genre: "mascot",
|
|
232
|
+
note: "Nearest: the Atlanta Hawks' hawk head. This one is a faceted head in profile, in navy and amber.",
|
|
233
|
+
parts: [
|
|
234
|
+
part("a", "M15.2 94Q14 94 13.9 92.8L10.1 59.2Q10 58 10.3 56.8L17.7 31.2Q18 30 18.9 29.2L35.1 14.8Q36 14 37.2 13.7L58.8 8.3Q60 8 61.1 8.5L76.9 15.5Q78 16 78.7 16.9L85.3 25.1Q86 26 85 26.6L73 33.4Q72 34 72.1 35.2L72.9 48.8Q73 50 72.1 50.8L64.9 57.2Q64 58 64 59.2L64 68.8Q64 70 64.7 71L71.3 81Q72 82 71 82.7L59 91.3Q58 92 57.2 91.1L48.8 80.9Q48 80 47.2 80.9L36.8 93.1Q36 94 34.8 94ZM44 24L64 26L55 36Z"),
|
|
235
|
+
part("b", "M87 26.7Q88 26 88.6 27L96.4 41Q97 42 96.9 43.2L95.1 58.8Q95 60 94.2 59.1L86.8 50.9Q86 50 84.8 50L77.2 50Q76 50 75.9 48.8L75.1 37.2Q75 36 76 35.3Z"),
|
|
236
|
+
],
|
|
237
|
+
light: { a: "#1f3b6f", b: "#f2a900", c: "#ffffff" },
|
|
238
|
+
dark: { a: "#6f95e0", b: "#ffc233", c: "#ffffff" },
|
|
239
|
+
},
|
|
240
|
+
larkmoor: {
|
|
241
|
+
id: "larkmoor",
|
|
242
|
+
city: "Larkmoor",
|
|
243
|
+
nickname: "Foxes",
|
|
244
|
+
genre: "mascot",
|
|
245
|
+
note: "Nearest: the Fox Racing head and the Leicester City fox. This is a front-facing fox made of seven flat facets.",
|
|
246
|
+
parts: [
|
|
247
|
+
part("a", "M9.9 7.5Q10 6 11.2 6.9L36.8 27.1Q38 28 39.5 28L60.5 28Q62 28 63.2 27.1L88.8 6.9Q90 6 90.1 7.5L93.9 48.5Q94 50 92.6 50.4L67.4 57.6Q66 58 64.8 57.1L51.2 46.9Q50 46 48.8 46.9L35.2 57.1Q34 58 32.6 57.6L7.4 50.4Q6 50 6.1 48.5ZM22 38L38 40L30 47ZM78 38L62 40L70 47Z"),
|
|
248
|
+
part("b", "M9.6 57Q8.5 56 9.9 56.4L32.6 63.6Q34 64 35.2 63.1L48.8 52.9Q50 52 51.2 52.9L64.8 63.1Q66 64 67.4 63.6L90.1 56.4Q91.5 56 90.4 57L51.1 94Q50 95 48.9 94Z"),
|
|
249
|
+
part("c", "M42.6 82.8Q42 82 43 82L57 82Q58 82 57.4 82.8L50.6 91.2Q50 92 49.4 91.2Z"),
|
|
250
|
+
],
|
|
251
|
+
light: { a: "#d4561e", b: "#f4ead8", c: "#1c1c1c" },
|
|
252
|
+
dark: { a: "#f07a3d", b: "#f4ead8", c: "#ffd9c2" },
|
|
253
|
+
},
|
|
254
|
+
ironport: {
|
|
255
|
+
id: "ironport",
|
|
256
|
+
city: "Ironport",
|
|
257
|
+
nickname: "Sharks",
|
|
258
|
+
genre: "emblem",
|
|
259
|
+
note: "Nearest: the San Jose Sharks' leaping shark. This one is only a fin, in a ring, over two wave bars.",
|
|
260
|
+
parts: [
|
|
261
|
+
part("c", "M4 50A46 46 0 1 0 96 50A46 46 0 1 0 4 50ZM9 50A41 41 0 1 0 91 50A41 41 0 1 0 9 50Z"),
|
|
262
|
+
part("a", "M86 72C76 54 62 30 40 8C46 30 40 54 24 72Z"),
|
|
263
|
+
part("b", "M18.3 76C34 70 42 82 50 76C58 70 66 82 81.7 76L74.3 83C66 89 58 77 50 83C42 89 34 77 25.7 83Z"),
|
|
264
|
+
part("b", "M32.3 87C34 81 42 93 50 87C58 81 66 93 67.7 87L50 91C66 97 58 85 50 91C42 97 34 85 50 91Z"),
|
|
265
|
+
],
|
|
266
|
+
light: { a: "#233447", b: "#2fa4b8", c: "#9aa7b4" },
|
|
267
|
+
dark: { a: "#7f9bb8", b: "#3fc2d6", c: "#b8c4d0" },
|
|
268
|
+
},
|
|
269
|
+
pinecrest: {
|
|
270
|
+
id: "pinecrest",
|
|
271
|
+
city: "Pinecrest",
|
|
272
|
+
nickname: "Firs",
|
|
273
|
+
genre: "badge",
|
|
274
|
+
note: "Nearest: forestry and outdoor badges; no well-known club uses a fir. Three stacked triangles cut out of a rounded square.",
|
|
275
|
+
parts: [
|
|
276
|
+
part("a", "M10 24Q10 10 24 10L76 10Q90 10 90 24L90 76Q90 90 76 90L24 90Q10 90 10 76ZM49.6 18.7Q50 18 50.4 18.7L61.6 37.3Q62 38 61.2 38L38.8 38Q38 38 38.4 37.3ZM49.5 32.6Q50 32 50.5 32.6L67.5 53.4Q68 54 67.2 54L32.8 54Q32 54 32.5 53.4ZM49.4 48.6Q50 48 50.6 48.6L73.4 71.4Q74 72 73.2 72L26.8 72Q26 72 26.6 71.4Z"),
|
|
277
|
+
part("b", "M45 74L55 74L55 84L45 84Z"),
|
|
278
|
+
],
|
|
279
|
+
light: { a: "#14573a", b: "#8a5a2b", c: "#ffffff" },
|
|
280
|
+
dark: { a: "#3fae7c", b: "#c58b4a", c: "#ffffff" },
|
|
281
|
+
},
|
|
282
|
+
redfern: {
|
|
283
|
+
id: "redfern",
|
|
284
|
+
city: "Redfern",
|
|
285
|
+
nickname: "Rovers",
|
|
286
|
+
genre: "crest",
|
|
287
|
+
note: "Nearest: the Dallas Cowboys' star. This is a gold star set inside a red diamond ring.",
|
|
288
|
+
parts: [
|
|
289
|
+
part("a", "M46.5 7.5Q50 4 53.5 7.5L92.5 46.5Q96 50 92.5 53.5L53.5 92.5Q50 96 46.5 92.5L7.5 53.5Q4 50 7.5 46.5ZM48.6 15.4Q50 14 51.4 15.4L84.6 48.6Q86 50 84.6 51.4L51.4 84.6Q50 86 48.6 84.6L15.4 51.4Q14 50 15.4 48.6Z"),
|
|
290
|
+
part("b", "M49.5 29.4Q50 28 50.5 29.4L55.4 42.5Q55.9 43.9 57.4 44L71.3 44.5Q72.8 44.6 71.6 45.5L60.7 54.2Q59.5 55.1 59.9 56.5L63.7 70Q64.1 71.4 62.9 70.6L51.2 62.8Q50 62 48.8 62.8L37.1 70.6Q35.9 71.4 36.3 70L40.1 56.5Q40.5 55.1 39.3 54.2L28.4 45.5Q27.2 44.6 28.7 44.5L42.6 44Q44.1 43.9 44.6 42.5Z"),
|
|
291
|
+
],
|
|
292
|
+
light: { a: "#b01e2e", b: "#f0c24b", c: "#ffffff" },
|
|
293
|
+
dark: { a: "#e4505f", b: "#f6cf63", c: "#ffffff" },
|
|
294
|
+
},
|
|
295
|
+
tarn: {
|
|
296
|
+
id: "tarn",
|
|
297
|
+
city: "Tarn Valley",
|
|
298
|
+
nickname: "Peaks",
|
|
299
|
+
genre: "badge",
|
|
300
|
+
note: "Nearest: Patagonia's skyline and The North Face's half dome. Two cut-out peaks and a sun in a hexagon.",
|
|
301
|
+
parts: [
|
|
302
|
+
part("a", "M45.7 6.5Q50 4 54.3 6.5L85.5 24.5Q89.8 27 89.8 32L89.8 68Q89.8 73 85.5 75.5L54.3 93.5Q50 96 45.7 93.5L14.5 75.5Q10.2 73 10.2 68L10.2 32Q10.2 27 14.5 24.5ZM17 70Q16 70 16.6 69.2L39.4 34.8Q40 34 40.6 34.8L63.4 69.2Q64 70 63 70ZM45 70Q44 70 44.6 69.2L65.4 42.8Q66 42 66.6 42.8L87.4 69.2Q88 70 87 70Z"),
|
|
303
|
+
part("b", "M60 28A8 8 0 1 0 76 28A8 8 0 1 0 60 28Z"),
|
|
304
|
+
],
|
|
305
|
+
light: { a: "#26527a", b: "#f2c14e", c: "#ffffff" },
|
|
306
|
+
dark: { a: "#5f9bd0", b: "#f6cf63", c: "#ffffff" },
|
|
307
|
+
},
|
|
308
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** How a wordmark is lettered. */
|
|
2
|
+
export interface LetterStyle {
|
|
3
|
+
/** Stroke weight, in units of a letter 100 high. */
|
|
4
|
+
weight: number;
|
|
5
|
+
/** Corner treatment: `round` (a curve), `cut` (a straight cut) or `sharp`. */
|
|
6
|
+
corner: "round" | "cut" | "sharp";
|
|
7
|
+
/** The size of the corner, in the same units. */
|
|
8
|
+
radius: number;
|
|
9
|
+
/** Width of a letter, 1 being 60 units across. */
|
|
10
|
+
width: number;
|
|
11
|
+
/** Space between letters, in the same units. */
|
|
12
|
+
gap: number;
|
|
13
|
+
/** Lean to the right, in degrees (negative leans left). */
|
|
14
|
+
slant: number;
|
|
15
|
+
/** The ends of a stroke. */
|
|
16
|
+
cap: "butt" | "round" | "square";
|
|
17
|
+
}
|
|
18
|
+
/** The letters the alphabet draws. */
|
|
19
|
+
export declare const LETTERS: readonly string[];
|
|
20
|
+
/** A word laid out: the path of all its letters (stroked, not filled) and the box it fills. */
|
|
21
|
+
export interface Lettering {
|
|
22
|
+
d: string;
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
25
|
+
/** The stroke weight the path is to be drawn with. */
|
|
26
|
+
weight: number;
|
|
27
|
+
}
|
|
28
|
+
/** The unit height the lettering is drawn at. */
|
|
29
|
+
export declare const LETTER_HEIGHT = 100;
|
|
30
|
+
/** 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. */
|
|
31
|
+
export declare function lettering(word: string, style: LetterStyle): Lettering;
|
|
@@ -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,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
|
+
});
|