@johnmorrisdotca/kyogijo-stadiums 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/NOTICE.md +179 -3
  3. package/README.md +43 -11
  4. package/dist/arenas-entry.d.ts +4 -0
  5. package/dist/arenas-entry.js +3 -0
  6. package/dist/arenas.d.ts +125 -0
  7. package/dist/arenas.data.d.ts +2 -0
  8. package/dist/arenas.data.js +3763 -0
  9. package/dist/arenas.js +72 -0
  10. package/dist/atlas-entry.d.ts +3 -1
  11. package/dist/atlas-entry.js +3 -2
  12. package/dist/atlas.d.ts +37 -19
  13. package/dist/atlas.js +92 -7
  14. package/dist/background.js +2 -1
  15. package/dist/budo/describe.d.ts +13 -0
  16. package/dist/budo/describe.js +120 -0
  17. package/dist/budo/dojo.api.d.ts +64 -0
  18. package/dist/budo/dojo.api.js +46 -0
  19. package/dist/budo/dojo.d.ts +72 -0
  20. package/dist/budo/dojo.js +300 -0
  21. package/dist/budo/judo.d.ts +61 -0
  22. package/dist/budo/judo.js +109 -0
  23. package/dist/budo/karate.d.ts +29 -0
  24. package/dist/budo/karate.js +80 -0
  25. package/dist/budo/kendo.d.ts +18 -0
  26. package/dist/budo/kendo.js +44 -0
  27. package/dist/budo/kimarite.d.ts +19 -0
  28. package/dist/budo/kimarite.js +33 -0
  29. package/dist/budo/kit.d.ts +16 -0
  30. package/dist/budo/kit.js +24 -0
  31. package/dist/budo/kyudo.d.ts +28 -0
  32. package/dist/budo/kyudo.js +66 -0
  33. package/dist/budo/looks.d.ts +28 -0
  34. package/dist/budo/looks.js +58 -0
  35. package/dist/budo/parts.d.ts +32 -0
  36. package/dist/budo/parts.js +10 -0
  37. package/dist/budo/plan.d.ts +64 -0
  38. package/dist/budo/plan.js +139 -0
  39. package/dist/budo/room.d.ts +133 -0
  40. package/dist/budo/room.js +111 -0
  41. package/dist/budo/sumo.d.ts +31 -0
  42. package/dist/budo/sumo.js +71 -0
  43. package/dist/budo/tatami.d.ts +55 -0
  44. package/dist/budo/tatami.js +156 -0
  45. package/dist/budo/types.d.ts +192 -0
  46. package/dist/budo/types.js +2 -0
  47. package/dist/budo-entry.d.ts +22 -0
  48. package/dist/budo-entry.js +13 -0
  49. package/dist/budo.board.d.ts +28 -0
  50. package/dist/budo.board.js +81 -0
  51. package/dist/budo.score.d.ts +18 -0
  52. package/dist/budo.score.js +52 -0
  53. package/dist/budo.style.d.ts +6 -0
  54. package/dist/budo.style.js +67 -0
  55. package/dist/charts.baseball.js +1 -1
  56. package/dist/charts.js +4 -4
  57. package/dist/charts.soccer.js +3 -3
  58. package/dist/charts.types.d.ts +10 -0
  59. package/dist/colour.d.ts +4 -4
  60. package/dist/colour.js +4 -4
  61. package/dist/crowd.d.ts +11 -1
  62. package/dist/crowd.draw.js +15 -9
  63. package/dist/crowd.js +17 -2
  64. package/dist/draw.js +156 -31
  65. package/dist/element-entry.d.ts +2 -0
  66. package/dist/element-entry.js +1 -0
  67. package/dist/element.d.ts +2 -2
  68. package/dist/element.js +2 -1
  69. package/dist/emblems-source.d.ts +50 -0
  70. package/dist/emblems-source.js +56 -0
  71. package/dist/eras.d.ts +3 -1
  72. package/dist/eras.js +8 -3
  73. package/dist/features.js +73 -0
  74. package/dist/field.data.d.ts +16 -0
  75. package/dist/field.data.js +50 -0
  76. package/dist/fields.kit.d.ts +2 -2
  77. package/dist/fields.types.d.ts +9 -3
  78. package/dist/formations.js +18 -7
  79. package/dist/formations.sports.d.ts +8 -0
  80. package/dist/formations.sports.js +251 -0
  81. package/dist/frames.providers.js +9 -1
  82. package/dist/halls.d.ts +65 -0
  83. package/dist/halls.js +122 -0
  84. package/dist/heat.js +17 -10
  85. package/dist/heat.zones.d.ts +4 -2
  86. package/dist/heat.zones.js +55 -3
  87. package/dist/homeside.js +7 -0
  88. package/dist/index.d.ts +15 -3
  89. package/dist/index.js +8 -1
  90. package/dist/layers-entry.d.ts +2 -1
  91. package/dist/layers-entry.js +1 -0
  92. package/dist/layers.d.ts +2 -1
  93. package/dist/layers.env.d.ts +10 -1
  94. package/dist/layers.env.js +33 -3
  95. package/dist/layers.js +30 -11
  96. package/dist/layers.types.d.ts +9 -2
  97. package/dist/leagues/budo.d.ts +196 -0
  98. package/dist/leagues/budo.js +105 -0
  99. package/dist/leagues/hockey.js +41 -19
  100. package/dist/leagues/sources.js +21 -0
  101. package/dist/leagues/types.d.ts +1 -1
  102. package/dist/leagues.d.ts +4 -1
  103. package/dist/leagues.js +102 -2
  104. package/dist/lineup.codes.d.ts +23 -0
  105. package/dist/lineup.codes.js +122 -0
  106. package/dist/logo.d.ts +25 -0
  107. package/dist/logo.js +47 -0
  108. package/dist/outline.d.ts +1 -1
  109. package/dist/outline.js +17 -3
  110. package/dist/pageant.js +7 -3
  111. package/dist/pointer-entry.d.ts +2 -0
  112. package/dist/pointer-entry.js +2 -0
  113. package/dist/pointer.d.ts +113 -0
  114. package/dist/pointer.js +151 -0
  115. package/dist/pool.d.ts +7 -7
  116. package/dist/pool.figures.d.ts +57 -55
  117. package/dist/pool.figures.js +59 -55
  118. package/dist/pool.js +7 -7
  119. package/dist/pool.labels.js +2 -1
  120. package/dist/ranges.names.js +6 -0
  121. package/dist/road.draw.js +3 -2
  122. package/dist/road.js +2 -1
  123. package/dist/road.types.d.ts +3 -0
  124. package/dist/rules.d.ts +138 -0
  125. package/dist/rules.js +511 -0
  126. package/dist/rules.types.d.ts +4 -0
  127. package/dist/rules.types.js +64 -0
  128. package/dist/score.d.ts +3 -0
  129. package/dist/score.js +23 -1
  130. package/dist/situation.d.ts +135 -0
  131. package/dist/situation.draw.d.ts +34 -0
  132. package/dist/situation.draw.js +202 -0
  133. package/dist/situation.js +337 -0
  134. package/dist/situation.style.d.ts +2 -0
  135. package/dist/situation.style.js +45 -0
  136. package/dist/situation.types.d.ts +77 -0
  137. package/dist/situation.types.js +3 -0
  138. package/dist/situation.widgets.d.ts +39 -0
  139. package/dist/situation.widgets.js +129 -0
  140. package/dist/strings.d.ts +175 -1
  141. package/dist/strings.js +364 -20
  142. package/dist/style.js +9 -2
  143. package/dist/surfaces/artistic.d.ts +3 -3
  144. package/dist/surfaces/artistic.js +3 -3
  145. package/dist/surfaces/baseball.js +2 -0
  146. package/dist/surfaces/basketball.js +1 -1
  147. package/dist/surfaces/budo.d.ts +6 -0
  148. package/dist/surfaces/budo.js +104 -0
  149. package/dist/surfaces/dive.d.ts +3 -3
  150. package/dist/surfaces/dive.js +3 -3
  151. package/dist/surfaces/football.js +7 -0
  152. package/dist/surfaces/hockey.js +3 -2
  153. package/dist/surfaces/polo.d.ts +4 -4
  154. package/dist/surfaces/polo.js +5 -5
  155. package/dist/surfaces/pool.d.ts +1 -1
  156. package/dist/surfaces/pool.js +3 -3
  157. package/dist/surfaces/surface.d.ts +32 -0
  158. package/dist/surfaces/venue.d.ts +1 -1
  159. package/dist/surfaces/venue.js +1 -1
  160. package/dist/target-entry.d.ts +2 -0
  161. package/dist/target-entry.js +2 -0
  162. package/dist/target.d.ts +200 -0
  163. package/dist/target.js +525 -0
  164. package/dist/team.common.d.ts +1 -1
  165. package/dist/team.common.js +3 -3
  166. package/dist/team.formation.d.ts +3 -1
  167. package/dist/team.formation.js +3 -3
  168. package/dist/team.layers.d.ts +2 -2
  169. package/dist/team.layers.js +4 -1
  170. package/dist/team.lineup.d.ts +27 -0
  171. package/dist/team.lineup.js +207 -0
  172. package/dist/team.network.js +6 -5
  173. package/dist/team.shape.js +5 -5
  174. package/dist/team.types.d.ts +40 -1
  175. package/dist/tenants.data.js +848 -0
  176. package/dist/turn-entry.d.ts +2 -2
  177. package/dist/turn-entry.js +1 -1
  178. package/dist/turn.camera.d.ts +12 -1
  179. package/dist/turn.camera.js +18 -2
  180. package/dist/turn.dom.js +11 -9
  181. package/dist/turn.kit.d.ts +2 -2
  182. package/dist/turn.style.js +4 -3
  183. package/dist/types.d.ts +43 -7
  184. package/dist/units.js +7 -0
  185. package/dist/uprights.budo.d.ts +17 -0
  186. package/dist/uprights.budo.js +87 -0
  187. package/dist/uprights.js +10 -1
  188. package/dist/uprights.pools.js +4 -4
  189. package/dist/version.d.ts +1 -1
  190. package/dist/version.js +1 -1
  191. package/dist/zones-entry.d.ts +2 -0
  192. package/dist/zones-entry.js +2 -0
  193. package/package.json +39 -3
@@ -0,0 +1,80 @@
1
+ import { rectArea } from "./kit.js";
2
+ import { emptyParts, grow, union } from "./parts.js";
3
+ import { lay, seams, tatamiAreas, tint } from "./tatami.js";
4
+ /** The mat of a karate area: 1 m by 1 m, a WKF-approved mat's size (ours: the rules do not give it). */
5
+ export const KARATE_MAT = { length: 1, width: 1 };
6
+ /** The plan of the karate area the options ask for. */
7
+ export function karateParts(o) {
8
+ const { fig, across, down } = o;
9
+ const a = fig.area;
10
+ const gap = fig.between;
11
+ const width = across * a + (across - 1) * gap + 2 * fig.safety;
12
+ const height = down * a + (down - 1) * gap + 2 * fig.safety;
13
+ const mats = { x0: 0, y0: 0, x1: width, y1: height };
14
+ const areas = [];
15
+ for (let j = 0; j < down; j += 1)
16
+ for (let i = 0; i < across; i += 1)
17
+ areas.push({ x0: fig.safety + i * (a + gap), y0: fig.safety + j * (a + gap), x1: fig.safety + i * (a + gap) + a, y1: fig.safety + j * (a + gap) + a });
18
+ const inner = areas.map((b) => grow(b, -fig.band));
19
+ const parts = emptyParts();
20
+ const zones = [...inner.map((b) => ({ box: b, tone: 1 })), ...(fig.band > 0 ? areas.map((b) => ({ box: b, tone: 3 })) : [])];
21
+ const pieces = tint(lay(mats, KARATE_MAT, "x", false), zones, 2, KARATE_MAT);
22
+ parts.areas.push(...tatamiAreas("mats", pieces, { 1: "ky-bud-t1", 2: "ky-bud-t2", 3: "ky-bud-t3" }, { 1: "competition-area", 2: "safety-area", 3: "boundary-band" }));
23
+ if (o.seams)
24
+ parts.shapes.push(...seams("mats", pieces, 0.02));
25
+ // Kumite: the two mats turned over, red side up, 1 m from the centre, where the athletes stand, front and centre, facing each other.
26
+ if (fig.startMats !== null) {
27
+ const s = fig.startMats.size;
28
+ areas.forEach((b, k) => {
29
+ const cx = (b.x0 + b.x1) / 2;
30
+ const cy = (b.y0 + b.y1) / 2;
31
+ for (const [side, dx] of [["left", -1], ["right", 1]]) {
32
+ const near = cx + dx * fig.startMats.fromCentre;
33
+ const far = cx + dx * (fig.startMats.fromCentre + s);
34
+ parts.areas.push(rectArea(`start-mat-${k + 1}-${side}`, "start-mats", "ky-bud-t3", { x0: Math.min(near, far), y0: cy - s / 2, x1: Math.max(near, far), y1: cy + s / 2 }));
35
+ }
36
+ });
37
+ }
38
+ const desks = [];
39
+ const seats = [];
40
+ if (o.officials) {
41
+ for (const b of areas.filter((_, k) => k < across)) {
42
+ const cx = (b.x0 + b.x1) / 2;
43
+ desks.push({ x0: cx - 1.5, y0: -2.3, x1: cx + 1.5, y1: -1.5 });
44
+ }
45
+ desks.forEach((d, k) => parts.areas.push(rectArea(`table-${k + 1}`, "officials", "ky-bud-desk", d)));
46
+ }
47
+ // The judges sit about 1.5 m off the corners, in the safety area; the referee stands at the middle, 2 m inside the boundary on the near side.
48
+ if (o.judges) {
49
+ areas.forEach((b, k) => {
50
+ const d = fig.judges / Math.SQRT2;
51
+ const at = [[b.x0 - d, b.y0 - d], [b.x1 + d, b.y0 - d], [b.x0 - d, b.y1 + d], [b.x1 + d, b.y1 + d]];
52
+ at.forEach(([x, y], n) => {
53
+ const seat = { x0: x - 0.3, y0: y - 0.3, x1: x + 0.3, y1: y + 0.3 };
54
+ seats.push(seat);
55
+ parts.areas.push(rectArea(`judge-${k + 1}-${n + 1}`, "judges", "ky-bud-seat", seat));
56
+ });
57
+ const cx = (b.x0 + b.x1) / 2;
58
+ const ref = { x0: cx - 0.3, y0: b.y1 - fig.referee - 0.3, x1: cx + 0.3, y1: b.y1 - fig.referee + 0.3 };
59
+ seats.push(ref);
60
+ parts.areas.push({ id: `referee-${k + 1}`, feature: "referee", cls: "ky-bud-seat", ellipse: [cx, b.y1 - fig.referee, 0.3, 0.3] });
61
+ });
62
+ }
63
+ const first = areas[0];
64
+ const fx = (first.x0 + first.x1) / 2;
65
+ const marks = [];
66
+ marks.push({ id: "competition-area", x: fx, y: first.y0 + a * 0.28, side: "top" });
67
+ marks.push({ id: "safety-area", x: fx, y: fig.safety / 2, side: "top" });
68
+ if (fig.band > 0)
69
+ marks.push({ id: "boundary-band", x: first.x0 + a * 0.22, y: first.y1 - fig.band / 2, side: "bottom" });
70
+ if (fig.startMats !== null)
71
+ marks.push({ id: "start-mat", x: fx + fig.startMats.fromCentre + fig.startMats.size / 2, y: (first.y0 + first.y1) / 2, side: "bottom" });
72
+ if (o.judges) {
73
+ marks.push({ id: "referee", x: fx, y: first.y1 - fig.referee, side: "bottom" });
74
+ marks.push({ id: "judge", x: first.x1 + fig.judges / Math.SQRT2, y: first.y1 + fig.judges / Math.SQRT2, side: "bottom" });
75
+ }
76
+ if (across > 1)
77
+ marks.push({ id: "between-areas", x: first.x1 + gap / 2, y: (first.y0 + first.y1) / 2, side: "bottom" });
78
+ const extent = union([mats, ...desks.map((d) => grow(d, 0.3)), ...seats.map((d) => grow(d, 0.2))]);
79
+ return { parts, mats, extent, areas, inner, gap, pieces, marks };
80
+ }
@@ -0,0 +1,18 @@
1
+ import type { KendoFigures } from "../leagues/budo.ts";
2
+ import { type MBox, type MMark, type Parts } from "./parts.ts";
3
+ /** What a kendo plan is. */
4
+ export interface KendoLayout {
5
+ parts: Parts;
6
+ /** The floor inside the boundary lines, the shiai-jo itself. */
7
+ floor: MBox;
8
+ extent: MBox;
9
+ side: number;
10
+ /** The centre, and the two kaishi-sen as lines. */
11
+ centre: [number, number];
12
+ starts: [MBox, MBox];
13
+ marks: MMark[];
14
+ }
15
+ /** The side the options ask for, held to 9 m to 11 m. */
16
+ export declare const kendoSide: (asked: number | undefined, fig: KendoFigures) => number;
17
+ /** The plan of the shiai-jo the options ask for. */
18
+ export declare function kendoParts(fig: KendoFigures, side: number, seams: boolean): KendoLayout;
@@ -0,0 +1,44 @@
1
+ import { box, line } from "../fields.kit.js";
2
+ import { rectArea, within } from "./kit.js";
3
+ import { emptyParts, grow } from "./parts.js";
4
+ /** The width of a floorboard: 18 cm (ours; a sprung floor's boards are laid lengthwise). */
5
+ const BOARD = 0.18;
6
+ /** The side the options ask for, held to 9 m to 11 m. */
7
+ export const kendoSide = (asked, fig) => (asked === undefined ? fig.side.drawn : within(asked, fig.side.min, fig.side.max, "The shiai-jo", "Article 2 of the FIK's Regulations"));
8
+ /** The plan of the shiai-jo the options ask for. */
9
+ export function kendoParts(fig, side, seams) {
10
+ const floor = { x0: 0, y0: 0, x1: side, y1: side };
11
+ const parts = emptyParts();
12
+ const w = fig.lineWidth.min;
13
+ const outer = grow(floor, fig.outside);
14
+ parts.areas.push(rectArea("outside", "outside", "ky-bud-free", outer));
15
+ parts.areas.push(rectArea("floor", "floor", "ky-bud-floor", floor));
16
+ const shapes = [];
17
+ // The boards run the length of the floor.
18
+ if (seams)
19
+ for (let y = BOARD; y < side - 1e-6; y += BOARD)
20
+ shapes.push(line("board", "boards", 0, y, side, y, { w: 0.008, cls: "ky-bud-seam", least: 0 }));
21
+ // The boundary lines, white, 5 cm wide and inside the 9 m to 11 m, so that the floor's size includes them.
22
+ shapes.push(box("boundary", "boundary-lines", w / 2, w / 2, side - w / 2, side - w / 2, { w, cls: "ky-bud-line" }));
23
+ const cx = side / 2;
24
+ const cy = side / 2;
25
+ const c = fig.cross.drawn / 2;
26
+ shapes.push(line("cross-a", "cross", cx - c, cy - c, cx + c, cy + c, { w, cls: "ky-bud-line" }), line("cross-b", "cross", cx - c, cy + c, cx + c, cy - c, { w, cls: "ky-bud-line" }));
27
+ const l = fig.startLine.length / 2;
28
+ const left = { x0: cx - fig.startLine.fromCentre - w / 2, y0: cy - l, x1: cx - fig.startLine.fromCentre + w / 2, y1: cy + l };
29
+ const right = { x0: cx + fig.startLine.fromCentre - w / 2, y0: cy - l, x1: cx + fig.startLine.fromCentre + w / 2, y1: cy + l };
30
+ for (const [k, b] of [left, right].entries())
31
+ shapes.push(line(`start-${k === 0 ? "left" : "right"}`, "start-lines", (b.x0 + b.x1) / 2, b.y0, (b.x0 + b.x1) / 2, b.y1, { w, cls: "ky-bud-line" }));
32
+ // The outer boundary, 1.5 m outside, as a dashed line (Figure 1).
33
+ shapes.push(box("outer-boundary", "outer-boundary", -fig.outside, -fig.outside, side + fig.outside, side + fig.outside, { w: 0.03, dash: [0.25, 0.2], cls: "ky-bud-ink", least: 0.03 }));
34
+ parts.shapes.push(...shapes);
35
+ const marks = [
36
+ { id: "boundary-line", x: side * 0.2, y: w / 2, side: "top" },
37
+ { id: "centre-cross", x: cx, y: cy - 0.5, side: "top" },
38
+ { id: "kaishi-sen", x: cx + fig.startLine.fromCentre, y: cy + l, side: "bottom" },
39
+ { id: "outer-boundary", x: side * 0.8, y: side + fig.outside, side: "bottom" },
40
+ { id: "shiai-jo", x: side * 0.5, y: side * 0.85, side: "bottom" },
41
+ { id: "floorboard", x: side * 0.2, y: side * 0.35, side: "top" },
42
+ ];
43
+ return { parts, floor, extent: grow(outer, 0.15), side, centre: [cx, cy], starts: [left, right], marks };
44
+ }
@@ -0,0 +1,19 @@
1
+ /** The groups of the kimarite. */
2
+ export type KimariteGroup = "kihon" | "kake" | "nage" | "hineri" | "sori" | "tokushu" | "hi";
3
+ /** One kimarite. */
4
+ export interface Kimarite {
5
+ key: string;
6
+ ja: string;
7
+ en: string;
8
+ group: KimariteGroup;
9
+ }
10
+ /** The kimarite, in the order of the groups: basic, leg tripping, throwing, twisting down, backwards body drop, special, and the non-techniques with the two other results. */
11
+ export declare const KIMARITE: readonly Kimarite[];
12
+ /** How many techniques there are, as the Association counts them. */
13
+ export declare const KIMARITE_COUNT: number;
14
+ /** The five non-techniques and the two other results. */
15
+ export declare const KIMARITE_OTHERS: Kimarite[];
16
+ /** The kimarite a key, a Japanese name or an English gloss names, or `undefined`. */
17
+ export declare function kimariteOf(query: string): Kimarite | undefined;
18
+ /** The name of a kimarite in a language: its Japanese name, or its key in capitals-first romanisation; text that is no kimarite is kept as it was written. */
19
+ export declare function kimariteName(query: string, language: "en" | "ja"): string;
@@ -0,0 +1,33 @@
1
+ // The kimarite (決まり手), the winning techniques of sumo, as the Japan Sumo Association recognises them: 82 techniques in seven groups, the five non-techniques (a win because the opponent lost by his own
2
+ // step or touch) and the two other results, a win by default and by foul. Each has its key (the romanisation, lower case, without macrons), its name in Japanese and its English gloss. The list
3
+ // is read from English Wikipedia's article "Kimarite" (CC BY-SA 4.0) on 2026-10-14, which says the JSA has recognised 82 since 2001; no text of it is copied, only the names. Nothing here draws.
4
+ const group = (g, rows) => rows.map(([key, ja, en]) => ({ key, ja, en, group: g }));
5
+ /** The kimarite, in the order of the groups: basic, leg tripping, throwing, twisting down, backwards body drop, special, and the non-techniques with the two other results. */
6
+ export const KIMARITE = Object.freeze([
7
+ ...group("kihon", [["abisetaoshi", "浴びせ倒し", "backward force down"], ["oshidashi", "押し出し", "frontal push out"], ["oshitaoshi", "押し倒し", "frontal push down"], ["tsukidashi", "突き出し", "frontal thrust out"], ["tsukitaoshi", "突き倒し", "frontal thrust down"], ["yorikiri", "寄り切り", "frontal force out"], ["yoritaoshi", "寄り倒し", "frontal crush out"]]),
8
+ ...group("kake", [["ashitori", "足取り", "leg pick"], ["chongake", "ちょん掛け", "pulling heel hook"], ["kawazugake", "河津掛け", "hooking backward counter throw"], ["kekaeshi", "蹴返し", "minor inner foot sweep"], ["ketaguri", "蹴手繰り", "pulling inside ankle sweep"], ["kirikaeshi", "切り返し", "twisting backward knee trip"], ["komatasukui", "小股掬い", "over thigh scooping body drop"], ["kozumatori", "小褄取り", "ankle pick"], ["mitokorozeme", "三所攻め", "triple attack force out"], ["nimaigeri", "二枚蹴り", "ankle kicking twist down"], ["omata", "大股", "thigh scooping body drop"], ["sotogake", "外掛け", "outside leg trip"], ["sotokomata", "外小股", "over thigh scooping body drop"], ["susoharai", "裾払い", "rear foot sweep"], ["susotori", "裾取り", "toe pick"], ["tsumatori", "褄取り", "rear ankle pick"], ["uchigake", "内掛け", "inside leg trip"], ["watashikomi", "渡し込み", "thigh grabbing push down"]]),
9
+ ...group("nage", [["ipponzeoi", "一本背負い", "one-armed shoulder throw"], ["kakenage", "掛け投げ", "hooking inner thigh throw"], ["koshinage", "腰投げ", "hip throw"], ["kotenage", "小手投げ", "armlock throw"], ["kubinage", "首投げ", "headlock throw"], ["nichonage", "二丁投げ", "body drop throw"], ["shitatedashinage", "下手出し投げ", "pulling underarm throw"], ["shitatenage", "下手投げ", "underarm throw"], ["sukuinage", "掬い投げ", "beltless arm throw"], ["tsukaminage", "つかみ投げ", "lifting throw"], ["uwatedashinage", "上手出し投げ", "pulling overarm throw"], ["uwatenage", "上手投げ", "overarm throw"], ["yaguranage", "櫓投げ", "inner thigh throw"]]),
10
+ ...group("hineri", [["amiuchi", "網打ち", "the fisherman's throw"], ["gasshohineri", "合掌捻り", "clasped hand twist down"], ["harimanage", "波離間投げ", "backward belt throw"], ["kainahineri", "腕捻り", "two-handed arm twist down"], ["katasukashi", "肩透かし", "under-shoulder swing down"], ["kotehineri", "小手捻り", "arm locking twist down"], ["kubihineri", "首捻り", "head twisting throw"], ["makiotoshi", "巻き落とし", "twist down"], ["osakate", "大逆手", "backward twisting overarm throw"], ["sabaori", "鯖折り", "forward force down"], ["sakatottari", "逆とったり", "arm bar throw counter"], ["shitatehineri", "下手捻り", "twisting underarm throw"], ["sotomuso", "外無双", "outer thigh propping twist down"], ["tokkurinage", "徳利投げ", "two handed head twist down"], ["tottari", "とったり", "arm bar throw"], ["tsukiotoshi", "突き落とし", "thrust down"], ["uchimuso", "内無双", "inner thigh propping twist down"], ["uwatehineri", "上手捻り", "twisting overarm throw"], ["zubuneri", "ずぶねり", "head pivot throw"]]),
11
+ ...group("sori", [["izori", "居反り", "backwards body drop"], ["kakezori", "掛け反り", "hooking backwards body drop"], ["shumokuzori", "撞木反り", "bell hammer backwards body drop"], ["sototasukizori", "外たすき反り", "outer reverse backwards body drop"], ["tasukizori", "たすき反り", "reverse backwards body drop"], ["tsutaezori", "伝え反り", "underarm forward body drop"]]),
12
+ ...group("tokushu", [["hatakikomi", "叩き込み", "slap down"], ["hikiotoshi", "引き落とし", "hand pull down"], ["hikkake", "引っ掛け", "arm grabbing force out"], ["kimedashi", "極め出し", "arm barring force out"], ["kimetaoshi", "極め倒し", "arm barring force down"], ["okuridashi", "送り出し", "rear push out"], ["okurigake", "送り掛け", "rear leg trip"], ["okurihikiotoshi", "送り引き落とし", "rear pull down"], ["okurinage", "送り投げ", "rear throw down"], ["okuritaoshi", "送り倒し", "rear push down"], ["okuritsuridashi", "送り吊り出し", "rear lift out"], ["okuritsuriotoshi", "送り吊り落とし", "rear lifting body slam"], ["sokubiotoshi", "素首落とし", "head chop down"], ["tsuridashi", "吊り出し", "frontal lift out"], ["tsuriotoshi", "吊り落とし", "frontal lifting body slam"], ["ushiromotare", "後ろもたれ", "backward lean out"], ["utchari", "うっちゃり", "backward pivot throw"], ["waridashi", "割り出し", "upper-arm force out"], ["yobimodoshi", "呼び戻し", "pulling body slam"]]),
13
+ ...group("hi", [["fumidashi", "踏み出し", "rear step out"], ["isamiashi", "勇み足", "forward step out"], ["koshikudake", "腰砕け", "inadvertent collapse"], ["tsukihiza", "つきひざ", "knee touch down"], ["tsukite", "つき手", "hand touch down"], ["fusen", "不戦勝", "default (absence)"], ["hansoku", "反則勝ち", "foul"]]),
14
+ ]);
15
+ /** How many techniques there are, as the Association counts them. */
16
+ export const KIMARITE_COUNT = KIMARITE.filter((k) => k.group !== "hi").length;
17
+ /** The five non-techniques and the two other results. */
18
+ export const KIMARITE_OTHERS = KIMARITE.filter((k) => k.group === "hi");
19
+ const plain = (s) => s.toLowerCase().normalize("NFKD").replace(/[̀-ͯ]/g, "").replace(/[^a-z0-9ぁ-んァ-ヶ一-龠]/g, "");
20
+ /** The kimarite a key, a Japanese name or an English gloss names, or `undefined`. */
21
+ export function kimariteOf(query) {
22
+ const q = plain(query);
23
+ if (q === "")
24
+ return undefined;
25
+ return KIMARITE.find((k) => k.key === q || plain(k.ja) === q || plain(k.en) === q);
26
+ }
27
+ /** The name of a kimarite in a language: its Japanese name, or its key in capitals-first romanisation; text that is no kimarite is kept as it was written. */
28
+ export function kimariteName(query, language) {
29
+ const k = kimariteOf(query);
30
+ if (k === undefined)
31
+ return query.trim();
32
+ return language === "ja" ? k.ja : k.key.charAt(0).toUpperCase() + k.key.slice(1);
33
+ }
@@ -0,0 +1,16 @@
1
+ import type { Area, BarShape, Shape } from "../fields.types.ts";
2
+ import type { MBox } from "./parts.ts";
3
+ /** The path of a box. */
4
+ export declare const boxD: (b: MBox) => string;
5
+ /** A painted rectangle. */
6
+ export declare const rectArea: (id: string, feature: string, cls: Area["cls"], b: MBox) => Area;
7
+ /** A painted ellipse. */
8
+ export declare const discArea: (id: string, feature: string, cls: Area["cls"], cx: number, cy: number, rx: number, ry?: number) => Area;
9
+ /** A piece of tape: a filled rectangle in a colour of the budō marks. */
10
+ export declare const tapeBar: (id: string, feature: string, cls: NonNullable<BarShape["cls"]>, b: MBox) => Shape;
11
+ /** The path of a ring (a circle between two radii), filled by the even-odd rule. */
12
+ export declare const annulusD: (cx: number, cy: number, r0: number, r1: number) => string;
13
+ /** A value held between two bounds. */
14
+ export declare const clamp: (v: number, lo: number, hi: number) => number;
15
+ /** The number of a size option held to the range a rule allows. @throws TypeError for a value that is not a number, RangeError for one outside the range. */
16
+ export declare function within(value: unknown, lo: number, hi: number, label: string, rule: string): number;
@@ -0,0 +1,24 @@
1
+ import { num } from "../format.js";
2
+ /** The path of a box. */
3
+ export const boxD = (b) => `M${num(b.x0)} ${num(b.y0)}H${num(b.x1)}V${num(b.y1)}H${num(b.x0)}Z`;
4
+ /** A painted rectangle. */
5
+ export const rectArea = (id, feature, cls, b) => ({ id, feature, cls, rect: [b.x0, b.y0, b.x1, b.y1] });
6
+ /** A painted ellipse. */
7
+ export const discArea = (id, feature, cls, cx, cy, rx, ry = rx) => ({ id, feature, cls, ellipse: [cx, cy, rx, ry] });
8
+ /** A piece of tape: a filled rectangle in a colour of the budō marks. */
9
+ export const tapeBar = (id, feature, cls, b) => ({ kind: "bar", id, feature, cls, x0: b.x0, y0: b.y0, x1: b.x1, y1: b.y1 });
10
+ /** The path of a ring (a circle between two radii), filled by the even-odd rule. */
11
+ export const annulusD = (cx, cy, r0, r1) => {
12
+ const c = (r) => `M${num(cx - r)} ${num(cy)}A${num(r)} ${num(r)} 0 1 0 ${num(cx + r)} ${num(cy)}A${num(r)} ${num(r)} 0 1 0 ${num(cx - r)} ${num(cy)}Z`;
13
+ return `${c(r1)}${r0 > 0 ? c(r0) : ""}`;
14
+ };
15
+ /** A value held between two bounds. */
16
+ export const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
17
+ /** The number of a size option held to the range a rule allows. @throws TypeError for a value that is not a number, RangeError for one outside the range. */
18
+ export function within(value, lo, hi, label, rule) {
19
+ if (typeof value !== "number" || !Number.isFinite(value))
20
+ throw new TypeError(`${label} is a number of metres`);
21
+ if (value < lo - 1e-9 || value > hi + 1e-9)
22
+ throw new RangeError(`${label} of ${value} m is outside what ${rule} allows: ${lo} m to ${hi} m`);
23
+ return value;
24
+ }
@@ -0,0 +1,28 @@
1
+ import type { KyudoFigures } from "../leagues/budo.ts";
2
+ import { type MBox, type MMark, type Parts } from "./parts.ts";
3
+ /** What a kyūdōjō plan is. */
4
+ export interface KyudoLayout {
5
+ parts: Parts;
6
+ /** The whole range: the shajō, the yamichi and the azuchi. */
7
+ range: MBox;
8
+ extent: MBox;
9
+ /** The shajō's floor (with the judges' side), the yamichi, the azuchi's footprint. */
10
+ shajo: MBox;
11
+ yamichi: MBox;
12
+ azuchi: MBox;
13
+ /** The x of the shooting positions, of the honza and of the targets' faces, and the y of each shooter. */
14
+ shooting: number;
15
+ honza: number;
16
+ target: number;
17
+ lanes: number[];
18
+ shooters: number;
19
+ marks: MMark[];
20
+ }
21
+ /** The number of shooters the options ask for, 1 to 12. @throws RangeError for a number outside it. */
22
+ export declare function shootersOf(asked: number | undefined, fig: KyudoFigures): number;
23
+ /** The plan of the kyūdōjō the options ask for. */
24
+ export declare function kyudoParts(fig: KyudoFigures, o: {
25
+ shooters: number;
26
+ targets: boolean;
27
+ roof: boolean;
28
+ }): KyudoLayout;
@@ -0,0 +1,66 @@
1
+ import { box, dot, line } from "../fields.kit.js";
2
+ import { discArea, rectArea } from "./kit.js";
3
+ import { emptyParts, grow } from "./parts.js";
4
+ /** The width of the path beside the yamichi, for fetching the arrows (ours). */
5
+ const PATH = 1;
6
+ /** The number of shooters the options ask for, 1 to 12. @throws RangeError for a number outside it. */
7
+ export function shootersOf(asked, fig) {
8
+ if (asked === undefined)
9
+ return fig.count;
10
+ if (!Number.isInteger(asked) || asked < 1 || asked > 12)
11
+ throw new RangeError("budo.shooters is a whole number of 1 to 12");
12
+ return asked;
13
+ }
14
+ /** The plan of the kyūdōjō the options ask for. */
15
+ export function kyudoParts(fig, o) {
16
+ const n = o.shooters;
17
+ const step = fig.step.drawn;
18
+ const h = fig.hall;
19
+ // The frontage is the shooters' line and the side room at each end: 12.6 m for five at 1.8 m, 10.8 m at 1.6 m with 2.2 m to the walls.
20
+ const frontage = (n - 1) * step + 2 * h.side;
21
+ const rearX = 0;
22
+ const frontX = h.rear + h.depth;
23
+ const shooting = frontX - h.front;
24
+ const honza = shooting - fig.honza;
25
+ const target = shooting + fig.distance;
26
+ const lanes = Array.from({ length: n }, (_, i) => h.side + i * step);
27
+ const parts = emptyParts();
28
+ const shajo = { x0: rearX, y0: 0, x1: frontX, y1: frontage + h.judges };
29
+ const azuchiW = (n - 1) * step + 2 * fig.azuchi.margin;
30
+ const cy = h.side + ((n - 1) * step) / 2;
31
+ const azuchi = { x0: target - 1, y0: cy - azuchiW / 2, x1: target + fig.azuchi.depth - 1, y1: cy + azuchiW / 2 };
32
+ const yamichi = { x0: frontX, y0: lanes[0] - fig.yamichi.margin, x1: azuchi.x0, y1: lanes[n - 1] + fig.yamichi.margin };
33
+ // The yamichi lies open to the sky; the path for the arrows runs beside it on the left as the archers face the targets (the north side).
34
+ parts.areas.push(rectArea("yamichi", "yamichi", "ky-bud-yamichi", yamichi));
35
+ parts.areas.push(rectArea("yatori-michi", "yatori-michi", "ky-bud-lane", { x0: yamichi.x0, y0: yamichi.y0 - PATH, x1: yamichi.x1, y1: yamichi.y0 }));
36
+ parts.areas.push(rectArea("shajo", "shajo", "ky-bud-floor", shajo));
37
+ parts.areas.push(rectArea("azuchi", "azuchi", "ky-bud-azuchi", azuchi));
38
+ parts.shapes.push(box("hall", "shajo", shajo.x0, shajo.y0, shajo.x1, shajo.y1, { w: 0.08, cls: "ky-bud-ink", least: 0.08 }));
39
+ // The judges' side: the officials' row at the back of the hall (the figure's dashed line) is not drawn; the judges' room beside the shooters is the floor's last 3.6 m.
40
+ parts.shapes.push(line("judges-line", "shajo", shajo.x0, frontage, shajo.x1, frontage, { w: 0.03, dash: [0.3, 0.25], cls: "ky-bud-ink", least: 0.03 }));
41
+ lanes.forEach((y, i) => {
42
+ parts.shapes.push(dot(`shooting-${i + 1}`, "shooting-positions", shooting, y, 0.1));
43
+ parts.shapes.push(dot(`honza-${i + 1}`, "honza", honza, y, 0.07));
44
+ if (o.targets)
45
+ parts.areas.push(discArea(`mato-${i + 1}`, "targets", "ky-bud-mato", target, y, fig.target.diameter / 2));
46
+ });
47
+ // The line of the shooting positions and of the honza, drawn faint; and the line of the targets' faces.
48
+ parts.shapes.push(line("shooting-line", "shooting-positions", shooting, 0.4, shooting, frontage - 0.4, { w: 0.03, dash: [0.2, 0.2], cls: "ky-bud-line", least: 0.03 }));
49
+ parts.shapes.push(line("honza-line", "honza", honza, 0.4, honza, frontage - 0.4, { w: 0.03, dash: [0.12, 0.3], cls: "ky-bud-line", least: 0.03 }));
50
+ if (o.roof) {
51
+ parts.shapes.push(box("roof-shajo", "roofs", rearX - 0.4, -0.4, frontX + 0.5, frontage + h.judges + 0.4, { w: 0.05, dash: [0.5, 0.35], cls: "ky-bud-ink", least: 0.05 }));
52
+ parts.shapes.push(box("roof-matoba", "roofs", azuchi.x0 - 2.2, azuchi.y0 - 0.5, azuchi.x1 + 0.4, azuchi.y1 + 0.5, { w: 0.05, dash: [0.5, 0.35], cls: "ky-bud-ink", least: 0.05 }));
53
+ }
54
+ const range = { x0: 0, y0: Math.min(0, yamichi.y0 - PATH, azuchi.y0), x1: azuchi.x1, y1: Math.max(shajo.y1, azuchi.y1) };
55
+ const marks = [
56
+ { id: "shajo", x: shajo.x0 + 1.5, y: 0.8, side: "top" },
57
+ { id: "shooting-position", x: shooting, y: lanes[0], side: "top" },
58
+ { id: "honza", x: honza, y: lanes[n - 1], side: "bottom" },
59
+ { id: "yamichi", x: (yamichi.x0 + yamichi.x1) / 2, y: yamichi.y1 - 0.4, side: "bottom" },
60
+ { id: "yatori-michi", x: yamichi.x0 + (yamichi.x1 - yamichi.x0) * 0.35, y: yamichi.y0 - PATH / 2, side: "top" },
61
+ { id: "azuchi", x: azuchi.x1 - 0.6, y: azuchi.y1 - 0.8, side: "bottom" },
62
+ ];
63
+ if (o.targets)
64
+ marks.push({ id: "mato", x: target, y: lanes[0], side: "top" });
65
+ return { parts, range, extent: grow(range, 0.6), shajo, yamichi, azuchi, shooting, honza, target, lanes, shooters: n, marks };
66
+ }
@@ -0,0 +1,28 @@
1
+ import type { BudoKind } from "./types.ts";
2
+ /** What a look sets: the properties of the stylesheet its sport's surface is painted with. */
3
+ export interface BudoLook {
4
+ /** The first tone of the mats (the contest area, the mats of a dojo), the second (the safety area, the other mats of a checker floor) and the third (a danger zone, a border: the sheet's `--ky-red`). */
5
+ surface: string;
6
+ alt: string;
7
+ red: string;
8
+ /** The ground round the surface, the free zone round the mats, and the floor of the hall: wood, the boards of a kendo floor, the walls. */
9
+ apron: string;
10
+ free: string;
11
+ floor: string;
12
+ boards: string;
13
+ /** The clay of a dohyō, the sand of its jano-me, the straw of its tawara. */
14
+ dirt?: string;
15
+ sand?: string;
16
+ straw?: string;
17
+ }
18
+ interface Pair {
19
+ light: BudoLook;
20
+ dark: BudoLook;
21
+ }
22
+ /** The looks of each sport: the names, the default first, and the colours. */
23
+ export declare const BUDO_LOOKS: Readonly<Record<BudoKind, Readonly<Record<string, Pair>>>>;
24
+ /** The names of a sport's looks, the default first. */
25
+ export declare const lookNames: (sport: BudoKind) => string[];
26
+ /** The look a name asks for, or the sport's first. @throws Error for a name the sport has no look of. */
27
+ export declare function lookOf(sport: BudoKind, name: unknown): string;
28
+ export {};
@@ -0,0 +1,58 @@
1
+ /** A colour darkened by a share, 0 to 1, towards black. */
2
+ function dim(hex, k) {
3
+ const n = Number.parseInt(hex.slice(1), 16);
4
+ const c = [(n >> 16) & 255, (n >> 8) & 255, n & 255].map((v) => Math.round(v * (1 - k)));
5
+ return `#${c.map((v) => v.toString(16).padStart(2, "0")).join("")}`;
6
+ }
7
+ /** A look made from its light colours: the dark one is the same hues dimmed. */
8
+ function pair(light, k = 0.34) {
9
+ const dark = { ...light };
10
+ for (const key of Object.keys(light)) {
11
+ const v = light[key];
12
+ if (v !== undefined)
13
+ dark[key] = key === "apron" ? "#1c1e1d" : key === "free" ? dim(v, 0.5) : dim(v, k);
14
+ }
15
+ return { light, dark };
16
+ }
17
+ const FLOOR = "#c9a26a";
18
+ const WALLS = "#7d756a";
19
+ const COMMON = { apron: "#d6d3cb", free: "#e8e4d8", floor: FLOOR, boards: WALLS };
20
+ const MATS = {
21
+ "yellow-red": pair({ ...COMMON, surface: "#f4c430", alt: "#c9343b", red: "#b32a2f" }),
22
+ "yellow-blue": pair({ ...COMMON, surface: "#f2c230", alt: "#2f6db3", red: "#b32a2f" }),
23
+ "blue-grey": pair({ ...COMMON, surface: "#3a74c2", alt: "#9aa4ad", red: "#b32a2f" }),
24
+ "green-beige": pair({ ...COMMON, surface: "#7da157", alt: "#d6c595", red: "#b32a2f" }),
25
+ "green-red": pair({ ...COMMON, surface: "#8bb561", alt: "#5a8a46", red: "#c0392b" }),
26
+ "black-red": pair({ ...COMMON, surface: "#2d2f33", alt: "#b8323a", red: "#b8323a" }),
27
+ };
28
+ /** The dojo's own two: pale yellow contest areas on green mats (the Kodokan's main dojo as it is now), and green mats of one tone with red-orange border mats (as it was). Ours, from the owner's photographs. */
29
+ const DOJO_ONLY = {
30
+ "yellow-green": pair({ ...COMMON, surface: "#e8d98e", alt: "#5f9a52", red: "#c8462a" }),
31
+ "green-orange": pair({ ...COMMON, surface: "#6fa352", alt: "#69a04f", red: "#d4572a" }),
32
+ };
33
+ /** The looks of each sport: the names, the default first, and the colours. */
34
+ export const BUDO_LOOKS = Object.freeze({
35
+ judo: MATS,
36
+ dojo: { "green-beige": MATS["green-beige"], "yellow-red": MATS["yellow-red"], "yellow-blue": MATS["yellow-blue"], "blue-grey": MATS["blue-grey"], "black-red": MATS["black-red"], "green-red": MATS["green-red"], ...DOJO_ONLY },
37
+ karate: {
38
+ "blue-red": pair({ ...COMMON, surface: "#2b66b9", alt: "#1f4a85", red: "#c43a3a" }),
39
+ "blue-black": pair({ ...COMMON, surface: "#2b66b9", alt: "#26282b", red: "#c43a3a" }),
40
+ "green-beige": pair({ ...COMMON, surface: "#7da157", alt: "#d6c595", red: "#c43a3a" }),
41
+ },
42
+ kendo: {
43
+ wood: pair({ ...COMMON, surface: "#c8955a", alt: "#b98650", red: "#b32a2f", floor: "#c8955a", free: "#e6dccb" }),
44
+ blond: pair({ ...COMMON, surface: "#e0bf8a", alt: "#d3b27c", red: "#b32a2f", floor: "#e0bf8a", free: "#ece4d3" }),
45
+ },
46
+ sumo: { clay: pair({ ...COMMON, surface: "#b0794a", alt: "#a06c40", red: "#b32a2f", dirt: "#b0794a", sand: "#e8dcc2", straw: "#c8a45c" }) },
47
+ kyudo: { wood: pair({ ...COMMON, surface: "#9db57d", alt: "#d8cfb0", red: "#b32a2f", floor: "#b98c58", dirt: "#c9ad7a" }) },
48
+ });
49
+ /** The names of a sport's looks, the default first. */
50
+ export const lookNames = (sport) => Object.keys(BUDO_LOOKS[sport]);
51
+ /** The look a name asks for, or the sport's first. @throws Error for a name the sport has no look of. */
52
+ export function lookOf(sport, name) {
53
+ if (name === undefined)
54
+ return lookNames(sport)[0];
55
+ if (typeof name !== "string" || !Object.prototype.hasOwnProperty.call(BUDO_LOOKS[sport], name))
56
+ throw new Error(`Unknown look "${String(name)}" for "${sport}": use one of ${lookNames(sport).join(", ")}`);
57
+ return name;
58
+ }
@@ -0,0 +1,32 @@
1
+ import type { Area, Shape } from "../fields.types.ts";
2
+ /** What a part of a plan adds. */
3
+ export interface Parts {
4
+ areas: Area[];
5
+ shapes: Shape[];
6
+ }
7
+ export declare const emptyParts: () => Parts;
8
+ /** Add `more` to `into`. */
9
+ export declare function addParts(into: Parts, more: Parts): void;
10
+ /** A box in metres. */
11
+ export interface MBox {
12
+ x0: number;
13
+ y0: number;
14
+ x1: number;
15
+ y1: number;
16
+ }
17
+ /** A named part of the plan to crop to, in metres: one box, or one at each end (`left` and `right` as the surface is drawn wide). */
18
+ export type MRange = MBox | {
19
+ left: MBox;
20
+ right: MBox;
21
+ };
22
+ /** A part of the plan to label (`landmarks`): where it is, in metres, and the side of the drawing its label stands on. */
23
+ export interface MMark {
24
+ id: string;
25
+ x: number;
26
+ y: number;
27
+ side: "top" | "bottom";
28
+ }
29
+ export declare const grow: (b: MBox, m: number) => MBox;
30
+ export declare const union: (boxes: readonly MBox[]) => MBox;
31
+ export declare const boxOf: (cx: number, cy: number, w: number, h: number) => MBox;
32
+ export declare const shifted: (b: MBox, dx: number, dy: number) => MBox;
@@ -0,0 +1,10 @@
1
+ export const emptyParts = () => ({ areas: [], shapes: [] });
2
+ /** Add `more` to `into`. */
3
+ export function addParts(into, more) {
4
+ into.areas.push(...more.areas);
5
+ into.shapes.push(...more.shapes);
6
+ }
7
+ export const grow = (b, m) => ({ x0: b.x0 - m, y0: b.y0 - m, x1: b.x1 + m, y1: b.y1 + m });
8
+ export const union = (boxes) => ({ x0: Math.min(...boxes.map((b) => b.x0)), y0: Math.min(...boxes.map((b) => b.y0)), x1: Math.max(...boxes.map((b) => b.x1)), y1: Math.max(...boxes.map((b) => b.y1)) });
9
+ export const boxOf = (cx, cy, w, h) => ({ x0: cx - w / 2, y0: cy - h / 2, x1: cx + w / 2, y1: cy + h / 2 });
10
+ export const shifted = (b, dx, dy) => ({ x0: b.x0 + dx, y0: b.y0 + dy, x1: b.x1 + dx, y1: b.y1 + dy });
@@ -0,0 +1,64 @@
1
+ import type { Area, Shape } from "../fields.types.ts";
2
+ import { type BudoFigures, type BudoLeague } from "../leagues/budo.ts";
3
+ import type { SurfaceOptions } from "../types.ts";
4
+ import { type DojoLayout } from "./dojo.ts";
5
+ import { type JudoLayout } from "./judo.ts";
6
+ import { type KarateLayout } from "./karate.ts";
7
+ import { type KendoLayout } from "./kendo.ts";
8
+ import { type KyudoLayout } from "./kyudo.ts";
9
+ import { boxD } from "./kit.ts";
10
+ import { type MBox, type MMark, type MRange } from "./parts.ts";
11
+ import { type SumoLayout } from "./sumo.ts";
12
+ import type { BudoKind } from "./types.ts";
13
+ export type { MBox, MMark, MRange };
14
+ /** The apothem of the Nippon Budokan's arena, an octagon 55 m across the flats (the Budokan's leaflet). */
15
+ export declare const BUDOKAN_ARENA = 27.5;
16
+ /** What a budō drawing is. */
17
+ export interface BudoPlan {
18
+ sport: BudoKind;
19
+ league: string;
20
+ figures: BudoFigures;
21
+ /** The look (the colours of the mats and the floor). */
22
+ look: string;
23
+ /** The mats are drawn with the weave of rice straw. */
24
+ texture: boolean;
25
+ /** The playing surface: the mats of a competition area, the shiai-jo's floor, the dohyō's clay, the whole range of a kyūdōjō, a dojo's floor. The data frame's own box. */
26
+ box: MBox;
27
+ /** Everything drawn: the box and what lies beyond it (the free zone, the furniture). */
28
+ extent: MBox;
29
+ areas: Area[];
30
+ shapes: Shape[];
31
+ /** The width the ordinary line is painted at by the rules, and the width it is drawn at unless `exactLines` says otherwise. */
32
+ lineWidth: number;
33
+ drawnLine: number;
34
+ ranges: Readonly<Record<string, MRange>>;
35
+ marks: MMark[];
36
+ /** The arena floor under the surface, for the Nippon Budokan. */
37
+ hall: "budokan" | undefined;
38
+ /** The centre of the surface and the radius of the circle a pageant's emblem lies in, in metres. */
39
+ centre: {
40
+ x: number;
41
+ y: number;
42
+ r: number;
43
+ };
44
+ /** The layout of the sport: one of these is set. */
45
+ judo?: JudoLayout;
46
+ karate?: KarateLayout;
47
+ kendo?: KendoLayout;
48
+ sumo?: SumoLayout;
49
+ kyudo?: KyudoLayout;
50
+ dojo?: DojoLayout;
51
+ }
52
+ /** The sports of the budō family. */
53
+ export declare const BUDO_SPORTS: readonly BudoKind[];
54
+ /** True for a sport of the budō family. */
55
+ export declare const isBudoSport: (sport: string) => sport is BudoKind;
56
+ /** The league a set of options asks for: a rulebook's, else the sport's own. */
57
+ export declare function budoLeague(o: Pick<SurfaceOptions, "sport" | "league" | "budo" | "dojo">): BudoLeague;
58
+ /** The octagon of the Budokan's arena as a path, centred on (cx, cy). */
59
+ export declare function octagonD(cx: number, cy: number, a: number): string;
60
+ /** True when a point lies inside the Budokan's octagon about (cx, cy). */
61
+ export declare const inOctagon: (cx: number, cy: number, a: number, x: number, y: number) => boolean;
62
+ /** The budō plan the options ask for. */
63
+ export declare function budoPlan(o: Pick<SurfaceOptions, "sport" | "league" | "budo" | "dojo" | "range" | "detail">): BudoPlan;
64
+ export { boxD };