@johnmorrisdotca/kyogijo-stadiums 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,23 @@ All notable changes to this project are written here. The format follows
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.22.0] - 2026-10-20
11
+
12
+ ### Added
13
+
14
+ - **The wrestling mats** (`sport: "wrestling"`, [the combat sports page](./docs/combat.md)): the UWW's mat (freestyle, Greco-Roman and women's wrestling are wrestled on the same one: a circle of 9 m with a protection area of 1.5 m, an orange passivity band of 1 m inside the circle, a central circle of 1 m, a platform of 0.80 to 1.10 m), the NCAA's folkstyle mat (a competition circle of 32 to 42 feet with a 2 inch line, a matted area of at least 5 feet, two starting lines closed by a green and a red line) and the high schools' (a circle of at least 28 feet, a safety mat of about 5 feet, the circle of 10 feet, optional from 2024-25, the same starting lines), to scale. The leagues are `uww`, `ncaa-wrestling` and `nfhs-wrestling`; `budo.size` (the circle), `budo.height` (the platform), `budo.circle` and `budo.start` stay within each league and refuse a number outside it; the looks are `blue-red`, `green-beige` and `yellow-blue`; `RANGES.wrestling` has `start`, `passivity` (the UWW's) and `half`. In 3D the UWW's platform is a solid block with the mat as its top, and a folkstyle mat lies on the floor. A figure that is the rule's, one that is typical and one that is ours are told apart in [Sources](./docs/sources.md#the-combat-sports). It is the forty-second sport.
15
+ - **The demo** has the mats in its sport picker, with their league and looks, the score of a bout and the 3D view.
16
+
17
+
18
+ ## [0.21.0] - 2026-10-20
19
+
20
+ ### Added
21
+
22
+ - **The boxing ring** (`sport: "boxing"`, [the combat sports page](./docs/combat.md)): a square raised platform with its canvas, four ropes that turn to a post at each corner by an extension, the posts and their pads in red, blue and white, an apron and three sets of steps, to scale from the Nevada Rules of Unarmed Combat (2.050), Wisconsin's SPS 192.38 and the WBC Amateur rules, with Ontario's amateur rules beside them. The leagues are `nruc-ring` (20 feet within the ropes), `wisconsin` (16 to 20 feet) and `wbc-amateur` (4.5 to 6.1 m); `budo.size` and `budo.height` stay within each league's range and refuse a number outside it, `budo.steps` and `budo.corners` take the steps away and make the corners plain; the looks are `white`, `blue` and `black`, light and dark. `RANGES.boxing` has `ropes`, `corner` and `half`; the parts are named for `landmarks` and the features for `featureColors`, in English and Japanese. A figure that is the rule's, one that is typical and one that is ours are told apart in [Sources](./docs/sources.md#the-combat-sports). It is the forty-first sport.
23
+ - **The ring in 3D:** the platform is a solid block as the cage's is, the four posts are solid in their corner's colour at 58 inches over the ring floor, each of the four ropes is a thin round bar along each side and out to its post at each corner so that the canvas stays in sight, two ties a side hold the ropes in line, and the steps are three blocks each. Tests hold the order the parts are drawn in from every side, the size of the view as it turns and the scene inside its box at every angle.
24
+ - **The demo** has the ring in its sport picker, with its league, its looks, the score of a bout and the 3D view.
25
+
26
+
10
27
  ## [0.20.0] - 2026-10-20
11
28
 
12
29
  ### Added
package/NOTICE.md CHANGED
@@ -35,7 +35,7 @@ picture or code of the sources is copied; each source is named here so that the
35
35
  | `leagues`: the skating rinks | The International Skating Union's Sports Rules - Speed Skating (Special Regulations and Technical Rules, Rules 203 to 206, 226 to 228 and 253 to 257, and "H. Track", effective 12 June 2026), Special Regulations and Technical Rules Short Track Speed Skating (Rule 280 and the diagram of the tracks, 2024) and Sports Rules - Figure Skating (Rule 342, effective 12 June 2026) | Facts; no text or drawing copied |
36
36
  | `leagues` and `halls`: the budō surfaces | The International Judo Federation's Sport and Organisation Rules (version of 21 January 2026, 8.7, Article 9, B1.8; and the June 2020 version, 18.1) and its Kata Commission's Tournament Handbook (2024) and Criteria for the Evaluation (January 2025); the All Japan Judo Federation's 大会運営ガイドブック2023; the World Karate Federation's Kumite and Kata Competition Rules (2026); the International Kendo Federation's Regulations of Kendo Shiai and Shinpan (Article 2 and Figure 1); the Japan Sumo Association's 相撲規則 土俵規定 第一条 and 大相撲クイズ, as the Sasakawa Sports Foundation and ozumo.jp quote them; the All Nippon Kyudo Federation's 弓道競技運営要領 (2016) and the National Sports Festival 2015's rules for kinteki and enteki; the tatami sizes of English and Japanese Wikipedia; the Kodokan's 施設のご案内, the Nippon Budokan's 日本武道館建物等概要 (October 2021), and English and Japanese Wikipedia and Wikidata on the five halls and the kimarite | Facts |
37
37
  | `frames`: the soccer providers' coordinates | StatsBomb's Open Data Events specification (Appendix 2), the Wyscout and Impect glossaries, the Metrica Sports and SkillCorner open-data READMEs; for Opta, Tracab and Second Spectrum, whose specifications are not public, the figures of mplsoccer, ggsoccer, kloppy and floodlight (docs/sources.md) | Facts; no text, table or code copied |
38
- | `leagues`: the MMA cage | The Nevada Rules of Unarmed Combat (NRUC 5.010, the file of 20 November 2024), Oregon Administrative Rule 230-070-0025, the IMMAF's Unified Rules for amateur, junior and senior competition (January 2021), and the English Wikipedia articles "Mixed martial arts cage" (revision 1377260922) and "Mixed martial arts" (revision 1381048799), for the sizes that are typical | Facts, CC BY-SA 4.0 for the Wikipedia text read |
38
+ | `leagues`: the MMA cage, the boxing ring and the wrestling mats | The Nevada Rules of Unarmed Combat (NRUC 5.010, the file of 20 November 2024), Oregon Administrative Rule 230-070-0025, the IMMAF's Unified Rules for amateur, junior and senior competition (January 2021), Wisconsin's SPS 192.38, the UWW's Wrestling Rules (January 2026), the NCAA's Wrestling Rules (2025-26 and 2026-27), the NFHS's mat rules as the KHSAA, Resilite and the NJSIAA quote them, the WBC Amateur competition rules (2026), Ontario's Amateur combative sport rules: Boxing (Part II), and the English Wikipedia articles "Mixed martial arts cage" (revision 1377260922), "Mixed martial arts" (revision 1381048799) and "Boxing ring" (revision 1370389178), for the sizes that are typical | Facts, CC BY-SA 4.0 for the Wikipedia text read |
39
39
  | `parks`: the fence of each ballpark, current and past, and the seasons of a past park | The distances (and, for a park whose fence moved, the years an article dates them) published in the English and Japanese Wikipedia article of each park, at the revision cited below; the seasons a club played there from the same article's list of tenants | Facts. The articles are CC BY-SA 4.0 (https://creativecommons.org/licenses/by-sa/4.0/); none of their text, tables or images is used, and the angles between the distances are our own reading |
40
40
  | `parks`: the Wikidata item of each ballpark (`wikidata`) | The item (`Q49136`) that each cited article is linked to, read with the MediaWiki API (`pageprops`, `wikibase_item`) and checked against the item's label | Wikidata's data is CC0 (https://creativecommons.org/publicdomain/zero/1.0/) |
41
41
  | `parks` and `grounds`: the names (`name`, `nameJa`, `readingJa`, `localName`, `aliases`) | The names are facts. Each alias says where it was read (`source`): the title of the English or Japanese Wikipedia article a place cites (with its revision), a name the infobox or the opening text of the same revision gives (a former or sponsor's name with the years it dates, a nickname, the name in Japanese and its reading), or Wikidata's labels, aliases and properties "official name" (P1448), "nickname" (P1449), "name" (P2561), "short name" (P1813), read with the Wikidata API by `scripts/fetch-names.mjs` into `scripts/names.wikidata.json` | Facts; Wikidata's data is CC0 (https://creativecommons.org/publicdomain/zero/1.0/), and the articles are CC BY-SA 4.0 as above, none of their text copied. Which name is the everyday one is our reading, in docs/references.md ("Names") |
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <h1 align="center">Kyogijo Stadiums <sub>競技場</sub></h1>
2
2
 
3
3
  <p align="center"><strong>Sports surfaces as SVG, drawn to scale, with the score on them.</strong><br>
4
- The surfaces of forty sports, from football and curling to the budō and the MMA cage, each drawn from its rulebook or its published distances, with each team's name and logo on its side and the score in the middle, a lineup and the situation of the game on them, with stands and a crowd, a pageant of flags and a 3D view. Wide or tall, light or dark, a badge for a list, a helper for React, a custom element and a frame for a page that runs no script. One function, no dependencies.</p>
4
+ The surfaces of forty-two sports, from football and curling to the budō and the combat sports, each drawn from its rulebook or its published distances, with each team's name and logo on its side and the score in the middle, a lineup, stands and a crowd, a pageant of flags and a 3D view. Wide or tall, light or dark, a badge for a list, a helper for React, a custom element and a frame for a page that runs no script. One function, no dependencies.</p>
5
5
 
6
6
  <p align="center">
7
7
  <a href="https://github.com/johnmorrisdotca/kyogijo-stadiums/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/johnmorrisdotca/kyogijo-stadiums/actions/workflows/ci.yml/badge.svg"></a>
@@ -34,7 +34,7 @@ The surfaces of forty sports, from football and curling to the budō and the MMA
34
34
  </tr>
35
35
  </table>
36
36
 
37
- Kyogijo Stadiums draws the places a game is played on, and puts a game on them. It was made to show the score of a game or a championship on the surface it was played on: the teams at their ends, the score in the middle, a label for what it was. The surfaces are drawn to scale from the rulebooks, so that a football field has its hash marks where the rules put them and a ballpark has its fence where its published distances put it.
37
+ Kyogijo Stadiums draws the places a game is played on, with the score of the game on them: the teams at their ends, the score in the middle, a label for what it was. The surfaces are drawn to scale from the rulebooks: a football field has its hash marks where the rules put them, a ballpark its fence where its published distances put it.
38
38
 
39
39
  ## In 30 seconds
40
40
 
@@ -72,29 +72,29 @@ console.log(svg.startsWith("<svg"), svg.includes("USA 3, Canada 2"));
72
72
 
73
73
  ## Features
74
74
 
75
- - **Forty surfaces, to scale.** The NFL, CFL and IFAF fields, the NHL rink, the NBA court, the soccer pitch and futsal court, the baseball field, the curling sheet, twelve net and racket sports, the pools, the athletics stadium, the skating rinks, seven field sports, the budō and the MMA cage. Every figure is cited in [sources](./docs/sources.md). [The surfaces](./docs/surfaces.md).
75
+ - **Forty-two surfaces, to scale.** The NFL, CFL and IFAF fields, the NHL rink, the NBA court, the soccer pitch and futsal court, the baseball field, the curling sheet, twelve net and racket sports, the pools, the athletics stadium, the skating rinks, seven field sports, the budō, the MMA cage, the boxing ring and the wrestling mats. Every figure is cited in [sources](./docs/sources.md). [The surfaces](./docs/surfaces.md).
76
76
  - **Each league's rulebook.** `league: "fiba"` draws a court as FIBA marks it: 48 variants, from the WNBA, the NCAA and the IIHF to Little League, PONY, softball, Curling Canada, FIVB's beach volleyball, rugby league and the NLL's box lacrosse, each cited. [League variants](./docs/variants.md).
77
77
  - **A realistic basketball floor.** `court: { hardwood: true }` draws maple boards that run the length of the court with staggered ends, grain, stained keys, the baskets and stanchions with soft shadows, a coaching box and benches, and a satin sheen, in every league and renderer. The clean floor stays the default. [Hardwood](./docs/hardwood.md).
78
78
  - **The stands and the crowd.** `crowd: true` draws the seating round any surface that has spectators: a bowl, two sides, a horseshoe, courtside rows or a ballpark's grandstands, with the people as seeded heads and shoulders in the home colours and the empty seats showing (`density`, or `attendance` over `capacity`). [The crowd](./docs/crowd.md).
79
- - **Curling, from the rule books.** A sheet from World Curling's and Curling Canada's rules, tall by default, with the board and the hammer in a score, `curlingStones` for the stones of an end, scored by the rules, `show: "folded"` for the whole sheet with both houses enlarged beside it, and a heat map and statistics for many ends. [Curling](./docs/curling.md).
80
- - **Net, racket and court sports, from their rulebooks.** The ITF's, FIVB's (indoor, beach, sitting), BWF's, USA Pickleball's and ITTF's courts and table, the padel, squash, racquetball, sepak takraw, teqball, roundnet and netball courts, each in its look (hard court, clay, grass, wood, sand), with a board of sets and games. [Net, racket and court sports](./docs/courts.md).
81
- - **Swimming, water polo, diving and artistic swimming, from World Aquatics' regulations.** The 50 or 25 m pool with its lanes, ropes, blocks and touch panels; the water polo field; the diving well; the artistic swimming area; several pools in a natatorium. A race's lanes carry names, flags, places, times and splits, with a replay and a `splitsChart`. [Pools](./docs/pools.md).
82
- - **Lacrosse, rugby, Australian football, Gaelic games, cricket, field hockey and handball, from their rulebooks.** The fields and floors of World Lacrosse, World Rugby, the NRL, the AFL, the GAA, the FIH and the IHF, and a cricket ground with a boundary of your own. A score is goals and behinds, goals and points or a board of runs, wickets and overs. [Field sports](./docs/field-sports.md).
83
- - **The athletics stadium, from World Athletics' rules.** The 400 m track with its lanes and staggers worked out from the running lines, curved and relay starts, hurdles, the steeplechase, every field event, a close-up of each start, the covered 200 m track, and lane draws, results, a race replay and the marks of throws and jumps. [The athletics stadium](./docs/athletics.md).
84
- - **The skating rinks, from the ISU's rules.** The 400 m speed skating track with its lanes, blocks and the lines of every race worked out lane by lane; the short track's oval; the figure skating rink of 60 by 30 m with its judges' seats; and pairs, results, a race replay and the elements of a programme on the ice. [The skating rinks](./docs/skating.md).
79
+ - **Curling, from the rule books.** A sheet from World Curling's and Curling Canada's rules, tall by default, with the board and the hammer in a score, `curlingStones` for the stones of an end, `show: "folded"` for the whole sheet with both houses enlarged beside it. [Curling](./docs/curling.md).
80
+ - **Net, racket and court sports, from their rulebooks.** The ITF's, FIVB's (indoor, beach, sitting), BWF's, USA Pickleball's and ITTF's courts and table, the padel, squash, racquetball, sepak takraw, teqball, roundnet and netball courts, each in its look, with a board of sets and games. [Net, racket and court sports](./docs/courts.md).
81
+ - **Swimming, water polo, diving and artistic swimming, from World Aquatics' regulations.** The 50 or 25 m pool with its lanes, ropes, blocks and touch panels; the water polo field; the diving well; the artistic swimming area. A race's lanes carry names, flags, places and times, with a replay. [Pools](./docs/pools.md).
82
+ - **Lacrosse, rugby, Australian football, Gaelic games, cricket, field hockey and handball, from their rulebooks.** The fields and floors of World Lacrosse, World Rugby, the NRL, the AFL, the GAA, the FIH and the IHF, and a cricket ground with a boundary of your own. A score is goals and behinds, goals and points, or runs, wickets and overs. [Field sports](./docs/field-sports.md).
83
+ - **The athletics stadium, from World Athletics' rules.** The 400 m track with its lanes and staggers worked out from the running lines, curved and relay starts, hurdles, the steeplechase, every field event, a close-up of each start, the covered 200 m track, with lane draws, results and a race replay. [The athletics stadium](./docs/athletics.md).
84
+ - **The skating rinks, from the ISU's rules.** The 400 m speed skating track with its lanes, blocks and the lines of every race worked out lane by lane; the short track's oval; the figure skating rink with its judges' seats; and results, a race replay and the elements of a programme. [The skating rinks](./docs/skating.md).
85
85
  - **The budō, from the federations' rules.** The IJF's and the All Japan Judo Federation's judo areas, the WKF's karate areas, the kendo shiai-jo, the sumo dohyō, the kyūdōjō, and **a dojo builder**: a floor of tatami laid as real units, in jō or metres, with its walls, doors, windows and shrine. Scores are judo's ippon, waza-ari and shido, karate's and kendo's points and sumo's kimarite. [The budō](./docs/budo.md).
86
86
  - **Soccer, to the Laws.** A pitch from Law 1 of the IFAB Laws of the Game of any size, with presets (international, UEFA, MLS, NCAA, the FA's 9-, 7- and 5-a-side, FIFA's futsal), half pitches, five mowing patterns, four goal styles, penalties and extra time in a score. [Soccer](./docs/soccer.md).
87
87
  - **Every ballpark.** The 30 current MLB parks and 44 that MLB clubs have left, and the 12 home parks of Nippon Professional Baseball with eight other NPB grounds, each with its fence drawn from the distances published for it, as it stood in a season. [Ballparks](./docs/ballparks.md).
88
88
  - **Soccer grounds, arenas and an atlas.** 64 soccer grounds at their published sizes, 167 NHL, NBA, WNBA and PWHL arenas (`drawKyogijo({ sport: "nhl", arena: "boston-garden" })`), and every park, ground, arena and budō hall (330 places) on a map, found by any of its names. [The grounds](./docs/grounds.md), [the arenas](./docs/arenas.md), [the atlas](./docs/atlas.md), [names](./docs/ballparks.md#names).
89
- - **Walls and quirks.** How high the fence stands, stretch by stretch and season by season (the Green Monster at 37 feet 2 inches), drawn as a band outside the fence whose width and shade say the height, with a key (`walls`); and Tal's Hill, Wrigley Field's ivy and basket, poles, bullpens and dugouts (`quirks`), each from the park's article, none guessed: [ballparks](./docs/ballparks.md).
90
- - **Special games.** A surface set inside another, to scale: an NHL rink on a ballpark's infield or a football stadium's field, a college basketball court on the deck of a carrier, a baseball field laid over a London stadium's pitch. 18 games, each with its day, its venue and its sources. [Special games](./docs/special-games.md).
89
+ - **Walls and quirks.** How high the fence stands, stretch by stretch and season by season (the Green Monster at 37 feet 2 inches) (`walls`); and Tal's Hill, Wrigley Field's ivy and basket, poles, bullpens and dugouts (`quirks`), each from the park's article, none guessed: [ballparks](./docs/ballparks.md).
90
+ - **Special games.** A surface set inside another, to scale: an NHL rink on a ballpark's infield or a football stadium's field or a baseball field laid over a London stadium's pitch. 18 games, each cited. [Special games](./docs/special-games.md).
91
91
  - **Surfaces through the years.** `year: 1975` draws a surface as its league's rules marked it that season, each change cited. [Surfaces through the years](./docs/eras.md).
92
92
  - **Score mode.** Each team's name and logo on its side (the end zones, the ends of the ice, the halves of the court, the dugouts) and the score large in the middle, with the competition, the status and the date, and the winner emphasised; a flag or a crest can be round, in a circle with a ring (`markShape: "round"`). [Score and layout](./docs/score.md#round-marks).
93
93
  - **The situation of a game.** `situation` draws what is happening: hockey's power play or empty net and a shootout; baseball's runners lit on the diamond with a scorebug; football's line of scrimmage, first-down line, red zone and down-and-distance tag, with a drive chart; in the badge and the compact card too. [The situation](./docs/situation.md).
94
- - **Lineups.** A `lineup` layer places a team's players by position code (`GK`, `CB`, `HK`, `C`) with no coordinates: it reads where each stands from a formation (36 of them, in 13 sports), draws a disc or a jersey with the shirt number and the name under it, a captain's C and a flag, and puts the visitors at the other end. [Lineups](./docs/team-shape.md#lineups).
95
- - **A pageant.** Each team's flag or crest laid large over its half of the surface: `pageant: "carpet"` (a flag at its own ratio with a border) or `"stage"` (a crest on a round disc with a gold ring), an emblem or a trophy in the centre circle, the score in the middle or in the strip, with an entrance in CSS for readers who have not asked for less motion. [The pageant](./docs/pageant.md).
96
- - **Trophies, medals, balls and crests, by id.** `useEmblems(renderEmblem)` plugs in the sister package [Dougu Sports](https://johnmorrisdotca.github.io/dougu-sports/) in one line, and an id goes wherever a logo, a flag or a mark is taken: `logo: "crest:shield"`, `pageant: { emblem: "trophy:hockey-cup" }`, `"ball:puck"`. Kyogijo bundles no emblem and keeps zero dependencies. [Emblems](./docs/emblems.md).
97
- - **Country flags, by code.** `useFlags(render)` plugs in the sister package [Hata](https://github.com/johnmorrisdotca/hata) through a small adapter, and a team's `flag: "CA"` is its flag: round in a round mark, at its own proportions on a banner, a badge or a carpet. Kyogijo bundles no flag and keeps zero dependencies. [Flags](./docs/flags.md).
94
+ - **Lineups.** A `lineup` layer places a team's players by position code (`GK`, `CB`, `HK`, `C`) with no coordinates: it reads where each stands from a formation (36 of them, in 13 sports), draws a disc or a jersey with the shirt number and the name under it, a captain's C and a flag. [Lineups](./docs/team-shape.md#lineups).
95
+ - **A pageant.** Each team's flag or crest laid large over its half of the surface: `pageant: "carpet"` (a flag at its own ratio with a border) or `"stage"` (a crest on a round disc with a gold ring), an emblem or a trophy in the centre circle, the score in the middle or in the strip; an entrance in CSS for readers who have not asked for less motion. [The pageant](./docs/pageant.md).
96
+ - **Trophies, medals, balls and crests, by id.** `useEmblems(renderEmblem)` plugs in the sister package [Dougu Sports](https://johnmorrisdotca.github.io/dougu-sports/) in one line, and an id goes wherever a logo, a flag or a mark is taken: `logo: "crest:shield"`, `pageant: { emblem: "trophy:hockey-cup" }`, `"ball:puck"`. [Emblems](./docs/emblems.md).
97
+ - **Country flags, by code.** `useFlags(render)` plugs in the sister package [Hata](https://github.com/johnmorrisdotca/hata) through a small adapter, and a team's `flag: "CA"` is its flag: round in a round mark, at its own proportions on a banner, a badge or a carpet. [Flags](./docs/flags.md).
98
98
  - **Zoom to a part of a surface.** `range: "offensive-zone"` crops a drawing to a rink's zone, a half court, the paint, the red zone, a soccer half, third or penalty area, the infield, a curling house, or a box of your own in any frame, with its data, heat, labels and score following. [Display ranges](./docs/ranges.md).
99
99
  - **Wide, tall or fit the box.** Every surface lies wide or tall: tall turns it a quarter, keeps every word upright and puts the teams top and bottom. With `orientation: "auto"` the browser helpers follow the box.
100
100
  - **Where a point lies, by the rules, and a click as a place.** `zoneAt("nhl", [69, 22], { frame: "nhl-api" })` names the zone and the area in it from the surface's own figures, with `isThreePointer`, `inSlot`, `isFair`, `isHomeRun` and the like; `clientPointToField(svg, x, y, { provider })` is a pointer's place in any of the frames, with the zone. [Zones](./docs/zones.md), [pointing](./docs/pointer.md).
@@ -119,7 +119,7 @@ console.log(svg.startsWith("<svg"), svg.includes("USA 3, Canada 2"));
119
119
  | Part | What it is |
120
120
  | --- | --- |
121
121
  | `drawKyogijo`, `drawSurface`, `drawScore`, `drawBadge` | The drawing, as a string of SVG. |
122
- | `SPORTS`, `PARKS`, `PARK_IDS`, `COURT_THEMES` | The forty sports, the 94 ballparks, the court looks. |
122
+ | `SPORTS`, `PARKS`, `PARK_IDS`, `COURT_THEMES` | The forty-two sports, the 94 ballparks, the court looks. |
123
123
  | `SOCCER_PITCHES`, `SOCCER_PROVIDERS`, `rescale`, `soccerSpec` | The soccer pitches, the data providers' coordinate systems and the map between them. |
124
124
  | `GROUNDS`, `groundById` | The 64 soccer grounds, each pitch at its own size. |
125
125
  | `EVENTS`, `eventOptions` | The 18 special games: a rink in a ballpark, a court on a carrier's deck, with `host` and `placement` in the options. |
@@ -233,7 +233,7 @@ console.log(box(wide), box(tall));
233
233
  <br><em>The same game tall: the teams top and bottom, every word upright.</em>
234
234
  </p>
235
235
 
236
- [The surfaces](./docs/surfaces.md) lists the forty, with their sizes and what is drawn; [score and layout](./docs/score.md) has the options of a score, a strip and a compact card.
236
+ [The surfaces](./docs/surfaces.md) lists the forty-two, with their sizes and what is drawn; [score and layout](./docs/score.md) has the options of a score, a strip and a compact card.
237
237
 
238
238
  ### A league's rulebook
239
239
 
@@ -613,14 +613,14 @@ A table in the ITTF's playing area, 14 m by 7 m, with surrounds and chairs ([cou
613
613
  <br><em>Close up: the centre tape and the two starting tapes.</em>
614
614
  </p>
615
615
 
616
- ### An MMA cage
616
+ ### The combat sports
617
617
 
618
- [The combat sports page](./docs/combat.md).
618
+ An MMA cage, a boxing ring and wrestling mats ([the combat sports page](./docs/combat.md)).
619
619
 
620
620
  <p align="center">
621
621
  <picture>
622
622
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/mma-cage-desk-dark.webp">
623
- <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/mma-cage-desk-light.webp" alt="An MMA cage from above, with a score" width="660">
623
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/mma-cage-desk-light.webp" alt="An MMA cage from above with a score" width="660">
624
624
  </picture>
625
625
  <br><em>With a score.</em>
626
626
  </p>
@@ -633,6 +633,22 @@ A table in the ITTF's playing area, 14 m by 7 m, with surrounds and chairs ([cou
633
633
  <br><em>The cage in 3D.</em>
634
634
  </p>
635
635
 
636
+ <p align="center">
637
+ <picture>
638
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/boxing-ring-3d-desk-dark.webp">
639
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/boxing-ring-3d-desk-light.webp" alt="The boxing ring in 3D: coloured corner posts, ropes and steps" width="660">
640
+ </picture>
641
+ <br><em>The ring in 3D.</em>
642
+ </p>
643
+
644
+ <p align="center">
645
+ <picture>
646
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/wrestling-mat-3d-desk-dark.webp">
647
+ <img src="https://raw.githubusercontent.com/johnmorrisdotca/kyogijo-stadiums/main/docs/images/wrestling-mat-3d-desk-light.webp" alt="The UWW's wrestling mat in 3D on its platform" width="660">
648
+ </picture>
649
+ <br><em>The UWW's mat in 3D.</em>
650
+ </p>
651
+
636
652
  ### The element in a page
637
653
 
638
654
  ```html
@@ -696,17 +712,17 @@ A page that moves (`mountKyogijo`), a file written on a server and a frame for a
696
712
 
697
713
  ## API
698
714
 
699
- The [API reference](https://johnmorrisdotca.github.io/kyogijo-stadiums/api.html) lists every export of every entry point with its signature and its doc comment. It is made from the source by `pnpm site`, so it cannot fall behind the code. [Entry points](./docs/entry-points.md) says what each of the 15 holds: the main one draws; `/geometry`, `/frames`, `/layers`, `/charts`, `/replay`, `/parks`, `/eras`, `/leagues`, `/grounds` and `/atlas` stand apart and need nothing else; `/mount`, `/turn`, `/react`, `/element` and `/element/define` put a drawing in a page.
715
+ The [API reference](https://johnmorrisdotca.github.io/kyogijo-stadiums/api.html) lists every export of every entry point with its signature and its doc comment. It is made from the source by `pnpm site`. [Entry points](./docs/entry-points.md) says what each of the 15 holds: the main one draws; `/geometry`, `/frames`, `/layers`, `/charts`, `/replay`, `/parks`, `/eras`, `/leagues`, `/grounds` and `/atlas` stand apart; `/mount`, `/turn`, `/react`, `/element` and `/element/define` put a drawing in a page.
700
716
 
701
717
  Every function is pure: it returns new values and never changes what it was given.
702
718
 
703
719
  ## Theming
704
720
 
705
- Nothing is branded. The drawing is coloured by custom properties on its `svg`, with a light set and a dark set that follow the device (or `data-theme` on the page's root, or `theme` in the options); a page sets only the ones it wants different, and its own rule always wins. Each property is listed with its light and dark value, with the court's five looks, in [theming](./docs/theming.md).
721
+ Nothing is branded. The drawing is coloured by custom properties on its `svg`, with a light set and a dark set that follow the device (or `data-theme` on the page's root, or `theme` in the options); a page's own rule always wins. Each property is listed with its light and dark value, with the court's five looks, in [theming](./docs/theming.md).
706
722
 
707
723
  ## Limits
708
724
 
709
- Each is held by a test: forty sports, ten soccer pitches and ten providers, 94 ballparks, 64 grounds, six units, forty-eight frames, a drawing of under 22 kB. The table, made from the code, is [limits](./docs/limits.md).
725
+ Each is held by a test: forty-two sports, ten soccer pitches and ten providers, 94 ballparks, 64 grounds, six units, forty-eight frames, a drawing of under 22 kB. The table, made from the code, is [limits](./docs/limits.md).
710
726
 
711
727
  ## Accessibility
712
728
 
@@ -718,7 +734,7 @@ The rest, with the contrast and what is not yet done, is in [accessibility](./do
718
734
 
719
735
  ## Browser and runtime support
720
736
 
721
- Any browser with ES modules, `:where()` and SVG 2's `href` on images: Chrome and Edge 88, Safari 14, Firefox 78, all from 2021 on. The custom element needs shadow DOM and `part`, in every browser of 2021 on. The drawing function runs on Node 22 or later and in any other JavaScript runtime: it touches no DOM. The demo is played in a real browser, at a phone's width and a desk's, in Chromium and WebKit, before every release.
737
+ Any browser with ES modules, `:where()` and SVG 2's `href` on images: Chrome and Edge 88, Safari 14, Firefox 78, all from 2021 on. The custom element needs shadow DOM and `part`. The drawing function runs on Node 22 or later and in any other JavaScript runtime: it touches no DOM. The demo is played in Chromium and WebKit, at a phone's width and a desk's, before every release.
722
738
 
723
739
  ## Languages
724
740
 
@@ -741,7 +757,7 @@ The drawing is plain functions over plain data with no DOM and no dependency. Th
741
757
 
742
758
  ## The name
743
759
 
744
- *Kyogijo* (競技場, kyōgijō, きょうぎじょう) is Japanese for a sports ground: the place a contest is held. "Stadiums" is added in English, so that the name says what it draws; in Japanese the name stays 競技場. It is written with 競技, "contest" or "competition", and 場, "place", and said in five beats, *kyo-u-gi-jo-u*. In Japanese it is the general word for a place where sport is played, a stadium or a ground; the package uses it as a name for every surface it draws, the field, the rink, the court and the diamond. The long vowels are written without a macron in the package's name, as in the other packages of the family.
760
+ *Kyogijo* (競技場, kyōgijō, きょうぎじょう) is Japanese for a sports ground, the place a contest is held, written with 競技, "contest", and 場, "place", and said *kyo-u-gi-jo-u*. "Stadiums" is added in English so that the name says what it draws; the package uses the word for every surface it draws. The long vowels are written without a macron, as in the other packages of the family.
745
761
 
746
762
  ## Where it comes from, and where it is used
747
763
 
@@ -40,6 +40,19 @@ export function budoAbout(o, language, plan = budoPlan(o)) {
40
40
  const platform = L.height > 0.0005 ? fill(words.mmaPlatform, { height: cm(L.height) }) : words.mmaFloor;
41
41
  return fill(words.mma, { width: trim(L.width), feet: trim(L.width / 0.3048), fence: cm(L.fence), platform });
42
42
  }
43
+ if (plan.boxing !== undefined) {
44
+ const L = plan.boxing;
45
+ const platform = L.height > 0.0005 ? fill(words.boxingPlatform, { height: cm(L.height) }) : words.boxingFloor;
46
+ return fill(words.boxing, { size: trim(L.size), feet: trim(L.size / 0.3048), apron: cm(L.apron), platform });
47
+ }
48
+ if (plan.wrestling !== undefined) {
49
+ const L = plan.wrestling;
50
+ const fig = plan.figures;
51
+ const platform = L.height > 0.0005 ? fill(words.wrestlingPlatform, { height: trim(L.height) }) : words.wrestlingFloor;
52
+ if (fig.passivity > 0)
53
+ return fill(words.wrestlingUww, { circle: trim(L.circle), border: trim(L.border), band: trim(fig.passivity), platform });
54
+ return fill(words.wrestlingFolk, { feet: trim(L.circle / 0.3048), circle: trim(L.circle), border: trim(L.border / 0.3048), platform });
55
+ }
43
56
  if (plan.kyudo !== undefined) {
44
57
  const L = plan.kyudo;
45
58
  const fig = plan.figures;
@@ -78,6 +91,19 @@ export function budoSentences(o, language, plan = budoPlan(o)) {
78
91
  if (plan.mma.steps.length > 0)
79
92
  out.push(words.mmaSteps);
80
93
  }
94
+ if (plan.wrestling !== undefined) {
95
+ const fig = plan.figures;
96
+ if (fig.centre !== null && o.budo?.circle !== false)
97
+ out.push(fill(words.wrestlingCentre, { d: trim(fig.centre.diameter) }));
98
+ if (fig.lines !== null && plan.wrestling.start !== undefined)
99
+ out.push(words.wrestlingLines);
100
+ }
101
+ if (plan.boxing !== undefined) {
102
+ if (o.budo?.corners !== false)
103
+ out.push(words.boxingCorners);
104
+ if (plan.boxing.steps.length > 0)
105
+ out.push(words.boxingSteps);
106
+ }
81
107
  if (plan.dojo !== undefined) {
82
108
  const L = plan.dojo;
83
109
  out.push(fill(words.dojoKamiza, { side: words.sides[L.kamiza] }));
@@ -14,6 +14,8 @@ export interface BudoLook {
14
14
  dirt?: string;
15
15
  sand?: string;
16
16
  straw?: string;
17
+ /** The ropes of a ring. */
18
+ rope?: string;
17
19
  }
18
20
  interface Pair {
19
21
  light: BudoLook;
@@ -52,6 +52,18 @@ export const BUDO_LOOKS = Object.freeze({
52
52
  black: lifted(pair({ ...COMMON, surface: "#2b2e33", alt: "#1f2226", red: "#b32a2f", floor: "#24272b" }), "#3b3f45"),
53
53
  blue: lifted(pair({ ...COMMON, surface: "#3a68ad", alt: "#2b528d", red: "#b32a2f", floor: "#2c3440" }), "#3a4452"),
54
54
  },
55
+ // The ring's canvas over the dark skirt of its platform: a pale canvas with dark red ropes (the default), a blue one and a black one with white ropes. Ours: the rules do not paint a ring.
56
+ boxing: {
57
+ white: lifted(pair({ ...COMMON, surface: "#e6e3da", alt: "#d4d0c4", red: "#b32a2f", floor: "#2d3a56", rope: "#b32a2f" }), "#3b4a6e"),
58
+ blue: lifted(pair({ ...COMMON, surface: "#3a68ad", alt: "#2b528d", red: "#b32a2f", floor: "#1f3358", rope: "#f4f1e8" }), "#324a78"),
59
+ black: lifted(pair({ ...COMMON, surface: "#2b2e33", alt: "#1f2226", red: "#b32a2f", floor: "#17191c", rope: "#f4f1e8" }), "#3b3f45"),
60
+ },
61
+ // The wrestling mat's colours: the circle over the border (a UWW mat's protection area is a different colour from the mat, as its rules say), with the passivity band orange in every look. Ours.
62
+ wrestling: {
63
+ "blue-red": lifted(pair({ ...COMMON, surface: "#2f6db0", alt: "#c0392b", red: "#f07a1a", floor: "#2e3138" }), "#3b3f48"),
64
+ "green-beige": lifted(pair({ ...COMMON, surface: "#4f9560", alt: "#d6c595", red: "#f07a1a", floor: "#2e3138" }), "#3b3f48"),
65
+ "yellow-blue": lifted(pair({ ...COMMON, surface: "#e6c02e", alt: "#2f5fa6", red: "#f07a1a", floor: "#2e3138" }), "#3b3f48"),
66
+ },
55
67
  kyudo: { wood: pair({ ...COMMON, surface: "#9db57d", alt: "#d8cfb0", red: "#b32a2f", floor: "#b98c58", dirt: "#c9ad7a" }) },
56
68
  });
57
69
  /** The names of a sport's looks, the default first. */
@@ -0,0 +1,34 @@
1
+ import type { WrestlingFigures } from "../leagues/combat.ts";
2
+ import { type MBox, type MMark, type Parts } from "./parts.ts";
3
+ /** What a wrestling plan is. */
4
+ export interface MatLayout {
5
+ parts: Parts;
6
+ /** The mat's square: the circle and the matted area round it. The surface's own box. */
7
+ mat: MBox;
8
+ /** The platform under the mat (a square a metre wider each side), when there is one. */
9
+ platform: MBox | undefined;
10
+ extent: MBox;
11
+ centre: [number, number];
12
+ /** The wrestling area's diameter, and the middle part of it inside the passivity band (the UWW's). */
13
+ circle: number;
14
+ inner: number;
15
+ /** The matted area's width round the circle. */
16
+ border: number;
17
+ /** The platform's height over the floor of the building, in metres. */
18
+ height: number;
19
+ /** The starting lines: the rectangle they enclose, when drawn. */
20
+ start: MBox | undefined;
21
+ marks: MMark[];
22
+ ranges: Record<string, MBox>;
23
+ }
24
+ /** The circle's diameter the options ask for, held to what the league allows. */
25
+ export declare const matCircle: (asked: number | undefined, fig: WrestlingFigures, rule: string) => number;
26
+ /** The platform's height the options ask for, held to what the league allows. */
27
+ export declare function matHeight(asked: number | undefined, fig: WrestlingFigures, rule: string): number;
28
+ /** The plan of the mat the options ask for. */
29
+ export declare function matParts(fig: WrestlingFigures, o: {
30
+ circle: number;
31
+ height: number;
32
+ centre: boolean;
33
+ lines: boolean;
34
+ }): MatLayout;
@@ -0,0 +1,71 @@
1
+ // A wrestling mat: the wrestling area's circle with the matted area round it, and on the UWW's mat the orange passivity band, the central circle and the platform it stands on; on a folkstyle mat the line that outlines the
2
+ // circle, the circle of 10 feet and the two starting lines closed by a green and a red line. From the UWW's Wrestling Rules (Article 4, January 2026), the NCAA's Wrestling Rules (Rule 1) and the NFHS's (Rule 2-1). In metres,
3
+ // the origin at the top left of the mat's square, north at the top. Nothing here draws SVG.
4
+ import { ring } from "../fields.kit.js";
5
+ import { annulusD, discArea, rectArea, tapeBar, within } from "./kit.js";
6
+ import { emptyParts, grow } from "./parts.js";
7
+ /** The circle's diameter the options ask for, held to what the league allows. */
8
+ export const matCircle = (asked, fig, rule) => (asked === undefined ? fig.circle.drawn : within(asked, fig.circle.min, fig.circle.max, "The wrestling area", rule));
9
+ /** The platform's height the options ask for, held to what the league allows. */
10
+ export function matHeight(asked, fig, rule) {
11
+ if (asked === undefined)
12
+ return fig.platform.height.drawn;
13
+ const h = within(asked, fig.platform.height.min, fig.platform.height.max, "The platform", rule);
14
+ // A platform, when there is one, is at least the league's least (the UWW's 0.80 m); none at all is allowed.
15
+ if (h > 0 && h < fig.platform.least - 1e-9)
16
+ throw new RangeError(`The platform of ${h} m is outside what ${rule} allows: none, or ${fig.platform.least} m to ${fig.platform.height.max} m`);
17
+ return h;
18
+ }
19
+ /** The plan of the mat the options ask for. */
20
+ export function matParts(fig, o) {
21
+ const b = fig.border.drawn;
22
+ const side = o.circle + 2 * b;
23
+ const mat = { x0: 0, y0: 0, x1: side, y1: side };
24
+ const c = side / 2;
25
+ const r = o.circle / 2;
26
+ const parts = emptyParts();
27
+ const platform = o.height > 0 ? grow(mat, fig.platform.around) : undefined;
28
+ if (platform !== undefined)
29
+ parts.areas.push(rectArea("platform", "platform", "ky-bud-platform", platform));
30
+ parts.areas.push(rectArea("border", "border", "ky-bud-t2", mat));
31
+ parts.areas.push(discArea("circle", "circle", "ky-bud-t1", c, c, r));
32
+ const inner = fig.passivity > 0 ? o.circle - 2 * fig.passivity : o.circle;
33
+ if (fig.passivity > 0)
34
+ parts.areas.push({ id: "passivity", feature: "passivity", cls: "ky-bud-t3", d: annulusD(c, c, inner / 2, r), evenodd: true });
35
+ // The line that outlines the circle (folkstyle): part of the wrestling area, in bounds.
36
+ if (fig.rim > 0)
37
+ parts.shapes.push(ring("rim", "rim", c, c, r - fig.rim / 2, r - fig.rim / 2, { w: fig.rim, cls: "ky-bud-line" }));
38
+ // The circle in the middle: a band round a circle of the stated inside diameter.
39
+ if (fig.centre !== null && o.centre)
40
+ parts.shapes.push(ring("centre-circle", "centre-circle", c, c, fig.centre.diameter / 2 + fig.centre.band / 2, fig.centre.diameter / 2 + fig.centre.band / 2, { w: fig.centre.band, cls: "ky-bud-line" }));
41
+ // The starting lines: two parallel lines, closed at their ends by a green line (home, left) and a red line (visitors, right).
42
+ let start;
43
+ if (fig.lines !== null && o.lines) {
44
+ const L = fig.lines;
45
+ const half = L.apart / 2 + L.width;
46
+ start = { x0: c - L.length / 2, y0: c - half, x1: c + L.length / 2, y1: c + half };
47
+ parts.shapes.push(tapeBar("start-line-1", "starting-lines", "ky-bud-white-fill", { x0: start.x0, y0: c - L.apart / 2 - L.width, x1: start.x1, y1: c - L.apart / 2 }));
48
+ parts.shapes.push(tapeBar("start-line-2", "starting-lines", "ky-bud-white-fill", { x0: start.x0, y0: c + L.apart / 2, x1: start.x1, y1: c + L.apart / 2 + L.width }));
49
+ parts.shapes.push(tapeBar("start-green", "starting-lines", "ky-bud-green-fill", { x0: start.x0, y0: start.y0, x1: start.x0 + L.width, y1: start.y1 }));
50
+ parts.shapes.push(tapeBar("start-red", "starting-lines", "ky-bud-red-fill", { x0: start.x1 - L.width, y0: start.y0, x1: start.x1, y1: start.y1 }));
51
+ }
52
+ const extent = grow(platform ?? mat, 0.6);
53
+ const ranges = { start: { x0: c - 1.5, y0: c - 1.5, x1: c + 1.5, y1: c + 1.5 } };
54
+ if (fig.passivity > 0)
55
+ ranges.passivity = { x0: c - r - 0.3, y0: c - r - 0.3, x1: c + r + 0.3, y1: c + r + 0.3 };
56
+ const marks = [
57
+ { id: "mat-circle", x: c - r * 0.72, y: c - r * 0.72, side: "top" },
58
+ { id: "mat-border", x: b / 2, y: c + r * 0.55, side: "bottom" },
59
+ ];
60
+ if (fig.passivity > 0)
61
+ marks.push({ id: "mat-central", x: c - inner / 2 * Math.SQRT1_2, y: c + inner / 2 * Math.SQRT1_2, side: "bottom" });
62
+ if (fig.passivity > 0)
63
+ marks.push({ id: "mat-passivity", x: c + (inner / 2 + fig.passivity / 2) * Math.SQRT1_2, y: c - (inner / 2 + fig.passivity / 2) * Math.SQRT1_2, side: "top" });
64
+ if (fig.centre !== null && o.centre)
65
+ marks.push({ id: "mat-centre-circle", x: c + fig.centre.diameter / 2, y: c + fig.centre.diameter / 2, side: "bottom" });
66
+ if (start !== undefined)
67
+ marks.push({ id: "mat-starting-lines", x: start.x1, y: c, side: "bottom" });
68
+ if (platform !== undefined)
69
+ marks.push({ id: "mat-platform", x: platform.x1 - 0.3, y: platform.y0 + 0.3, side: "top" });
70
+ return { parts, mat, platform, extent, centre: [c, c], circle: o.circle, inner, border: b, height: o.height, start, marks, ranges };
71
+ }
@@ -8,6 +8,8 @@ import { type KendoLayout } from "./kendo.ts";
8
8
  import { type KyudoLayout } from "./kyudo.ts";
9
9
  import { boxD } from "./kit.ts";
10
10
  import { type CageLayout } from "./cage.ts";
11
+ import { type RingLayout } from "./ring.ts";
12
+ import { type MatLayout } from "./mat.ts";
11
13
  import { type MBox, type MMark, type MRange } from "./parts.ts";
12
14
  import { type SumoLayout } from "./sumo.ts";
13
15
  import type { BudoKind, CombatKind } from "./types.ts";
@@ -50,12 +52,14 @@ export interface BudoPlan {
50
52
  kyudo?: KyudoLayout;
51
53
  dojo?: DojoLayout;
52
54
  mma?: CageLayout;
55
+ boxing?: RingLayout;
56
+ wrestling?: MatLayout;
53
57
  }
54
58
  /** The sports of the budō family. */
55
59
  export declare const BUDO_SPORTS: readonly BudoKind[];
56
60
  /** True for a sport of the budō family. */
57
61
  export declare const isBudoSport: (sport: string) => sport is Exclude<BudoKind, CombatKind>;
58
- /** The combat sports the engine of the budō also draws: the MMA cage. */
62
+ /** The combat sports the engine of the budō also draws: the MMA cage and the boxing ring. */
59
63
  export declare const COMBAT_SPORTS: readonly CombatKind[];
60
64
  /** True for a combat sport (the MMA cage). */
61
65
  export declare const isCombatSport: (sport: string) => sport is CombatKind;
package/dist/budo/plan.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { chooseLeague } from "../leagues.js";
2
2
  import { BUDO_LEAGUES, DOJO_LEAGUES, JUDO_LEAGUES, KARATE_LEAGUES, KENDO_LEAGUES, KYUDO_LEAGUES, SUMO_LEAGUES } from "../leagues/budo.js";
3
- import { MMA_LEAGUES } from "../leagues/combat.js";
3
+ import { BOXING_LEAGUES, MMA_LEAGUES, WRESTLING_LEAGUES } from "../leagues/combat.js";
4
4
  import { dojoLayout, dojoLeague, dojoSpecOf } from "./dojo.js";
5
5
  import { contestOf, gridOf, judoParts, matOf, safetyOf, snapTo } from "./judo.js";
6
6
  import { karateParts } from "./karate.js";
@@ -8,6 +8,8 @@ import { kendoParts, kendoSide } from "./kendo.js";
8
8
  import { kyudoParts, shootersOf } from "./kyudo.js";
9
9
  import { boxD } from "./kit.js";
10
10
  import { cageHeight, cageParts, cageWidth, fenceHeight } from "./cage.js";
11
+ import { ringHeight, ringParts, ringSize } from "./ring.js";
12
+ import { matCircle, matHeight, matParts } from "./mat.js";
11
13
  import { emptyParts, grow, union } from "./parts.js";
12
14
  import { dohyoHeight, sumoParts } from "./sumo.js";
13
15
  import { lookOf } from "./looks.js";
@@ -18,13 +20,13 @@ const isBudoLeague = (l) => typeof l === "object" && l !== null && BUDO_LEAGUES.
18
20
  export const BUDO_SPORTS = Object.freeze(["judo", "karate", "kendo", "sumo", "kyudo", "dojo"]);
19
21
  /** True for a sport of the budō family. */
20
22
  export const isBudoSport = (sport) => BUDO_SPORTS.includes(sport);
21
- /** The combat sports the engine of the budō also draws: the MMA cage. */
22
- export const COMBAT_SPORTS = Object.freeze(["mma"]);
23
+ /** The combat sports the engine of the budō also draws: the MMA cage and the boxing ring. */
24
+ export const COMBAT_SPORTS = Object.freeze(["mma", "boxing", "wrestling"]);
23
25
  /** True for a combat sport (the MMA cage). */
24
26
  export const isCombatSport = (sport) => COMBAT_SPORTS.includes(sport);
25
27
  /** True for a sport this engine draws: a sport of the budō or a combat sport. */
26
28
  export const isMatSport = (sport) => isBudoSport(sport) || isCombatSport(sport);
27
- const OWN = { judo: JUDO_LEAGUES, karate: KARATE_LEAGUES, kendo: KENDO_LEAGUES, sumo: SUMO_LEAGUES, kyudo: KYUDO_LEAGUES, dojo: DOJO_LEAGUES, mma: MMA_LEAGUES };
29
+ const OWN = { judo: JUDO_LEAGUES, karate: KARATE_LEAGUES, kendo: KENDO_LEAGUES, sumo: SUMO_LEAGUES, kyudo: KYUDO_LEAGUES, dojo: DOJO_LEAGUES, mma: MMA_LEAGUES, boxing: BOXING_LEAGUES, wrestling: WRESTLING_LEAGUES };
28
30
  /** What `budo.style` asks of a judo area: true for a kata area, false for a contest area, undefined for neither said. @throws TypeError for a value that is not `shiai` or `kata`. */
29
31
  function kataOf(style) {
30
32
  if (style === undefined)
@@ -132,6 +134,20 @@ export function budoPlan(o) {
132
134
  const ranges = { ...L.ranges, half: halves(L.platform) };
133
135
  return finish({ box: L.platform, extent: L.extent, areas: L.parts.areas, shapes: L.parts.shapes, lineWidth: f.post.diameter, ranges, marks: L.marks, centre: { x: L.centre[0], y: L.centre[1], r: L.apothem * 0.35 }, mma: L });
134
136
  }
137
+ case "boxing": {
138
+ const f = fig;
139
+ const rule = `the rules of ${league.id === "wbc-amateur" ? "the WBC Amateur" : league.id === "wisconsin" ? "Wisconsin" : "Nevada"}`;
140
+ const L = ringParts(f, { size: ringSize(style.size, f, rule), height: ringHeight(style.height, f, rule), steps: flag(style.steps, true, "budo.steps"), corners: flag(style.corners, true, "budo.corners") });
141
+ const ranges = { ...L.ranges, half: halves(L.platform) };
142
+ return finish({ box: L.platform, extent: L.extent, areas: L.parts.areas, shapes: L.parts.shapes, lineWidth: f.ropes.diameter.drawn, ranges, marks: L.marks, centre: { x: L.centre[0], y: L.centre[1], r: L.size * 0.2 }, boxing: L });
143
+ }
144
+ case "wrestling": {
145
+ const f = fig;
146
+ const rule = `the rules of ${league.id === "uww" ? "the UWW" : league.id === "ncaa-wrestling" ? "the NCAA" : "the NFHS"}`;
147
+ const L = matParts(f, { circle: matCircle(style.size, f, rule), height: matHeight(style.height, f, rule), centre: flag(style.circle, true, "budo.circle"), lines: flag(style.start, true, "budo.start") });
148
+ const ranges = { ...L.ranges, half: halves(L.mat) };
149
+ return finish({ box: L.mat, extent: L.extent, areas: L.parts.areas, shapes: L.parts.shapes, lineWidth: 0.05, ranges, marks: L.marks, centre: { x: L.centre[0], y: L.centre[1], r: L.circle * 0.2 }, wrestling: L });
150
+ }
135
151
  default: {
136
152
  const L = dojoLayout(o.dojo ?? {}, dojoLeague(league.id));
137
153
  const f = L.floor;
@@ -0,0 +1,47 @@
1
+ import type { RingFigures } from "../leagues/combat.ts";
2
+ import { type MBox, type MMark, type Parts } from "./parts.ts";
3
+ /** The colour of a corner's post and pad: the red and the blue corner of the two boxers, and two neutral ones in white. */
4
+ export type CornerColour = "red" | "blue" | "white";
5
+ /** One corner of the ring: its post's place on the platform, the corner of the rope square its ropes turn at, its colour and which of the four it is (0 top left, clockwise). */
6
+ export interface RingCorner {
7
+ index: number;
8
+ colour: CornerColour;
9
+ post: [number, number];
10
+ rope: [number, number];
11
+ }
12
+ /** A set of steps: the box it covers outside the platform's edge, and the edge it is on. */
13
+ export interface RingSteps {
14
+ edge: "north" | "south";
15
+ corner: number;
16
+ box: MBox;
17
+ }
18
+ /** What a ring plan is. */
19
+ export interface RingLayout {
20
+ parts: Parts;
21
+ /** The platform, which is the surface's own box: the canvas inside the ropes and the apron round it. */
22
+ platform: MBox;
23
+ extent: MBox;
24
+ centre: [number, number];
25
+ /** The ring inside the ropes, and its side. */
26
+ ring: MBox;
27
+ size: number;
28
+ /** The apron's width as drawn, from the ropes to the platform's edge. */
29
+ apron: number;
30
+ corners: RingCorner[];
31
+ steps: RingSteps[];
32
+ /** The platform's height over the floor of the building, in metres. */
33
+ height: number;
34
+ marks: MMark[];
35
+ ranges: Record<string, MBox>;
36
+ }
37
+ /** The size the options ask for, held to what the rules allow. */
38
+ export declare const ringSize: (asked: number | undefined, fig: RingFigures, rule: string) => number;
39
+ /** The platform's height the options ask for, held to what the rules allow. */
40
+ export declare const ringHeight: (asked: number | undefined, fig: RingFigures, rule: string) => number;
41
+ /** The plan of the ring the options ask for. */
42
+ export declare function ringParts(fig: RingFigures, o: {
43
+ size: number;
44
+ height: number;
45
+ steps: boolean;
46
+ corners: boolean;
47
+ }): RingLayout;