@johnmorrisdotca/dougu-sports 0.1.0 → 0.2.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.
Files changed (184) hide show
  1. package/CHANGELOG.md +38 -1
  2. package/NOTICE.md +9 -58
  3. package/README.md +168 -32
  4. package/dist/emblems/award/badge.d.ts +2 -2
  5. package/dist/emblems/award/badge.js +14 -5
  6. package/dist/emblems/award/crown.d.ts +1 -1
  7. package/dist/emblems/award/crown.js +14 -4
  8. package/dist/emblems/award/medal.d.ts +2 -2
  9. package/dist/emblems/award/medal.js +14 -5
  10. package/dist/emblems/award/shield.d.ts +1 -1
  11. package/dist/emblems/award/shield.js +10 -4
  12. package/dist/emblems/award/star.d.ts +1 -1
  13. package/dist/emblems/award/star.js +10 -4
  14. package/dist/emblems/ball/ball.afl.js +1 -1
  15. package/dist/emblems/ball/ball.basketball6.js +1 -1
  16. package/dist/emblems/ball/ball.core.d.ts +9 -3
  17. package/dist/emblems/ball/ball.core.js +13 -0
  18. package/dist/emblems/ball/ball.cricket.js +1 -1
  19. package/dist/emblems/ball/ball.engine.js +3 -3
  20. package/dist/emblems/ball/ball.football.js +3 -3
  21. package/dist/emblems/ball/ball.gaelic.js +1 -1
  22. package/dist/emblems/ball/ball.object.js +2 -2
  23. package/dist/emblems/ball/ball.shuttlecock.js +2 -2
  24. package/dist/emblems/ball/ball.squash.js +5 -5
  25. package/dist/emblems/emblem.api.d.ts +39 -1
  26. package/dist/emblems/emblem.api.js +20 -2
  27. package/dist/emblems/emblem.compose.d.ts +31 -0
  28. package/dist/emblems/emblem.compose.js +91 -0
  29. package/dist/emblems/emblem.core.d.ts +48 -2
  30. package/dist/emblems/emblem.core.js +30 -0
  31. package/dist/emblems/emblem.descriptions.d.ts +7 -0
  32. package/dist/emblems/emblem.descriptions.js +60 -0
  33. package/dist/emblems/emblem.display.d.ts +75 -0
  34. package/dist/emblems/emblem.display.js +214 -0
  35. package/dist/emblems/emblem.engrave.d.ts +50 -0
  36. package/dist/emblems/emblem.engrave.js +145 -0
  37. package/dist/emblems/emblem.equipment.d.ts +24 -0
  38. package/dist/emblems/emblem.equipment.js +57 -0
  39. package/dist/emblems/emblem.flip.d.ts +10 -0
  40. package/dist/emblems/emblem.flip.js +45 -0
  41. package/dist/emblems/emblem.ids.d.ts +19 -11
  42. package/dist/emblems/emblem.ids.js +21 -6
  43. package/dist/emblems/emblem.lathe.d.ts +3 -0
  44. package/dist/emblems/emblem.lathe.js +26 -4
  45. package/dist/emblems/emblem.medal.js +4 -4
  46. package/dist/emblems/emblem.pennant.d.ts +3 -0
  47. package/dist/emblems/emblem.pennant.js +79 -0
  48. package/dist/emblems/emblem.registry.js +20 -0
  49. package/dist/emblems/emblem.shapes.d.ts +19 -2
  50. package/dist/emblems/emblem.shapes.js +53 -12
  51. package/dist/emblems/emblem.sprite.d.ts +38 -0
  52. package/dist/emblems/emblem.sprite.js +65 -0
  53. package/dist/emblems/emblem.uri.d.ts +22 -0
  54. package/dist/emblems/emblem.uri.js +29 -0
  55. package/dist/emblems/gear/gear.badmintonracket.d.ts +1 -1
  56. package/dist/emblems/gear/gear.badmintonracket.js +18 -14
  57. package/dist/emblems/gear/gear.baseballglove.d.ts +1 -1
  58. package/dist/emblems/gear/gear.baseballglove.js +20 -14
  59. package/dist/emblems/gear/gear.budo.d.ts +17 -0
  60. package/dist/emblems/gear/gear.budo.js +60 -0
  61. package/dist/emblems/gear/gear.core.d.ts +12 -31
  62. package/dist/emblems/gear/gear.core.js +61 -54
  63. package/dist/emblems/gear/gear.cricketbat.d.ts +1 -1
  64. package/dist/emblems/gear/gear.cricketbat.js +16 -14
  65. package/dist/emblems/gear/gear.fieldhockeystick.d.ts +1 -1
  66. package/dist/emblems/gear/gear.fieldhockeystick.js +15 -14
  67. package/dist/emblems/gear/gear.footballhelmet.d.ts +1 -1
  68. package/dist/emblems/gear/gear.footballhelmet.js +15 -14
  69. package/dist/emblems/gear/gear.goaliemask.d.ts +1 -1
  70. package/dist/emblems/gear/gear.goaliemask.js +22 -16
  71. package/dist/emblems/gear/gear.goalnet.d.ts +1 -1
  72. package/dist/emblems/gear/gear.goalnet.js +24 -14
  73. package/dist/emblems/gear/gear.hockeystick.d.ts +1 -1
  74. package/dist/emblems/gear/gear.hockeystick.js +14 -14
  75. package/dist/emblems/gear/gear.index.js +5 -1
  76. package/dist/emblems/gear/gear.kendo.d.ts +2 -0
  77. package/dist/emblems/gear/gear.kendo.js +41 -0
  78. package/dist/emblems/gear/gear.kyudo.d.ts +2 -0
  79. package/dist/emblems/gear/gear.kyudo.js +31 -0
  80. package/dist/emblems/gear/gear.lacrossestick.d.ts +1 -1
  81. package/dist/emblems/gear/gear.lacrossestick.js +25 -14
  82. package/dist/emblems/gear/gear.skates.js +1 -1
  83. package/dist/emblems/gear/gear.sticks.js +2 -2
  84. package/dist/emblems/gear/gear.sumo.d.ts +2 -0
  85. package/dist/emblems/gear/gear.sumo.js +43 -0
  86. package/dist/emblems/gear/gear.tabletennispaddle.d.ts +1 -1
  87. package/dist/emblems/gear/gear.tabletennispaddle.js +15 -14
  88. package/dist/emblems/gear/gear.tennisracket.d.ts +1 -1
  89. package/dist/emblems/gear/gear.tennisracket.js +16 -14
  90. package/dist/emblems/pennant/championship.d.ts +2 -0
  91. package/dist/emblems/pennant/championship.js +4 -0
  92. package/dist/emblems/sport/afl.js +1 -1
  93. package/dist/emblems/sport/artisticswimming.js +1 -1
  94. package/dist/emblems/sport/cfl.d.ts +1 -1
  95. package/dist/emblems/sport/cfl.js +4 -4
  96. package/dist/emblems/sport/cricket.d.ts +1 -1
  97. package/dist/emblems/sport/cricket.js +13 -4
  98. package/dist/emblems/sport/fieldhockey.js +1 -1
  99. package/dist/emblems/sport/gaelic.js +1 -1
  100. package/dist/emblems/sport/handball.d.ts +1 -1
  101. package/dist/emblems/sport/handball.js +14 -4
  102. package/dist/emblems/sport/ifaf.d.ts +1 -1
  103. package/dist/emblems/sport/ifaf.js +4 -4
  104. package/dist/emblems/sport/judo.d.ts +2 -0
  105. package/dist/emblems/sport/judo.js +13 -0
  106. package/dist/emblems/sport/karate.d.ts +2 -0
  107. package/dist/emblems/sport/karate.js +13 -0
  108. package/dist/emblems/sport/kendo.d.ts +2 -0
  109. package/dist/emblems/sport/kendo.js +14 -0
  110. package/dist/emblems/sport/kyudo.d.ts +2 -0
  111. package/dist/emblems/sport/kyudo.js +15 -0
  112. package/dist/emblems/sport/mlb.d.ts +1 -1
  113. package/dist/emblems/sport/mlb.js +27 -4
  114. package/dist/emblems/sport/nba.d.ts +1 -1
  115. package/dist/emblems/sport/nba.js +11 -4
  116. package/dist/emblems/sport/netball.js +1 -1
  117. package/dist/emblems/sport/nfl.d.ts +2 -1
  118. package/dist/emblems/sport/nfl.js +14 -4
  119. package/dist/emblems/sport/nhl.d.ts +1 -1
  120. package/dist/emblems/sport/nhl.js +12 -4
  121. package/dist/emblems/sport/pickleball.js +1 -1
  122. package/dist/emblems/sport/racquetball.js +1 -1
  123. package/dist/emblems/sport/roundnet.js +1 -1
  124. package/dist/emblems/sport/rugby.d.ts +1 -1
  125. package/dist/emblems/sport/rugby.js +11 -4
  126. package/dist/emblems/sport/sepaktakraw.js +1 -1
  127. package/dist/emblems/sport/soccer.d.ts +1 -1
  128. package/dist/emblems/sport/soccer.js +30 -4
  129. package/dist/emblems/sport/squash.js +1 -1
  130. package/dist/emblems/sport/sumo.d.ts +2 -0
  131. package/dist/emblems/sport/sumo.js +15 -0
  132. package/dist/emblems/sport/tabletennis.js +1 -1
  133. package/dist/emblems/sport/tennis.d.ts +1 -1
  134. package/dist/emblems/sport/tennis.js +14 -4
  135. package/dist/emblems/sport/teqball.js +1 -1
  136. package/dist/emblems/sport/volleyball.d.ts +1 -1
  137. package/dist/emblems/sport/volleyball.js +24 -4
  138. package/dist/emblems/trophy/banner.d.ts +2 -0
  139. package/dist/emblems/trophy/banner.js +20 -0
  140. package/dist/emblems/trophy/baseball.js +1 -0
  141. package/dist/emblems/trophy/basketball.js +1 -0
  142. package/dist/emblems/trophy/belt.js +2 -1
  143. package/dist/emblems/trophy/bowl.js +1 -0
  144. package/dist/emblems/trophy/canadian-bowl.js +1 -0
  145. package/dist/emblems/trophy/championship-banner.d.ts +2 -0
  146. package/dist/emblems/trophy/championship-banner.js +67 -0
  147. package/dist/emblems/trophy/cricket-urn.js +1 -0
  148. package/dist/emblems/trophy/cup.d.ts +1 -1
  149. package/dist/emblems/trophy/cup.js +15 -4
  150. package/dist/emblems/trophy/football.js +2 -1
  151. package/dist/emblems/trophy/globe.js +1 -0
  152. package/dist/emblems/trophy/hockey-cup.js +2 -1
  153. package/dist/emblems/trophy/lidded-cup.js +1 -0
  154. package/dist/emblems/trophy/plaque.js +2 -1
  155. package/dist/emblems/trophy/ring.d.ts +2 -0
  156. package/dist/emblems/trophy/ring.js +30 -0
  157. package/dist/emblems/trophy/rugby-cup.js +1 -0
  158. package/dist/emblems/trophy/salver.js +1 -0
  159. package/dist/emblems/trophy/soccer-ball.js +2 -1
  160. package/dist/emblems/trophy/soccer-globe.js +1 -0
  161. package/dist/emblems/trophy/sumo-cup.d.ts +2 -0
  162. package/dist/emblems/trophy/sumo-cup.js +28 -0
  163. package/dist/emblems/trophy/tennis-cup.js +2 -1
  164. package/dist/emblems/trophy/tennis-plate.js +1 -0
  165. package/dist/emblems-entry.d.ts +15 -6
  166. package/dist/emblems-entry.js +7 -2
  167. package/dist/index.d.ts +17 -0
  168. package/dist/index.js +15 -0
  169. package/dist/turn-control.d.ts +101 -0
  170. package/dist/turn-control.js +363 -0
  171. package/dist/turn-entry.d.ts +2 -0
  172. package/dist/turn-entry.js +1 -0
  173. package/dist/version.d.ts +1 -1
  174. package/dist/version.js +1 -1
  175. package/package.json +7 -1
  176. package/LICENSES/Apache-2.0.txt +0 -202
  177. package/LICENSES/CC-BY-3.0.txt +0 -319
  178. package/LICENSES/upstream/game-icons.license.txt +0 -45
  179. package/LICENSES/upstream/noto-emoji-2D-svg.LICENSE +0 -13
  180. package/LICENSES/upstream/pictogrammers-mdi.LICENSE +0 -20
  181. package/dist/emblems/emblem.material.d.ts +0 -9
  182. package/dist/emblems/emblem.material.data.d.ts +0 -34
  183. package/dist/emblems/emblem.material.data.js +0 -85
  184. package/dist/emblems/emblem.material.js +0 -23
@@ -1,7 +1,9 @@
1
1
  // A flat object or an icon: a list of shapes, each with a role (the metal, its shade, a glint, a second colour, a fixed colour, ink, a line), drawn with gradients in the metal style, in flat fills in the
2
2
  // `color` style and as one outline in the `line` style. A flat object (a medal, a crest, a plaque) also has a back face and a rim, so the turning view flips it like a coin; an icon (a sport's pictogram)
3
3
  // is drawn as it is. Imports only the core.
4
- import { bevelGradient, defsOf, degrees, escape, hexOf, mainOf, mix, n2, onColour, orbGradient, readColour, resolve, sheetGradient, wrap, } from "./emblem.core.js";
4
+ import { bevelGradient, defsOf, degrees, escape, hexOf, labelled, mainOf, mix, n2, onColour, orbGradient, readColour, resolve, sheetGradient, wrap, } from "./emblem.core.js";
5
+ import { engravingOf, linesOf, plateMarkup } from "./emblem.engrave.js";
6
+ import { flipSvg } from "./emblem.flip.js";
5
7
  const use = (ctx, g) => {
6
8
  ctx.used.push(g);
7
9
  return g.fill;
@@ -55,14 +57,28 @@ function letters(model, ctx) {
55
57
  const fs = n === 1 ? size : n === 2 ? size * 0.82 : size * 0.64;
56
58
  return `<text x="${x}" y="${n2(y + fs * 0.36)}" font-size="${n2(fs)}" font-weight="800" font-family="system-ui,sans-serif" text-anchor="middle" fill="${ctx.style === "line" ? "currentColor" : onColour(ctx.main)}" stroke="none">${escape(ctx.initials)}</text>`;
57
59
  }
58
- /** One face of an object as markup. */
59
- function face(model, shapes, ctx) {
60
+ /** The lines cut into the face on `side`, as markup, or an empty string when there is nothing to cut or nowhere to cut it. */
61
+ function engraved(model, ctx, side) {
62
+ const e = ctx.engrave;
63
+ const plates = model.engrave;
64
+ if (plates === undefined)
65
+ return "";
66
+ if (side === "back")
67
+ return plates.back === undefined || e.back === undefined ? "" : plateMarkup(linesOf({ free: e.back }).main, plates.back, ctx.main, ctx.style);
68
+ if (e.free === undefined && e.label === undefined && e.year === undefined && e.rank === undefined)
69
+ return "";
70
+ const { main, year } = linesOf(e, { rank: plates.rank, yearApart: plates.year !== undefined });
71
+ return plateMarkup(main, plates.front, ctx.main, ctx.style) + (year === undefined || plates.year === undefined ? "" : plateMarkup([[{ text: year, weight: 1 }]], plates.year, ctx.main, ctx.style));
72
+ }
73
+ /** One face of an object as markup: its shapes (the ones an engraving replaces left out when there is one), then the engraving, and a crest's letters. */
74
+ function face(model, shapes, ctx, text = "") {
75
+ const shown = shapes.filter((x) => text === "" || x[0] === x[0].toLowerCase()).map((x) => (x[0] === x[0].toLowerCase() ? x : [x[0].toLowerCase(), x[1], x[2]]));
60
76
  const blank = ctx.initials === "" && model.blank !== undefined ? shapesMarkup(model.blank, ctx) : "";
61
- return shapesMarkup(shapes, ctx) + blank + letters(model, ctx);
77
+ return shapesMarkup(shown, ctx) + blank + letters(model, ctx) + text;
62
78
  }
63
79
  function context(model, r) {
64
80
  const main = r.tint ?? (model.color === undefined ? mainOf(model.metal, undefined) : readColour(model.color));
65
- return { main, style: r.style, sheet: sheetGradient(main), orb: orbGradient(main), bevel: bevelGradient(main), ribbon: r.accent ?? model.ribbon ?? "#c0392b", initials: r.initials, used: [] };
81
+ return { main, style: r.style, sheet: sheetGradient(main), orb: orbGradient(main), bevel: bevelGradient(main), ribbon: r.accent ?? model.ribbon ?? "#c0392b", initials: r.initials, engrave: {}, used: [] };
66
82
  }
67
83
  function document(title, model, r, ctx, body) {
68
84
  return wrap({ title, size: r.size, style: r.style, theme: r.theme, defs: r.style === "metal" ? defsOf(ctx.used) : "", body, box: model.box, edge: model.ink === true ? undefined : mix(ctx.main, -0.5), width: model.ink === true ? undefined : 0.8 });
@@ -72,8 +88,9 @@ export function defineFlat(id, en, ja, source, model) {
72
88
  const draw = (o, yaw, pitch) => {
73
89
  const r = resolve(o);
74
90
  const ctx = context(model, r);
91
+ ctx.engrave = engravingOf(o);
75
92
  if (yaw === 0 && pitch === 0)
76
- return document(en, model, r, ctx, face(model, model.front, ctx));
93
+ return document(en, model, r, ctx, face(model, model.front, ctx, engraved(model, ctx, "front")));
77
94
  const across = Math.cos((yaw * Math.PI) / 180);
78
95
  const tilt = Math.cos((pitch * Math.PI) / 180);
79
96
  const shown = across >= 0 ? model.front : (model.back ?? model.front.filter((x) => x[0] === "m" || x[0] === "o" || x[0] === "s"));
@@ -82,18 +99,19 @@ export function defineFlat(id, en, ja, source, model) {
82
99
  const rim = (model.rim ?? 0) * Math.sin((yaw * Math.PI) / 180);
83
100
  const [x0, y0, w, h] = (model.box ?? "0 0 64 64").split(" ").map(Number);
84
101
  const thick = rim === 0 ? "" : `<g transform="translate(${n2(rim)} 0)">${shapesMarkup(model.front.filter((x) => x[0] === "m" || x[0] === "o").map((x) => ["s", x[1]]), ctx)}</g>`;
85
- return document(en, model, r, ctx, `<g transform="translate(${n2(x0 + w / 2)} ${n2(y0 + h / 2)}) scale(${n2(sx)} ${n2(sy)}) translate(${n2(-x0 - w / 2)} ${n2(-y0 - h / 2)})">${thick}${face(model, shown, ctx)}</g>`);
102
+ return document(en, model, r, ctx, `<g transform="translate(${n2(x0 + w / 2)} ${n2(y0 + h / 2)}) scale(${n2(sx)} ${n2(sy)}) translate(${n2(-x0 - w / 2)} ${n2(-y0 - h / 2)})">${thick}${face(model, shown, ctx, engraved(model, ctx, across >= 0 ? "front" : "back"))}</g>`);
86
103
  };
87
- return { id, en, ja, source, kind: "flat", model, svg: (o) => draw(o, 0, 0), frame: (o) => draw(o, degrees(o?.yaw), degrees(o?.pitch)) };
104
+ return { id, en, ja, source, kind: "flat", model, svg: labelled(en, ja, (o) => draw(o, 0, 0)), frame: labelled(en, ja, (o) => draw(o, degrees(o?.yaw), degrees(o?.pitch))) };
88
105
  }
89
- /** An icon: one drawing from shapes, which is not turned. */
106
+ /** An icon: one drawing from shapes. Turned, it is a thin cut-out: it squeezes like a coin, shows its front mirrored and a little darker past a quarter turn, and has a dark rim. */
90
107
  export function defineIcon(id, en, ja, source, model) {
91
- const svg = (o) => {
108
+ const svg = labelled(en, ja, (o) => {
92
109
  const r = resolve(o);
93
110
  const ctx = context(model, r);
94
111
  return document(en, model, r, ctx, face(model, model.front, ctx));
95
- };
96
- return { id, en, ja, source, kind: "icon", model, svg, frame: svg };
112
+ });
113
+ const frame = (o) => flipSvg(svg(o), { yaw: degrees(o?.yaw), pitch: degrees(o?.pitch), line: o?.style === "line", thick: 0.03 });
114
+ return { id, en, ja, source, kind: "icon", model, svg, frame: labelled(en, ja, frame) };
97
115
  }
98
116
  /** A circle as a path, so every shape is one kind of thing. */
99
117
  export const circlePath = (cx, cy, r) => `M${n2(cx - r)} ${n2(cy)}a${n2(r)} ${n2(r)} 0 1 0 ${n2(2 * r)} 0a${n2(r)} ${n2(r)} 0 1 0 ${n2(-2 * r)} 0Z`;
@@ -109,3 +127,26 @@ export function starPath(cx, cy, outer, inner, points = 5) {
109
127
  }
110
128
  return `${parts.join("")}Z`;
111
129
  }
130
+ /** A regular polygon of `n` sides with a corner at `deg` degrees (0 is straight up), as a path. */
131
+ export function polygon(cx, cy, r, n, deg = 0) {
132
+ let d = "";
133
+ for (let i = 0; i < n; i++) {
134
+ const a = ((deg + (360 * i) / n - 90) * Math.PI) / 180;
135
+ d += `${i === 0 ? "M" : "L"}${n2(cx + r * Math.cos(a))} ${n2(cy + r * Math.sin(a))}`;
136
+ }
137
+ return `${d}Z`;
138
+ }
139
+ /** An ellipse turned `deg` degrees about its centre, as a path. */
140
+ export function tiltedEllipse(cx, cy, rx, ry, deg) {
141
+ const a = (deg * Math.PI) / 180;
142
+ const x = rx * Math.cos(a);
143
+ const y = rx * Math.sin(a);
144
+ return `M${n2(cx - x)} ${n2(cy - y)}A${n2(rx)} ${n2(ry)} ${deg} 1 1 ${n2(cx + x)} ${n2(cy + y)}A${n2(rx)} ${n2(ry)} ${deg} 1 1 ${n2(cx - x)} ${n2(cy - y)}Z`;
145
+ }
146
+ /** A bar with square ends from one point to another, `w` wide, as a path. */
147
+ export function bar(x1, y1, x2, y2, w) {
148
+ const l = Math.hypot(x2 - x1, y2 - y1) || 1;
149
+ const nx = (-(y2 - y1) / l) * (w / 2);
150
+ const ny = ((x2 - x1) / l) * (w / 2);
151
+ return `M${n2(x1 + nx)} ${n2(y1 + ny)}L${n2(x2 + nx)} ${n2(y2 + ny)}L${n2(x2 - nx)} ${n2(y2 - ny)}L${n2(x1 - nx)} ${n2(y1 - ny)}Z`;
152
+ }
@@ -0,0 +1,38 @@
1
+ import { type EmblemLocale, type EmblemOptions } from "./emblem.core.ts";
2
+ import { type EmblemRef } from "./emblem.api.ts";
3
+ /** What `emblemSprite` takes: the options every symbol is drawn with, and the prefix of its ids. */
4
+ export interface SpriteOptions extends EmblemOptions {
5
+ /** The start of every id in the sheet (letters, digits and hyphens, starting with a letter). By default it is made from the emblems and the options, so the same call gives the same sheet. */
6
+ prefix?: string;
7
+ }
8
+ /** What one `<use>` takes. */
9
+ export interface UseOptions {
10
+ /** The width and height in pixels (64 by default). */
11
+ size?: number;
12
+ /** A class for the `<svg>` that holds the `<use>`. */
13
+ class?: string;
14
+ /** The `<title>`: a string writes that title, `false` drops it and hides the drawing from a screen reader. By default it is the emblem's name. */
15
+ title?: string | false;
16
+ /** The language of the default title, `"en"` or `"ja"`. */
17
+ locale?: EmblemLocale;
18
+ }
19
+ /** A sheet of symbols and the snippets that draw them. */
20
+ export interface Sprite {
21
+ /** One hidden `<svg>` of `<symbol>`s; put it once in the page, anywhere in `<body>`. */
22
+ sheet: string;
23
+ /** The markup for one use of a symbol: `<svg><title>…</title><use href="#…"/></svg>`. The emblem must be one the sprite was made with. */
24
+ use: (ref: EmblemRef, options?: UseOptions) => string;
25
+ }
26
+ /**
27
+ * A sprite sheet: every emblem in `ids` drawn once as a `<symbol>`, with the gradients and other definitions shared and every id unique across the sheet, and a `use(id, { size, class, title })` that returns the
28
+ * markup for one more of it. Put `sheet` in the page once; a bracket or a table that shows the same ball or medal fifty times then adds a few nodes each time, not the whole drawing. The symbols are drawn without the
29
+ * grain a large ball has by default (pass `grain: true` to keep it). `style`, `tint`, `accent` and `theme` are the sheet's, for every symbol; a different look is another sprite, or an id that names its style (`"medal:gold/line"`).
30
+ * @example
31
+ * ```ts
32
+ * import { emblemSprite } from "@johnmorrisdotca/dougu-sports/emblems";
33
+ * const sprite = emblemSprite(["ball:soccer", "medal:gold"]);
34
+ * console.log(sprite.use("ball:soccer", { size: 24 }).startsWith("<svg"));
35
+ * // true
36
+ * ```
37
+ */
38
+ export declare function emblemSprite(ids: readonly EmblemRef[], options?: SpriteOptions): Sprite;
@@ -0,0 +1,65 @@
1
+ // A sheet of symbols: each emblem drawn once, then used as many times as a page wants it with a `<use>` that costs a few nodes and a few dozen bytes.
2
+ import { EMBLEM_INK, escape, resolve } from "./emblem.core.js";
3
+ import { emblemOf, parseEmblem, renderEmblem } from "./emblem.api.js";
4
+ import { IdSpace, partsOf } from "./emblem.compose.js";
5
+ const hash = (text) => {
6
+ let h = 2166136261;
7
+ for (let i = 0; i < text.length; i++)
8
+ h = Math.imul(h ^ text.charCodeAt(i), 16777619);
9
+ return (h >>> 0).toString(36);
10
+ };
11
+ /** The key a reference goes by in a sprite: the id, and the style when the reference names one. */
12
+ function keyOf(ref) {
13
+ if (typeof ref !== "string")
14
+ return ref.id;
15
+ const parsed = parseEmblem(ref);
16
+ if (parsed === undefined)
17
+ throw new Error(`Unknown emblem "${ref.slice(0, 60)}". Ids look like "ball:soccer" or "medal:gold/line"; see EMBLEM_IDS.`);
18
+ return parsed.style === undefined ? parsed.id : `${parsed.id}/${parsed.style}`;
19
+ }
20
+ /**
21
+ * A sprite sheet: every emblem in `ids` drawn once as a `<symbol>`, with the gradients and other definitions shared and every id unique across the sheet, and a `use(id, { size, class, title })` that returns the
22
+ * markup for one more of it. Put `sheet` in the page once; a bracket or a table that shows the same ball or medal fifty times then adds a few nodes each time, not the whole drawing. The symbols are drawn without the
23
+ * grain a large ball has by default (pass `grain: true` to keep it). `style`, `tint`, `accent` and `theme` are the sheet's, for every symbol; a different look is another sprite, or an id that names its style (`"medal:gold/line"`).
24
+ * @example
25
+ * ```ts
26
+ * import { emblemSprite } from "@johnmorrisdotca/dougu-sports/emblems";
27
+ * const sprite = emblemSprite(["ball:soccer", "medal:gold"]);
28
+ * console.log(sprite.use("ball:soccer", { size: 24 }).startsWith("<svg"));
29
+ * // true
30
+ * ```
31
+ */
32
+ export function emblemSprite(ids, options) {
33
+ const keys = [...new Set(ids.map(keyOf))];
34
+ const { prefix: asked, ...drawn } = options ?? {};
35
+ const prefix = typeof asked === "string" && /^[A-Za-z][\w-]{0,31}$/.test(asked) ? asked : `dgs${hash(`${keys.join(",")}|${JSON.stringify(drawn)}`)}`;
36
+ const theme = drawn.theme === "dark" || drawn.theme === "light" || drawn.theme === "auto" ? drawn.theme : "inherit";
37
+ const space = new IdSpace(prefix);
38
+ const symbols = [];
39
+ const symbolOf = new Map();
40
+ for (const key of keys) {
41
+ const svg = renderEmblem(key, { ...drawn, theme: "inherit", title: false, locale: undefined, grain: drawn.grain ?? false });
42
+ const parts = partsOf(svg);
43
+ const name = `${prefix}-${key.replace(/[^a-z0-9]+/gi, "-").toLowerCase()}`;
44
+ symbolOf.set(key, name);
45
+ symbols.push(`<symbol id="${name}" viewBox="${escape(parts.box)}">${space.add(parts)}</symbol>`);
46
+ }
47
+ const rule = theme === "auto" ? `<style>@media(prefers-color-scheme:dark){svg.${prefix}{color:${EMBLEM_INK.dark}}}</style>` : "";
48
+ const sheet = `<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" style="position:absolute;width:0;height:0;overflow:hidden" aria-hidden="true" focusable="false">` +
49
+ `${rule}${space.defs.length === 0 ? "" : `<defs>${space.defs.join("")}</defs>`}${symbols.join("")}</svg>`;
50
+ const color = theme === "dark" ? EMBLEM_INK.dark : theme === "light" ? EMBLEM_INK.light : "";
51
+ const use = (ref, o) => {
52
+ const key = keyOf(ref);
53
+ const symbol = symbolOf.get(key);
54
+ if (symbol === undefined)
55
+ throw new Error(`"${key}" is not in this sprite; it holds ${keys.slice(0, 8).join(", ")}${keys.length > 8 ? ", …" : ""}.`);
56
+ const size = resolve({ size: o?.size }).size;
57
+ const classes = [theme === "auto" ? prefix : "", typeof o?.class === "string" ? o.class.trim() : ""].filter(Boolean).join(" ");
58
+ const { emblem } = emblemOf(ref);
59
+ const title = o?.title === false ? false : typeof o?.title === "string" && o.title.trim() !== "" ? o.title.trim().slice(0, 300) : o?.locale === "ja" ? emblem.ja : emblem.en;
60
+ const lang = o?.locale === "ja" && typeof o?.title !== "string" ? ' lang="ja"' : "";
61
+ return (`<svg width="${size}" height="${size}"${title === false ? ' aria-hidden="true"' : ` role="img"${lang}`}${classes === "" ? "" : ` class="${escape(classes)}"`}${color === "" ? "" : ` color="${color}"`}>` +
62
+ `${title === false ? "" : `<title>${escape(title)}</title>`}<use href="#${symbol}"/></svg>`);
63
+ };
64
+ return { sheet, use };
65
+ }
@@ -0,0 +1,22 @@
1
+ import { type EmblemOptions } from "./emblem.core.ts";
2
+ import { type EmblemRef } from "./emblem.api.ts";
3
+ /** What `emblemDataUri` takes: the emblem's options, and the colour of the line. */
4
+ export interface DataUriOptions extends EmblemOptions {
5
+ /** The colour of the outline and of anything drawn in the ink: `#rgb`, `#rrggbb` or `rgb()`. It wins over `theme`. Anything else is ignored. */
6
+ color?: string;
7
+ }
8
+ /** Text as the body of a data address: every character that could end an attribute, a quoted `url()` or an unquoted one is percent-encoded, and the rest is left alone. */
9
+ export declare function encodeSvg(svg: string): string;
10
+ /**
11
+ * An emblem as a data address, `data:image/svg+xml;utf8,…`, with every character that could break an attribute or a CSS `url()` percent-encoded, so the string goes anywhere: `img.src`, `background-image:
12
+ * url("…")`, `new Image().src` for a canvas. The ink is settled for you, because `currentColor` does not cross an `<img>` boundary: `color` is the line's colour; without it `theme: "dark"` is pale ink, and `"light"`
13
+ * and `"inherit"` (the default) are dark ink. `theme: "auto"` keeps the page's colour scheme (`prefers-color-scheme`) in the image.
14
+ * @example
15
+ * ```ts
16
+ * import { emblemDataUri } from "@johnmorrisdotca/dougu-sports/emblems";
17
+ * const src = emblemDataUri("medal:gold", { size: 48 });
18
+ * console.log(src.startsWith("data:image/svg+xml;utf8,%3Csvg"));
19
+ * // true
20
+ * ```
21
+ */
22
+ export declare function emblemDataUri(ref: EmblemRef, options?: DataUriOptions): string;
@@ -0,0 +1,29 @@
1
+ // An emblem as a data address, for an `<img>`, a CSS background or a canvas. An image cannot inherit its page's text colour, so the colour is settled here: the line style, a pictogram and a Material
2
+ // icon are drawn in `currentColor`, and that becomes a concrete colour.
3
+ import { EMBLEM_INK, hexOf, readColour } from "./emblem.core.js";
4
+ import { renderEmblem } from "./emblem.api.js";
5
+ /** Text as the body of a data address: every character that could end an attribute, a quoted `url()` or an unquoted one is percent-encoded, and the rest is left alone. */
6
+ export function encodeSvg(svg) {
7
+ return encodeURIComponent(svg).replace(/%(3A|2F|2C|3B|3D|40)/g, (_, hex) => String.fromCharCode(parseInt(hex, 16))).replace(/['()*!]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
8
+ }
9
+ /**
10
+ * An emblem as a data address, `data:image/svg+xml;utf8,…`, with every character that could break an attribute or a CSS `url()` percent-encoded, so the string goes anywhere: `img.src`, `background-image:
11
+ * url("…")`, `new Image().src` for a canvas. The ink is settled for you, because `currentColor` does not cross an `<img>` boundary: `color` is the line's colour; without it `theme: "dark"` is pale ink, and `"light"`
12
+ * and `"inherit"` (the default) are dark ink. `theme: "auto"` keeps the page's colour scheme (`prefers-color-scheme`) in the image.
13
+ * @example
14
+ * ```ts
15
+ * import { emblemDataUri } from "@johnmorrisdotca/dougu-sports/emblems";
16
+ * const src = emblemDataUri("medal:gold", { size: 48 });
17
+ * console.log(src.startsWith("data:image/svg+xml;utf8,%3Csvg"));
18
+ * // true
19
+ * ```
20
+ */
21
+ export function emblemDataUri(ref, options) {
22
+ const { color, ...rest } = options ?? {};
23
+ const picked = readColour(color);
24
+ const ink = picked !== undefined ? hexOf(picked) : rest.theme === "dark" ? EMBLEM_INK.dark : rest.theme === "auto" ? undefined : EMBLEM_INK.light;
25
+ let svg = renderEmblem(ref, { ...rest, theme: ink === undefined ? "auto" : "inherit" });
26
+ // `currentColor` becomes the ink. A drawing that asked for `auto` keeps its colour-scheme rule, with the dark ink as its light default.
27
+ svg = ink === undefined ? svg.replace("<style>@media", `<style>svg{color:${EMBLEM_INK.light}}@media`) : svg.replace(/currentColor/g, ink);
28
+ return `data:image/svg+xml;utf8,${encodeSvg(svg)}`;
29
+ }
@@ -1 +1 @@
1
- export declare const GEAR_BADMINTON_RACKET: import("./gear.index.ts").Piece<import("./gear.core.ts").CopiedSpec>;
1
+ export declare const GEAR_BADMINTON_RACKET: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
@@ -1,15 +1,19 @@
1
- // Gear: Badminton racket and shuttlecock. Copied, with changes, from Noto Emoji `2D/svg/emoji_u1f3f8.svg` (googlefonts/noto-emoji at e20cbc2bbec1926686be9f9bee7d1d2cfa1fea0e), Apache-2.0, Copyright 2013 Google, Inc. All Rights Reserved..
2
- // SHA-256 of the file as published: 266494709be72814f7482cd06f32121112c271c623096a008bc321e48f56a51c.
3
- // The line style is the one-path icon Pictogrammers Material Design Icons `svg/badminton.svg` (Templarian/MaterialDesign-SVG at 9e04201d4557e729822fb57f62a316c3dea1d4a8), Apache-2.0, icon by Nick (SHA-256 e1e32a5816d1bc7a2aee49f06b19e656be503b0d11704d96307a802ca26f6e2c).
4
- // Changes: editor wrappers, metadata and ids removed, coordinates written absolute and rounded. Modified files are marked as the Apache-2.0 licence asks. Do not edit by hand: scripts/dougu/build-gear.mjs writes this file.
5
- import { copied } from "./gear.core.js";
6
- export const GEAR_BADMINTON_RACKET = /* @__PURE__ */ copied({
7
- id: "gear:badminton-racket",
8
- en: "Badminton racket and shuttlecock",
9
- ja: "バドミントンのラケットとシャトルコック",
10
- source: "noto",
11
- credit: "Noto Emoji `2D/svg/emoji_u1f3f8.svg` (googlefonts/noto-emoji at e20cbc2bbec1926686be9f9bee7d1d2cfa1fea0e), Apache-2.0, Copyright 2013 Google, Inc. All Rights Reserved.. Line style: Pictogrammers Material Design Icons `svg/badminton.svg` (Templarian/MaterialDesign-SVG at 9e04201d4557e729822fb57f62a316c3dea1d4a8), Apache-2.0, icon by Nick.",
12
- box: "0 0 128 128",
13
- colour: `<g><path fill="#168DFC" d="M114.3 8.7C93.1 -4 69.3 16.9 63 33.1C56.7 49.3 66.8 60 66.8 60C66.8 60 35.3 93 33.1 93.8L33.9 97.5L68.5 63.3C68.5 63.3 74.3 68.9 84.1 68.5C101.5 68 109.7 58.8 113.5 54.5C117.5 50.2 122.6 43 123.7 31.9C124.6 23.5 123.2 14.1 114.3 8.7ZM107.1 55.7C94.6 66.8 81.8 65.2 77.2 62.8C72.7 60.4 71.6 58.8 69.9 56.9C68.9 55.7 63.7 49.9 65.5 38.3C66.8 30.1 71.1 24.5 76.8 18.9C83.2 12.5 101.4 2.6 114.1 14.4C125.1 24.5 119.5 44.7 107.1 55.7Z"/><path fill="#05BEF2" d="M112.1 48.4C101.7 62.6 82.3 68.6 71.6 58.6L69.9 56.9C69.9 56.9 69.2 57.5 67.6 57C66 56.5 62.8 52.1 62.5 46.3C61.7 33.9 65.8 25.8 74.7 17.6C88.1 5.3 106.5 3.5 115.6 14.2C119.4 18.7 123.5 32.9 112.1 48.4ZM122.7 20.8C122.3 17.9 120.5 13.9 117.7 11.2C103.2 -2.7 82.7 6.5 73 15.4C62.6 25.1 60.3 33.3 59.6 42.2C58.8 53.3 64.5 59.1 64.5 59.1L31.1 92.5L31.7 97.2L68.4 60.7C68.4 60.7 73.3 65.9 84.2 66.4C93 66.8 102 62.3 108.4 56.7C116.3 49.7 124.4 37.1 122.7 20.8Z"/><path fill="#62666A" d="M58.6 62.5C58.5 63.2 64.4 68.8 65.2 68.8C66 68.8 69.6 65.1 69.6 64.7C69.6 64.2 63.9 58 63 58.1C62.1 58.2 58.8 61.4 58.6 62.5Z"/><path fill="#62666A" d="M27.9 92.6C27.9 92.6 27.7 91.6 28.8 90.6C30.1 89.3 31.3 89.9 34.4 93.2C37.5 96.5 38.4 97.6 37.2 99.1C36.1 100.5 34.7 100.1 34.7 100.1L14.3 120.4C14.3 120.4 14.5 122.4 13.2 123.3C12.2 124 10.6 123.7 10.6 123.7L4 116.9C4 116.9 3.6 115.3 4.6 114.2C5.7 113 7.3 113.5 7.3 113.5L27.9 92.6Z"/><path fill="#858485" d="M30.9 94.6C30.3 94.2 29 94.5 28.3 95.4C27.6 96.3 28 97.6 27.3 98.2C26.6 98.7 25 98.6 23.5 100.1C22 101.7 22.2 104 21.1 105C19.9 106 17.8 106.1 16.7 107.3C15 108.9 14.9 111.3 14 112.1C13 112.8 11.3 112.5 10.3 113.4C9.4 114.3 8.8 116.7 10.6 117.3C12.4 117.9 12.3 116 13.5 115.7C14.8 115.3 15.9 115.1 17 113.7C18 112.2 17.9 110.8 19 109.8C20.1 108.7 21.9 108.8 23.3 107.6C24.6 106.4 24.4 103.9 25.9 102.6C27.5 101.3 28.2 102 29.4 100.6C30.6 99.2 30.3 97.8 31.2 97.3C32.2 96.9 32.1 95.3 30.9 94.6Z"/><g><path fill="#B9CED4" d="M104.4 56.3L71.5 23.5C71.1 23.1 71.1 22.4 71.5 22C72 21.6 72.6 21.6 73 22L106.1 54.9C106.1 54.9 105.8 55.2 105.2 55.6C104.8 55.9 104.4 56.3 104.4 56.3Z"/></g><g><path fill="#B9CED4" d="M111.1 49.7L77.6 16.5C77.2 16.1 77.2 15.5 77.6 15.1C78 14.7 78.7 14.7 79.1 15.1L112.4 47.9C112.4 47.9 112.2 48.3 111.8 48.8C111.6 49.1 111.1 49.7 111.1 49.7Z"/></g><g><path fill="#B9CED4" d="M95.9 61.2L66.7 31.1C66.3 30.7 66.3 30 66.8 29.6C67.2 29.2 67.8 29.2 68.2 29.6L98 60.3C98 60.3 97.5 60.5 97 60.8C96.5 61 95.9 61.2 95.9 61.2Z"/></g><g><path fill="#B9CED4" d="M85 63.5L64.3 41.6C63.9 41.2 63.9 40.5 64.3 40.1C64.7 39.7 65.4 39.8 65.8 40.2C65.8 40.2 87.5 62.8 87.4 62.9C87.4 63 87.1 63.4 86.3 63.4C85.9 63.5 85 63.5 85 63.5Z"/></g><g><path fill="#B9CED4" d="M116.2 41.7L86.3 12.4C85.9 12.1 85.9 11.4 86.3 11C86.7 10.6 87.3 10.5 87.8 10.9L117.1 39.7C117.1 39.7 116.9 40.1 116.7 40.5C116.5 41 116.2 41.7 116.2 41.7Z"/></g><g><path fill="#B9CED4" d="M119.2 32L97 9.5C96.5 9.1 96.6 8.4 97 8C97.4 7.6 98 7.6 98.5 8L119.5 29.1C119.5 29.1 119.4 30.8 119.2 32Z"/></g><g><path fill="#B9CED4" d="M65 37.8C64.7 37.8 64.5 37.7 64.3 37.5C63.8 37.1 63.8 36.5 64.2 36.1L91.9 8.7C92.3 8.3 92.9 8.3 93.3 8.7C93.8 9.1 93.8 9.8 93.4 10.2L65.7 37.5C65.5 37.7 65.3 37.8 65 37.8Z"/></g><g><path fill="#B9CED4" d="M65.3 49.1C65 49.1 64.8 49 64.5 48.8C64.1 48.4 64.1 47.7 64.5 47.3L103.7 8.3C104.1 7.8 104.7 7.8 105.1 8.3C105.5 8.7 105.5 9.3 105.1 9.7L66 48.8C65.8 49 65.5 49.1 65.3 49.1Z"/></g><g><path fill="#B9CED4" d="M69.5 57.5C69.2 57.5 69 57.4 68.8 57.2C68.4 56.8 68.3 56.2 68.8 55.7L111.4 12.4C111.8 12 112.5 11.9 112.9 12.4C113.3 12.8 113.3 13.4 112.9 13.8L70.3 57.2C70 57.4 69.8 57.5 69.5 57.5Z"/></g><g><path fill="#B9CED4" d="M75.2 61.2L117.6 18.7C117.6 18.7 117.8 18.7 118.1 19.3C118.4 19.8 118.6 20.7 118.6 20.7L77.2 62.2C77.2 62.2 76.8 62 76.2 61.8C75.6 61.5 75.2 61.2 75.2 61.2Z"/></g><g><path fill="#B9CED4" d="M85 63.5L119.6 27.5C119.6 28.5 119.4 30.8 119.4 30.8L88.3 63.3C88.3 63.3 86.9 63.5 85 63.5Z"/></g><g><path fill="#E1F7FE" d="M79.5 88.9C79 89.5 69.9 112.8 69.9 112.8C69.9 112.8 69.2 115 71 116.8C72.8 118.6 74.8 118.8 74.8 118.8C74.8 118.8 75.2 121.4 79 122.7C81.4 123.5 83.8 122.5 83.8 122.5C83.8 122.5 85.3 124.3 88.9 124.1C91.7 123.9 93 121.2 93 121.2C93 121.2 95.3 122.2 97.3 121.4C100 120.4 100.2 117.6 100.2 117.6C100.2 117.6 102.6 117.7 104.3 115.3C106 113 104.3 109.9 104.3 109.9L93.8 89L86.3 89.8L79.5 88.9Z"/><path fill="#E1E1E1" d="M79.1 87.3C79.1 87.3 78.9 84.1 80.2 81.5C81.5 78.9 83.4 78.1 86.1 77.9C89.1 77.7 91.2 78.2 93 80.4C95 83 94.3 86.8 94.3 86.8C94.3 86.8 92.6 89.6 91.3 90C89.9 90.4 84.1 90.5 82.6 90C79.7 89.2 79.1 87.3 79.1 87.3Z"/><path fill="#FFFFFF" d="M83.2 80.3C81.3 81 81.3 84.6 83.9 86.4C86.5 88.2 89 87 89.3 85.4C89.6 83.9 86.8 83.2 86.1 82.1C85.5 81.1 84.8 79.7 83.2 80.3Z"/><g><path fill="#AAE2F9" d="M75.6 118.5C75.5 118.7 75.5 118.7 75.5 118.8C75.2 119.3 74.6 119.6 74.1 119.3C73.6 119.1 73.3 118.5 73.5 118C73.5 117.9 75.1 112.6 76.7 106.8C78.7 99.5 80.7 90.2 80.7 90.2C80.8 89.6 81.4 89.2 82 89.4C82.5 89.5 82.9 90 82.8 90.6C82.7 90.7 80.6 100 78.7 107.4C77.2 113.1 76 117.3 75.6 118.5Z"/></g><g><path fill="#AAE2F9" d="M84.3 122.6C84.3 122.6 84.2 123.6 83.2 123.5C82.2 123.5 82.2 122.5 82.2 122.5C82.2 122.5 82.8 111.3 83 106.7C83.2 102.2 83.6 91.2 83.6 91.1C83.6 90.6 84.1 90.1 84.7 90.1C85.2 90.2 85.7 90.6 85.7 91.2C85.7 91.3 85.3 102.3 85.1 106.8C84.9 111.4 84.3 122.6 84.3 122.6Z"/></g><g><path fill="#AAE2F9" d="M93.5 121.5C93.3 121.8 93.1 122 92.7 122.1C92.1 122.2 91.6 121.9 91.5 121.3C91.5 121.2 90 113.6 88.7 105.4C87.5 97.5 86.8 91.3 86.8 91.2C86.8 90.6 87.2 90.1 87.7 90C88.3 90 88.8 90.4 88.9 91C88.9 91 89.6 97.2 90.8 105.1C92 113.2 93.5 120.8 93.5 120.9C93.6 121.1 93.5 121.3 93.5 121.5Z"/></g><g><path fill="#AAE2F9" d="M101.5 117.3C101.4 117.6 101.2 117.8 100.9 117.9C100.3 118.1 99.7 117.9 99.5 117.3C99.5 117.2 96.4 109.1 94.7 104C92.9 99 89.9 90.9 89.9 90.9L91.9 90.2C91.9 90.2 94.9 98.3 96.6 103.4C98.4 108.3 101.4 116.5 101.5 116.6C101.6 116.8 101.6 117.1 101.5 117.3Z"/></g><path fill="#FD1B0D" d="M79.1 87L78.8 90C78.8 90 80.6 92 86.5 91.9C91.4 91.9 94.5 90.1 94.5 90.1L94.3 86.8C94.3 86.8 90.6 88.4 86.5 88.5C82.2 88.6 79.1 87 79.1 87Z"/></g></g>`,
14
- line: { box: "0 0 24 24", d: `M12.3 2C11.33 2.03 10.58 2.84 10.61 3.8C10.62 4.04 10.67 4.27 10.77 4.5L11.06 5.14V5.14C11.1 5.27 11.03 5.41 10.89 5.45C10.8 5.5 10.7 5.45 10.63 5.37L10.21 4.82C9.88 4.4 9.38 4.14 8.85 4.13C7.88 4.11 7.08 4.88 7.06 5.84C7.05 6.26 7.19 6.66 7.45 7L7.87 7.5H7.88C7.96 7.63 7.93 7.79 7.82 7.87C7.73 7.94 7.61 7.94 7.53 7.87L7 7.45C6.66 7.19 6.25 7.05 5.84 7.06C4.88 7.08 4.11 7.88 4.13 8.85C4.14 9.38 4.4 9.88 4.82 10.21L5.39 10.65C5.5 10.75 5.5 10.91 5.38 11C5.31 11.07 5.21 11.09 5.12 11.05H5.11L4.5 10.77C4.27 10.68 4.04 10.62 3.8 10.61C2.84 10.58 2.03 11.34 2 12.31C2 13.03 2.4 13.69 3.06 13.97L14.45 19.04L19.04 14.45L13.97 3.06C13.69 2.39 13 1.97 12.3 2M13.13 6.1C13.55 6.09 13.93 6.33 14.09 6.71L17.14 13.55L13.19 9.61L12.26 7.5C11.96 6.87 12.42 6.12 13.13 6.1M9.85 8.85C10.12 8.85 10.37 8.95 10.56 9.15L15.37 13.96C15.77 14.34 15.78 14.97 15.4 15.37C15 15.77 14.38 15.78 13.96 15.37L9.15 10.56C8.75 10.18 8.74 9.54 9.13 9.15C9.32 8.95 9.58 8.85 9.85 8.85M7.13 12.17C7.26 12.17 7.4 12.21 7.5 12.26L9.63 13.2L13.57 17.14L6.71 14.09C5.69 13.65 6.03 12.14 7.13 12.17M20.28 16.04L16.04 20.28L16.89 21.13C17.65 21.88 18.75 22.17 19.78 21.9C20.81 21.62 21.62 20.81 21.9 19.78C22.17 18.75 21.88 17.65 21.13 16.89L20.28 16.04Z` },
1
+ // A badminton racket and a shuttlecock, drawn for this package: an oval strung head on a slender frame, a T-shaped throat and a grip, and a feathered shuttlecock on its cork.
2
+ import { capsule, drawn, ellipse, seg, strings } from "./gear.core.js";
3
+ const T = "rotate(34 32 32)";
4
+ const S = "translate(50.5 50) rotate(48) scale(.95) translate(-32 -13)";
5
+ export const GEAR_BADMINTON_RACKET = /* @__PURE__ */ drawn("gear:badminton-racket", "Badminton racket", "バドミントンのラケット", {
6
+ main: "#2f8fe0",
7
+ accent: "#2a2f38",
8
+ parts: [
9
+ { d: strings(32, 15, 10.4, 13.4, 3.1), fill: "none", stroke: "#9aa7b6", w: 0.6, t: T },
10
+ { d: ellipse(32, 15, 11, 14), fill: "none", stroke: "$main", w: 2.6, t: T },
11
+ { d: "M24.2 24.6L30.6 36M39.8 24.6L33.4 36", fill: "none", stroke: "$main", w: 2.2, t: T },
12
+ { d: capsule(32, 34, 32, 50, 2.2), fill: "#aeb6c0", t: T, cyl: 0.9, shade: 0 },
13
+ { d: capsule(32, 46, 32, 62, 4.4), fill: "$accent", t: T, cyl: 0.8, shade: 0 },
14
+ { d: seg(30, 52, 34, 52) + seg(30, 56, 34, 56), fill: "none", stroke: "#6a7482", w: 0.7, t: T, line: "none" },
15
+ { d: "M28.4 20L24 4Q32 1 40 4L35.6 20z", fill: "#f4f6f8", stroke: "#9aa7b6", t: S, shade: 0.8 },
16
+ { d: "M29.6 19L27 5M32 19.4V3.4M34.4 19L37 5", fill: "none", stroke: "#9aa7b6", w: 0.7, t: S, line: "none" },
17
+ { d: "M27.6 20h8.8a4.4 4.4 0 0 1-8.8 0z", fill: "#e8cf9a", t: S, shade: 0.9 },
18
+ ],
15
19
  });
@@ -1 +1 @@
1
- export declare const GEAR_BASEBALL_GLOVE: import("./gear.index.ts").Piece<import("./gear.core.ts").CopiedSpec>;
1
+ export declare const GEAR_BASEBALL_GLOVE: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
@@ -1,15 +1,21 @@
1
- // Gear: Baseball glove. Copied, with changes, from game-icons.net https://game-icons.net/1x1/delapouite/baseball-glove.html, CC BY 3.0, Baseball glove icon by Delapouite under CC BY 3.0.
2
- // SHA-256 of the file as published: 1701836df19776a8d6f101963e260531bd5e83b4d0c4cdcc10a0081b509804c1.
3
- // Changes: the black background square of the original is left out, the shape is filled with leather and shaded. Modified files are marked as the Apache-2.0 licence asks. Do not edit by hand: scripts/dougu/build-gear.mjs writes this file.
4
- import { copied } from "./gear.core.js";
5
- export const GEAR_BASEBALL_GLOVE = /* @__PURE__ */ copied({
6
- id: "gear:baseball-glove",
7
- en: "Baseball glove",
8
- ja: "野球のグラブ",
9
- source: "gameicons",
10
- credit: "game-icons.net https://game-icons.net/1x1/delapouite/baseball-glove.html, CC BY 3.0, Baseball glove icon by Delapouite under CC BY 3.0.",
11
- box: "0 0 512 512",
12
- colour: `M122 29C109 29 96 40 89 50C57 103 39 168 33 228C27 288 35 345 52 379C88 450 134 476 177 482C220 488 262 474 289 462C391 401 438 348 475 264C485 243 481 224 474 217C471 214 467 213 460 214C454 216 445 221 436 231L444 229L447 248L425 252L434 277L417 284L411 266C401 279 391 292 378 306L365 293C376 281 386 269 394 257L380 259L377 241L399 237L392 216L409 210L415 227C425 208 438 182 440 164C443 141 419 123 407 142C399 157 391 172 382 187L396 184L400 202L374 208L380 228L362 234L359 223C349 238 338 253 325 268L311 255C323 242 333 229 342 216L328 219L324 201L351 194L343 170L361 165L365 179C373 165 381 151 389 137C392 92 360 73 340 109C336 122 331 134 326 146L341 143L345 161L320 167L328 190L310 196L307 187C299 203 288 219 275 234L261 221C274 206 285 191 293 174L275 179L270 161L296 155L287 129L304 123L310 139C314 127 318 115 322 103C325 84 324 72 321 64C316 49 294 43 287 56C271 89 253 137 232 176C222 195 211 212 199 224C187 237 172 245 157 241C140 237 129 226 123 211C117 196 116 178 117 159C120 121 131 78 142 42C137 32 129 28 122 29ZM156 59C154 67 152 76 149 85C168 91 190 97 210 99C224 101 236 101 247 101C251 92 254 84 258 76C220 76 184 68 156 59ZM180 113L176 136C181 137 186 138 191 139L195 116C190 115 185 114 180 113ZM137 145C137 150 136 155 136 160C136 163 136 166 136 169C160 177 183 183 206 185C209 179 213 173 216 167C217 166 217 164 218 163C190 159 164 152 137 145ZM163 197L158 222C159 222 159 223 160 223C165 224 170 223 175 220L179 200C173 199 168 198 163 197ZM209 250C266 250 312 296 312 353C312 381 301 407 282 426C285 427 287 429 290 430L282 447C231 422 175 400 100 416L96 398C103 397 109 396 115 395C109 382 106 368 106 353C106 296 153 250 209 250ZM209 268C185 268 163 278 148 295C163 311 172 330 175 351C177 365 176 379 172 393C206 396 236 406 263 418C266 416 268 414 270 412C253 392 244 370 242 348C240 326 246 304 258 284C244 274 228 268 209 268ZM272 296C263 312 259 329 261 347C262 363 269 381 282 397C289 384 294 369 294 353C294 331 286 311 272 296ZM137 310C129 322 125 337 125 353C125 367 129 381 135 393C141 392 147 392 153 392H153C157 379 158 366 156 354C154 337 147 323 137 310Z`,
13
- line: { box: "0 0 512 512", d: `M122 29C109 29 96 40 89 50C57 103 39 168 33 228C27 288 35 345 52 379C88 450 134 476 177 482C220 488 262 474 289 462C391 401 438 348 475 264C485 243 481 224 474 217C471 214 467 213 460 214C454 216 445 221 436 231L444 229L447 248L425 252L434 277L417 284L411 266C401 279 391 292 378 306L365 293C376 281 386 269 394 257L380 259L377 241L399 237L392 216L409 210L415 227C425 208 438 182 440 164C443 141 419 123 407 142C399 157 391 172 382 187L396 184L400 202L374 208L380 228L362 234L359 223C349 238 338 253 325 268L311 255C323 242 333 229 342 216L328 219L324 201L351 194L343 170L361 165L365 179C373 165 381 151 389 137C392 92 360 73 340 109C336 122 331 134 326 146L341 143L345 161L320 167L328 190L310 196L307 187C299 203 288 219 275 234L261 221C274 206 285 191 293 174L275 179L270 161L296 155L287 129L304 123L310 139C314 127 318 115 322 103C325 84 324 72 321 64C316 49 294 43 287 56C271 89 253 137 232 176C222 195 211 212 199 224C187 237 172 245 157 241C140 237 129 226 123 211C117 196 116 178 117 159C120 121 131 78 142 42C137 32 129 28 122 29ZM156 59C154 67 152 76 149 85C168 91 190 97 210 99C224 101 236 101 247 101C251 92 254 84 258 76C220 76 184 68 156 59ZM180 113L176 136C181 137 186 138 191 139L195 116C190 115 185 114 180 113ZM137 145C137 150 136 155 136 160C136 163 136 166 136 169C160 177 183 183 206 185C209 179 213 173 216 167C217 166 217 164 218 163C190 159 164 152 137 145ZM163 197L158 222C159 222 159 223 160 223C165 224 170 223 175 220L179 200C173 199 168 198 163 197ZM209 250C266 250 312 296 312 353C312 381 301 407 282 426C285 427 287 429 290 430L282 447C231 422 175 400 100 416L96 398C103 397 109 396 115 395C109 382 106 368 106 353C106 296 153 250 209 250ZM209 268C185 268 163 278 148 295C163 311 172 330 175 351C177 365 176 379 172 393C206 396 236 406 263 418C266 416 268 414 270 412C253 392 244 370 242 348C240 326 246 304 258 284C244 274 228 268 209 268ZM272 296C263 312 259 329 261 347C262 363 269 381 282 397C289 384 294 369 294 353C294 331 286 311 272 296ZM137 310C129 322 125 337 125 353C125 367 129 381 135 393C141 392 147 392 153 392H153C157 379 158 366 156 354C154 337 147 323 137 310Z` },
14
- leather: "#a8622a",
1
+ // A baseball glove with a ball, drawn for this package: a leather mitt of four fingers and a thumb round a deep pocket, a laced web, a wrist strap and a ball in the pocket.
2
+ import { capsule, circle, drawn, ellipse } from "./gear.core.js";
3
+ export const GEAR_BASEBALL_GLOVE = /* @__PURE__ */ drawn("gear:baseball-glove", "Baseball glove", "野球のグラブ", {
4
+ main: "#b5702f",
5
+ accent: "#e6cfa0",
6
+ parts: [
7
+ { d: capsule(17, 30, 12.6, 16, 9.6), fill: "$main", cyl: 0.8, shade: 0.3 },
8
+ { d: capsule(28, 28, 26.6, 11.6, 10), fill: "$main", cyl: 0.8, shade: 0.3 },
9
+ { d: capsule(39, 28.4, 40.6, 12.6, 9.8), fill: "$main", cyl: 0.8, shade: 0.3 },
10
+ { d: capsule(48, 32, 52.6, 19.4, 9), fill: "$main", cyl: 0.8, shade: 0.3 },
11
+ { d: capsule(12, 42, 5.8, 34.6, 10), fill: "$main", cyl: 0.8, shade: 0.3 },
12
+ { d: "M9 34C7 47 16 59 32 59C48 59 58 49 56 34C53 25 45 23 36 23C27 23 13 23 9 34Z", fill: "$main", shade: 0.6 },
13
+ { d: ellipse(32, 42, 15.4, 12.4), fill: "#8f5220", stroke: "#6a3a14", shade: 0, line: "stroke" },
14
+ { d: "M13.4 24.2L17 29.4M23.4 20L24.6 26M34 20.6L34 26M45 22.6L42.4 27.4M8.6 36L13.4 36.6", fill: "none", stroke: "$accent", w: 1.4, line: "none" },
15
+ { d: "M20 55.6Q32 61 45 55.4", fill: "none", stroke: "$accent", w: 1.6, line: "none" },
16
+ { d: "M22 56.4L44 56.6L43.4 60.8Q32 63.4 23 60.8Z", fill: "#7a4318", stroke: "#4a280c", shade: 0.3, line: "none" },
17
+ { d: circle(32, 41, 7.8), fill: "#f6f3ec", stroke: "#8f98a3", shade: 0.9 },
18
+ { d: "M27.2 35.4Q31 41 27.2 46.6M36.8 35.4Q33 41 36.8 46.6", fill: "none", stroke: "#c4262e", w: 1, line: "none" },
19
+ { d: "M8.6 35Q9.6 29 13 26.4", fill: "none", stroke: "#fff", w: 1.6, op: 0.4, line: "none", fx: true },
20
+ ],
15
21
  });
@@ -0,0 +1,17 @@
1
+ import type { PieceOptions } from "../ball/ball.core.ts";
2
+ /** The colours of a judo belt from the first rank to the black belt, in order, which `tint` takes. */
3
+ export declare const OBI_RANKS: {
4
+ readonly white: "#f2efe8";
5
+ readonly yellow: "#f2c21b";
6
+ readonly orange: "#ee8a1c";
7
+ readonly green: "#2f9a52";
8
+ readonly blue: "#2b64c8";
9
+ readonly brown: "#7a4a24";
10
+ readonly black: "#1f2228";
11
+ };
12
+ export type ObiRank = keyof typeof OBI_RANKS;
13
+ export declare const GEAR_JUDOGI: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
14
+ export declare const GEAR_KARATE_GI: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
15
+ export declare const GEAR_OBI: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
16
+ /** The belt of a rank, `"white"` to `"black"`: the same as `GEAR_OBI.svg({ ...options, tint: OBI_RANKS[rank] })`. An unknown rank is the black belt. */
17
+ export declare const obi: (rank: ObiRank, options?: PieceOptions) => string;
@@ -0,0 +1,60 @@
1
+ import { drawn, seg } from "./gear.core.js";
2
+ /** The colours of a judo belt from the first rank to the black belt, in order, which `tint` takes. */
3
+ export const OBI_RANKS = {
4
+ white: "#f2efe8",
5
+ yellow: "#f2c21b",
6
+ orange: "#ee8a1c",
7
+ green: "#2f9a52",
8
+ blue: "#2b64c8",
9
+ brown: "#7a4a24",
10
+ black: "#1f2228",
11
+ };
12
+ const CLOTH = "#f4f2ec";
13
+ const EDGE = "#7b8491";
14
+ /** A belt tied at the waist (a flat band, a knot, two ends hanging) from `x0` to `x1` at height `y`. */
15
+ const tied = (x0, x1, y) => {
16
+ const c = (x0 + x1) / 2;
17
+ return `M${x0} ${y}H${x1}V${y + 4}H${x0}zM${c - 3} ${y - 0.6}h6v5.2h-6zM${c - 1.4} ${y + 4.6}L${c - 4.6} ${y + 14}h3.4L${c + 0.4} ${y + 4.6}zM${c + 1.4} ${y + 4.6}L${c + 4.8} ${y + 13.4}h-3.4L${c - 0.4} ${y + 4.6}z`;
18
+ };
19
+ export const GEAR_JUDOGI = /* @__PURE__ */ drawn("gear:judogi", "Judo suit", "柔道衣", {
20
+ main: CLOTH,
21
+ accent: "#1f2228",
22
+ parts: [
23
+ { d: "M22.4 44.4H31.6L30.8 61H21.2ZM32.4 44.4H41.6L42.8 61H33.2Z", fill: "$main", cyl: 0.6, shade: 0.3 },
24
+ { d: "M23.6 9.4L8 36.4Q6.6 39.4 9.4 41.4L14.6 45Q17.4 46.4 19 43.4L29 27.4Z", fill: "$main", cyl: 0.5, shade: 0.4 },
25
+ { d: "M40.4 9.4L56 36.4Q57.4 39.4 54.6 41.4L49.4 45Q46.6 46.4 45 43.4L35 27.4Z", fill: "$main", cyl: 0.5, shade: 0.4 },
26
+ { d: "M23.6 9.4Q32 7 40.4 9.4L45 27.4V46H19V27.4Z", fill: "$main", cyl: 0.6, shade: 0.4 },
27
+ { d: "M26 8.6L35.4 31M38 8.6L28.6 31", fill: "none", stroke: "#cfc8b8", w: 3.6, line: "none" },
28
+ { d: "M26 8.6L35.4 31M38 8.6L28.6 31", fill: "none", stroke: "#8f98a3", w: 0.7, line: "stroke" },
29
+ { d: "M29.2 9.4Q32 12 34.8 9.4L32 16Z", fill: "#3a414b", stroke: "none", op: 0.5, line: "none", fx: true },
30
+ { d: "M13 31L19.4 39.4M11.4 34.4L17.6 42.4M47 31L40.6 39.4M48.6 34.4L42.4 42.4", fill: "none", stroke: "#a9b1bb", w: 0.7, line: "none" },
31
+ { d: tied(19, 45, 40.4), fill: "$accent", stroke: EDGE, cyl: 0.8, shade: 0.2 },
32
+ ],
33
+ });
34
+ export const GEAR_KARATE_GI = /* @__PURE__ */ drawn("gear:karate-gi", "Karate suit", "空手衣", {
35
+ main: CLOTH,
36
+ accent: "#1f2228",
37
+ parts: [
38
+ { d: "M20.4 46H31.4L28.4 61H17.8ZM32.6 46H43.6L46.2 61H35.6Z", fill: "$main", cyl: 0.6, shade: 0.3 },
39
+ { d: "M22.6 9.6L9 27.4Q7 30.4 9.6 32.4L13 34.6Q15.6 36.6 17.6 33.6L26 22Z", fill: "$main", cyl: 0.5, shade: 0.4 },
40
+ { d: "M41.4 9.6L55 27.4Q57 30.4 54.4 32.4L51 34.6Q48.4 36.6 46.4 33.6L38 22Z", fill: "$main", cyl: 0.5, shade: 0.4 },
41
+ { d: "M22.6 9.6Q32 7.4 41.4 9.6L44.8 28V48H19.2V28Z", fill: "$main", cyl: 0.6, shade: 0.4 },
42
+ { d: "M25.4 8.8L37 37M38.6 8.8L27 37", fill: "none", stroke: "#8f98a3", w: 0.9, line: "stroke" },
43
+ { d: "M28.8 9.6Q32 13 35.2 9.6L32 19Z", fill: "#3a414b", stroke: "none", op: 0.5, line: "none", fx: true },
44
+ { d: tied(19.2, 44.8, 40), fill: "$accent", stroke: EDGE, cyl: 0.8, shade: 0.2 },
45
+ ],
46
+ });
47
+ export const GEAR_OBI = /* @__PURE__ */ drawn("gear:obi", "Belt", "武道の帯", {
48
+ main: OBI_RANKS.black,
49
+ parts: [
50
+ { d: "M35 34L24.4 57.6L30 61L40.6 36Z", fill: "$main", stroke: EDGE, cyl: 0.7, shade: 0.3 },
51
+ { d: "M29 34L40.4 57.6L46 55.4L34.6 34Z", fill: "$main", stroke: EDGE, cyl: 0.7, shade: 0.3 },
52
+ { d: seg(27.4, 55.6, 31.4, 58.4) + seg(38.4, 54.6, 42.4, 53), fill: "none", stroke: "$accent", w: 1.6, line: "none" },
53
+ { d: "M2.6 23.4Q32 27.6 61.4 23.4V34.4Q32 38.6 2.6 34.4Z", fill: "$main", stroke: EDGE, cyl: 0.7, shade: 0.3 },
54
+ { d: "M2.6 27.2Q32 31.4 61.4 27.2", fill: "none", stroke: "$accent", w: 1.4, line: "none" },
55
+ { d: "M25.4 22.4h13.2v15.6H25.4z", fill: "$main", stroke: EDGE, cyl: 1, shade: 0.3 },
56
+ { d: "M25.4 27.6h13.2M25.4 32.6h13.2", fill: "none", stroke: "$accent", w: 0.8, line: "none" },
57
+ ],
58
+ });
59
+ /** The belt of a rank, `"white"` to `"black"`: the same as `GEAR_OBI.svg({ ...options, tint: OBI_RANKS[rank] })`. An unknown rank is the black belt. */
60
+ export const obi = (rank, options) => GEAR_OBI.svg({ ...options, tint: Object.hasOwn(OBI_RANKS, rank) ? OBI_RANKS[rank] : OBI_RANKS.black });
@@ -13,8 +13,12 @@ export interface Part {
13
13
  line?: "stroke" | "ink" | "none";
14
14
  /** A transform for the part. */
15
15
  t?: string;
16
- /** How much light and shade the part takes, 0 (flat) to 1 (the default). */
16
+ /** How much light and shade the part takes along a diagonal, 0 (flat) to 1 (the default). */
17
17
  shade?: number;
18
+ /** How much a part is shaded across its own width, as a round shaft is (a bright band, a dark side), 0 to 1. Drawn in the part's own frame, so it follows the part's transform. */
19
+ cyl?: number;
20
+ /** A highlight or a shadow laid on a part: drawn in the metal style only, never flat and never as a line. */
21
+ fx?: boolean;
18
22
  /** Opacity of the part in colour. */
19
23
  op?: number;
20
24
  }
@@ -36,9 +40,9 @@ export interface GearDef<Model = unknown> {
36
40
  model: Model;
37
41
  draw: (options: PieceOptions | undefined) => string;
38
42
  }
39
- /** A piece of gear from its drawing function. Gear is not turned: `frame` draws it as it is. */
43
+ /** A piece of gear from its drawing function. Turned, it flips like a coin (`flipSvg`): the front, then its mirrored back, with a thin rim. */
40
44
  export declare function defineGear<Model>(def: GearDef<Model>): Piece<Model>;
41
- /** A drawn piece: its parts become a document in either style. */
45
+ /** A drawn piece: its parts become a document in the metal, color or line style, whole or turned (the turn is `flipSvg`'s). */
42
46
  export declare function drawGear(id: string, title: string, spec: GearSpec, options: PieceOptions | undefined): string;
43
47
  /** The pieces' drawing helpers: shapes written as path strings. */
44
48
  export declare const rect: (x: number, y: number, w: number, h: number, r?: number) => string;
@@ -49,35 +53,12 @@ export declare const poly: (...pts: Array<[number, number]>) => string;
49
53
  export declare const seg: (x1: number, y1: number, x2: number, y2: number) => string;
50
54
  /** A capsule: a thick line with round ends, as a closed path (so it has an outline in the line style). */
51
55
  export declare function capsule(x1: number, y1: number, x2: number, y2: number, w: number): string;
52
- /** The ink of a copied colour drawing worked out as a line drawing: dark fills and strokes become `currentColor`, light ones are left out, the rest are a faint tint of it. Used where no other line artwork exists. */
53
- export declare function monoOf(markup: string): string;
54
56
  /** A piece we drew: the common case of `defineGear`. */
55
57
  export declare function drawn(id: string, en: string, ja: string, spec: GearSpec, size?: PieceSize): Piece<GearSpec>;
56
58
  /** The strings of a racket's head: a grid of lines clipped to an ellipse. */
57
59
  export declare function strings(cx: number, cy: number, rx: number, ry: number, step: number): string;
58
- /** A piece of gear copied, with changes, from an open icon set. */
59
- export interface CopiedSpec {
60
- id: string;
61
- en: string;
62
- ja: string;
63
- source: PieceSource;
64
- /** The attribution the licence asks for: the author and the licence. */
65
- credit: string;
66
- /** The colour artwork's box and its (minified) markup. For a piece drawn in one colour (the glove) it is the path alone. */
67
- box: string;
68
- colour: string;
69
- /** The line artwork: a one-path icon, or `derived` to work it out of the colour one. */
70
- line: {
71
- box: string;
72
- d: string;
73
- } | "derived";
74
- /** A pale shape to lay under line artwork that is only ink (a mask's face), so that it reads as a solid thing in colour. */
75
- underlay?: string;
76
- /** The colour a one-path piece is filled with (a glove's leather). */
77
- leather?: string;
78
- /** The ink of one-colour artwork in the colour style. */
79
- ink?: string;
80
- size?: PieceSize;
81
- }
82
- /** Copied artwork as a piece: the colour version as it was drawn, the line version in `currentColor`. */
83
- export declare function copied(spec: CopiedSpec): Piece<CopiedSpec>;
60
+ /**
61
+ * A shape of varying width along a curve, as a closed path: a cubic Bezier from `a` to `b` through the controls `c1` and `c2`, drawn `width(t)` wide at the fraction `t` of the way along. A bow, a blade or a feather
62
+ * is one of these. `steps` is how many segments each side has.
63
+ */
64
+ export declare function swell(a: readonly [number, number], c1: readonly [number, number], c2: readonly [number, number], b: readonly [number, number], width: (t: number) => number, steps?: number): string;