@johnmorrisdotca/dougu-sports 0.5.0 → 0.5.2

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 CHANGED
@@ -6,6 +6,42 @@ All notable changes to this project are written here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.5.2] - 2026-10-14
10
+
11
+ The README's pictures are redone, because npm shows only the README that was published: every picture now stands on one of the family's shared backgrounds, and the demo can put one behind an emblem.
12
+
13
+ ### Changed
14
+
15
+ - **Every README picture stands on a background** from the family's shared set (`scripts/family-backgrounds.ts`, version 1.0.0, copied byte for byte from taisen-brackets and held to its sha256 by `test/family-backgrounds.test.ts`): the balls under floodlights, the cups, medals and crests on royal purple, the gear on carbon fibre (dark) or a hardwood floor (light), the vintage balls on a warm sunburst, the printed pucks on the ice, the phone sheet on a glow and the turned emblems on a dark royal, each in a light and a dark twin where the README uses both. Labels take the ink the background returns, and every grid is full and runs edge to edge. The pictures stay webp (2.4 MB in all).
16
+ - The balls picture shows the 36 balls and pucks of the sports on four full rows; the vintage, baseball and era-style balls have a picture of their own (`vintage-desk-light.webp`, `vintage-desk-dark.webp`), the pucks have a dark twin (`pucks-dark.webp`), and the turned emblems are `turn-desk.webp` (it was `turn-desk-light.webp`).
17
+ - `pnpm screenshots` makes every picture, on port 7210 or `TEST_PORT`.
18
+
19
+ ### Added
20
+
21
+ - **A background choice in the demo's preview**, off by default (`?background=ice`): one of the twenty-five, in the variant of the look, behind the stage, with the stage's text in the ink it returns. It is presentation only: the emblem the package draws is the same string with or without it, and the module is loaded only when a background is chosen. The package has no new code and still no dependency.
22
+
23
+ ## [0.5.1] - 2026-10-14
24
+
25
+ The judo suit, the belt and the football pictograms were wrong, and are redrawn from the rules: the judogi is a real jacket and trousers (white or blue, flat and folded), the belt is tied in the flat square knot, and there is a belt for every grade. 261 emblems.
26
+
27
+ ### Fixed
28
+
29
+ - **`gear:judogi` was not a judogi.** It was a robe with an X of two thin bands, sleeves like bat wings and a belt with a block for a buckle. It is now the jacket laid flat with long sleeves that cover the wrist bone, a thick stitched collar crossed left over right (the crossing under 10 cm below the top of the sternum), a quilted upper body, a skirt with side vents, and trousers with a drawstring waist and reinforced knees, from the IJF judogi rules (Sport and Organisation Rules, C1.9 and C1.10; [docs/references.md](docs/references.md#judo-and-karate-suits-and-belts)).
30
+ - **`gear:obi` is the belt as it is tied**: two layers round the waist, a flat square (reef) knot and two equal ends hanging a little apart; it was a strap with a buckle. The judogi, the folded judogi and the karate-gi wear the same knot.
31
+ - **`gear:karate-gi` is its own cut** from the WKF rules (2.2.1): lighter cloth with no quilting, a plain narrow collar, shorter sleeves and jacket than the judogi's, tie strings, straight trousers and a red (AKA) belt by default (`accent` takes a blue one).
32
+ - **`sport:judo` and `sport:karate` are suit pictograms** that read at 16 pixels in the metal, colour and line styles (the karate one was a fist that looked like a glove).
33
+ - **`sport:nfl`, `sport:cfl` and `sport:ifaf` are footballs** drawn from `ball:football`, `ball:football-cfl` and `ball:football-ifaf` (a prolate ball with laces; they were a thin pointed leaf): the CFL's has the white stripe round both ends, the IFAF's the stripes on the laces' side only, the NFL's none (CFL Rule 1 Section 2; IFAF Rule 1 Section 3).
34
+
35
+ ### Added
36
+
37
+ - **`gear:judogi-blue`, `gear:judogi-folded` and `gear:judogi-blue-folded`**: the blue judogi (IJF colour rule C1.9, `JUDOGI_BLUE`), and both suits folded into a neat rectangle with the collar and lapel stitching on top and the belt tied round it. `JUDOGI_WHITE` and `JUDOGI_BLUE` are exported.
38
+ - **A belt for every grade**: `gear:obi-white`, `-yellow`, `-orange`, `-green`, `-blue`, `-brown`, `gear:obi-kohaku` (red and white panels, 6th to 8th dan), `gear:obi-red` (9th and 10th dan), `gear:obi-women` (the black belt with the white stripe women wear in Japan) and the two-colour belts `gear:obi-white-yellow`, `-yellow-orange`, `-orange-green`, `-green-blue` and `-blue-brown`. `OBI_RANKS` gains `kohaku` and `red`, and `obi(rank, options)` takes a grade or a pair of grades (`obi(["white", "yellow"])`), `tint` as one colour or a pair, and `women: true`.
39
+ - Japanese names and descriptions read by a Japanese reviewer (右前 for the lapels, 本結び for the knot; the two-colour belts are a European custom with no Japanese standard name, so they are 「A と B の二色帯」), tests (`test/judo.test.ts`) for the colours, the belts and the football stripes, regenerated gallery pages and gear contact sheet.
40
+
41
+ ### Changed
42
+
43
+ - The judo and karate suits and belts are layered drawings with a larger size budget (14000 characters) than the other gear (6000).
44
+
9
45
  ## [0.5.0] - 2026-10-14
10
46
 
11
47
  Fifty balls in true 3D: vintage leather soccer balls, soccer balls in the style of an era, patterns of a shop wall, baseballs of other threads and volleyballs in national colours. 244 emblems.
package/NOTICE.md CHANGED
@@ -10,6 +10,7 @@ No emblem carries the name, mark or logo of a league, a team, a federation or an
10
10
  - The balls (`src/emblems/ball/`) are drawn by this package's own code: a rotation, a projection and our own geometry (a seam curve, the truncated icosahedron, an octahedron and an icosahedron, a layout of curved panels, a fitted basketball channel). The vintage, era-style and patterned balls ([docs/vintage-balls.md](docs/vintage-balls.md)) are our own graphics laid on those constructions (shapes placed on the sphere, rows of stitches, a lace, scuffs): the shop-wall patterns and the era styles were suggested by photographs the package's author supplied, which were looked at and not copied or traced, and no real ball's pattern, mark or name is used. The volleyballs take only three colours from a country's flag, and draw no flag.
11
11
  - The printed pucks (`puck:*`, `src/emblems/ball/ball.puck.print.ts`) are our own drawings: the maple leaf, the flags of the Canadian and United States patterns and the stars are drawn from simple geometry, the lettering is a stroke alphabet adapted from the block letters of the author's own senshu-jerseys (same author, same MIT licence, no font file), and the signature is made by a seeded pen, so it is no real person's. Photographs of souvenir pucks were looked at for what such a puck shows (a flag, a name, a number, a signature, a ring of words) and nothing was copied or traced. No team's or league's logo or wordmark, no maker's mark and no real player's name is used.
12
12
  - The gear (`src/emblems/gear/`) is drawn by us from a list of parts (a path, a colour, how it reads as a line); the bow, the arrow and the other tapering shapes are made by a small function of ours (`swell`), and the rest are paths written for this package.
13
+ - The backgrounds behind the README pictures and the demo's preview (`scripts/family-backgrounds.ts`, version 1.0.0) are the family's shared module, copied byte for byte from taisen-brackets: twenty-five backgrounds drawn in code from gradients, patterns and paths, all by this package's author, none traced from a picture, a poster, a logo, a trophy or a photograph (MIT). It is tooling: the package ships none of it, and no emblem is drawn on a background.
13
14
  - The Japanese words for the Japanese items are the ones the sports' governing bodies use in their own rules and equipment lists (kendo, judo, kyudo and karate federations and the sumo association); the bodies' names and marks are not used in any id, title or drawing.
14
15
 
15
16
  ## The balls' sizes
package/README.md CHANGED
@@ -16,7 +16,14 @@ The ball and the gear of every sport, trophies, medals, crests and the icon of e
16
16
  <p align="center">
17
17
  <picture>
18
18
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/balls-desk-dark.webp">
19
- <img alt="Forty-five balls and pucks drawn in 3D, in five rows of nine: soccer balls of several constructions and colours, then basketball, the 3x3 ball, baseball, softball, a football, a rugby ball, an Australian football and two volleyballs, then tennis, padel, pickleball with its holes, squash with its two dots, racquetball, golf, red and pink cricket and water polo, then sepak takraw, a shuttlecock, a puck, a curling stone, lacrosse, handball, table tennis, a sliotar and a roundnet ball, and last a row of vintage leather balls (hand-stitched, laced, 18 strips, 12 panels, 32 panels), a lemon-peel baseball and an aged baseball, and soccer balls in the style of the late 1970s and the early 2020s." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/balls-desk-light.webp" width="760">
19
+ <img alt="Thirty-six balls and pucks drawn in 3D under floodlights, in four rows of nine: soccer balls of several constructions and colours, then basketball, the 3x3 ball, baseball, softball, a football, a rugby ball, an Australian football and two volleyballs, then tennis, padel, pickleball with its holes, squash with its two dots, racquetball, golf, red and pink cricket and water polo, and last sepak takraw, a shuttlecock, a puck, a curling stone, lacrosse, handball, table tennis, a sliotar and a roundnet ball." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/balls-desk-light.webp" width="760">
20
+ </picture>
21
+ </p>
22
+
23
+ <p align="center">
24
+ <picture>
25
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/vintage-desk-dark.webp">
26
+ <img alt="Eighteen more balls on a warm sunburst, in two rows of nine: five vintage leather soccer balls (hand-stitched, laced, 18 strips, 12 panels, 32 panels), a lemon-peel baseball, two baseballs stitched in two colours and an aged baseball, then nine soccer balls in the style of an era, from the late 1970s to the early 2020s." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/vintage-desk-light.webp" width="760">
20
27
  </picture>
21
28
  </p>
22
29
 
@@ -37,7 +44,7 @@ The ball and the gear of every sport, trophies, medals, crests and the icon of e
37
44
  <table align="center">
38
45
  <tr>
39
46
  <td align="center" valign="top">
40
- <img alt="A two-handled cup, a medal, a soccer ball and a championship banner each turned through seven angles: the cup keeps its outline and moves its light and handles, the medal and the banner flip like a coin to show their plain backs, and the ball rolls." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/turn-desk-light.webp" width="470"><br><em>Turned: a ball rolls, a medal flips</em>
47
+ <img alt="A two-handled cup, a medal, a soccer ball and a championship banner each turned through seven angles: the cup keeps its outline and moves its light and handles, the medal and the banner flip like a coin to show their plain backs, and the ball rolls." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/turn-desk.webp" width="470"><br><em>Turned: a ball rolls, a medal flips</em>
41
48
  </td>
42
49
  <td align="center" valign="top">
43
50
  <img alt="Cups, a medal, balls and gear on a phone, three to a row." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/phone-light.webp" width="200"><br><em>On a phone</em>
@@ -45,7 +52,7 @@ The ball and the gear of every sport, trophies, medals, crests and the icon of e
45
52
  </tr>
46
53
  </table>
47
54
 
48
- > **Status: preview.** 244 emblems: 24 trophies, 5 awards, 6 medals, 4 crests, a pictogram for each of the 38 sports, 116 balls and implements drawn in 3D, 8 printed pucks ([docs/pucks.md](./docs/pucks.md)), 42 pieces of gear (among them the Japanese sports and budo, [docs/japanese-sports.md](./docs/japanese-sports.md)) and a championship pennant; [docs/layout.md](./docs/layout.md) says where each goes. All of it is drawn for this package: no art is copied from another project.
55
+ > **Status: preview.** 261 emblems: 24 trophies, 5 awards, 6 medals, 4 crests, a pictogram for each of the 38 sports, 116 balls and implements drawn in 3D, 8 printed pucks ([docs/pucks.md](./docs/pucks.md)), 59 pieces of gear (among them the Japanese sports and budo, [docs/japanese-sports.md](./docs/japanese-sports.md)) and a championship pennant; [docs/layout.md](./docs/layout.md) says where each goes. All of it is drawn for this package: no art is copied from another project.
49
56
 
50
57
  ## In 30 seconds
51
58
 
@@ -83,7 +90,7 @@ Put the string in a page (`element.innerHTML = svg`), write it to a file, or sen
83
90
  - **One module per item**, so a bundler takes only what is imported; see [Use it in your project](#use-it-in-your-project).
84
91
  - **Short names and helpers**: `"cup"` is `"trophy:cup"`, `"trophy:cup/line"` is the line style, and `crest`, `medal`, `sportIcon` and `pennant` draw a team's crest, a medal, a sport's icon and a championship pennant.
85
92
  - **Typed ids**: `EmblemId` is a union of `award:*`, `trophy:*`, `medal:*`, `crest:*`, `ball:*`, `gear:*`, `sport:*` and `pennant:*` ids.
86
- - **Japanese sports and budō** (道具 is the name): a sumo cup, a championship banner, and the war fan, belt, bamboo sword, kendo helmet, judo and karate suits, rank belts, long bow and arrow, with Japanese names that are the governing bodies' words; see [docs/japanese-sports.md](./docs/japanese-sports.md).
93
+ - **Japanese sports and budō** (道具 is the name): a sumo cup, a championship banner, and the war fan, belt, bamboo sword, kendo helmet, judo and karate suits, the white and blue judo suit flat and folded, the belts of every grade, long bow and arrow, with Japanese names that are the governing bodies' words; see [docs/japanese-sports.md](./docs/japanese-sports.md).
87
94
  - **Generic by design**: no emblem carries a league's, a team's or a federation's name or mark.
88
95
  - **Accessible**: every drawing is `role="img"` with a `<title>`; see [Accessibility](#accessibility).
89
96
  - **Deterministic**: the same id and options give the same string; a gradient's id comes from its colour.
@@ -94,7 +101,7 @@ Put the string in a page (`element.innerHTML = svg`), write it to a file, or sen
94
101
  <table>
95
102
  <tr>
96
103
  <td align="center" valign="top"><img alt="Balls and pucks in four rows of nine." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/balls-desk-light.webp" width="360"><br><em>Balls and pucks, trophies, medals and gear</em></td>
97
- <td align="center" valign="top"><img alt="A cup, a medal, a ball and a banner turned through seven angles." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/turn-desk-light.webp" width="360"><br><em>Turned through seven angles</em></td>
104
+ <td align="center" valign="top"><img alt="A cup, a medal, a ball and a banner turned through seven angles." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/turn-desk.webp" width="360"><br><em>Turned through seven angles</em></td>
98
105
  </tr>
99
106
  </table>
100
107
 
@@ -409,7 +416,7 @@ An emblem is a small object: `id`, `en` and `ja` names, a `source` (who drew it)
409
416
  | `crest` | Four generic crests, tinted by a team's colours, with its letters | `src/emblems/crest/` |
410
417
  | `ball` | 116 balls and implements, in 3D, each with its official size: soccer (in 32, 26, 18, 14, 12 and 6 panels, in three colourways, with futsal and beach soccer; [docs/soccer-balls.md](./docs/soccer-balls.md); and vintage leather, era-style and patterned balls, [docs/vintage-balls.md](./docs/vintage-balls.md)), basketball, baseball, tennis, rugby, the footballs, golf, the puck, the curling stone and the rest | `src/emblems/ball/` |
411
418
  | `puck` | 8 printed pucks: the same puck with a print on its top face that turns with it (a flag and CANADA, a red leaf, stars and stripes, a player's name and number, a made-up signature, a souvenir), and a `face` option for any picture, emblem or flag code; [docs/pucks.md](./docs/pucks.md) | `src/emblems/ball/ball.puck.print.ts` |
412
- | `gear` | 42 pieces of equipment: sticks, rackets, skates, a glove, a helmet, nets and posts, a javelin, starting blocks, and for the Japanese sports a war fan, a sumo belt, a bamboo sword, a kendo helmet, a judo suit, a belt, a long bow, an arrow and a karate suit | `src/emblems/gear/` |
419
+ | `gear` | 59 pieces of equipment: sticks, rackets, skates, a glove, a helmet, nets and posts, a javelin, starting blocks, and for the Japanese sports a war fan, a sumo belt, a bamboo sword, a kendo helmet, the judo suit (white and blue, laid flat and folded), the belts of every grade (white to red, the red-and-white belt, the women's black belt and the two-colour belts), a long bow, an arrow and a karate suit | `src/emblems/gear/` |
413
420
  | `sport` | One pictogram for each of the thirty-eight sports | `src/emblems/sport/` |
414
421
  | `pennant` | A felt championship pennant on a dowel, with a stitched edge, lettered with its words and its year | `src/emblems/pennant/` |
415
422
 
@@ -446,7 +453,8 @@ The thirty-eight sports the ball, gear and sport emblems are made for are `SPORT
446
453
  | `MEDAL_KINDS`, `CREST_SHAPES` | The kinds of medal, and the shapes of crest |
447
454
  | `SPORT_NAMES` | The thirty-eight sports |
448
455
  | `JAPANESE_IDS` | The ids of the Japanese sports and budo, together: sumo, kendo, judo, kyudo and karate, with their trophies and gear ([docs/japanese-sports.md](./docs/japanese-sports.md)) |
449
- | `OBI_RANKS`, `obi(rank, options?)` | The colours of a belt from `white` to `black`, and the belt of a rank drawn |
456
+ | `OBI_RANKS`, `obi(rank, options?)` | The colours of a belt from `white` to `red` (the kyu, black, the red-and-white belt, red), and the belt of a rank, or of a pair of ranks (a two-colour belt), drawn; `women: true` is the white stripe of the women's black belt |
457
+ | `JUDOGI_WHITE`, `JUDOGI_BLUE` | The two colours the IJF allows a judogi to be ([docs/japanese-sports.md](./docs/japanese-sports.md)) |
450
458
  | `EMBLEM_DESCRIPTIONS` | The longer description of an emblem, in English and Japanese; `emblemInfo(id).description` is the one of an id |
451
459
  | `EMBLEM_STYLES`, `EMBLEM_INK`, `EMBLEM_PAGE`, `METALS` | The styles, the ink and page colours the themes use, and the metals |
452
460
  | `VERSION` | The package's version |
@@ -594,7 +602,7 @@ Bug reports and ideas go in the [issues](https://github.com/johnmorrisdotca/doug
594
602
 
595
603
  ## Changes
596
604
 
597
- See [CHANGELOG.md](./CHANGELOG.md). 0.5.0 adds fifty balls: vintage leather soccer balls, era-style and shop-wall soccer balls, baseballs of other threads and volleyballs in national colours, with a `colors` option (244 emblems: [docs/vintage-balls.md](./docs/vintage-balls.md)); 0.4.0 adds eight printed pucks and a `face` option (194 emblems: [docs/pucks.md](./docs/pucks.md)); 0.3.0 adds nineteen soccer balls (26, 18, 14, 12 and 6 panels, winter orange and high-visibility yellow, futsal and beach soccer: 186 emblems); 0.2.1 draws every ball and implement to the rulebook's proportions; 0.2.0 is 167 emblems, every one drawn here, with the Japanese sports, engraving, a turn for every emblem and the compose helpers; 0.1.0 brought the first full set of 148; 0.0.1 was the first preview.
605
+ See [CHANGELOG.md](./CHANGELOG.md). 0.5.1 redraws the judo suit, the belt and the football pictograms and adds the blue and folded suits and the belts of every grade (261 emblems: [docs/japanese-sports.md](./docs/japanese-sports.md)); 0.5.0 adds fifty balls: vintage leather soccer balls, era-style and shop-wall soccer balls, baseballs of other threads and volleyballs in national colours, with a `colors` option (244 emblems: [docs/vintage-balls.md](./docs/vintage-balls.md)); 0.4.0 adds eight printed pucks and a `face` option (194 emblems: [docs/pucks.md](./docs/pucks.md)); 0.3.0 adds nineteen soccer balls (26, 18, 14, 12 and 6 panels, winter orange and high-visibility yellow, futsal and beach soccer: 186 emblems); 0.2.1 draws every ball and implement to the rulebook's proportions; 0.2.0 is 167 emblems, every one drawn here, with the Japanese sports, engraving, a turn for every emblem and the compose helpers; 0.1.0 brought the first full set of 148; 0.0.1 was the first preview.
598
606
 
599
607
  ## Credits
600
608
 
@@ -74,18 +74,35 @@ export const EMBLEM_DESCRIPTIONS = {
74
74
  "sport:sumo": { en: "Two wrestlers in the crouch they face each other in at the start of a bout, with their belts", ja: "仕切りの姿勢で向かい合う、廻しを締めた二人の力士" },
75
75
  "sport:handball": { en: "A hand throwing the ball, with lines of speed", ja: "ボールを投げる手と、速さを表す線" },
76
76
  "sport:kendo": { en: "The kendo helmet", ja: "剣道の面" },
77
- "sport:judo": { en: "The judo suit and belt", ja: "柔道衣と帯" },
77
+ "sport:judo": { en: "A judo suit: jacket with crossed lapels, a belt in a flat knot with two ends hanging, and trousers", ja: "柔道衣。右前に合わせた襟の上衣、本結びで二本の端を垂らした帯、ズボン" },
78
78
  "sport:kyudo": { en: "A long bow, its string and an arrow", ja: "弦を張った長弓と矢" },
79
- "sport:karate": { en: "A clenched fist", ja: "握りしめた拳" },
79
+ "sport:karate": { en: "A karate suit: a short jacket with a wide V of lapels, a belt in a flat knot, and straight trousers", ja: "空手衣。襟を広いV字に合わせた短めの上衣、本結びの帯、まっすぐなズボン" },
80
80
  "gear:gunbai": { en: "The sumo referee's war fan, with its tassel", ja: "行司が持つ軍配と、その房" },
81
81
  "gear:mawashi": { en: "The wrestler's belt, with the stiff cords that hang from its front", ja: "力士の廻しと、前に垂らした下がり" },
82
82
  "gear:shinai": { en: "The kendo practice sword: four bamboo staves with a leather tip, a tie and a hilt", ja: "剣道の竹刀。四つ割りの竹に先革、中結、柄が付く" },
83
83
  "gear:kendo-men": { en: "The kendo helmet: a steel grille, cloth flaps and a throat guard", ja: "剣道の面。面金、面布団、突き垂れが付く" },
84
- "gear:judogi": { en: "The judo suit: a jacket with crossed lapels, trousers and a belt", ja: "柔道衣。上衣、ズボン、帯" },
85
- "gear:obi": { en: "A tied belt in the colour of a rank, white to black", ja: "段級に応じた色の、結んだ帯(白から黒まで)" },
84
+ "gear:judogi": { en: "The white judo suit laid flat: a jacket with long sleeves, thick stitched lapels crossed left over right and a quilted upper body, trousers with reinforced knees, and the belt tied in a flat knot", ja: "白い柔道衣を広げた姿。長い袖、右前に合わせた刺し子で厚い襟、刺し子の身頃、膝を補強したズボン、本結びにした帯" },
85
+ "gear:obi": { en: "A belt in the flat square knot: two layers round the waist and two equal ends hanging, black", ja: "本結びにした黒帯。腰に二周巻き、同じ長さの端を二本垂らした形" },
86
+ "gear:judogi-blue": { en: "The blue judo suit laid flat, in the blue the competition rules allow beside white", ja: "試合で白と並んで認められている青の柔道衣を広げた姿" },
87
+ "gear:judogi-folded": { en: "The white judo suit folded into a neat rectangle, collar and lapel stitching on top, the belt tied round it", ja: "白い柔道衣をきちんと四角く畳んだ姿。上に襟の刺し子が見え、帯を巻いて結んである" },
88
+ "gear:judogi-blue-folded": { en: "The blue judo suit folded into a neat rectangle, collar and lapel stitching on top, the belt tied round it", ja: "青い柔道衣をきちんと四角く畳んだ姿。上に襟の刺し子が見え、帯を巻いて結んである" },
89
+ "gear:obi-white": { en: "A white belt in the flat square knot, the first kyu belt", ja: "本結びにした白帯。初級の帯" },
90
+ "gear:obi-yellow": { en: "A yellow belt in the flat square knot", ja: "本結びにした黄帯" },
91
+ "gear:obi-orange": { en: "An orange belt in the flat square knot", ja: "本結びにした橙帯" },
92
+ "gear:obi-green": { en: "A green belt in the flat square knot", ja: "本結びにした緑帯" },
93
+ "gear:obi-blue": { en: "A blue belt in the flat square knot", ja: "本結びにした青帯" },
94
+ "gear:obi-brown": { en: "A brown belt in the flat square knot, the highest kyu belt", ja: "本結びにした茶帯。級の上位の帯" },
95
+ "gear:obi-kohaku": { en: "The red and white belt of the 6th to 8th dan, in panels, in the flat square knot", ja: "本結びにした紅白帯。六段から八段の帯で、赤と白を交互に縫い合わせてある" },
96
+ "gear:obi-red": { en: "The solid red belt of the 9th and 10th dan, in the flat square knot", ja: "本結びにした紅帯。九段と十段の帯" },
97
+ "gear:obi-women": { en: "A black belt with the white stripe down its middle that women wear in Japan", ja: "中央に白線の入った女子用の黒帯" },
98
+ "gear:obi-white-yellow": { en: "A two-colour belt, white above and yellow below, between the white and yellow grades", ja: "上半分が白、下半分が黄の二色帯。白帯と黄帯の間の級の帯" },
99
+ "gear:obi-yellow-orange": { en: "A two-colour belt, yellow above and orange below, between the yellow and orange grades", ja: "上半分が黄、下半分が橙の二色帯。黄帯と橙帯の間の級の帯" },
100
+ "gear:obi-orange-green": { en: "A two-colour belt, orange above and green below, between the orange and green grades", ja: "上半分が橙、下半分が緑の二色帯。橙帯と緑帯の間の級の帯" },
101
+ "gear:obi-green-blue": { en: "A two-colour belt, green above and blue below, between the green and blue grades", ja: "上半分が緑、下半分が青の二色帯。緑帯と青帯の間の級の帯" },
102
+ "gear:obi-blue-brown": { en: "A two-colour belt, blue above and brown below, between the blue and brown grades", ja: "上半分が青、下半分が茶の二色帯。青帯と茶帯の間の級の帯" },
86
103
  "gear:yumi": { en: "The long asymmetric bow, held a third of the way up, with its string and wrapped grip", ja: "上が長い非対称の長弓。弦を張り、握り革と籐巻きが付く" },
87
104
  "gear:ya": { en: "A kyudo arrow with feather fletching, a nock and a steel point", ja: "弓道の矢。矢羽根、筈、矢尻が付く" },
88
- "gear:karate-gi": { en: "The karate suit: a jacket with crossed lapels, trousers and a belt", ja: "空手衣。上衣、ズボン、帯" },
105
+ "gear:karate-gi": { en: "The white karate suit laid flat: a lighter jacket with shorter sleeves, a wide V of plain lapels and tie strings, straight trousers, and a red belt in a flat knot", ja: "白い空手衣を広げた姿。袖が短く軽い上衣、広いV字の襟と結び紐、まっすぐなズボン、本結びにした赤い帯" },
89
106
  "ball:soccer-26": { en: "26 panels: 8 triangles and 18 squares, the faces of a rhombicuboctahedron", ja: "三角形8枚と正方形18枚の26枚貼り。斜方立方八面体の26面と同じ構成" },
90
107
  "ball:soccer-18": { en: "18 panels: three strips on each of the six faces of a cube, the strips of neighbouring faces square to each other", ja: "立方体の6面に3枚ずつ帯状のパネルを貼った18枚貼り。隣り合う面の帯は互いに直角" },
91
108
  "ball:soccer-14": { en: "14 panels: 6 propellers and 8 triangles, on a truncated cube whose 12 long edges are bent into S curves", ja: "プロペラ形6枚と三角形8枚の14枚貼り。切頂立方体の長い辺12本をS字に曲げた形" },
@@ -24,10 +24,10 @@ export type BallId = (typeof BALL_IDS)[number];
24
24
  export declare const PUCK_IDS: readonly ["puck:canada", "puck:canada-red", "puck:canada-white", "puck:usa", "puck:usa-navy", "puck:player", "puck:signed", "puck:souvenir"];
25
25
  export type PuckId = (typeof PUCK_IDS)[number];
26
26
  /** The pieces of gear: a piece of equipment for each sport, flat, drawn for this package, turning like a coin. */
27
- export declare const GEAR_IDS: readonly ["gear:hockey-stick", "gear:goalie-stick", "gear:hockey-skate", "gear:goalie-mask", "gear:goal-net", "gear:field-hockey-stick", "gear:lacrosse-stick", "gear:cricket-bat", "gear:wicket", "gear:table-tennis-paddle", "gear:badminton-racket", "gear:tennis-racket", "gear:squash-racket", "gear:racquetball-racket", "gear:padel-racket", "gear:pickleball-paddle", "gear:roundnet-set", "gear:volleyball-net", "gear:basketball-hoop", "gear:baseball-bat", "gear:baseball-glove", "gear:football-helmet", "gear:goalposts", "gear:hurley", "gear:curling-broom", "gear:figure-skate", "gear:speed-skate", "gear:diving-board", "gear:swim-goggles", "gear:starting-blocks", "gear:relay-baton", "gear:javelin", "gear:hurdles", "gear:gunbai", "gear:mawashi", "gear:shinai", "gear:kendo-men", "gear:judogi", "gear:obi", "gear:yumi", "gear:ya", "gear:karate-gi"];
27
+ export declare const GEAR_IDS: readonly ["gear:hockey-stick", "gear:goalie-stick", "gear:hockey-skate", "gear:goalie-mask", "gear:goal-net", "gear:field-hockey-stick", "gear:lacrosse-stick", "gear:cricket-bat", "gear:wicket", "gear:table-tennis-paddle", "gear:badminton-racket", "gear:tennis-racket", "gear:squash-racket", "gear:racquetball-racket", "gear:padel-racket", "gear:pickleball-paddle", "gear:roundnet-set", "gear:volleyball-net", "gear:basketball-hoop", "gear:baseball-bat", "gear:baseball-glove", "gear:football-helmet", "gear:goalposts", "gear:hurley", "gear:curling-broom", "gear:figure-skate", "gear:speed-skate", "gear:diving-board", "gear:swim-goggles", "gear:starting-blocks", "gear:relay-baton", "gear:javelin", "gear:hurdles", "gear:gunbai", "gear:mawashi", "gear:shinai", "gear:kendo-men", "gear:judogi", "gear:judogi-blue", "gear:judogi-folded", "gear:judogi-blue-folded", "gear:obi", "gear:obi-white", "gear:obi-yellow", "gear:obi-orange", "gear:obi-green", "gear:obi-blue", "gear:obi-brown", "gear:obi-kohaku", "gear:obi-red", "gear:obi-women", "gear:obi-white-yellow", "gear:obi-yellow-orange", "gear:obi-orange-green", "gear:obi-green-blue", "gear:obi-blue-brown", "gear:yumi", "gear:ya", "gear:karate-gi"];
28
28
  export type GearId = (typeof GEAR_IDS)[number];
29
29
  /** The Japanese sports and budo: sumo, kendo, judo, kyudo and karate, with the trophies and the gear that belong to them. Every one is also in its own group; this list is for showing them together. */
30
- export declare const JAPANESE_IDS: readonly ["sport:sumo", "trophy:sumo-cup", "gear:gunbai", "gear:mawashi", "trophy:championship-banner", "sport:kendo", "gear:shinai", "gear:kendo-men", "sport:judo", "gear:judogi", "gear:obi", "sport:kyudo", "gear:yumi", "gear:ya", "sport:karate", "gear:karate-gi"];
30
+ export declare const JAPANESE_IDS: readonly ["sport:sumo", "trophy:sumo-cup", "gear:gunbai", "gear:mawashi", "trophy:championship-banner", "sport:kendo", "gear:shinai", "gear:kendo-men", "sport:judo", "gear:judogi", "gear:judogi-blue", "gear:judogi-folded", "gear:judogi-blue-folded", "gear:obi", "gear:obi-white", "gear:obi-yellow", "gear:obi-orange", "gear:obi-green", "gear:obi-blue", "gear:obi-brown", "gear:obi-kohaku", "gear:obi-red", "gear:obi-women", "gear:obi-white-yellow", "gear:obi-yellow-orange", "gear:obi-orange-green", "gear:obi-green-blue", "gear:obi-blue-brown", "sport:kyudo", "gear:yumi", "gear:ya", "sport:karate", "gear:karate-gi"];
31
31
  export type JapaneseId = (typeof JAPANESE_IDS)[number];
32
32
  /** The pennants: a felt championship pennant with a stitched edge. */
33
33
  export declare const PENNANT_IDS: readonly ["pennant:championship"];
@@ -45,7 +45,7 @@ export declare const EMBLEM_GROUPS: {
45
45
  readonly crest: readonly ["crest:shield", "crest:roundel", "crest:diamond", "crest:pennant"];
46
46
  readonly ball: readonly ["ball:soccer", "ball:soccer-colour", "ball:soccer-26", "ball:soccer-18", "ball:soccer-14", "ball:soccer-12", "ball:soccer-6", "ball:soccer-orange", "ball:soccer-26-orange", "ball:soccer-18-orange", "ball:soccer-14-orange", "ball:soccer-12-orange", "ball:soccer-6-orange", "ball:soccer-yellow", "ball:soccer-26-yellow", "ball:soccer-18-yellow", "ball:soccer-14-yellow", "ball:soccer-12-yellow", "ball:soccer-6-yellow", "ball:futsal", "ball:beach-soccer", "ball:soccer-1870-hand-stitched", "ball:soccer-1900-laced", "ball:soccer-1930-18-panel", "ball:soccer-1950-12-panel", "ball:soccer-1960-32-panel-leather", "ball:soccer-1970-black-white", "ball:soccer-1978-triad", "ball:soccer-1986-decorated-triad", "ball:soccer-1998-coloured-triad", "ball:soccer-2002-triangle-sweep", "ball:soccer-2006-propeller", "ball:soccer-2010-grooved", "ball:soccer-2014-ribbon", "ball:soccer-2018-pixel", "ball:soccer-2022-speed-shell", "ball:soccer-training-high-vis", "ball:soccer-stars-blue", "ball:soccer-stars-red", "ball:soccer-stars-night", "ball:soccer-hexagons-cyan", "ball:soccer-hexagons-magenta", "ball:soccer-hexagons-lime", "ball:soccer-flames-fire", "ball:soccer-flames-ice", "ball:soccer-flames-toxic", "ball:soccer-chevrons-red", "ball:soccer-chevrons-green", "ball:soccer-chevrons-blue", "ball:soccer-swirl-blue", "ball:soccer-swirl-red", "ball:soccer-swirl-teal", "ball:soccer-metallic-gold", "ball:soccer-metallic-silver", "ball:soccer-metallic-cobalt", "ball:teqball", "ball:basketball", "ball:basketball-6", "ball:basketball-3x3", "ball:baseball", "ball:softball", "ball:baseball-lemon-peel", "ball:baseball-red-blue", "ball:baseball-black-red", "ball:baseball-vintage-leather", "ball:softball-11-optic", "ball:tennis", "ball:padel", "ball:sliotar", "ball:volleyball", "ball:volleyball-8", "ball:beach-volleyball", "ball:volleyball-colours", "ball:volleyball-brazil", "ball:volleyball-japan", "ball:volleyball-canada", "ball:volleyball-usa", "ball:volleyball-italy", "ball:volleyball-poland", "ball:volleyball-france", "ball:volleyball-serbia", "ball:volleyball-netherlands", "ball:volleyball-germany", "ball:cricket-red", "ball:cricket-white", "ball:cricket-pink", "ball:football", "ball:football-cfl", "ball:football-ifaf", "ball:rugby", "ball:afl", "ball:gaelic-football", "ball:netball", "ball:pickleball-outdoor", "ball:pickleball-indoor", "ball:squash", "ball:squash-yellow", "ball:squash-green", "ball:squash-red", "ball:squash-blue", "ball:racquetball", "ball:lacrosse", "ball:field-hockey", "ball:table-tennis", "ball:handball", "ball:water-polo", "ball:golf", "ball:puck", "ball:curling-stone", "ball:shot", "ball:discus", "ball:hammer", "ball:sepak-takraw", "ball:roundnet", "ball:shuttlecock-feather", "ball:shuttlecock-nylon"];
47
47
  readonly puck: readonly ["puck:canada", "puck:canada-red", "puck:canada-white", "puck:usa", "puck:usa-navy", "puck:player", "puck:signed", "puck:souvenir"];
48
- readonly gear: readonly ["gear:hockey-stick", "gear:goalie-stick", "gear:hockey-skate", "gear:goalie-mask", "gear:goal-net", "gear:field-hockey-stick", "gear:lacrosse-stick", "gear:cricket-bat", "gear:wicket", "gear:table-tennis-paddle", "gear:badminton-racket", "gear:tennis-racket", "gear:squash-racket", "gear:racquetball-racket", "gear:padel-racket", "gear:pickleball-paddle", "gear:roundnet-set", "gear:volleyball-net", "gear:basketball-hoop", "gear:baseball-bat", "gear:baseball-glove", "gear:football-helmet", "gear:goalposts", "gear:hurley", "gear:curling-broom", "gear:figure-skate", "gear:speed-skate", "gear:diving-board", "gear:swim-goggles", "gear:starting-blocks", "gear:relay-baton", "gear:javelin", "gear:hurdles", "gear:gunbai", "gear:mawashi", "gear:shinai", "gear:kendo-men", "gear:judogi", "gear:obi", "gear:yumi", "gear:ya", "gear:karate-gi"];
48
+ readonly gear: readonly ["gear:hockey-stick", "gear:goalie-stick", "gear:hockey-skate", "gear:goalie-mask", "gear:goal-net", "gear:field-hockey-stick", "gear:lacrosse-stick", "gear:cricket-bat", "gear:wicket", "gear:table-tennis-paddle", "gear:badminton-racket", "gear:tennis-racket", "gear:squash-racket", "gear:racquetball-racket", "gear:padel-racket", "gear:pickleball-paddle", "gear:roundnet-set", "gear:volleyball-net", "gear:basketball-hoop", "gear:baseball-bat", "gear:baseball-glove", "gear:football-helmet", "gear:goalposts", "gear:hurley", "gear:curling-broom", "gear:figure-skate", "gear:speed-skate", "gear:diving-board", "gear:swim-goggles", "gear:starting-blocks", "gear:relay-baton", "gear:javelin", "gear:hurdles", "gear:gunbai", "gear:mawashi", "gear:shinai", "gear:kendo-men", "gear:judogi", "gear:judogi-blue", "gear:judogi-folded", "gear:judogi-blue-folded", "gear:obi", "gear:obi-white", "gear:obi-yellow", "gear:obi-orange", "gear:obi-green", "gear:obi-blue", "gear:obi-brown", "gear:obi-kohaku", "gear:obi-red", "gear:obi-women", "gear:obi-white-yellow", "gear:obi-yellow-orange", "gear:obi-orange-green", "gear:obi-green-blue", "gear:obi-blue-brown", "gear:yumi", "gear:ya", "gear:karate-gi"];
49
49
  readonly sport: readonly ("sport:sumo" | "sport:kendo" | "sport:judo" | "sport:kyudo" | "sport:karate" | "sport:nfl" | "sport:cfl" | "sport:ifaf" | "sport:nhl" | "sport:nba" | "sport:mlb" | "sport:soccer" | "sport:curling" | "sport:tennis" | "sport:volleyball" | "sport:badminton" | "sport:pickleball" | "sport:tabletennis" | "sport:padel" | "sport:squash" | "sport:racquetball" | "sport:sepaktakraw" | "sport:teqball" | "sport:roundnet" | "sport:netball" | "sport:swimming" | "sport:waterpolo" | "sport:diving" | "sport:artisticswimming" | "sport:lacrosse" | "sport:rugby" | "sport:afl" | "sport:gaelic" | "sport:cricket" | "sport:fieldhockey" | "sport:handball" | "sport:athletics" | "sport:skating")[];
50
50
  readonly pennant: readonly ["pennant:championship"];
51
51
  };
@@ -39,14 +39,17 @@ export const GEAR_IDS = [
39
39
  "gear:table-tennis-paddle", "gear:badminton-racket", "gear:tennis-racket", "gear:squash-racket", "gear:racquetball-racket", "gear:padel-racket", "gear:pickleball-paddle",
40
40
  "gear:roundnet-set", "gear:volleyball-net", "gear:basketball-hoop", "gear:baseball-bat", "gear:baseball-glove", "gear:football-helmet", "gear:goalposts", "gear:hurley",
41
41
  "gear:curling-broom", "gear:figure-skate", "gear:speed-skate", "gear:diving-board", "gear:swim-goggles", "gear:starting-blocks", "gear:relay-baton", "gear:javelin", "gear:hurdles",
42
- "gear:gunbai", "gear:mawashi", "gear:shinai", "gear:kendo-men", "gear:judogi", "gear:obi", "gear:yumi", "gear:ya", "gear:karate-gi"
42
+ "gear:gunbai", "gear:mawashi", "gear:shinai", "gear:kendo-men", "gear:judogi", "gear:judogi-blue", "gear:judogi-folded", "gear:judogi-blue-folded",
43
+ "gear:obi", "gear:obi-white", "gear:obi-yellow", "gear:obi-orange", "gear:obi-green", "gear:obi-blue", "gear:obi-brown", "gear:obi-kohaku", "gear:obi-red", "gear:obi-women", "gear:obi-white-yellow", "gear:obi-yellow-orange", "gear:obi-orange-green", "gear:obi-green-blue", "gear:obi-blue-brown",
44
+ "gear:yumi", "gear:ya", "gear:karate-gi"
43
45
  ];
44
46
  /** The Japanese sports and budo: sumo, kendo, judo, kyudo and karate, with the trophies and the gear that belong to them. Every one is also in its own group; this list is for showing them together. */
45
47
  export const JAPANESE_IDS = [
46
48
  "sport:sumo", "trophy:sumo-cup", "gear:gunbai", "gear:mawashi",
47
49
  "trophy:championship-banner",
48
50
  "sport:kendo", "gear:shinai", "gear:kendo-men",
49
- "sport:judo", "gear:judogi", "gear:obi",
51
+ "sport:judo", "gear:judogi", "gear:judogi-blue", "gear:judogi-folded", "gear:judogi-blue-folded",
52
+ "gear:obi", "gear:obi-white", "gear:obi-yellow", "gear:obi-orange", "gear:obi-green", "gear:obi-blue", "gear:obi-brown", "gear:obi-kohaku", "gear:obi-red", "gear:obi-women", "gear:obi-white-yellow", "gear:obi-yellow-orange", "gear:obi-orange-green", "gear:obi-green-blue", "gear:obi-blue-brown",
50
53
  "sport:kyudo", "gear:yumi", "gear:ya",
51
54
  "sport:karate", "gear:karate-gi",
52
55
  ];
@@ -1,5 +1,8 @@
1
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. */
2
+ /**
3
+ * The colours of the judo belts, which `tint` takes: the six kyu colours in order, black (1st to 5th dan), `kohaku` (the red of the red-and-white belt of the 6th to 8th dan, whose white panels are the accent) and
4
+ * `red` (9th and 10th dan). The Kodokan's own kyu belts are white and brown only; the colours between are a later, national addition, so a country's order may differ.
5
+ */
3
6
  export declare const OBI_RANKS: {
4
7
  readonly white: "#f2efe8";
5
8
  readonly yellow: "#f2c21b";
@@ -8,10 +11,43 @@ export declare const OBI_RANKS: {
8
11
  readonly blue: "#2b64c8";
9
12
  readonly brown: "#7a4a24";
10
13
  readonly black: "#1f2228";
14
+ readonly kohaku: "#c4202e";
15
+ readonly red: "#c4202e";
11
16
  };
12
17
  export type ObiRank = keyof typeof OBI_RANKS;
18
+ /** Judogi colours: the IJF white ("snow white") and blue (between Pantone 285M and 286M). */
19
+ export declare const JUDOGI_WHITE = "#f6f4ee";
20
+ export declare const JUDOGI_BLUE = "#1456b6";
13
21
  export declare const GEAR_JUDOGI: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
22
+ export declare const GEAR_JUDOGI_BLUE: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
23
+ export declare const GEAR_JUDOGI_FOLDED: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
24
+ export declare const GEAR_JUDOGI_BLUE_FOLDED: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
14
25
  export declare const GEAR_KARATE_GI: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
15
26
  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;
27
+ export declare const GEAR_OBI_WHITE: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
28
+ export declare const GEAR_OBI_YELLOW: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
29
+ export declare const GEAR_OBI_ORANGE: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
30
+ export declare const GEAR_OBI_GREEN: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
31
+ export declare const GEAR_OBI_BLUE: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
32
+ export declare const GEAR_OBI_BROWN: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
33
+ export declare const GEAR_OBI_RED: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
34
+ /** The red-and-white belt of the 6th to 8th dan: panels of red and white (about 21 cm long), red at both ends. */
35
+ export declare const GEAR_OBI_KOHAKU: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
36
+ /** The black belt of a woman in Japan: a white stripe down the middle of the belt along its whole length. */
37
+ export declare const GEAR_OBI_WOMEN: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
38
+ export declare const GEAR_OBI_WHITE_YELLOW: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
39
+ export declare const GEAR_OBI_YELLOW_ORANGE: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
40
+ export declare const GEAR_OBI_ORANGE_GREEN: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
41
+ export declare const GEAR_OBI_GREEN_BLUE: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
42
+ export declare const GEAR_OBI_BLUE_BROWN: import("./gear.index.ts").Piece<import("./gear.core.ts").GearSpec>;
43
+ /** What `obi` takes beside the usual options. `tint` may be one colour or a pair (a two-colour belt, the first colour above and the second below); `women` draws the white stripe of the women's black belt (only the black belt has one; every other belt ignores it). */
44
+ export interface ObiOptions extends Omit<PieceOptions, "tint"> {
45
+ tint?: string | readonly [string, string];
46
+ women?: boolean;
47
+ }
48
+ /**
49
+ * The belt of a rank: `"white"`, `"yellow"`, `"orange"`, `"green"`, `"blue"`, `"brown"` (the kyu), `"black"` (1st to 5th dan), `"kohaku"` (red and white panels, 6th to 8th dan) or `"red"` (9th and 10th dan), or
50
+ * a pair of ranks (`["white", "yellow"]`) for a two-colour belt. An unknown rank is the black belt. `tint` takes one colour, or a pair for a two-colour belt. `women: true` adds the white stripe that women wear on a
51
+ * black belt in Japan.
52
+ */
53
+ export declare const obi: (rank: ObiRank | readonly [ObiRank, ObiRank], options?: ObiOptions) => string;
@@ -1,5 +1,8 @@
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. */
1
+ import { drawn, rect } from "./gear.core.js";
2
+ /**
3
+ * The colours of the judo belts, which `tint` takes: the six kyu colours in order, black (1st to 5th dan), `kohaku` (the red of the red-and-white belt of the 6th to 8th dan, whose white panels are the accent) and
4
+ * `red` (9th and 10th dan). The Kodokan's own kyu belts are white and brown only; the colours between are a later, national addition, so a country's order may differ.
5
+ */
3
6
  export const OBI_RANKS = {
4
7
  white: "#f2efe8",
5
8
  yellow: "#f2c21b",
@@ -8,53 +11,311 @@ export const OBI_RANKS = {
8
11
  blue: "#2b64c8",
9
12
  brown: "#7a4a24",
10
13
  black: "#1f2228",
14
+ kohaku: "#c4202e",
15
+ red: "#c4202e",
11
16
  };
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`;
17
+ /** Judogi colours: the IJF white ("snow white") and blue (between Pantone 285M and 286M). */
18
+ export const JUDOGI_WHITE = "#f6f4ee";
19
+ export const JUDOGI_BLUE = "#1456b6";
20
+ const f = (n) => String(Math.round(n * 10) / 10);
21
+ const path = (pts, close = true) => `M${pts.map((p) => `${f(p[0])} ${f(p[1])}`).join("L")}${close ? "z" : ""}`;
22
+ const mirror = (pts) => pts.map((p) => [64 - p[0], p[1]]);
23
+ /** A rectangle of width `w` along the segment from `a` to `b`, as a polygon. */
24
+ const strip = (a, b, w) => {
25
+ const dx = b[0] - a[0], dy = b[1] - a[1];
26
+ const l = Math.hypot(dx, dy) || 1;
27
+ const nx = (-dy / l) * (w / 2), ny = (dx / l) * (w / 2);
28
+ return [[a[0] + nx, a[1] + ny], [b[0] + nx, b[1] + ny], [b[0] - nx, b[1] - ny], [a[0] - nx, a[1] - ny]];
29
+ };
30
+ const lerp = (a, b, t) => [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
31
+ /** A line parallel to the segment from `a` to `b`, `off` to its side, between the fractions `t0` and `t1` of its length. */
32
+ const along = (a, b, off, t0, t1) => {
33
+ const dx = b[0] - a[0], dy = b[1] - a[1];
34
+ const l = Math.hypot(dx, dy) || 1;
35
+ const nx = (-dy / l) * off, ny = (dx / l) * off;
36
+ const p0 = lerp(a, b, t0), p1 = lerp(a, b, t1);
37
+ return `M${f(p0[0] + nx)} ${f(p0[1] + ny)}L${f(p1[0] + nx)} ${f(p1[1] + ny)}`;
38
+ };
39
+ /** Horizontal rows (every `step`, from `y0` to `y1`) clipped to a convex polygon, as one path. */
40
+ function rows(poly, y0, y1, step, inset = 0) {
41
+ let d = "";
42
+ for (let y = y0; y <= y1 + 1e-6; y += step) {
43
+ const xs = [];
44
+ for (let i = 0; i < poly.length; i++) {
45
+ const a = poly[i], b = poly[(i + 1) % poly.length];
46
+ if ((a[1] <= y && b[1] > y) || (b[1] <= y && a[1] > y))
47
+ xs.push(a[0] + ((y - a[1]) / (b[1] - a[1])) * (b[0] - a[0]));
48
+ }
49
+ if (xs.length >= 2) {
50
+ const xa = Math.min(...xs) + inset, xb = Math.max(...xs) - inset;
51
+ if (xb > xa)
52
+ d += `M${f(xa)} ${f(y)}H${f(xb)}`;
53
+ }
54
+ }
55
+ return d;
56
+ }
57
+ // Cloth lines are laid over the cloth as ink at low opacity (dark rows) or as light rows, so they follow any tint.
58
+ const INK = "#0d1522";
59
+ /** The edge of a black belt: light enough to show on a dark page. */
60
+ const BELT_EDGE = "#5d6672";
61
+ const dark = (d, w = 0.3, op = 0.2) => ({ d, fill: "none", stroke: INK, w, op, line: "none" });
62
+ const light = (d, w = 0.3, op = 0.3) => ({ d, fill: "none", stroke: "#ffffff", w, op, line: "none" });
63
+ /** A belt tied at the front: two wraps, a flat square knot and two equal ends hanging a little apart. Parts, back to front. */
64
+ function belt(s) {
65
+ const parts = [];
66
+ const hw = (s.x1 - s.x0) / 2;
67
+ const w = s.w;
68
+ const alt = s.alt ?? s.main;
69
+ const edge = (x, y) => y + s.sag * (1 - ((x - s.cx) / hw) ** 2);
70
+ const sample = (xa, xb) => {
71
+ const n = Math.max(2, Math.ceil((xb - xa) / 9));
72
+ return Array.from({ length: n + 1 }, (_, i) => xa + ((xb - xa) * i) / n);
73
+ };
74
+ /** The wrap between `xa` and `xb`, from the fraction `f0` to `f1` of its width, whose top is at `y`, as a polygon that follows the sag. */
75
+ const band = (xa, xb, y, f0 = 0, f1 = 1) => {
76
+ const xs = sample(xa, xb);
77
+ return [...xs.map((x) => [x, edge(x, y + w * f0)]), ...xs.map((x) => [x, edge(x, y + w * f1)]).reverse()];
78
+ };
79
+ const line = (y, xa, xb) => path(sample(xa, xb).map((x) => [x, edge(x, y)]), false);
80
+ const colourAt = (cuts, start, other) => {
81
+ const xs = [s.x0, ...cuts, s.x1];
82
+ return xs.slice(0, -1).map((x, i) => [x, xs[i + 1], i % 2 === 0 ? start : other]);
83
+ };
84
+ const yU = s.y, yL = s.y + w - 0.3;
85
+ const wraps = [
86
+ [yL, s.panels === undefined ? [[s.x0, s.x1, s.main]] : colourAt(s.panels.lower, alt, s.main)],
87
+ [yU, s.panels === undefined ? [[s.x0, s.x1, s.main]] : colourAt(s.panels.upper, s.main, alt)],
88
+ ];
89
+ const stitches = (y, xa, xb) => {
90
+ parts.push(dark(line(y + w * 0.3, xa, xb) + line(y + w * 0.7, xa, xb), 0.28, 0.3));
91
+ parts.push(light(line(y + w * 0.3 + 0.35, xa, xb) + line(y + w * 0.7 + 0.35, xa, xb), 0.25, 0.2));
92
+ };
93
+ for (const [y, segments] of wraps) {
94
+ for (const [xa, xb, fill] of segments)
95
+ parts.push({ d: path(band(xa, xb, y)), fill, stroke: s.edge, cyl: 0.5, shade: 0.25 });
96
+ if (s.half === true)
97
+ parts.push({ d: path(band(s.x0, s.x1, y, 0.5, 1)), fill: alt, stroke: "none", cyl: 0.5, shade: 0.25, line: "none" });
98
+ stitches(y, s.x0 + 0.8, s.x1 - 0.8);
99
+ if (s.stripe === true)
100
+ parts.push({ d: path(band(s.x0, s.x1, y, 0.425, 0.575)), fill: "#f6f4ee", stroke: "none", line: "none" });
101
+ }
102
+ // The knot sits over both wraps. The two ends come out from under it, a little apart and of one length; the knot is a flat blob closed across the middle by the turn of the second end.
103
+ const yc = (yU + yL + w) / 2 + s.sag;
104
+ const hh = w * 1.2;
105
+ const kw = s.knot;
106
+ const yt = yc - hh, yb = yc + hh;
107
+ const rad = (s.splay * Math.PI) / 180;
108
+ const tw = w * 1.02;
109
+ const tailFill = s.panels?.tail ?? s.main;
110
+ for (const side of [-1, 1]) {
111
+ const a = [s.cx + side * kw * 0.2, yc + hh * 0.2];
112
+ const b = [a[0] + side * Math.sin(rad) * s.tail, a[1] + Math.cos(rad) * s.tail];
113
+ parts.push({ d: path(strip(a, b, tw)), fill: tailFill, stroke: s.edge, cyl: 0.55, shade: 0.25 });
114
+ if (s.half === true) {
115
+ const q = strip(a, b, tw);
116
+ parts.push({ d: path([lerp(q[0], q[3], 0.5), lerp(q[1], q[2], 0.5), q[2], q[3]]), fill: alt, stroke: "none", cyl: 0.55, shade: 0.25, line: "none" });
117
+ }
118
+ parts.push(dark(along(a, b, -tw * 0.18, 0.3, 0.98) + along(a, b, tw * 0.18, 0.3, 0.98), 0.28, 0.3));
119
+ parts.push(light(along(a, b, -tw * 0.18 + 0.35, 0.3, 0.98) + along(a, b, tw * 0.18 + 0.35, 0.3, 0.98), 0.25, 0.2));
120
+ if (s.stripe === true)
121
+ parts.push({ d: path(strip(lerp(a, b, 0.25), lerp(a, b, 1), tw * 0.15)), fill: "#f6f4ee", stroke: "none", line: "none" });
122
+ if (s.bars === true)
123
+ parts.push({ d: path(strip(lerp(a, b, 1 - 3.4 / s.tail), lerp(a, b, 1 - 2.2 / s.tail), tw)), fill: "$accent", stroke: "none", op: 0.9, line: "none" });
124
+ }
125
+ const kfill = s.panels === undefined ? s.main : alt;
126
+ const blob = rect(s.cx - kw / 2, yt, kw, hh * 2, Math.min(2.4, kw * 0.22));
127
+ parts.push({ d: blob, fill: kfill, stroke: s.edge, cyl: 0.6, shade: 0.3 });
128
+ if (s.half === true)
129
+ parts.push({ d: rect(s.cx - kw / 2, yc, kw, hh, Math.min(2.4, kw * 0.22)), fill: alt, stroke: "none", cyl: 0.6, shade: 0.3, line: "none" });
130
+ // the folds of the knot: two diagonals that cross, from the top corners to the foot of the knot
131
+ const fx0 = s.cx - kw / 2, fx1 = s.cx + kw / 2;
132
+ parts.push(dark(`M${f(fx0 + 0.9)} ${f(yt + 0.9)}L${f(fx1 - 1.6)} ${f(yb - 0.9)}M${f(fx1 - 0.9)} ${f(yt + 0.9)}L${f(fx0 + 1.6)} ${f(yb - 0.9)}`, 0.34, 0.42));
133
+ parts.push(light(`M${f(fx0 + 1.5)} ${f(yt + 0.9)}L${f(fx1 - 1)} ${f(yb - 0.9)}M${f(fx1 - 1.5)} ${f(yt + 0.9)}L${f(fx0 + 1)} ${f(yb - 0.9)}`, 0.3, 0.3));
134
+ const wt = yc - w * 0.46, wh = w * 0.92;
135
+ parts.push({ d: rect(fx0 - 0.5, wt, kw + 1, wh, 0.9), fill: s.main, stroke: s.edge, cyl: 0.9, shade: 0.3 });
136
+ if (s.half === true)
137
+ parts.push({ d: rect(fx0 - 0.5, yc, kw + 1, wh / 2, 0.5), fill: alt, stroke: "none", cyl: 0.9, shade: 0.3, line: "none" });
138
+ parts.push(dark(`M${f(fx0)} ${f(yc)}H${f(fx1)}`, 0.28, 0.3));
139
+ if (s.stripe === true)
140
+ parts.push({ d: rect(fx0 - 0.3, yc - w * 0.075, kw + 0.6, w * 0.15), fill: "#f6f4ee", stroke: "none", line: "none" });
141
+ return parts;
142
+ }
143
+ // ───────────────────────────── the judogi ─────────────────────────────
144
+ /**
145
+ * The judogi laid flat: jacket (sleeves out to the sides, lapels crossed left over right, thick stitched collar, quilted upper body, vented skirt), the belt tied over it and the trousers below with a drawstring
146
+ * waist and reinforced knees. `$main` is the cloth, `$accent` the belt.
147
+ */
148
+ function judogiFlat() {
149
+ const parts = [];
150
+ // Trousers, behind everything: straight legs, a waistband with its drawstring, reinforced knees.
151
+ const trousers = [[18.4, 37], [45.6, 37], [46.6, 62], [34.6, 62], [32, 43.6], [29.4, 62], [17.4, 62]];
152
+ parts.push({ d: path(trousers), fill: "$main", shade: 0.3, cyl: 0.25 });
153
+ parts.push({ d: path([[18.4, 37], [45.6, 37], [45.7, 39.8], [18.3, 39.8]]), fill: "$main", shade: 0.2 });
154
+ parts.push(dark("M18.6 38.9H45.4", 0.3, 0.35));
155
+ parts.push({ d: "M40.6 39.8Q39.4 42.8 40.4 45.2M42 39.8Q43 42.6 42.2 45", fill: "none", stroke: INK, w: 0.4, op: 0.5, line: "none" });
156
+ const knees = [[[19.2, 49.8], [30.8, 49.8], [30, 57.6], [18.8, 57.6]], [[33.2, 49.8], [44.8, 49.8], [45.2, 57.6], [34, 57.6]]];
157
+ for (const k of knees) {
158
+ parts.push({ d: path(k), fill: "$main", stroke: "none", shade: 0, line: "none" });
159
+ parts.push(dark(path(k) + rows(k, 51.4, 56.4, 1.6, 0.3), 0.28, 0.35));
160
+ }
161
+ parts.push(dark("M17.6 60.2H29.6M34.4 60.2H46.4", 0.3, 0.3));
162
+ // Sleeves: long, wide, ending past the wrist, laid out and down.
163
+ const sleeve = [[19.8, 6.4], [1.4, 20.2], [4.6, 27.6], [18.6, 22.4]];
164
+ for (const pts of [sleeve, mirror(sleeve)])
165
+ parts.push({ d: path(pts), fill: "$main", cyl: 0.15, shade: 0.35 });
166
+ const jacket = [[19.4, 6.6], [26.2, 4], [32, 3.2], [37.8, 4], [44.6, 6.6], [45.6, 8], [45.6, 36], [18.4, 36], [18.4, 8]];
167
+ parts.push({ d: path(jacket), fill: "$main", shade: 0.35, cyl: 0.18 });
168
+ // Quilting: rows over the shoulders, chest and sleeves (the cloth of a judogi is heavy and woven double).
169
+ const body = [[19, 7], [45, 7], [45.6, 26], [18.4, 26]];
170
+ parts.push(dark(rows(body, 8, 25, 1.4, 0.5), 0.28, 0.1));
171
+ parts.push(light(rows(body, 8.5, 25.5, 1.4, 0.5), 0.24, 0.2));
172
+ for (const pts of [sleeve, mirror(sleeve)]) {
173
+ let d = "";
174
+ for (let t = 0.1; t <= 0.9; t += 0.08) {
175
+ const a = lerp(pts[0], pts[1], t), b = lerp(pts[3], pts[2], t);
176
+ const a2 = lerp(a, b, 0.07), b2 = lerp(a, b, 0.93);
177
+ d += `M${f(a2[0])} ${f(a2[1])}L${f(b2[0])} ${f(b2[1])}`;
178
+ }
179
+ parts.push(dark(d, 0.28, 0.1));
180
+ }
181
+ // The neck: the collar goes round the back of the neck, and the opening is a V that ends under 10 cm below the sternum.
182
+ parts.push({ d: path([[26.4, 4.2], [37.6, 4.2], [33.4, 14]]), fill: INK, stroke: INK, w: 0.3, op: 0.62, line: "none" });
183
+ parts.push({ d: "M25.4 5.4Q32 2 38.6 5.4L37.6 8.2Q32 5.4 26.4 8.2Z", fill: "$main", cyl: 0.4, shade: 0.3 });
184
+ // Under lapel (the right front, worn under), its band running down to where the left front covers it.
185
+ parts.push({ d: path(strip([26.8, 5.4], [33.8, 14.4], 2.9)), fill: "$main", cyl: 0.5, shade: 0.3 });
186
+ // The left front, laid over: its panel and its thick, stitched lapel from the right of the neck to the hem.
187
+ const over = [[36.4, 4.4], [44.6, 6.6], [45.6, 8], [45.6, 36], [22.8, 36]];
188
+ parts.push({ d: path(over), fill: "$main", shade: 0.35, cyl: 0.1 });
189
+ const overBody = [[36, 5], [45.6, 8], [45.6, 26], [28.8, 26]];
190
+ parts.push(dark(rows(overBody, 8, 25, 1.4, 0.5), 0.3, 0.14));
191
+ parts.push(light(rows(overBody, 8.5, 25.5, 1.4, 0.5), 0.26, 0.22));
192
+ parts.push({ d: path(strip([37, 4.8], [24.4, 35], 3.9)), fill: "$main", cyl: 0.55, shade: 0.35 });
193
+ parts.push({ d: path(strip([37, 4.8], [24.4, 35], 3.9)), fill: "none", stroke: INK, w: 0.3, op: 0.5, line: "none" });
194
+ // Rows of stitching down both lapels.
195
+ const lapelRows = (a, b, shift = 0) => [-1.3, -0.45, 0.45, 1.3].map((o) => along([a[0] + shift, a[1]], [b[0] + shift, b[1]], o, 0, 1)).join("");
196
+ parts.push(dark(lapelRows([36.6, 7.4], [24.8, 34.4]), 0.28, 0.45));
197
+ parts.push(light(lapelRows([36.6, 7.4], [24.8, 34.4], 0.35), 0.25, 0.3));
198
+ parts.push(dark(lapelRows([27.2, 6.4], [33.4, 14]), 0.28, 0.45));
199
+ // Shadow of the lapel on the cloth under it.
200
+ parts.push({ d: path(strip([34.6, 5.4], [22.6, 36], 1.2)), fill: INK, stroke: "none", op: 0.14, fx: true });
201
+ // Hem: the skirt reaches past the belt, with short vents at the sides and a stitched edge.
202
+ parts.push(dark("M18.8 34.4H44.8", 0.3, 0.32));
203
+ parts.push(dark("M20.2 31.4V36M43.8 31.4V36", 0.4, 0.45));
204
+ // The belt, over the jacket, wrapped twice.
205
+ parts.push(...belt({ edge: BELT_EDGE, main: "$accent", cx: 32, x0: 18.2, x1: 45.8, y: 25.2, w: 2.5, sag: 0, knot: 6.4, tail: 11.4, splay: 6 }));
206
+ return parts;
207
+ }
208
+ /** The judogi folded into a neat rectangle: collar and lapel stitching on top, the belt tied round it. */
209
+ function judogiFolded() {
210
+ const parts = [];
211
+ // The front of the pile (its thickness) under the top.
212
+ const front = [[8.4, 41], [55.6, 41], [55.2, 52], [8.8, 52]];
213
+ parts.push({ d: path(front), fill: "$main", shade: 0.25, cyl: 0.4 });
214
+ parts.push({ d: path(front), fill: INK, stroke: "none", op: 0.12, fx: true });
215
+ parts.push(dark("M9 44.6H55M8.9 48.2H55.1", 0.3, 0.3));
216
+ parts.push(light("M9 45.2H55M8.9 48.8H55.1", 0.26, 0.25));
217
+ // The top: sleeves folded back at the sides, the body folded over in thirds.
218
+ const top = [[9, 9.4], [55, 9.4], [55.6, 41], [8.4, 41]];
219
+ parts.push({ d: path(top), fill: "$main", shade: 0.35, cyl: 0.18 });
220
+ parts.push(dark(rows(top, 10.4, 40, 1.4, 0.8), 0.3, 0.14));
221
+ parts.push(light(rows(top, 10.9, 40.5, 1.4, 0.8), 0.26, 0.22));
222
+ parts.push(dark("M14.6 10.4L14.2 40.4M49.4 10.4L49.8 40.4", 0.35, 0.28));
223
+ // The collar, lapels crossed left over right, with rows of stitching.
224
+ parts.push({ d: path([[27.2, 9.4], [36.8, 9.4], [32.8, 18]]), fill: INK, stroke: INK, w: 0.3, op: 0.34, line: "none" });
225
+ parts.push({ d: "M23.6 10.6Q32 5.6 40.4 10.6L39.2 14Q32 10.2 24.8 14Z", fill: "$main", cyl: 0.4, shade: 0.3 });
226
+ parts.push({ d: path(strip([27.2, 10.8], [33.4, 18.6], 3.1)), fill: "$main", cyl: 0.5, shade: 0.3 });
227
+ const over = [[36.4, 9.8], [55, 9.4], [55.6, 41], [22.4, 41]];
228
+ parts.push({ d: path(over), fill: "$main", shade: 0.35, cyl: 0.1 });
229
+ parts.push(dark(rows([[36.4, 10], [55, 10], [55, 26], [29, 26]], 10.4, 25.6, 1.4, 0.8), 0.3, 0.14));
230
+ parts.push({ d: path(strip([37.2, 10], [23.2, 40], 3.8)), fill: "$main", cyl: 0.55, shade: 0.35 });
231
+ parts.push({ d: path(strip([37.2, 10], [23.2, 40], 3.8)), fill: "none", stroke: INK, w: 0.3, op: 0.5, line: "none" });
232
+ const rowsAlong = (a, b) => [-1.3, -0.45, 0.45, 1.3].map((o) => along(a, b, o, 0, 1)).join("");
233
+ parts.push(dark(rowsAlong([37, 12], [24, 39]), 0.28, 0.45));
234
+ parts.push(dark(rowsAlong([28, 11.4], [33.2, 18]), 0.28, 0.45));
235
+ parts.push({ d: path(strip([36, 10.6], [22.6, 41], 1.4)), fill: INK, stroke: "none", op: 0.12, fx: true });
236
+ // The belt wrapped round it and tied on top.
237
+ parts.push(...belt({ edge: BELT_EDGE, main: "$accent", cx: 32, x0: 7.6, x1: 56.4, y: 26.4, w: 3, sag: 0, knot: 7.4, tail: 12.6, splay: 6 }));
238
+ return parts;
239
+ }
240
+ export const GEAR_JUDOGI = /* @__PURE__ */ drawn("gear:judogi", "Judo suit", "柔道衣", { main: JUDOGI_WHITE, accent: OBI_RANKS.black, parts: judogiFlat() });
241
+ export const GEAR_JUDOGI_BLUE = /* @__PURE__ */ drawn("gear:judogi-blue", "Blue judo suit", "青い柔道衣", { main: JUDOGI_BLUE, accent: OBI_RANKS.black, parts: judogiFlat() });
242
+ export const GEAR_JUDOGI_FOLDED = /* @__PURE__ */ drawn("gear:judogi-folded", "Folded judo suit", "畳んだ柔道衣", { main: JUDOGI_WHITE, accent: OBI_RANKS.black, parts: judogiFolded() });
243
+ export const GEAR_JUDOGI_BLUE_FOLDED = /* @__PURE__ */ drawn("gear:judogi-blue-folded", "Folded blue judo suit", "畳んだ青い柔道衣", { main: JUDOGI_BLUE, accent: OBI_RANKS.black, parts: judogiFolded() });
244
+ // ───────────────────────────── the karate-gi ─────────────────────────────
245
+ /** The karate-gi laid flat: lighter cloth (no quilting), a plain narrow collar, shorter jacket and sleeves than the judogi, tie strings, ankle-length trousers and the belt. `$main` is the cloth, `$accent` the belt. */
246
+ function karateFlat() {
247
+ const parts = [];
248
+ const trousers = [[19.4, 40], [44.6, 40], [45.4, 61.4], [34.4, 61.4], [32, 49], [29.6, 61.4], [18.6, 61.4]];
249
+ parts.push({ d: path(trousers), fill: "$main", shade: 0.3, cyl: 0.15 });
250
+ parts.push({ d: path([[19.4, 40], [44.6, 40], [44.6, 41.8], [19.4, 41.8]]), fill: "$main", shade: 0.15 });
251
+ parts.push(dark("M19.6 41.4H44.4", 0.3, 0.3));
252
+ parts.push({ d: "M26 41.8Q24.4 44.6 25.4 47M27.6 41.8Q28.4 44.4 27.4 46.8", fill: "none", stroke: INK, w: 0.35, op: 0.45, line: "none" });
253
+ parts.push(dark("M18.8 60H29.6M34.4 60H45.2", 0.3, 0.25));
254
+ // Sleeves reach the bend of the wrist at most (WKF 2.2.1 j), so they are shorter than a judogi's, with a wide cuff.
255
+ const sleeve = [[20.6, 8], [8.6, 16.6], [11.8, 23], [19.4, 22]];
256
+ for (const pts of [sleeve, mirror(sleeve)])
257
+ parts.push({ d: path(pts), fill: "$main", shade: 0.3, cyl: 0.12 });
258
+ const jacket = [[20.2, 8], [26.6, 5.2], [32, 4.4], [37.4, 5.2], [43.8, 8], [44.8, 38.6], [19.2, 38.6]];
259
+ parts.push({ d: path(jacket), fill: "$main", shade: 0.3, cyl: 0.15 });
260
+ // Neck: a wide V that ends lower than the judogi's, a plain thin collar.
261
+ parts.push({ d: path([[27.4, 5.4], [36.6, 5.4], [32, 19.6]]), fill: INK, stroke: INK, w: 0.3, op: 0.3, line: "none" });
262
+ parts.push({ d: "M26.4 6.2Q32 3.4 37.6 6.2L37 8Q32 5.6 27 8Z", fill: "$main", cyl: 0.3, shade: 0.2 });
263
+ parts.push({ d: path(strip([26.6, 6.6], [32.6, 19.8], 1.8)), fill: "$main", cyl: 0.3, shade: 0.2 });
264
+ const over = [[36.4, 6.2], [43.8, 8], [44.8, 38.6], [24.6, 38.6]];
265
+ parts.push({ d: path(over), fill: "$main", shade: 0.3, cyl: 0.08 });
266
+ parts.push({ d: path(strip([36.8, 6.4], [23.4, 38], 2)), fill: "$main", cyl: 0.35, shade: 0.25 });
267
+ parts.push({ d: path(strip([36.8, 6.4], [23.4, 38], 2)), fill: "none", stroke: INK, w: 0.3, op: 0.5, line: "none" });
268
+ parts.push({ d: path(strip([35.6, 7.2], [23, 38.6], 1)), fill: INK, stroke: "none", op: 0.1, fx: true });
269
+ // The ties of the jacket (WKF 2.2.1 i): two short strings at the chest.
270
+ parts.push({ d: "M29.6 21.6Q28 23.6 28.6 26M27.4 22.4Q26.2 24.4 26.4 26.4", fill: "none", stroke: INK, w: 0.4, op: 0.5, line: "none" });
271
+ parts.push(dark("M19.8 36.6H44.2", 0.3, 0.3));
272
+ // The belt: 5 cm wide, with 15 cm free on each side of the knot, tied low on the hips; red (AKA) by default.
273
+ parts.push(...belt({ main: "$accent", cx: 32, x0: 19, x1: 45, y: 27.4, w: 2.6, sag: 0, knot: 6.2, tail: 8.8, splay: 7 }));
274
+ return parts;
275
+ }
276
+ export const GEAR_KARATE_GI = /* @__PURE__ */ drawn("gear:karate-gi", "Karate suit", "空手衣", { main: "#fbfaf6", accent: "#c4202e", parts: karateFlat() });
277
+ // ───────────────────────────── the belts ─────────────────────────────
278
+ const obiSpec = (extra) => belt({ main: "$main", cx: 32, x0: 2.4, x1: 61.6, y: 13, w: 5, sag: 1.6, knot: 11.2, tail: 23, splay: 7, bars: true, ...extra });
279
+ const obiPiece = (id, en, ja, main, parts, accent) => drawn(id, en, ja, { main, accent, parts });
280
+ export const GEAR_OBI = /* @__PURE__ */ obiPiece("gear:obi", "Belt", "武道の帯", OBI_RANKS.black, obiSpec({ edge: BELT_EDGE }));
281
+ export const GEAR_OBI_WHITE = /* @__PURE__ */ obiPiece("gear:obi-white", "White belt", "白帯", OBI_RANKS.white, obiSpec());
282
+ export const GEAR_OBI_YELLOW = /* @__PURE__ */ obiPiece("gear:obi-yellow", "Yellow belt", "黄帯", OBI_RANKS.yellow, obiSpec());
283
+ export const GEAR_OBI_ORANGE = /* @__PURE__ */ obiPiece("gear:obi-orange", "Orange belt", "橙帯", OBI_RANKS.orange, obiSpec());
284
+ export const GEAR_OBI_GREEN = /* @__PURE__ */ obiPiece("gear:obi-green", "Green belt", "緑帯", OBI_RANKS.green, obiSpec());
285
+ export const GEAR_OBI_BLUE = /* @__PURE__ */ obiPiece("gear:obi-blue", "Blue belt", "青帯", OBI_RANKS.blue, obiSpec());
286
+ export const GEAR_OBI_BROWN = /* @__PURE__ */ obiPiece("gear:obi-brown", "Brown belt", "茶帯", OBI_RANKS.brown, obiSpec());
287
+ export const GEAR_OBI_RED = /* @__PURE__ */ obiPiece("gear:obi-red", "Red belt", "紅帯", OBI_RANKS.red, obiSpec());
288
+ /** The red-and-white belt of the 6th to 8th dan: panels of red and white (about 21 cm long), red at both ends. */
289
+ export const GEAR_OBI_KOHAKU = /* @__PURE__ */ obiPiece("gear:obi-kohaku", "Red and white belt", "紅白帯", OBI_RANKS.kohaku, obiSpec({ alt: "$accent", panels: { upper: [19, 45], lower: [11, 53], tail: "$main" }, bars: false }), "#f6f4ee");
290
+ /** The black belt of a woman in Japan: a white stripe down the middle of the belt along its whole length. */
291
+ export const GEAR_OBI_WOMEN = /* @__PURE__ */ obiPiece("gear:obi-women", "Women's black belt", "女子用の黒帯", OBI_RANKS.black, obiSpec({ stripe: true, edge: BELT_EDGE }));
292
+ const OBI_BY_RANK = { white: GEAR_OBI_WHITE, yellow: GEAR_OBI_YELLOW, orange: GEAR_OBI_ORANGE, green: GEAR_OBI_GREEN, blue: GEAR_OBI_BLUE, brown: GEAR_OBI_BROWN, black: GEAR_OBI, kohaku: GEAR_OBI_KOHAKU, red: GEAR_OBI_RED };
293
+ // Two-colour belts: the intermediate belts several countries give between two kyu (the IJF names white-yellow, yellow-orange, orange-green and green-blue; France has had them since 1990), drawn as two halves of the
294
+ // belt's width, running the whole length. `tint` is the colour of the upper half and `accent` the colour of the lower.
295
+ const SPLIT = obiSpec({ half: true, alt: "$accent", bars: false });
296
+ const split = (id, en, ja, a, b) => obiPiece(id, en, ja, OBI_RANKS[a], SPLIT, OBI_RANKS[b]);
297
+ export const GEAR_OBI_WHITE_YELLOW = /* @__PURE__ */ split("gear:obi-white-yellow", "White and yellow belt", "白と黄の二色帯", "white", "yellow");
298
+ export const GEAR_OBI_YELLOW_ORANGE = /* @__PURE__ */ split("gear:obi-yellow-orange", "Yellow and orange belt", "黄と橙の二色帯", "yellow", "orange");
299
+ export const GEAR_OBI_ORANGE_GREEN = /* @__PURE__ */ split("gear:obi-orange-green", "Orange and green belt", "橙と緑の二色帯", "orange", "green");
300
+ export const GEAR_OBI_GREEN_BLUE = /* @__PURE__ */ split("gear:obi-green-blue", "Green and blue belt", "緑と青の二色帯", "green", "blue");
301
+ export const GEAR_OBI_BLUE_BROWN = /* @__PURE__ */ split("gear:obi-blue-brown", "Blue and brown belt", "青と茶の二色帯", "blue", "brown");
302
+ /** Any two colours: the belt `obi` draws for a pair. */
303
+ const OBI_SPLIT = /* @__PURE__ */ split("gear:obi-split", "Two-colour belt", "二色の帯", "white", "yellow");
304
+ /**
305
+ * The belt of a rank: `"white"`, `"yellow"`, `"orange"`, `"green"`, `"blue"`, `"brown"` (the kyu), `"black"` (1st to 5th dan), `"kohaku"` (red and white panels, 6th to 8th dan) or `"red"` (9th and 10th dan), or
306
+ * a pair of ranks (`["white", "yellow"]`) for a two-colour belt. An unknown rank is the black belt. `tint` takes one colour, or a pair for a two-colour belt. `women: true` adds the white stripe that women wear on a
307
+ * black belt in Japan.
308
+ */
309
+ export const obi = (rank, options) => {
310
+ const { women, tint, ...rest } = options ?? {};
311
+ const colour = (r) => (Object.hasOwn(OBI_RANKS, r) ? OBI_RANKS[r] : OBI_RANKS.black);
312
+ if (Array.isArray(tint) && tint.length === 2)
313
+ return OBI_SPLIT.svg({ ...rest, tint: tint[0], accent: tint[1] });
314
+ if (Array.isArray(rank))
315
+ return OBI_SPLIT.svg({ ...rest, tint: colour(rank[0]), accent: colour(rank[1]) });
316
+ const known = typeof rank === "string" && Object.hasOwn(OBI_RANKS, rank) ? rank : "black";
317
+ const one = typeof tint === "string" ? { ...rest, tint } : rest;
318
+ if (women === true && known === "black")
319
+ return GEAR_OBI_WOMEN.svg(one);
320
+ return OBI_BY_RANK[known].svg(one);
18
321
  };
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 });
@@ -17,10 +17,10 @@ import { GEAR_STARTING_BLOCKS, GEAR_RELAY_BATON, GEAR_JAVELIN, GEAR_HURDLES } fr
17
17
  import { GEAR_DIVING_BOARD, GEAR_SWIM_GOGGLES } from "./gear.water.js";
18
18
  import { GEAR_GUNBAI, GEAR_MAWASHI } from "./gear.sumo.js";
19
19
  import { GEAR_SHINAI, GEAR_KENDO_MEN } from "./gear.kendo.js";
20
- import { GEAR_JUDOGI, GEAR_KARATE_GI, GEAR_OBI } from "./gear.budo.js";
20
+ import { GEAR_JUDOGI, GEAR_JUDOGI_BLUE, GEAR_JUDOGI_FOLDED, GEAR_JUDOGI_BLUE_FOLDED, GEAR_KARATE_GI, GEAR_OBI, GEAR_OBI_WHITE, GEAR_OBI_YELLOW, GEAR_OBI_ORANGE, GEAR_OBI_GREEN, GEAR_OBI_BLUE, GEAR_OBI_BROWN, GEAR_OBI_KOHAKU, GEAR_OBI_RED, GEAR_OBI_WOMEN, GEAR_OBI_WHITE_YELLOW, GEAR_OBI_YELLOW_ORANGE, GEAR_OBI_ORANGE_GREEN, GEAR_OBI_GREEN_BLUE, GEAR_OBI_BLUE_BROWN } from "./gear.budo.js";
21
21
  import { GEAR_YUMI, GEAR_YA } from "./gear.kyudo.js";
22
22
  /** Every piece of gear, in the order a gallery shows them. */
23
- export const GEARS = [GEAR_HOCKEY_STICK, GEAR_GOALIE_STICK, GEAR_HOCKEY_SKATE, GEAR_GOALIE_MASK, GEAR_GOAL_NET, GEAR_FIELD_HOCKEY_STICK, GEAR_LACROSSE_STICK, GEAR_CRICKET_BAT, GEAR_WICKET, GEAR_TABLE_TENNIS_PADDLE, GEAR_BADMINTON_RACKET, GEAR_TENNIS_RACKET, GEAR_SQUASH_RACKET, GEAR_RACQUETBALL_RACKET, GEAR_PADEL_RACKET, GEAR_PICKLEBALL_PADDLE, GEAR_ROUNDNET_SET, GEAR_VOLLEYBALL_NET, GEAR_BASKETBALL_HOOP, GEAR_BASEBALL_BAT, GEAR_BASEBALL_GLOVE, GEAR_FOOTBALL_HELMET, GEAR_GOALPOSTS, GEAR_HURLEY, GEAR_CURLING_BROOM, GEAR_FIGURE_SKATE, GEAR_SPEED_SKATE, GEAR_DIVING_BOARD, GEAR_SWIM_GOGGLES, GEAR_STARTING_BLOCKS, GEAR_RELAY_BATON, GEAR_JAVELIN, GEAR_HURDLES, GEAR_GUNBAI, GEAR_MAWASHI, GEAR_SHINAI, GEAR_KENDO_MEN, GEAR_JUDOGI, GEAR_OBI, GEAR_YUMI, GEAR_YA, GEAR_KARATE_GI];
23
+ export const GEARS = [GEAR_HOCKEY_STICK, GEAR_GOALIE_STICK, GEAR_HOCKEY_SKATE, GEAR_GOALIE_MASK, GEAR_GOAL_NET, GEAR_FIELD_HOCKEY_STICK, GEAR_LACROSSE_STICK, GEAR_CRICKET_BAT, GEAR_WICKET, GEAR_TABLE_TENNIS_PADDLE, GEAR_BADMINTON_RACKET, GEAR_TENNIS_RACKET, GEAR_SQUASH_RACKET, GEAR_RACQUETBALL_RACKET, GEAR_PADEL_RACKET, GEAR_PICKLEBALL_PADDLE, GEAR_ROUNDNET_SET, GEAR_VOLLEYBALL_NET, GEAR_BASKETBALL_HOOP, GEAR_BASEBALL_BAT, GEAR_BASEBALL_GLOVE, GEAR_FOOTBALL_HELMET, GEAR_GOALPOSTS, GEAR_HURLEY, GEAR_CURLING_BROOM, GEAR_FIGURE_SKATE, GEAR_SPEED_SKATE, GEAR_DIVING_BOARD, GEAR_SWIM_GOGGLES, GEAR_STARTING_BLOCKS, GEAR_RELAY_BATON, GEAR_JAVELIN, GEAR_HURDLES, GEAR_GUNBAI, GEAR_MAWASHI, GEAR_SHINAI, GEAR_KENDO_MEN, GEAR_JUDOGI, GEAR_JUDOGI_BLUE, GEAR_JUDOGI_FOLDED, GEAR_JUDOGI_BLUE_FOLDED, GEAR_OBI, GEAR_OBI_WHITE, GEAR_OBI_YELLOW, GEAR_OBI_ORANGE, GEAR_OBI_GREEN, GEAR_OBI_BLUE, GEAR_OBI_BROWN, GEAR_OBI_KOHAKU, GEAR_OBI_RED, GEAR_OBI_WOMEN, GEAR_OBI_WHITE_YELLOW, GEAR_OBI_YELLOW_ORANGE, GEAR_OBI_ORANGE_GREEN, GEAR_OBI_GREEN_BLUE, GEAR_OBI_BLUE_BROWN, GEAR_YUMI, GEAR_YA, GEAR_KARATE_GI];
24
24
  /** The id of every piece of gear: `"gear:hockey-stick"`. */
25
25
  export const GEAR_IDS = GEARS.map((g) => g.id);
26
26
  const TABLE = new Map(GEARS.map((g) => [g.id, g]));
@@ -1,5 +1,5 @@
1
- // Canadian football: a pictogram drawn for this package, in a 64 by 64 box. The metal style paints its main shapes with a grey sheet, the line style draws one outline.
1
+ // Canadian football: the pictogram of the ball with a white stripe all the way round near each end (CFL Rule 1, Section 2), drawn for this package from `ball:football-cfl`, in a 64 by 64 box.
2
2
  import { defineIcon } from "../emblem.shapes.js";
3
- import { SPORT_NFL } from "./nfl.js";
3
+ import { footballModel } from "./nfl.js";
4
4
  /** Canadian football. */
5
- export const SPORT_CFL = /* @__PURE__ */ defineIcon("sport:cfl", "Canadian football", "カナディアンフットボール", "ours", SPORT_NFL.model);
5
+ export const SPORT_CFL = /* @__PURE__ */ defineIcon("sport:cfl", "Canadian football", "カナディアンフットボール", "ours", footballModel("ring"));
@@ -1,5 +1,5 @@
1
- // International football: a pictogram drawn for this package, in a 64 by 64 box. The metal style paints its main shapes with a grey sheet, the line style draws one outline.
1
+ // International football: the pictogram of the ball with a stripe near each end on the two panels next to the laces only (IFAF Rule 1, Section 3), drawn for this package from `ball:football-ifaf`, in a 64 by 64 box.
2
2
  import { defineIcon } from "../emblem.shapes.js";
3
- import { SPORT_NFL } from "./nfl.js";
3
+ import { footballModel } from "./nfl.js";
4
4
  /** American football, international rules. */
5
- export const SPORT_IFAF = /* @__PURE__ */ defineIcon("sport:ifaf", "International football", "国際アメフト", "ours", SPORT_NFL.model);
5
+ export const SPORT_IFAF = /* @__PURE__ */ defineIcon("sport:ifaf", "International football", "国際アメフト", "ours", footballModel("top"));
@@ -1,13 +1,18 @@
1
- // Judo: a pictogram of the suit and its belt, drawn for this package, in a 64 by 64 box. The metal style paints its main shapes with a grey sheet, the line style draws one outline.
2
- import { defineIcon } from "../emblem.shapes.js";
1
+ // Judo: a pictogram of the judogi, drawn for this package in a 64 by 64 box: the jacket with its sleeves out, the lapels crossed left over right, the belt tied in a flat knot with the two ends hanging, and the trousers.
2
+ // The metal style paints its main shapes with a grey sheet, the line style draws one outline.
3
+ import { bar, defineIcon } from "../emblem.shapes.js";
3
4
  /** Judo. */
4
5
  export const SPORT_JUDO = /* @__PURE__ */ defineIcon("sport:judo", "Judo", "柔道", "ours", {
5
6
  metal: "flat",
6
7
  ink: true,
7
8
  front: [
8
- ["m", "M23.6 8L7 36.6Q5.6 39.6 8.4 41.6L14.4 45.4Q17.2 46.8 18.8 43.8L19.4 42.6V58H31V46.6H33V58H44.6V42.6L45.2 43.8Q46.8 46.8 49.6 45.4L55.6 41.6Q58.4 39.6 57 36.6L40.4 8Q32 5.6 23.6 8Z"],
9
- ["n", "M25.4 7.6L36 32M38.6 7.6L28 32"],
10
- ["k", "M19.4 38.4H44.6V44H19.4z"],
11
- ["k", "M29.4 44L26 56h3.6L32.4 44zM34.6 44L38 55h-3.6L31.6 44z"],
9
+ ["m", "M18.6 38H45.4L47.2 60H34.4L32 45.4L29.6 60H16.8Z"],
10
+ ["m", "M26 6Q32 3.8 38 6L45 9L60.4 23L56.6 30.4L46.4 26.2L46 39H18L17.6 26.2L7.4 30.4L3.6 23L19 9Z"],
11
+ ["k", "M27 5.6H37L32.8 16Z"],
12
+ ["n", bar(37.2, 6.4, 24.8, 38, 4.6)],
13
+ ["t", "M17.6 26.2L18 38M46.4 26.2L46 38"],
14
+ ["k", "M17.8 27.6H46.2V32H17.8Z"],
15
+ ["k", "M28 26.4H36V33H28Z"],
16
+ ["k", "M29.4 32L26.6 46h4.4L32.6 32zM34.6 32L37.4 46h-4.4L31.4 32z"],
12
17
  ],
13
18
  });
@@ -1,13 +1,17 @@
1
- // Karate: a pictogram of a clenched fist seen from the front, drawn for this package, in a 64 by 64 box. The metal style paints its main shapes with a grey sheet, the line style draws one outline.
2
- import { defineIcon } from "../emblem.shapes.js";
1
+ // Karate: a pictogram of the karate-gi, drawn for this package in a 64 by 64 box: a lighter suit than the judogi's, with shorter sleeves, a wide V of plain lapels, a short jacket, a belt tied low with its ends hanging
2
+ // and straight trousers. The metal style paints its main shapes with a grey sheet, the line style draws one outline.
3
+ import { bar, defineIcon } from "../emblem.shapes.js";
3
4
  /** Karate. */
4
5
  export const SPORT_KARATE = /* @__PURE__ */ defineIcon("sport:karate", "Karate", "空手", "ours", {
5
6
  metal: "flat",
6
7
  ink: true,
7
8
  front: [
8
- ["m", "M14 30V21a4.5 4.5 0 0 1 9 0v9zM23 30V17a4.5 4.5 0 0 1 9 0v13zM32 30V17a4.5 4.5 0 0 1 9 0v13zM41 30V21a4.5 4.5 0 0 1 9 0v9z"],
9
- ["m", "M14 28H50V46Q50 59 37 59H27Q14 59 14 46Z"],
10
- ["m", "M19 34H45a4.4 4.4 0 0 1 0 8.8H19a4.4 4.4 0 0 1 0-8.8z"],
11
- ["t", "M16 50Q32 55 48 50"],
9
+ ["m", "M20 36H44L45.6 61H34.6L32 46L29.4 61H18.4Z"],
10
+ ["m", "M26 6Q32 3.8 38 6L45 8.6L56 18L52.6 24.6L45.4 21L45 40H19L18.6 21L11.4 24.6L8 18L19 8.6Z"],
11
+ ["k", "M27 5.6H37L32 20Z"],
12
+ ["n", bar(37, 6.4, 24, 40, 3)],
13
+ ["k", "M18.8 31H45.2V35.4H18.8Z"],
14
+ ["k", "M28.4 29.8H35.6V36.4H28.4Z"],
15
+ ["k", "M29.6 36L27.2 48h4L32.6 36zM34.4 36L36.8 48h-4L31.4 36z"],
12
16
  ],
13
17
  });
@@ -1,3 +1,5 @@
1
1
  import { type FlatModel } from "../emblem.shapes.ts";
2
+ /** The football pictogram: no stripes (the NFL), a ring near each end (the CFL) or the arcs on the laces' side only (IFAF). */
3
+ export declare function footballModel(stripes: "none" | "ring" | "top"): FlatModel;
2
4
  /** American football. */
3
5
  export declare const SPORT_NFL: import("../emblem.core.ts").Emblem<FlatModel>;
@@ -1,15 +1,34 @@
1
- // American football: a pictogram of the ball, drawn for this package, in a 64 by 64 box. The Canadian and the international-rules pictograms are the same drawing.
1
+ // American football: a pictogram of the ball, drawn for this package from the drawings of the balls (`ball:football`, `ball:football-cfl`, `ball:football-ifaf`), in a 64 by 64 box: a prolate ball whose ends come to
2
+ // a blunt point, lying on the diagonal with its laces on the upper side. The Canadian ball has a white stripe all the way round near each end (CFL Rule 1, Section 2); the IFAF ball has a stripe near each end on the
3
+ // two panels next to the laces only, which is the upper half of the picture (IFAF Rule 1, Section 3); the NFL ball has none.
2
4
  import { defineIcon } from "../emblem.shapes.js";
3
- /** A pointed ball on the diagonal, with laces and a band near each end. */
4
- const FOOTBALL = {
5
- metal: "flat",
6
- ink: true,
7
- front: [
8
- ["m", "M8 56Q15.4 15.4 56 8Q48.6 48.6 8 56Z"],
9
- ["n", "M26 38L38 26"],
10
- ["t", "M29.4 31.2l3.4 3.4M32.2 28.4l3.4 3.4M26.6 34l3.4 3.4M23.8 36.8l3.4 3.4M35 25.6l3.4 3.4"],
11
- ["t", "M14.6 40.6l5.6 5.6M43.8 17.8l5.6 5.6"],
12
- ],
5
+ const f = (n) => String(Math.round(n * 10) / 10);
6
+ const TURN = (40 * Math.PI) / 180;
7
+ /** A point of the ball's own frame (long axis along x, the laces on the upper side, y negative) put on the picture: turned 40 degrees about the centre of the box. */
8
+ const at = (x, y) => `${f(32 + x * Math.cos(TURN) - y * Math.sin(TURN))} ${f(32 + x * Math.sin(TURN) + y * Math.cos(TURN))}`;
9
+ const HALF = 29.6;
10
+ const WIDTH = 17.4;
11
+ /** The half width of the ball at `x` along its axis: an ellipse whose ends are drawn out a little, so they come to a blunt point as the real ball's do. */
12
+ const half = (x) => WIDTH * (1 - Math.min(1, Math.abs(x / HALF)) ** 2) ** 0.72;
13
+ const outline = () => {
14
+ const xs = Array.from({ length: 33 }, (_, i) => -HALF * Math.cos((Math.PI * i) / 32));
15
+ return `M${xs.map((x) => at(x, -half(x))).join("L")}L${[...xs].reverse().map((x) => at(x, half(x))).join("L")}z`;
13
16
  };
17
+ /** The ball between `x0` and `x1` along its axis, over the part of its width from `y0` to `y1` (as fractions of the half width, -1 the upper edge): a stripe. */
18
+ const band = (x0, x1, y0, y1) => {
19
+ const xs = Array.from({ length: 7 }, (_, i) => x0 + ((x1 - x0) * i) / 6);
20
+ return `M${xs.map((x) => at(x, y0 * half(x))).join("L")}L${[...xs].reverse().map((x) => at(x, y1 * half(x))).join("L")}z`;
21
+ };
22
+ /** The football pictogram: no stripes (the NFL), a ring near each end (the CFL) or the arcs on the laces' side only (IFAF). */
23
+ export function footballModel(stripes) {
24
+ const front = [["m", outline()]];
25
+ if (stripes !== "none")
26
+ for (const sign of [-1, 1])
27
+ front.push(["f", band(sign * 15.6, sign * 20.6, stripes === "ring" ? -1 : -1, stripes === "ring" ? 1 : 0.05), "#f4f0e6"]);
28
+ // the laces: a row of short bars across a line, on the upper side of the middle
29
+ const rungs = [-8, -4.8, -1.6, 1.6, 4.8, 8].map((x) => `M${at(x, -9.4)}L${at(x, -3)}`).join("");
30
+ front.push(["t", `M${at(-9.6, -6.2)}L${at(9.6, -6.2)}${rungs}`]);
31
+ return { metal: "flat", ink: true, front };
32
+ }
14
33
  /** American football. */
15
- export const SPORT_NFL = /* @__PURE__ */ defineIcon("sport:nfl", "American football", "アメリカンフットボール", "ours", FOOTBALL);
34
+ export const SPORT_NFL = /* @__PURE__ */ defineIcon("sport:nfl", "American football", "アメリカンフットボール", "ours", footballModel("none"));
package/dist/index.d.ts CHANGED
@@ -138,7 +138,7 @@ export { GEAR_STARTING_BLOCKS, GEAR_RELAY_BATON, GEAR_JAVELIN, GEAR_HURDLES } fr
138
138
  export { GEAR_DIVING_BOARD, GEAR_SWIM_GOGGLES } from "./emblems/gear/gear.water.ts";
139
139
  export { GEAR_GUNBAI, GEAR_MAWASHI } from "./emblems/gear/gear.sumo.ts";
140
140
  export { GEAR_SHINAI, GEAR_KENDO_MEN } from "./emblems/gear/gear.kendo.ts";
141
- export { GEAR_JUDOGI, GEAR_KARATE_GI, GEAR_OBI, OBI_RANKS, obi } from "./emblems/gear/gear.budo.ts";
142
- export type { ObiRank } from "./emblems/gear/gear.budo.ts";
141
+ export { GEAR_JUDOGI, GEAR_JUDOGI_BLUE, GEAR_JUDOGI_FOLDED, GEAR_JUDOGI_BLUE_FOLDED, GEAR_KARATE_GI, GEAR_OBI, GEAR_OBI_WHITE, GEAR_OBI_YELLOW, GEAR_OBI_ORANGE, GEAR_OBI_GREEN, GEAR_OBI_BLUE, GEAR_OBI_BROWN, GEAR_OBI_KOHAKU, GEAR_OBI_RED, GEAR_OBI_WOMEN, GEAR_OBI_WHITE_YELLOW, GEAR_OBI_YELLOW_ORANGE, GEAR_OBI_ORANGE_GREEN, GEAR_OBI_GREEN_BLUE, GEAR_OBI_BLUE_BROWN, JUDOGI_WHITE, JUDOGI_BLUE, OBI_RANKS, obi } from "./emblems/gear/gear.budo.ts";
142
+ export type { ObiRank, ObiOptions } from "./emblems/gear/gear.budo.ts";
143
143
  export { GEAR_YUMI, GEAR_YA } from "./emblems/gear/gear.kyudo.ts";
144
144
  export { VERSION } from "./version.ts";
package/dist/index.js CHANGED
@@ -139,6 +139,6 @@ export { GEAR_STARTING_BLOCKS, GEAR_RELAY_BATON, GEAR_JAVELIN, GEAR_HURDLES } fr
139
139
  export { GEAR_DIVING_BOARD, GEAR_SWIM_GOGGLES } from "./emblems/gear/gear.water.js";
140
140
  export { GEAR_GUNBAI, GEAR_MAWASHI } from "./emblems/gear/gear.sumo.js";
141
141
  export { GEAR_SHINAI, GEAR_KENDO_MEN } from "./emblems/gear/gear.kendo.js";
142
- export { GEAR_JUDOGI, GEAR_KARATE_GI, GEAR_OBI, OBI_RANKS, obi } from "./emblems/gear/gear.budo.js";
142
+ export { GEAR_JUDOGI, GEAR_JUDOGI_BLUE, GEAR_JUDOGI_FOLDED, GEAR_JUDOGI_BLUE_FOLDED, GEAR_KARATE_GI, GEAR_OBI, GEAR_OBI_WHITE, GEAR_OBI_YELLOW, GEAR_OBI_ORANGE, GEAR_OBI_GREEN, GEAR_OBI_BLUE, GEAR_OBI_BROWN, GEAR_OBI_KOHAKU, GEAR_OBI_RED, GEAR_OBI_WOMEN, GEAR_OBI_WHITE_YELLOW, GEAR_OBI_YELLOW_ORANGE, GEAR_OBI_ORANGE_GREEN, GEAR_OBI_GREEN_BLUE, GEAR_OBI_BLUE_BROWN, JUDOGI_WHITE, JUDOGI_BLUE, OBI_RANKS, obi } from "./emblems/gear/gear.budo.js";
143
143
  export { GEAR_YUMI, GEAR_YA } from "./emblems/gear/gear.kyudo.js";
144
144
  export { VERSION } from "./version.js";
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.5.0";
1
+ export declare const VERSION = "0.5.2";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = "0.5.0";
1
+ export const VERSION = "0.5.2";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@johnmorrisdotca/dougu-sports",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Dougu Sports 道具, sports emblems as SVG strings: trophies, medals, crests, sport icons, and the ball and gear of every sport, in metal, line or flat colour, with optional 3D turning. Light and dark, accessible, tree-shakeable. Zero dependencies.",
5
5
  "keywords": [
6
6
  "sports",