@johnmorrisdotca/kyogijo-stadiums 0.10.2 → 0.12.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,25 @@ All notable changes to this project are written here. The format follows
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.12.0] - 2026-10-19
11
+
12
+ ### Added
13
+
14
+ - **Tournament layouts** (`@johnmorrisdotca/kyogijo-stadiums/multi`): `drawMulti` lays several of the package's own surfaces out together for one large event, to scale, on one floor, as one SVG, with the barriers, the officials' chairs, a scoreboard hung over the middle, the boards along the edges and empty places for the event's own words and marks (on the mats themselves for judo and karate, as those sports print them). Thirteen presets, each with its rule and sources, from table tennis (four and eight areas), pickleball (2 x 2, 2 x 4, 4 x 4), curling (four sheets), judo (three and four areas), karate (six and eight), badminton (the least spacing, and the 4 m the BWF recommends at Grade 1 and 2) and tennis; each says whether it is a rulebook's spacing or an arrangement an event used. `multiLayout` gives the floor a layout needs, `multiFit` whether it fits a hall (a rectangle, an octagon, or a floor of which only the area is known) with five halls and ice pads whose floors are published, and `venue` and `stadium` set the layout in a hall with a real stadium round it at the same scale, reusing the package's stands and crowd. `multiTable` is the text alternative; light and dark, English and Japanese. A demo page, `halls.html`, picks a preset, sets it in a hall and switches the stadium on and off (linked from the demo's gallery section), and the docs gallery has a page for every preset. See [Tournament layouts](./docs/multi.md).
15
+ - **Two more parks place a dugout or a bullpen, where their articles do:** `wrigley-field`'s home dugout (third base line) and `griffith-stadium`'s left-field bullpen (388 feet, 1956 to 1961). No generic dugout or bullpen is drawn for the others; `docs/ballparks.md` and `docs/references.md` list what was read and left out and why.
16
+
17
+ ### Changed
18
+
19
+ - **Docs only:** `docs/situation.md` says plainly what is left undrawn for want of a source (the NHL's older creases, an Olympic hybrid sheet, Buffalo Memorial Auditorium's rink) and what would be needed; `docs/team-shape.md` says the lineup's `jersey` is a flat marker of our own and where full jerseys are drawn.
20
+
21
+ ## [0.11.0] - 2026-10-19
22
+
23
+ ### Added
24
+
25
+ - **A ground with a running track offers the athletics stadium in the atlas:** `surfacesOf(place)` lists `{ sport: "athletics", ground }` for a ground whose `track` is set, and `surfaceOf(place, "athletics")` returns it; the six grounds Wikidata marks with a track are linked, no other place.
26
+ - **A `<title>` on every point and line when the marks are written** (`marks: true`, `pointer: true`): a datum with no `title` of its own is named from its outcome, its team and its place in the data ("goal, home, 3"), so a delegated listener, a hover and a screen reader reach every mark. Nothing is added without `marks`, so a drawing nobody points at is the same string as ever. Heat cells stay without one (size budget; their numbers are in the layer's table).
27
+ - **The IFAF's field is named and tested in the situation docs** (`docs/situation.md`): `sport: "ifaf"` takes a football situation on the NFL's 100-yard field, with four downs.
28
+
10
29
  ## [0.10.2] - 2026-10-14
11
30
 
12
31
  ### Fixed
package/README.md CHANGED
@@ -129,6 +129,7 @@ console.log(svg.startsWith("<svg"), svg.includes("USA 3, Canada 2"));
129
129
  | `./parks`, `./grounds`, `./arenas`, `./atlas`, `./eras`, `./leagues`, `./events` | The ballparks, the grounds, the arenas, every place, the markings of a season, each league's rulebook, the special games. |
130
130
  | `./turn` | A surface as a 3D view that turns, with the net, basket, goal or posts standing on it. |
131
131
  | `./scene`, `./canvas`, `./d3`, `./plot`, `./geojson`, `./png` | The drawing as data; on a canvas; in a d3 selection; as an Observable Plot mark; as GeoJSON; as a PNG (the optional peer `@resvg/resvg-js`). |
132
+ | `./multi` | `drawMulti`, `multiFit`: several surfaces laid out for one event, in a hall ([docs](./docs/multi.md), [demo](https://johnmorrisdotca.github.io/kyogijo-stadiums/halls.html)). |
132
133
  | `./layouts` | `drawGrid` and `GRID_PRESETS`: small multiples with a title, a subtitle, a key and a credit line; the grounds behind a drawing or a grid. |
133
134
  | `./mount`, `./react`, `./element`, `./element/define` | Draw into a container; React props; the `<kyogijo-field>` element and its registration. |
134
135
 
@@ -616,39 +617,67 @@ Using Kyogijo Stadiums in something? Open an *Add my project* issue and we will
616
617
  ### The family
617
618
 
618
619
  <!-- family:start (made by scripts/family-readme.mjs from scripts/family-template.mjs; change those, not this) -->
619
- Kyogijo Stadiums is one of twenty-eight packages, each made for the same site, each at
620
- [github.com/johnmorrisdotca](https://github.com/johnmorrisdotca). The code of every one is MIT.
620
+ Kyogijo Stadiums is one of thirty-two packages, each made for the same site, each at
621
+ [github.com/johnmorrisdotca](https://github.com/johnmorrisdotca) or [github.com/spxis](https://github.com/spxis). The code of every one is MIT.
621
622
 
622
- - [Korokoro](https://github.com/johnmorrisdotca/korokoro) (コロコロ): dice, with notation, exact odds, real sounds and the dice of many games. [Demo](https://johnmorrisdotca.github.io/korokoro/).
623
- - [Kyuubu](https://github.com/johnmorrisdotca/kyuubu) (キューブ): a turning cube for the browser, 2×2 to 7×7, with record solves to replay. [Demo](https://johnmorrisdotca.github.io/kyuubu/).
624
- - [Hitotsu](https://github.com/johnmorrisdotca/hitotsu) (一つ): a colour-card shedding game for two to eight, with the house rules people play. [Demo](https://johnmorrisdotca.github.io/hitotsu/).
625
- - [Toranpu](https://github.com/johnmorrisdotca/toranpu) (トランプ): a deck of playing cards, card games with computer players, and solitaires. [Demo](https://johnmorrisdotca.github.io/toranpu/).
626
- - [Tane](https://github.com/johnmorrisdotca/tane) (種): seeded random numbers and daily seeds, the same in every browser and on every server. [Demo](https://johnmorrisdotca.github.io/tane/).
623
+ **Games — board**
624
+
625
+ - [Domino](https://github.com/johnmorrisdotca/domino) (ドミノ): dominoes and Mexican Train. [Demo](https://johnmorrisdotca.github.io/domino/).
626
+ - [Gunjin](https://github.com/johnmorrisdotca/gunjin) (軍人): five hidden-rank strategy games with pass-the-device play. [Demo](https://johnmorrisdotca.github.io/gunjin/).
627
627
  - [Narabe](https://github.com/johnmorrisdotca/narabe) (並べ): one rules engine for abstract board games, from gomoku and Reversi to Go and checkers. [Demo](https://johnmorrisdotca.github.io/narabe/).
628
+ - [Sugoroku](https://github.com/johnmorrisdotca/sugoroku) (双六): backgammon and its variants, with the doubling cube and match play. [Demo](https://johnmorrisdotca.github.io/sugoroku/).
628
629
  - [Tenka](https://github.com/johnmorrisdotca/tenka) (天下): world conquest for two to six, on a map of the real world. [Demo](https://johnmorrisdotca.github.io/tenka/).
629
- - [Kumimoji](https://github.com/johnmorrisdotca/kumimoji) (組み文字): a crossword tile race, in English and Japanese kana. [Demo](https://johnmorrisdotca.github.io/kumimoji/).
630
- - [Tsunagi](https://github.com/johnmorrisdotca/tsunagi) (繋ぎ): a line-joining logic puzzle whose every level has exactly one answer. [Demo](https://johnmorrisdotca.github.io/tsunagi/).
630
+
631
+ **Games — cards & tiles**
632
+
633
+ - [Hitotsu](https://github.com/johnmorrisdotca/hitotsu) (一つ): a colour-card shedding game for two to eight, with the house rules people play. [Demo](https://johnmorrisdotca.github.io/hitotsu/).
631
634
  - [Jarajara](https://github.com/johnmorrisdotca/jarajara) (ジャラジャラ): mahjong tiles drawn as SVG, stacked layouts, and the matching solitaire Awase. [Demo](https://johnmorrisdotca.github.io/jarajara/).
632
- - [Suido](https://github.com/johnmorrisdotca/suido) (水道): a pipe puzzle: turn the pieces until the water reaches every drain. [Demo](https://johnmorrisdotca.github.io/suido/).
633
- - [Domino](https://github.com/johnmorrisdotca/domino) (ドミノ): dominoes and Mexican Train. [Demo](https://johnmorrisdotca.github.io/domino/).
634
- - [Kotoba](https://github.com/johnmorrisdotca/kotoba) (言葉): word lists and word-game rules in English, French, German and Japanese. [Demo](https://johnmorrisdotca.github.io/kotoba/).
635
- - [Sugoroku](https://github.com/johnmorrisdotca/sugoroku) (双六): backgammon and its variants, with the doubling cube and match play. [Demo](https://johnmorrisdotca.github.io/sugoroku/).
635
+ - [Kumimoji](https://github.com/johnmorrisdotca/kumimoji) (組み文字): a crossword tile race, in English and Japanese kana. [Demo](https://johnmorrisdotca.github.io/kumimoji/).
636
+ - [Toranpu](https://github.com/johnmorrisdotca/toranpu) (トランプ): a deck of playing cards, card games with computer players, and solitaires. [Demo](https://johnmorrisdotca.github.io/toranpu/).
637
+
638
+ **Games — puzzles**
639
+
640
+ - [Houseki](https://github.com/johnmorrisdotca/houseki) (宝石): gem and stone matching puzzles: falling triplets, stone collapse, colour chains and gem swap. [Demo](https://johnmorrisdotca.github.io/houseki/).
641
+ - [Jirai](https://github.com/johnmorrisdotca/jirai) (地雷): minesweeper on shaped grids with verified no-guess boards. [Demo](https://johnmorrisdotca.github.io/jirai/).
642
+ - [Karakuri](https://github.com/johnmorrisdotca/karakuri) (からくり): eight hyper-casual puzzle games, some of them physics: draw a shield, pull pins, cut ropes, slide blocks, pour tubes. [Demo](https://johnmorrisdotca.github.io/karakuri/).
636
643
  - [Kazu](https://github.com/johnmorrisdotca/kazu) (数): grid number puzzles: Sudoku and its variants, Futoshiki and Skyscrapers. [Demo](https://johnmorrisdotca.github.io/kazu/).
644
+ - [Kyuubu](https://github.com/johnmorrisdotca/kyuubu) (キューブ): a turning cube for the browser, 2×2 to 7×7, with record solves to replay. [Demo](https://johnmorrisdotca.github.io/kyuubu/).
637
645
  - [Meikyuu](https://github.com/johnmorrisdotca/meikyuu) (迷宮): mazes on squares, hexagons, triangles and circles, made from a seed and drawn through with a finger or the mouse. [Demo](https://johnmorrisdotca.github.io/meikyuu/).
646
+ - [Suido](https://github.com/johnmorrisdotca/suido) (水道): a pipe puzzle: turn the pieces until the water reaches every drain. [Demo](https://johnmorrisdotca.github.io/suido/).
647
+ - [Tobiishi](https://github.com/johnmorrisdotca/tobiishi) (飛び石): peg solitaire with nine boards and seeded solvable challenges. [Demo](https://johnmorrisdotca.github.io/tobiishi/).
648
+ - [Tsunagi](https://github.com/johnmorrisdotca/tsunagi) (繋ぎ): a line-joining logic puzzle whose every level has exactly one answer. [Demo](https://johnmorrisdotca.github.io/tsunagi/).
649
+
650
+ **Games — dice & random**
651
+
652
+ - [Korokoro](https://github.com/johnmorrisdotca/korokoro) (コロコロ): dice, with notation, exact odds, real sounds and the dice of many games. [Demo](https://johnmorrisdotca.github.io/korokoro/).
653
+ - [Tane](https://github.com/johnmorrisdotca/tane) (種): seeded random numbers and daily seeds, the same in every browser and on every server. [Demo](https://johnmorrisdotca.github.io/tane/).
654
+
655
+ **Language**
656
+
657
+ - [Bushu](https://github.com/johnmorrisdotca/bushu) (部首): find a kanji by the parts it is made of. [Demo](https://johnmorrisdotca.github.io/bushu/).
638
658
  - [Hikidashi](https://github.com/johnmorrisdotca/hikidashi) (引き出し): a drawer of small Japanese text tools: era dates, kanji numerals, readings and sentence difficulty. [Demo](https://johnmorrisdotca.github.io/hikidashi/).
659
+ - [Kotoba](https://github.com/johnmorrisdotca/kotoba) (言葉): word lists and word-game rules in English, French, German and Japanese. [Demo](https://johnmorrisdotca.github.io/kotoba/).
660
+
661
+ **Geography & data**
662
+
663
+ - [address-plus](https://github.com/johnmorrisdotca/address-plus) (アドレスプラス): parse and format addresses in the United States, Canada, Japan, Australia, France, Germany and the United Kingdom. [Demo](https://johnmorrisdotca.github.io/address-plus/).
639
664
  - [Chizu](https://github.com/johnmorrisdotca/chizu) (地図): maps of the world and of countries' regions, in English and Japanese, with a quiz and callouts. [Demo](https://johnmorrisdotca.github.io/chizu/).
640
- - [Bushu](https://github.com/johnmorrisdotca/bushu) (部首): find a kanji by the parts it is made of. [Demo](https://johnmorrisdotca.github.io/bushu/).
641
- - [Tobiishi](https://github.com/johnmorrisdotca/tobiishi) (飛び石): peg solitaire with nine boards and seeded solvable challenges. [Demo](https://johnmorrisdotca.github.io/tobiishi/).
642
- - [Jirai](https://github.com/johnmorrisdotca/jirai) (地雷): minesweeper on shaped grids with verified no-guess boards. [Demo](https://johnmorrisdotca.github.io/jirai/).
643
- - [Gunjin](https://github.com/johnmorrisdotca/gunjin) (軍人): five hidden-rank strategy games with pass-the-device play. [Demo](https://johnmorrisdotca.github.io/gunjin/).
644
- - [Karakuri](https://github.com/johnmorrisdotca/karakuri) (からくり): eight hyper-casual puzzle games, some of them physics: draw a shield, pull pins, cut ropes, slide blocks, pour tubes. [Demo](https://johnmorrisdotca.github.io/karakuri/).
645
- - [Houseki](https://github.com/johnmorrisdotca/houseki) (宝石): gem and stone matching puzzles: falling triplets, stone collapse, colour chains and gem swap. [Demo](https://johnmorrisdotca.github.io/houseki/).
646
- - [Kyogijo Stadiums](https://github.com/johnmorrisdotca/kyogijo-stadiums) (競技場): sports fields, rinks, courts and ballparks drawn to scale as SVG, with each team and the score on them. [Demo](https://johnmorrisdotca.github.io/kyogijo-stadiums/).
647
- - [Taisen Brackets](https://github.com/johnmorrisdotca/taisen-brackets) (対戦): a sport-agnostic tournament bracket, drawn as SVG, from a list of ties. [Demo](https://johnmorrisdotca.github.io/taisen-brackets/).
665
+ - [Hata](https://github.com/johnmorrisdotca/hata) (旗): country and regional flags as SVG, at their true proportions and keyed by ISO code. [Demo](https://johnmorrisdotca.github.io/hata/).
666
+ - [Kuni](https://github.com/johnmorrisdotca/kuni) (国): countries and their regions, with ISO codes and names in English and Japanese. [Demo](https://johnmorrisdotca.github.io/kuni/).
667
+
668
+ **Sports**
669
+
648
670
  - [Dougu Sports](https://github.com/johnmorrisdotca/dougu-sports) (道具): sports emblems as SVG: trophies, medals, crests, and the ball and gear of every sport, with optional 3D turning. [Demo](https://johnmorrisdotca.github.io/dougu-sports/).
671
+ - [Kyogijo Stadiums](https://github.com/johnmorrisdotca/kyogijo-stadiums) (競技場): sports fields, rinks, courts and ballparks drawn to scale as SVG, with each team and the score on them. [Demo](https://johnmorrisdotca.github.io/kyogijo-stadiums/).
649
672
  - [Senshu Jerseys](https://github.com/johnmorrisdotca/senshu-jerseys) (選手): sports jerseys, sweaters, kits, caps, helmets and retired-number banners as SVG, front and back, with optional 2.5D turning. [Demo](https://johnmorrisdotca.github.io/senshu-jerseys/).
673
+ - [Taisen Brackets](https://github.com/johnmorrisdotca/taisen-brackets) (対戦): a sport-agnostic tournament bracket, drawn as SVG, from a list of ties. [Demo](https://johnmorrisdotca.github.io/taisen-brackets/).
674
+
675
+ **Developer tools**
676
+
677
+ - [REST in Pieces](https://github.com/spxis/rest-in-pieces) (レスト・イン・ピーシーズ): seeded test data and REST APIs for frontend development, with latency and error drills. [Demo](https://spxis.github.io/rest-in-pieces/).
678
+
650
679
 
651
- **This package is Kyogijo Stadiums.** The demos of all twenty-eight share one header and footer, so each links the rest.
680
+ **This package is Kyogijo Stadiums.** The demos of all thirty-two share one header and footer, so each links the rest.
652
681
  <!-- family:end -->
653
682
 
654
683
  ## Development
package/dist/atlas.d.ts CHANGED
@@ -135,6 +135,9 @@ export type PlaceSurface = {
135
135
  } | {
136
136
  sport: "soccer";
137
137
  ground?: string;
138
+ } | {
139
+ sport: "athletics";
140
+ ground?: string;
138
141
  } | {
139
142
  sport: "nhl" | "nba";
140
143
  arena?: string;
@@ -158,7 +161,8 @@ export type SurfaceSport = PlaceSurface["sport"];
158
161
  export declare const hallSurfaces: (place: Place) => readonly HallSurface[];
159
162
  /**
160
163
  * Every surface a place offers, the place's own first: a park's fence (`mlb` with the park) or a ground's pitch at its size (`soccer` with the ground), then one for each
161
- * sport a tenant plays that the package draws (a CFL field for BC Place, an NFL field for MetLife Stadium, the rugby league field for Stadium Australia), each once. A ground
164
+ * sport a tenant plays that the package draws (a CFL field for BC Place, an NFL field for MetLife Stadium, the rugby league field for Stadium Australia), each once, and the
165
+ * athletics stadium (`athletics` with the ground) of a ground whose `track` is set. A ground
162
166
  * offers no ballpark, since its fence is not known; a park that a soccer club has played in offers the pitch at the international size, since its length and width are not known.
163
167
  * @example
164
168
  * ```ts
package/dist/atlas.js CHANGED
@@ -226,7 +226,8 @@ const hallOptions = (surface) => ({ sport: surface.sport, ...surface.options });
226
226
  export const hallSurfaces = (place) => (place.kind === "hall" ? (place.hall?.surfaces ?? []) : []);
227
227
  /**
228
228
  * Every surface a place offers, the place's own first: a park's fence (`mlb` with the park) or a ground's pitch at its size (`soccer` with the ground), then one for each
229
- * sport a tenant plays that the package draws (a CFL field for BC Place, an NFL field for MetLife Stadium, the rugby league field for Stadium Australia), each once. A ground
229
+ * sport a tenant plays that the package draws (a CFL field for BC Place, an NFL field for MetLife Stadium, the rugby league field for Stadium Australia), each once, and the
230
+ * athletics stadium (`athletics` with the ground) of a ground whose `track` is set. A ground
230
231
  * offers no ballpark, since its fence is not known; a park that a soccer club has played in offers the pitch at the international size, since its length and width are not known.
231
232
  * @example
232
233
  * ```ts
@@ -260,6 +261,9 @@ export function surfacesOf(place) {
260
261
  continue;
261
262
  out.push(surface);
262
263
  }
264
+ // A ground with a running track round its pitch (`track`) also offers the athletics stadium: the track and its field events round the ground's own pitch.
265
+ if (place.kind === "ground" && place.track === true && !out.some((have) => have.sport === "athletics"))
266
+ out.push({ sport: "athletics", ground: place.id });
263
267
  return out;
264
268
  }
265
269
  export function surfaceOf(place, sport) {
@@ -42,6 +42,16 @@ export interface Env {
42
42
  * `data-index` (its place in the layer's data) and `data-zone` (the zone it lies in, from `zoneAt`'s rules). The place is in feet in the drawing's wide frame.
43
43
  */
44
44
  export declare function markAttrs(env: Env, id: unknown, index: number, at?: readonly [number, number], name?: string): string;
45
+ /**
46
+ * The tooltip of a mark: the caller's own `title`, else (only when the layer writes `data-mark-id` and friends, for a listener that reads the mark's name)
47
+ * a short one made from what the datum says: its outcome, its team and its place in the data ("goal, home, 3"). Nothing is added when the marks are not
48
+ * written, so a drawing that nobody points at is the same text as ever.
49
+ */
50
+ export declare function markTitle(env: Env, d: {
51
+ title?: unknown;
52
+ outcome?: unknown;
53
+ team?: unknown;
54
+ }, index: number): string | undefined;
45
55
  /** What a layer made. */
46
56
  export interface Made {
47
57
  /** The elements of the layer, and its gradients as `defs`. */
@@ -40,6 +40,19 @@ export function markAttrs(env, id, index, at, name = "data-zone") {
40
40
  const zone = at === undefined ? undefined : env.zone(at[0], at[1]);
41
41
  return ` data-mark-id="${esc(given)}" data-index="${index}"${zone === undefined ? "" : ` ${name}="${esc(zone)}"`}`;
42
42
  }
43
+ /**
44
+ * The tooltip of a mark: the caller's own `title`, else (only when the layer writes `data-mark-id` and friends, for a listener that reads the mark's name)
45
+ * a short one made from what the datum says: its outcome, its team and its place in the data ("goal, home, 3"). Nothing is added when the marks are not
46
+ * written, so a drawing that nobody points at is the same text as ever.
47
+ */
48
+ export function markTitle(env, d, index) {
49
+ if (typeof d.title === "string" && d.title !== "")
50
+ return d.title;
51
+ if (!env.marks)
52
+ return undefined;
53
+ const word = (v) => (typeof v === "string" ? v.trim() : "");
54
+ return [word(d.outcome), word(d.team), String(index + 1)].filter((part) => part !== "").join(", ");
55
+ }
43
56
  export const toArray = (value, what) => {
44
57
  if (!Array.isArray(value))
45
58
  throw new TypeError(`${what} needs data: a list of marks`);
package/dist/layers.js CHANGED
@@ -11,7 +11,7 @@ import { FRAMES } from "./frames.js";
11
11
  import { KYOGIJO_HEAT_STYLE, KYOGIJO_TEAM_STYLE } from "./style.js";
12
12
  import { drawTeam, isTeamLayer, teamTables } from "./team.layers.js";
13
13
  import { drawHeat, drawLegend, heatTable } from "./heat.js";
14
- import { clamp01, envFor, isNum, markAttrs, newMade, opacityOf, own, place, toArray, unitOfLayer } from "./layers.env.js";
14
+ import { clamp01, envFor, isNum, markAttrs, markTitle, newMade, opacityOf, own, place, toArray, unitOfLayer } from "./layers.env.js";
15
15
  import { safeClass } from "./common.js";
16
16
  import { esc, num } from "./format.js";
17
17
  import { curveBetween, curvePath, headPath, isPolygon, polylinePath, rampColour, shapePath, taperPath, wavePath, } from "./layers.marks.js";
@@ -144,12 +144,12 @@ function drawPoints(layer, env) {
144
144
  const logo = shape === "logo" ? safeLogo(d.logo) ?? (role === undefined ? undefined : safeLogo(style.logos?.[role]) ?? env.logos[role]) : undefined;
145
145
  if (logo !== undefined) {
146
146
  const side = w * 1.8;
147
- out.push(titled("image", `${open} href="${esc(logo)}" x="${num(x - side / 2)}" y="${num(y - side / 2)}" width="${num(side)}" height="${num(side)}" preserveAspectRatio="xMidYMid meet"${env.back !== 0 ? ` transform="rotate(${num(env.back)} ${num(x)} ${num(y)})"` : ""}`, d.title));
147
+ out.push(titled("image", `${open} href="${esc(logo)}" x="${num(x - side / 2)}" y="${num(y - side / 2)}" width="${num(side)}" height="${num(side)}" preserveAspectRatio="xMidYMid meet"${env.back !== 0 ? ` transform="rotate(${num(env.back)} ${num(x)} ${num(y)})"` : ""}`, markTitle(env, d, i)));
148
148
  }
149
149
  else if (shape !== "logo" && isPolygon(shape))
150
- out.push(titled("path", `${open} d="${shapePath(shape, x, y, w, env.turned)}"`, d.title));
150
+ out.push(titled("path", `${open} d="${shapePath(shape, x, y, w, env.turned)}"`, markTitle(env, d, i)));
151
151
  else
152
- out.push(titled("circle", `${open} cx="${num(x)}" cy="${num(y)}" r="${num(w / 2)}"`, d.title));
152
+ out.push(titled("circle", `${open} cx="${num(x)}" cy="${num(y)}" r="${num(w / 2)}"`, markTitle(env, d, i)));
153
153
  });
154
154
  made.marks = out.join("");
155
155
  return made;
@@ -259,7 +259,8 @@ function drawLines(layer, env, index) {
259
259
  gradient = `stroke:url(#${gid})`;
260
260
  }
261
261
  const headEl = head === "" ? "" : `<path class="${headKind === "open" ? "ky-ln" : "ky-ah"}" d="${head}"${headKind === "open" ? ` stroke-width="${num(w)}"` : ""}/>`;
262
- const title = typeof d.title === "string" && d.title !== "" ? `<title>${esc(d.title)}</title>` : "";
262
+ const named = markTitle(env, d, i);
263
+ const title = named === undefined ? "" : `<title>${esc(named)}</title>`;
263
264
  const opacity = opacityOf(d.opacity);
264
265
  // Where it starts is its zone; where it ends is `data-zone-end`.
265
266
  const marks = env.marks ? markAttrs(env, d.id, i, first) + (env.zone(last[0], last[1]) === undefined ? "" : ` data-zone-end="${esc(env.zone(last[0], last[1]))}"`) : "";
@@ -0,0 +1,7 @@
1
+ export { drawMulti, multiSetting, multiTable } from "./multi.draw.ts";
2
+ export { MULTI_MAX, fitSentence, multiFit, multiLayout, needsSentence, specOf, venueOf } from "./multi.ts";
3
+ export { MULTI_PRESETS, MULTI_PRESET_IDS, MULTI_SOURCES, MULTI_VENUES, multiPreset, multiSource, multiVenueById } from "./multi.data.ts";
4
+ export { KYOGIJO_MULTI_STYLE } from "./multi.style.ts";
5
+ export { MULTI_WORDS } from "./multi.words.ts";
6
+ export type { MultiWords } from "./multi.words.ts";
7
+ export type { MultiBasis, MultiCell, MultiEvent, MultiFit, MultiFloor, MultiLayout, MultiNeeds, MultiOptions, MultiParts, MultiSize, MultiSlot, MultiSpec, MultiSurface, MultiUnit, MultiVenue, MultiWord } from "./multi.types.ts";
@@ -0,0 +1,8 @@
1
+ // Tournament layouts: several of the package's surfaces laid out together for one large event, to scale, on one floor (tables, courts, sheets, a judo floor's contest areas in a row), with the barriers, the
2
+ // officials' chairs, a scoreboard hung over the middle, the boards and the empty places for the event's own words and marks; the real configurations of events as presets, each with its rule; the halls whose
3
+ // floors are published, and whether a layout fits one; and a real stadium round the floor at the same scale. `multiTable` is the text alternative.
4
+ export { drawMulti, multiSetting, multiTable } from "./multi.draw.js";
5
+ export { MULTI_MAX, fitSentence, multiFit, multiLayout, needsSentence, specOf, venueOf } from "./multi.js";
6
+ export { MULTI_PRESETS, MULTI_PRESET_IDS, MULTI_SOURCES, MULTI_VENUES, multiPreset, multiSource, multiVenueById } from "./multi.data.js";
7
+ export { KYOGIJO_MULTI_STYLE } from "./multi.style.js";
8
+ export { MULTI_WORDS } from "./multi.words.js";
@@ -0,0 +1,42 @@
1
+ import type { MultiFit, MultiLayout, MultiNeeds, MultiOptions, MultiSpec, MultiVenue } from "./multi.types.ts";
2
+ import type { Language } from "./types.ts";
3
+ /** The most rows or columns a layout takes. */
4
+ export declare const MULTI_MAX = 12;
5
+ /** A number as a language writes it: thousands separated, two decimals at most (`3,234.5`). */
6
+ export declare const multiNumber: (value: number, language?: Language) => string;
7
+ /**
8
+ * The layout the options ask for: a preset or a layout of the caller's own, with the grid and the stagger it is given in place of its own.
9
+ * @throws Error for a preset that is not one, an option that is not a whole number or a share, or neither a preset nor a layout.
10
+ */
11
+ export declare function specOf(o: Pick<MultiOptions, "preset" | "layout" | "rows" | "columns" | "stagger">): MultiSpec;
12
+ /**
13
+ * A layout laid out: where each surface stands, the floor it needs and the empty places for the event's own words and marks, all in feet from the top left corner of the floor (and the floor's size
14
+ * and what the layout needs in metres).
15
+ * @example
16
+ * ```ts
17
+ * import { multiLayout } from "@johnmorrisdotca/kyogijo-stadiums/multi";
18
+ * const layout = multiLayout({ preset: "tabletennis-4" });
19
+ * console.log(layout.cells.length, layout.needs.length, layout.needs.width);
20
+ * // 4 28 14
21
+ * ```
22
+ */
23
+ export declare function multiLayout(options?: Pick<MultiOptions, "preset" | "layout" | "rows" | "columns" | "stagger" | "language">): MultiLayout;
24
+ /** A hall as the caller gives it, or a key of `MULTI_VENUES`. @throws Error for a key that is not one, a size that is not positive. */
25
+ export declare function venueOf(venue: MultiOptions["venue"]): MultiVenue | undefined;
26
+ /**
27
+ * Whether a layout fits a hall's floor. A floor that is a rectangle takes the layout as it is or turned a quarter; an octagon takes it if its corners are inside; a floor of which only the area is published
28
+ * can only be compared by area, and says so (`fits` is `null` when the area is enough, because the shape may still not take it).
29
+ * @example
30
+ * ```ts
31
+ * import { multiFit, multiLayout } from "@johnmorrisdotca/kyogijo-stadiums/multi";
32
+ * const four = multiFit(multiLayout({ preset: "curling-1x4" }), "nhl-ice-pad");
33
+ * const six = multiFit(multiLayout({ preset: "curling-1x4", columns: 6 }), "nhl-ice-pad");
34
+ * console.log(four.fits, four.turned, six.fits);
35
+ * // true true false
36
+ * ```
37
+ */
38
+ export declare function multiFit(layout: MultiLayout, venue: MultiOptions["venue"]): MultiFit;
39
+ /** The sentence that says how a layout sits in a hall, in a language. */
40
+ export declare function fitSentence(fit: MultiFit, language?: Language): string;
41
+ /** The size of a layout as words, in a language: `28 by 14 metres (392 square metres)`; along the layout first, then across it. */
42
+ export declare const needsSentence: (needs: MultiNeeds, language?: Language) => string;
@@ -0,0 +1,22 @@
1
+ import { type LeagueSource } from "./leagues/sources.ts";
2
+ import type { MultiSpec, MultiVenue } from "./multi.types.ts";
3
+ /** The documents a layout's figures were read from, by id, beside the rulebooks of `LEAGUE_SOURCES` (a key of either names a source). */
4
+ export declare const MULTI_SOURCES: Readonly<Record<string, Readonly<LeagueSource>>>;
5
+ /** The source a key names, from `MULTI_SOURCES` or `LEAGUE_SOURCES`. */
6
+ export declare const multiSource: (id: string) => Readonly<LeagueSource> | undefined;
7
+ /**
8
+ * The halls whose floor is published, and the two ice pads an arena lays in winter. A venue with no length and width (only an area) is compared by area. The package does not hold the floors of
9
+ * halls it could not source: a layout for such a hall is set on a floor of the caller's own size.
10
+ */
11
+ export declare const MULTI_VENUES: readonly MultiVenue[];
12
+ /** The hall with a key, or `undefined`. */
13
+ export declare const multiVenueById: (id: string | undefined) => MultiVenue | undefined;
14
+ /**
15
+ * The presets: layouts of real configurations, each with its rule and, where one is named, the event and the hall. `rulebook` means the spacing is what a rulebook or a specification asks for; `event`
16
+ * means an event used the arrangement (read from reports and photographs, with no plan seen). The list is in the order of the sports of this package's own menu.
17
+ */
18
+ export declare const MULTI_PRESETS: readonly MultiSpec[];
19
+ /** The keys of `MULTI_PRESETS`, in order. */
20
+ export declare const MULTI_PRESET_IDS: readonly string[];
21
+ /** The preset with a key, or `undefined`. */
22
+ export declare const multiPreset: (id: string | undefined) => MultiSpec | undefined;