@johnmorrisdotca/dougu-sports 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -1
- package/LICENSES/README.md +4 -3
- package/NOTICE.md +54 -14
- package/README.md +251 -80
- package/dist/emblems/award/badge.d.ts +2 -0
- package/dist/emblems/award/badge.js +14 -0
- package/dist/emblems/award/crown.d.ts +2 -0
- package/dist/emblems/award/crown.js +15 -0
- package/dist/emblems/award/medal.d.ts +1 -1
- package/dist/emblems/award/medal.js +10 -15
- package/dist/emblems/award/shield.d.ts +2 -0
- package/dist/emblems/award/shield.js +11 -0
- package/dist/emblems/award/star.d.ts +2 -0
- package/dist/emblems/award/star.js +11 -0
- package/dist/emblems/ball/ball.afl.d.ts +1 -0
- package/dist/emblems/ball/ball.afl.js +24 -0
- package/dist/emblems/ball/ball.baseball.d.ts +1 -0
- package/dist/emblems/ball/ball.baseball.js +14 -0
- package/dist/emblems/ball/ball.basketball.d.ts +7 -0
- package/dist/emblems/ball/ball.basketball.js +32 -0
- package/dist/emblems/ball/ball.basketball3x3.d.ts +1 -0
- package/dist/emblems/ball/ball.basketball3x3.js +10 -0
- package/dist/emblems/ball/ball.basketball6.d.ts +1 -0
- package/dist/emblems/ball/ball.basketball6.js +10 -0
- package/dist/emblems/ball/ball.core.d.ts +111 -0
- package/dist/emblems/ball/ball.core.js +79 -0
- package/dist/emblems/ball/ball.cricket.d.ts +5 -0
- package/dist/emblems/ball/ball.cricket.js +31 -0
- package/dist/emblems/ball/ball.curlingstone.d.ts +3 -0
- package/dist/emblems/ball/ball.curlingstone.js +46 -0
- package/dist/emblems/ball/ball.discus.d.ts +1 -0
- package/dist/emblems/ball/ball.discus.js +24 -0
- package/dist/emblems/ball/ball.engine.d.ts +114 -0
- package/dist/emblems/ball/ball.engine.js +342 -0
- package/dist/emblems/ball/ball.family.dotted.d.ts +27 -0
- package/dist/emblems/ball/ball.family.dotted.js +20 -0
- package/dist/emblems/ball/ball.family.panelled.d.ts +7 -0
- package/dist/emblems/ball/ball.family.panelled.js +60 -0
- package/dist/emblems/ball/ball.family.prolate.d.ts +16 -0
- package/dist/emblems/ball/ball.family.prolate.js +29 -0
- package/dist/emblems/ball/ball.family.seamed.d.ts +31 -0
- package/dist/emblems/ball/ball.family.seamed.js +26 -0
- package/dist/emblems/ball/ball.fieldhockey.d.ts +1 -0
- package/dist/emblems/ball/ball.fieldhockey.js +15 -0
- package/dist/emblems/ball/ball.football.d.ts +3 -0
- package/dist/emblems/ball/ball.football.js +51 -0
- package/dist/emblems/ball/ball.gaelic.d.ts +2 -0
- package/dist/emblems/ball/ball.gaelic.js +30 -0
- package/dist/emblems/ball/ball.golf.d.ts +1 -0
- package/dist/emblems/ball/ball.golf.js +15 -0
- package/dist/emblems/ball/ball.hammer.d.ts +1 -0
- package/dist/emblems/ball/ball.hammer.js +31 -0
- package/dist/emblems/ball/ball.handball.d.ts +1 -0
- package/dist/emblems/ball/ball.handball.js +25 -0
- package/dist/emblems/ball/ball.index.d.ts +48 -0
- package/dist/emblems/ball/ball.index.js +103 -0
- package/dist/emblems/ball/ball.math.d.ts +38 -0
- package/dist/emblems/ball/ball.math.js +105 -0
- package/dist/emblems/ball/ball.object.d.ts +38 -0
- package/dist/emblems/ball/ball.object.js +20 -0
- package/dist/emblems/ball/ball.padel.d.ts +1 -0
- package/dist/emblems/ball/ball.padel.js +13 -0
- package/dist/emblems/ball/ball.pickleball.d.ts +2 -0
- package/dist/emblems/ball/ball.pickleball.js +26 -0
- package/dist/emblems/ball/ball.polyhedra.d.ts +15 -0
- package/dist/emblems/ball/ball.polyhedra.js +63 -0
- package/dist/emblems/ball/ball.puck.d.ts +3 -0
- package/dist/emblems/ball/ball.puck.js +22 -0
- package/dist/emblems/ball/ball.roundnet.d.ts +1 -0
- package/dist/emblems/ball/ball.roundnet.js +15 -0
- package/dist/emblems/ball/ball.rugby.d.ts +1 -0
- package/dist/emblems/ball/ball.rugby.js +35 -0
- package/dist/emblems/ball/ball.sepaktakraw.d.ts +1 -0
- package/dist/emblems/ball/ball.sepaktakraw.js +48 -0
- package/dist/emblems/ball/ball.shuttlecock.d.ts +6 -0
- package/dist/emblems/ball/ball.shuttlecock.js +93 -0
- package/dist/emblems/ball/ball.sliotar.d.ts +1 -0
- package/dist/emblems/ball/ball.sliotar.js +14 -0
- package/dist/emblems/ball/ball.smooth.d.ts +4 -0
- package/dist/emblems/ball/ball.smooth.js +51 -0
- package/dist/emblems/ball/ball.soccer.d.ts +2 -0
- package/dist/emblems/ball/ball.soccer.js +54 -0
- package/dist/emblems/ball/ball.softball.d.ts +1 -0
- package/dist/emblems/ball/ball.softball.js +14 -0
- package/dist/emblems/ball/ball.squash.d.ts +7 -0
- package/dist/emblems/ball/ball.squash.js +27 -0
- package/dist/emblems/ball/ball.stack.d.ts +48 -0
- package/dist/emblems/ball/ball.stack.js +127 -0
- package/dist/emblems/ball/ball.stitch.d.ts +10 -0
- package/dist/emblems/ball/ball.stitch.js +59 -0
- package/dist/emblems/ball/ball.tennis.d.ts +1 -0
- package/dist/emblems/ball/ball.tennis.js +13 -0
- package/dist/emblems/ball/ball.teqball.d.ts +1 -0
- package/dist/emblems/ball/ball.teqball.js +27 -0
- package/dist/emblems/ball/ball.volleyball.d.ts +3 -0
- package/dist/emblems/ball/ball.volleyball.js +56 -0
- package/dist/emblems/ball/ball.waterpolo.d.ts +1 -0
- package/dist/emblems/ball/ball.waterpolo.js +31 -0
- package/dist/emblems/crest/diamond.d.ts +2 -0
- package/dist/emblems/crest/diamond.js +18 -0
- package/dist/emblems/crest/pennant.d.ts +2 -0
- package/dist/emblems/crest/pennant.js +18 -0
- package/dist/emblems/crest/roundel.d.ts +2 -0
- package/dist/emblems/crest/roundel.js +18 -0
- package/dist/emblems/crest/shield.d.ts +2 -0
- package/dist/emblems/crest/shield.js +17 -0
- package/dist/emblems/emblem.api.d.ts +77 -9
- package/dist/emblems/emblem.api.js +56 -10
- package/dist/emblems/emblem.compose.d.ts +31 -0
- package/dist/emblems/emblem.compose.js +91 -0
- package/dist/emblems/emblem.core.d.ts +89 -7
- package/dist/emblems/emblem.core.js +85 -11
- package/dist/emblems/emblem.descriptions.d.ts +7 -0
- package/dist/emblems/emblem.descriptions.js +60 -0
- package/dist/emblems/emblem.display.d.ts +75 -0
- package/dist/emblems/emblem.display.js +214 -0
- package/dist/emblems/emblem.engrave.d.ts +50 -0
- package/dist/emblems/emblem.engrave.js +145 -0
- package/dist/emblems/emblem.equipment.d.ts +24 -0
- package/dist/emblems/emblem.equipment.js +57 -0
- package/dist/emblems/emblem.flip.d.ts +10 -0
- package/dist/emblems/emblem.flip.js +45 -0
- package/dist/emblems/emblem.ids.d.ts +44 -30
- package/dist/emblems/emblem.ids.js +51 -17
- package/dist/emblems/emblem.lathe.d.ts +62 -0
- package/dist/emblems/emblem.lathe.js +426 -0
- package/dist/emblems/emblem.medal.d.ts +6 -0
- package/dist/emblems/emblem.medal.js +38 -0
- package/dist/emblems/emblem.pennant.d.ts +3 -0
- package/dist/emblems/emblem.pennant.js +79 -0
- package/dist/emblems/emblem.registry.js +162 -4
- package/dist/emblems/emblem.shapes.d.ts +48 -12
- package/dist/emblems/emblem.shapes.js +138 -31
- package/dist/emblems/emblem.sprite.d.ts +38 -0
- package/dist/emblems/emblem.sprite.js +65 -0
- package/dist/emblems/emblem.uri.d.ts +22 -0
- package/dist/emblems/emblem.uri.js +29 -0
- package/dist/emblems/gear/gear.badmintonracket.d.ts +1 -0
- package/dist/emblems/gear/gear.badmintonracket.js +19 -0
- package/dist/emblems/gear/gear.baseballglove.d.ts +1 -0
- package/dist/emblems/gear/gear.baseballglove.js +21 -0
- package/dist/emblems/gear/gear.budo.d.ts +17 -0
- package/dist/emblems/gear/gear.budo.js +60 -0
- package/dist/emblems/gear/gear.core.d.ts +64 -0
- package/dist/emblems/gear/gear.core.js +127 -0
- package/dist/emblems/gear/gear.cricketbat.d.ts +1 -0
- package/dist/emblems/gear/gear.cricketbat.js +17 -0
- package/dist/emblems/gear/gear.field.d.ts +6 -0
- package/dist/emblems/gear/gear.field.js +81 -0
- package/dist/emblems/gear/gear.fieldhockeystick.d.ts +1 -0
- package/dist/emblems/gear/gear.fieldhockeystick.js +16 -0
- package/dist/emblems/gear/gear.footballhelmet.d.ts +1 -0
- package/dist/emblems/gear/gear.footballhelmet.js +16 -0
- package/dist/emblems/gear/gear.goaliemask.d.ts +1 -0
- package/dist/emblems/gear/gear.goaliemask.js +23 -0
- package/dist/emblems/gear/gear.goalnet.d.ts +1 -0
- package/dist/emblems/gear/gear.goalnet.js +25 -0
- package/dist/emblems/gear/gear.hockeystick.d.ts +1 -0
- package/dist/emblems/gear/gear.hockeystick.js +15 -0
- package/dist/emblems/gear/gear.index.d.ts +22 -0
- package/dist/emblems/gear/gear.index.js +49 -0
- package/dist/emblems/gear/gear.kendo.d.ts +2 -0
- package/dist/emblems/gear/gear.kendo.js +41 -0
- package/dist/emblems/gear/gear.kyudo.d.ts +2 -0
- package/dist/emblems/gear/gear.kyudo.js +31 -0
- package/dist/emblems/gear/gear.lacrossestick.d.ts +1 -0
- package/dist/emblems/gear/gear.lacrossestick.js +26 -0
- package/dist/emblems/gear/gear.rackets.d.ts +4 -0
- package/dist/emblems/gear/gear.rackets.js +60 -0
- package/dist/emblems/gear/gear.skates.d.ts +3 -0
- package/dist/emblems/gear/gear.skates.js +39 -0
- package/dist/emblems/gear/gear.sticks.d.ts +3 -0
- package/dist/emblems/gear/gear.sticks.js +34 -0
- package/dist/emblems/gear/gear.sumo.d.ts +2 -0
- package/dist/emblems/gear/gear.sumo.js +43 -0
- package/dist/emblems/gear/gear.tabletennispaddle.d.ts +1 -0
- package/dist/emblems/gear/gear.tabletennispaddle.js +16 -0
- package/dist/emblems/gear/gear.tennisracket.d.ts +1 -0
- package/dist/emblems/gear/gear.tennisracket.js +17 -0
- package/dist/emblems/gear/gear.track.d.ts +4 -0
- package/dist/emblems/gear/gear.track.js +45 -0
- package/dist/emblems/gear/gear.water.d.ts +2 -0
- package/dist/emblems/gear/gear.water.js +25 -0
- package/dist/emblems/medal/bronze.d.ts +2 -0
- package/dist/emblems/medal/bronze.js +4 -0
- package/dist/emblems/medal/gold.d.ts +2 -0
- package/dist/emblems/medal/gold.js +4 -0
- package/dist/emblems/medal/place-1.d.ts +2 -0
- package/dist/emblems/medal/place-1.js +4 -0
- package/dist/emblems/medal/place-2.d.ts +2 -0
- package/dist/emblems/medal/place-2.js +4 -0
- package/dist/emblems/medal/place-3.d.ts +2 -0
- package/dist/emblems/medal/place-3.js +4 -0
- package/dist/emblems/medal/silver.d.ts +2 -0
- package/dist/emblems/medal/silver.js +4 -0
- package/dist/emblems/pennant/championship.d.ts +2 -0
- package/dist/emblems/pennant/championship.js +4 -0
- package/dist/emblems/sport/afl.d.ts +2 -0
- package/dist/emblems/sport/afl.js +12 -0
- package/dist/emblems/sport/artisticswimming.d.ts +2 -0
- package/dist/emblems/sport/artisticswimming.js +16 -0
- package/dist/emblems/sport/athletics.d.ts +2 -0
- package/dist/emblems/sport/athletics.js +12 -0
- package/dist/emblems/sport/badminton.d.ts +2 -0
- package/dist/emblems/sport/badminton.js +13 -0
- package/dist/emblems/sport/cfl.d.ts +2 -0
- package/dist/emblems/sport/cfl.js +5 -0
- package/dist/emblems/sport/cricket.d.ts +2 -0
- package/dist/emblems/sport/cricket.js +14 -0
- package/dist/emblems/sport/curling.d.ts +2 -0
- package/dist/emblems/sport/curling.js +14 -0
- package/dist/emblems/sport/diving.d.ts +2 -0
- package/dist/emblems/sport/diving.js +18 -0
- package/dist/emblems/sport/fieldhockey.d.ts +2 -0
- package/dist/emblems/sport/fieldhockey.js +11 -0
- package/dist/emblems/sport/gaelic.d.ts +2 -0
- package/dist/emblems/sport/gaelic.js +11 -0
- package/dist/emblems/sport/handball.d.ts +2 -0
- package/dist/emblems/sport/handball.js +15 -0
- package/dist/emblems/sport/ifaf.d.ts +2 -0
- package/dist/emblems/sport/ifaf.js +5 -0
- package/dist/emblems/sport/judo.d.ts +2 -0
- package/dist/emblems/sport/judo.js +13 -0
- package/dist/emblems/sport/karate.d.ts +2 -0
- package/dist/emblems/sport/karate.js +13 -0
- package/dist/emblems/sport/kendo.d.ts +2 -0
- package/dist/emblems/sport/kendo.js +14 -0
- package/dist/emblems/sport/kyudo.d.ts +2 -0
- package/dist/emblems/sport/kyudo.js +15 -0
- package/dist/emblems/sport/lacrosse.d.ts +2 -0
- package/dist/emblems/sport/lacrosse.js +13 -0
- package/dist/emblems/sport/mlb.d.ts +2 -0
- package/dist/emblems/sport/mlb.js +28 -0
- package/dist/emblems/sport/nba.d.ts +2 -0
- package/dist/emblems/sport/nba.js +12 -0
- package/dist/emblems/sport/netball.d.ts +2 -0
- package/dist/emblems/sport/netball.js +14 -0
- package/dist/emblems/sport/nfl.d.ts +3 -0
- package/dist/emblems/sport/nfl.js +15 -0
- package/dist/emblems/sport/nhl.d.ts +2 -0
- package/dist/emblems/sport/nhl.js +13 -0
- package/dist/emblems/sport/padel.d.ts +2 -0
- package/dist/emblems/sport/padel.js +14 -0
- package/dist/emblems/sport/pickleball.d.ts +2 -0
- package/dist/emblems/sport/pickleball.js +13 -0
- package/dist/emblems/sport/racquetball.d.ts +2 -0
- package/dist/emblems/sport/racquetball.js +13 -0
- package/dist/emblems/sport/roundnet.d.ts +2 -0
- package/dist/emblems/sport/roundnet.js +15 -0
- package/dist/emblems/sport/rugby.d.ts +2 -0
- package/dist/emblems/sport/rugby.js +12 -0
- package/dist/emblems/sport/sepaktakraw.d.ts +2 -0
- package/dist/emblems/sport/sepaktakraw.js +11 -0
- package/dist/emblems/sport/skating.d.ts +2 -0
- package/dist/emblems/sport/skating.js +14 -0
- package/dist/emblems/sport/soccer.d.ts +2 -0
- package/dist/emblems/sport/soccer.js +31 -0
- package/dist/emblems/sport/squash.d.ts +2 -0
- package/dist/emblems/sport/squash.js +15 -0
- package/dist/emblems/sport/sumo.d.ts +2 -0
- package/dist/emblems/sport/sumo.js +15 -0
- package/dist/emblems/sport/swimming.d.ts +2 -0
- package/dist/emblems/sport/swimming.js +15 -0
- package/dist/emblems/sport/tabletennis.d.ts +2 -0
- package/dist/emblems/sport/tabletennis.js +12 -0
- package/dist/emblems/sport/tennis.d.ts +2 -0
- package/dist/emblems/sport/tennis.js +15 -0
- package/dist/emblems/sport/teqball.d.ts +2 -0
- package/dist/emblems/sport/teqball.js +15 -0
- package/dist/emblems/sport/volleyball.d.ts +2 -0
- package/dist/emblems/sport/volleyball.js +25 -0
- package/dist/emblems/sport/waterpolo.d.ts +2 -0
- package/dist/emblems/sport/waterpolo.js +15 -0
- package/dist/emblems/trophy/banner.d.ts +2 -0
- package/dist/emblems/trophy/banner.js +20 -0
- package/dist/emblems/trophy/baseball.d.ts +2 -0
- package/dist/emblems/trophy/baseball.js +15 -0
- package/dist/emblems/trophy/basketball.d.ts +2 -0
- package/dist/emblems/trophy/basketball.js +17 -0
- package/dist/emblems/trophy/belt.d.ts +2 -0
- package/dist/emblems/trophy/belt.js +17 -0
- package/dist/emblems/trophy/bowl.d.ts +2 -0
- package/dist/emblems/trophy/bowl.js +8 -0
- package/dist/emblems/trophy/canadian-bowl.d.ts +2 -0
- package/dist/emblems/trophy/canadian-bowl.js +23 -0
- package/dist/emblems/trophy/championship-banner.d.ts +2 -0
- package/dist/emblems/trophy/championship-banner.js +67 -0
- package/dist/emblems/trophy/cricket-urn.d.ts +2 -0
- package/dist/emblems/trophy/cricket-urn.js +23 -0
- package/dist/emblems/trophy/cup.d.ts +2 -0
- package/dist/emblems/trophy/cup.js +16 -0
- package/dist/emblems/trophy/football.d.ts +2 -0
- package/dist/emblems/trophy/football.js +11 -0
- package/dist/emblems/trophy/globe.d.ts +2 -0
- package/dist/emblems/trophy/globe.js +9 -0
- package/dist/emblems/trophy/hockey-cup.d.ts +2 -0
- package/dist/emblems/trophy/hockey-cup.js +22 -0
- package/dist/emblems/trophy/laurel.d.ts +2 -0
- package/dist/emblems/trophy/laurel.js +40 -0
- package/dist/emblems/trophy/lidded-cup.d.ts +2 -0
- package/dist/emblems/trophy/lidded-cup.js +21 -0
- package/dist/emblems/trophy/plaque.d.ts +2 -0
- package/dist/emblems/trophy/plaque.js +17 -0
- package/dist/emblems/trophy/ring.d.ts +2 -0
- package/dist/emblems/trophy/ring.js +30 -0
- package/dist/emblems/trophy/rosette.d.ts +2 -0
- package/dist/emblems/trophy/rosette.js +27 -0
- package/dist/emblems/trophy/rugby-cup.d.ts +2 -0
- package/dist/emblems/trophy/rugby-cup.js +23 -0
- package/dist/emblems/trophy/salver.d.ts +2 -0
- package/dist/emblems/trophy/salver.js +9 -0
- package/dist/emblems/trophy/soccer-ball.d.ts +2 -0
- package/dist/emblems/trophy/soccer-ball.js +9 -0
- package/dist/emblems/trophy/soccer-globe.d.ts +2 -0
- package/dist/emblems/trophy/soccer-globe.js +18 -0
- package/dist/emblems/trophy/sumo-cup.d.ts +2 -0
- package/dist/emblems/trophy/sumo-cup.js +28 -0
- package/dist/emblems/trophy/tennis-cup.d.ts +2 -0
- package/dist/emblems/trophy/tennis-cup.js +24 -0
- package/dist/emblems/trophy/tennis-plate.d.ts +2 -0
- package/dist/emblems/trophy/tennis-plate.js +16 -0
- package/dist/emblems-entry.d.ts +20 -7
- package/dist/emblems-entry.js +8 -2
- package/dist/index.d.ts +131 -1
- package/dist/index.js +131 -3
- package/dist/turn-control.d.ts +101 -0
- package/dist/turn-control.js +363 -0
- package/dist/turn-entry.d.ts +2 -0
- package/dist/turn-entry.js +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +33 -7
- package/LICENSES/Apache-2.0.txt +0 -55
- package/LICENSES/CC-BY-3.0.md +0 -15
- package/dist/emblems/ball/soccer.d.ts +0 -2
- package/dist/emblems/ball/soccer.js +0 -9
- package/dist/emblems/emblem.ball.d.ts +0 -28
- package/dist/emblems/emblem.ball.js +0 -70
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Pickleball: a perforated plastic ball. The outdoor ball has 40 small holes; the indoor ball has 26 larger ones (the rulebook gives 26 to 40 holes; the split is how balls are sold).
|
|
2
|
+
import { dottedBall } from "./ball.family.dotted.js";
|
|
3
|
+
export const BALL_PICKLEBALL_OUTDOOR = /* @__PURE__ */ dottedBall({
|
|
4
|
+
id: "ball:pickleball-outdoor",
|
|
5
|
+
en: "Pickleball, outdoor",
|
|
6
|
+
ja: "ピックルボール(屋外用)",
|
|
7
|
+
size: { extentMm: 74.2, diameterMm: 74.2, massG: [22.1, 26.5], rule: "USA Pickleball Equipment Standards Manual (Jan 2025, Revision 3.0), 2.D.1 Design, 2.D.3 Size, 2.D.4 Weight, 2.D.8 Design (holes); USA Pickleball 2026 Official Rulebook rule 3.C Ball Specifications", note: "The rulebook does not tell indoor and outdoor balls apart: both are 26 to 40 holes; 40 small holes is the outdoor ball as sold." },
|
|
8
|
+
base: "#e6e83c",
|
|
9
|
+
count: 40,
|
|
10
|
+
radius: 0.13,
|
|
11
|
+
mat: { gloss: 0.55, shade: "#4a5008", grain: { f: 1.4, a: 0.1 } },
|
|
12
|
+
mark: "#454b0e",
|
|
13
|
+
depth: 0.75,
|
|
14
|
+
});
|
|
15
|
+
export const BALL_PICKLEBALL_INDOOR = /* @__PURE__ */ dottedBall({
|
|
16
|
+
id: "ball:pickleball-indoor",
|
|
17
|
+
en: "Pickleball, indoor",
|
|
18
|
+
ja: "ピックルボール(屋内用)",
|
|
19
|
+
size: { extentMm: 74.2, diameterMm: 74.2, massG: [22.1, 26.5], rule: "USA Pickleball Equipment Standards Manual (Jan 2025, Revision 3.0), 2.D.1 Design, 2.D.3 Size, 2.D.4 Weight, 2.D.8 Design (holes); USA Pickleball 2026 Official Rulebook rule 3.C Ball Specifications", note: "The rulebook does not tell indoor and outdoor balls apart: both are 26 to 40 holes; 26 large holes is the indoor ball as sold." },
|
|
20
|
+
base: "#f2f0e4",
|
|
21
|
+
count: 26,
|
|
22
|
+
radius: 0.19,
|
|
23
|
+
mat: { gloss: 0.6, shade: "#3a3a40", grain: { f: 1.4, a: 0.08 } },
|
|
24
|
+
mark: "#3d3d44",
|
|
25
|
+
depth: 0.7,
|
|
26
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type V3 } from "./ball.math.ts";
|
|
2
|
+
export interface Truncated {
|
|
3
|
+
pentagons: V3[][];
|
|
4
|
+
hexagons: V3[][];
|
|
5
|
+
/** The centre of each pentagon and hexagon, same order. */
|
|
6
|
+
pentagonCentres: V3[];
|
|
7
|
+
hexagonCentres: V3[];
|
|
8
|
+
/** Every edge between two panels once, as a curve on the sphere. */
|
|
9
|
+
edges: V3[][];
|
|
10
|
+
/** For each hexagon, the midpoints of the three edges it shares with a pentagon (alternate edges). */
|
|
11
|
+
hexagonPentagonSides: V3[][];
|
|
12
|
+
}
|
|
13
|
+
export declare function truncatedIcosahedron(samples?: number): Truncated;
|
|
14
|
+
/** A ring pulled toward its centre by a fraction, on the sphere: the face inside the seam. */
|
|
15
|
+
export declare function shrink(ring: readonly V3[], centre: V3, by: number): V3[];
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// The truncated icosahedron: the 32 panels of a classic soccer ball (12 pentagons and 20 hexagons), as rings of unit vectors. Each vertex is on an edge of an icosahedron, a third of the way
|
|
2
|
+
// along it; the edges between vertices follow the sphere (spherical interpolation), so the panels bulge as an inflated ball's do.
|
|
3
|
+
import { add, arc, cross, dot, mul, norm, slerp, sub } from "./ball.math.js";
|
|
4
|
+
const PHI = (1 + Math.sqrt(5)) / 2;
|
|
5
|
+
let cached;
|
|
6
|
+
export function truncatedIcosahedron(samples = 4) {
|
|
7
|
+
if (cached !== undefined && samples === 4)
|
|
8
|
+
return cached;
|
|
9
|
+
const verts = [];
|
|
10
|
+
for (const a of [-1, 1])
|
|
11
|
+
for (const b of [-PHI, PHI])
|
|
12
|
+
verts.push(norm([0, a, b]), norm([a, b, 0]), norm([b, 0, a]));
|
|
13
|
+
const near = (a, b) => Math.abs(dot(a, b) - 1 / Math.sqrt(5)) < 1e-6;
|
|
14
|
+
const third = (a, b) => slerp(verts[a], verts[b], 1 / 3);
|
|
15
|
+
const pentagons = [];
|
|
16
|
+
const pentagonCentres = [];
|
|
17
|
+
verts.forEach((c, i) => {
|
|
18
|
+
const nb = verts.map((_, j) => j).filter((j) => j !== i && near(c, verts[j]));
|
|
19
|
+
const ex = norm(sub(verts[nb[0]], mul(c, dot(verts[nb[0]], c))));
|
|
20
|
+
const ey = cross(c, ex);
|
|
21
|
+
nb.sort((p, q) => Math.atan2(dot(verts[p], ey), dot(verts[p], ex)) - Math.atan2(dot(verts[q], ey), dot(verts[q], ex)));
|
|
22
|
+
pentagons.push(nb.map((j) => third(i, j)));
|
|
23
|
+
pentagonCentres.push(c);
|
|
24
|
+
});
|
|
25
|
+
const hexagons = [];
|
|
26
|
+
const hexagonCentres = [];
|
|
27
|
+
const hexagonPentagonSides = [];
|
|
28
|
+
for (let i = 0; i < 12; i++) {
|
|
29
|
+
for (let j = i + 1; j < 12; j++) {
|
|
30
|
+
if (!near(verts[i], verts[j]))
|
|
31
|
+
continue;
|
|
32
|
+
for (let k = j + 1; k < 12; k++) {
|
|
33
|
+
if (!near(verts[i], verts[k]) || !near(verts[j], verts[k]))
|
|
34
|
+
continue;
|
|
35
|
+
hexagons.push([third(i, j), third(j, i), third(j, k), third(k, j), third(k, i), third(i, k)]);
|
|
36
|
+
hexagonCentres.push(norm(add(add(verts[i], verts[j]), verts[k])));
|
|
37
|
+
// The edges P(i,k)-P(i,j), P(j,i)-P(j,k) and P(k,j)-P(k,i) touch a pentagon (the one at i, j and k).
|
|
38
|
+
const mid = (a, b) => norm(add(a, b));
|
|
39
|
+
hexagonPentagonSides.push([mid(third(i, k), third(i, j)), mid(third(j, i), third(j, k)), mid(third(k, j), third(k, i))]);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const seen = new Set();
|
|
44
|
+
const edges = [];
|
|
45
|
+
for (const ring of [...pentagons, ...hexagons]) {
|
|
46
|
+
for (let i = 0; i < ring.length; i++) {
|
|
47
|
+
const a = ring[i], b = ring[(i + 1) % ring.length];
|
|
48
|
+
const key = [a, b].map((v) => v.map((x) => Math.round(x * 1000)).join(",")).sort().join("|");
|
|
49
|
+
if (seen.has(key))
|
|
50
|
+
continue;
|
|
51
|
+
seen.add(key);
|
|
52
|
+
edges.push(arc(a, b, samples));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const result = { pentagons, hexagons, pentagonCentres, hexagonCentres, edges, hexagonPentagonSides };
|
|
56
|
+
if (samples === 4)
|
|
57
|
+
cached = result;
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
/** A ring pulled toward its centre by a fraction, on the sphere: the face inside the seam. */
|
|
61
|
+
export function shrink(ring, centre, by) {
|
|
62
|
+
return ring.map((p) => norm(add(mul(p, 1 - by), mul(centre, by))));
|
|
63
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Ice hockey puck: vulcanised black rubber, 76.2 mm across and 25.4 mm thick (so 1 : 3), with a ridged edge. Drawn as a cylinder in true 3D, so it turns.
|
|
2
|
+
import { drawStack } from "./ball.stack.js";
|
|
3
|
+
import { defineObject } from "./ball.object.js";
|
|
4
|
+
const H = 25.4 / 76.2 / 2;
|
|
5
|
+
export const BALL_PUCK = /* @__PURE__ */ defineObject({
|
|
6
|
+
id: "ball:puck",
|
|
7
|
+
en: "Hockey puck",
|
|
8
|
+
ja: "アイスホッケーのパック",
|
|
9
|
+
size: { extentMm: 76, diameterMm: 76, thicknessMm: 25, massG: [156, 170], rule: "IIHF Official Rule Book, Rule 13 Puck, 13.1 Dimensions (the puck is Rule 13, not Rule 1)", note: "IIHF figures, rounded as the rule rounds them (the NHL puck is 3 in by 1 in). Colour is not stated in the rule." },
|
|
10
|
+
view: { yaw: 0, pitch: 36, roll: -8 },
|
|
11
|
+
model: { slices: 1 },
|
|
12
|
+
draw: (c) => drawStack(c, {
|
|
13
|
+
slices: [{ y0: -H, y1: H, r: 1, colour: "#26282d", outline: true }],
|
|
14
|
+
top: "#2e3036",
|
|
15
|
+
bottom: "#2e3036",
|
|
16
|
+
gloss: 0.5,
|
|
17
|
+
shade: "#000",
|
|
18
|
+
grain: { f: 1.6, a: 0.25 },
|
|
19
|
+
grooves: { count: 30, slices: [0], colour: "#000", opacity: 0.5 },
|
|
20
|
+
topRing: { r: 0.9, colour: "#4a4d56" },
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BALL_ROUNDNET: import("./ball.core.ts").Piece<import("./ball.engine.ts").BallSpec>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Roundnet ball: a small bright ball of eight panels, yellow and orange (our colouring).
|
|
2
|
+
import { defineBall } from "./ball.engine.js";
|
|
3
|
+
import { octants8 } from "./ball.family.panelled.js";
|
|
4
|
+
export const BALL_ROUNDNET = /* @__PURE__ */ defineBall({
|
|
5
|
+
id: "ball:roundnet",
|
|
6
|
+
en: "Roundnet ball",
|
|
7
|
+
ja: "ラウンドネットボール",
|
|
8
|
+
size: { extentMm: 105, diameterMm: 105, circumferenceMm: 330, massG: [80, 90], rule: "International Roundnet Federation (IRF) Rules, Chapter 1 Equipment and Court, 1.1.2 Set Dimensions, 1.1.4 Ball Characteristics, 1.1.5 Ball Inflation", note: "International Roundnet Federation rules (330 mm round, 10 mm either way); the rules give no diameter." },
|
|
9
|
+
spec: {
|
|
10
|
+
view: { yaw: 35, pitch: 28, roll: 0 },
|
|
11
|
+
base: "#f5dc16",
|
|
12
|
+
mat: { gloss: 0.6, shade: "#4a3a04", grain: { f: 1.4, a: 0.14 } },
|
|
13
|
+
draw: (s, base) => octants8(s, (sx, sy, sz) => (sx * sy * sz > 0 ? base : "#f08a1c"), "#7a5a10", 1.2),
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BALL_RUGBY: import("./ball.core.ts").Piece<import("./ball.engine.ts").BallSpec>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Rugby ball: a classic white ball, pointed at the ends, with four panels, a pebbled grip all over, and two bands of colour round it on each side: a wide one and a thin one. The colour is the ball's
|
|
2
|
+
// `tint` (a navy blue by default; the Laws do not set a colour and the ball carries no brand).
|
|
3
|
+
import { defineBall } from "./ball.engine.js";
|
|
4
|
+
import { seamAt, tipRing } from "./ball.family.prolate.js";
|
|
5
|
+
import { mix } from "./ball.core.js";
|
|
6
|
+
import { spread } from "./ball.math.js";
|
|
7
|
+
const GRIP = spread(260, 0.4);
|
|
8
|
+
const QUARTER = Math.PI / 2;
|
|
9
|
+
const WHITE = "#f4f2ec";
|
|
10
|
+
export const BALL_RUGBY = /* @__PURE__ */ defineBall({
|
|
11
|
+
id: "ball:rugby",
|
|
12
|
+
en: "Rugby ball",
|
|
13
|
+
ja: "ラグビーボール",
|
|
14
|
+
size: { extentMm: 290.0, lengthMm: 290.0, circumferenceMm: 600.0, longCircumferenceMm: 755.0, massG: [410, 460], rule: "World Rugby Laws of the Game (Rugby Union), Law 2 The ball, clauses 1-7" },
|
|
15
|
+
spec: {
|
|
16
|
+
axes: [1, 0.62, 0.62],
|
|
17
|
+
point: 0.72,
|
|
18
|
+
view: { yaw: -30, pitch: 20, roll: -30 },
|
|
19
|
+
base: "#1f4e9c",
|
|
20
|
+
ground: WHITE,
|
|
21
|
+
mat: { gloss: 0.4, shade: "#1a2030", grain: { f: 0.9, a: 0.18 } },
|
|
22
|
+
draw: (s, base) => {
|
|
23
|
+
let out = "";
|
|
24
|
+
// The grip: pebbles over the whole ball, a little darker than the white, each with its own highlight.
|
|
25
|
+
out += s.dots(GRIP, 0.03, mix(WHITE, -0.16), { opacity: 0.8, ink: false, light: false });
|
|
26
|
+
// The seams, tip to tip, then the bands over them.
|
|
27
|
+
out += s.strokes([0, 1, 2, 3].map((k) => seamAt(k * QUARTER + QUARTER / 2)), mix(WHITE, -0.3), 1.1);
|
|
28
|
+
for (const sign of [1, -1]) {
|
|
29
|
+
out += s.stroke(tipRing(sign, 1.02, 96), base, 9, { closed: true, ink: false });
|
|
30
|
+
out += s.stroke(tipRing(sign, 1.3, 96), base, 3, { closed: true, ink: false });
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BALL_SEPAK_TAKRAW: import("./ball.core.ts").Piece<import("./ball.engine.ts").BallSpec>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Sepak takraw ball: woven rattan. Six bands, each of three strands, run round the ball as the six great circles that pass through the corners of an icosahedron, which leaves twelve
|
|
2
|
+
// pentagonal holes and twenty triangular ones (the ISTAF law gives 12 holes and 20 intersections). Where two bands cross one goes over: the weave is worked out, not drawn by hand.
|
|
3
|
+
import { defineBall } from "./ball.engine.js";
|
|
4
|
+
import { cross, dot, norm, smallCircle } from "./ball.math.js";
|
|
5
|
+
import { mix } from "./ball.core.js";
|
|
6
|
+
const PHI = (1 + Math.sqrt(5)) / 2;
|
|
7
|
+
const CORNERS = [[0, 1, PHI], [0, 1, -PHI], [1, PHI, 0], [1, -PHI, 0], [PHI, 0, 1], [-PHI, 0, 1]];
|
|
8
|
+
const AXES = CORNERS.map((v) => norm(v));
|
|
9
|
+
const SAMPLES = 48;
|
|
10
|
+
/** Half the width of a band, and the gap between its strands, in radians. */
|
|
11
|
+
const GAP = 0.034;
|
|
12
|
+
const ring = (a, d = 0) => smallCircle(a, Math.PI / 2 + d, SAMPLES);
|
|
13
|
+
const piece = (a, centre, d = 0, half = 0.2) => smallCircle(a, Math.PI / 2 + d, 24).filter((p) => dot(p, centre) > Math.cos(half));
|
|
14
|
+
/** The two points where band `i` crosses band `j`. */
|
|
15
|
+
const crossings = (i, j) => {
|
|
16
|
+
const c = norm(cross(AXES[i], AXES[j]));
|
|
17
|
+
return [c, [-c[0], -c[1], -c[2]]];
|
|
18
|
+
};
|
|
19
|
+
export const BALL_SEPAK_TAKRAW = /* @__PURE__ */ defineBall({
|
|
20
|
+
id: "ball:sepak-takraw",
|
|
21
|
+
en: "Sepak takraw ball",
|
|
22
|
+
ja: "セパタクローボール",
|
|
23
|
+
size: { extentMm: 133.7, diameterMm: 133.7, circumferenceMm: 420, massG: [170, 180], rule: "ISTAF Law of the Game (Rules of the Game), Law 4 The Ball (Sepaktakraw Ball), 4.1-4.5", note: "Men's ball (410 to 430 mm round); diameter worked out from the middle of the range. The 2013 edition of the law, the newest found." },
|
|
24
|
+
spec: {
|
|
25
|
+
view: { yaw: 14, pitch: 20, roll: 0 },
|
|
26
|
+
base: "#d3a24f",
|
|
27
|
+
ground: "#2c1a0a",
|
|
28
|
+
mat: { gloss: 0.35, shade: "#2a1604", rim: 0.9, grain: { f: 1.8, a: 0.4 } },
|
|
29
|
+
draw: (s, base) => {
|
|
30
|
+
const edge = mix(base, -0.5);
|
|
31
|
+
const band = (curves, closed) => s.strokes(curves, edge, 6.2, { closed }) + s.strokes(curves, base, 5.0, { closed, ink: false }) + s.strokes(curves.flatMap((c) => [c]), mix(base, 0.3), 0.5, { closed, deco: true, opacity: 0.5 });
|
|
32
|
+
const strand = (curves, closed) => s.strokes(curves, edge, 0.55, { closed, ink: false, opacity: 0.8 });
|
|
33
|
+
// Every band, then the strands' dividing lines.
|
|
34
|
+
let out = band(AXES.map((a) => ring(a)), true);
|
|
35
|
+
out += strand(AXES.flatMap((a) => [ring(a, GAP), ring(a, -GAP)]), true);
|
|
36
|
+
// The weave: at each crossing, the band chosen by parity is drawn again over the other.
|
|
37
|
+
const over = [];
|
|
38
|
+
for (let i = 0; i < AXES.length; i++) {
|
|
39
|
+
for (let j = i + 1; j < AXES.length; j++) {
|
|
40
|
+
crossings(i, j).forEach((c, k) => over.push([AXES[(i + j + k) % 2 === 0 ? i : j], c]));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
out += band(over.map(([a, c]) => piece(a, c)), false);
|
|
44
|
+
out += strand(over.flatMap(([a, c]) => [piece(a, c, GAP), piece(a, c, -GAP)]), false);
|
|
45
|
+
return out;
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// Shuttlecocks: a cork base and a skirt of 16 feathers (a goose's, overlapped), or a molded nylon skirt. Drawn from its parts in true 3D: the feathers are blades that lean out from the base, painted
|
|
2
|
+
// far to near, so the shuttlecock turns like any ball. 16 feathers, 62 to 70 mm long, the skirt 58 to 68 mm across (the BWF Laws, Law 2).
|
|
3
|
+
import { defineObject } from "./ball.object.js";
|
|
4
|
+
import {} from "./ball.math.js";
|
|
5
|
+
import { blend, mix, num } from "./ball.core.js";
|
|
6
|
+
const FEATHERS = 16;
|
|
7
|
+
// One unit is 32 mm: the skirt is 2 units across at the top, the base 0.84 across and the whole 2.06 long.
|
|
8
|
+
const ROOT_R = 0.42;
|
|
9
|
+
const TIP_R = 1;
|
|
10
|
+
const ROOT_Y = -0.56;
|
|
11
|
+
const TIP_Y = 1.0;
|
|
12
|
+
const SLOPE = 0.4;
|
|
13
|
+
const drawShuttle = (c, p) => {
|
|
14
|
+
const line = c.opts.style === "line";
|
|
15
|
+
const tip = (a, r, y, k = 0) => [Math.cos(a) * r, y, Math.sin(a) * r + k];
|
|
16
|
+
const pts = (...v) => v.map((q) => c.at(q)).map((q) => `${num(q[0])} ${num(q[1])}`).join("L");
|
|
17
|
+
const blades = [];
|
|
18
|
+
const step = (2 * Math.PI) / FEATHERS;
|
|
19
|
+
const rootHalf = p.nylon ? step / 2 : step * 0.36;
|
|
20
|
+
const tipHalf = p.nylon ? step / 2 : step * 0.62;
|
|
21
|
+
for (let i = 0; i < FEATHERS; i++) {
|
|
22
|
+
const a = i * step;
|
|
23
|
+
const corners = [tip(a - rootHalf, ROOT_R, ROOT_Y), tip(a - tipHalf, TIP_R, TIP_Y), tip(a + tipHalf, TIP_R, TIP_Y), tip(a + rootHalf, ROOT_R, ROOT_Y)];
|
|
24
|
+
const mid = tip(a, (ROOT_R + TIP_R) / 2, (ROOT_Y + TIP_Y) / 2);
|
|
25
|
+
const m = c.at(mid);
|
|
26
|
+
// How squarely the blade faces the light (from the upper left): a blade whose outward normal points left and toward you is bright.
|
|
27
|
+
const nrm = [Math.cos(a), SLOPE * -0.5, Math.sin(a)];
|
|
28
|
+
const nv = c.at([nrm[0], nrm[1], nrm[2]]);
|
|
29
|
+
const origin = c.at([0, 0, 0]);
|
|
30
|
+
const lx = (nv[0] - origin[0]) / 46, ly = (nv[1] - origin[1]) / 46, lz = nv[2] - 0;
|
|
31
|
+
const lit = Math.max(0, Math.min(1, 0.55 + 0.4 * (-0.5 * lx + 0.55 * ly + 0.3 * lz)));
|
|
32
|
+
const fill = blend(mix(p.feather, -0.28), mix(p.feather, 0.1), lit);
|
|
33
|
+
const quill = `M${pts(tip(a, ROOT_R, ROOT_Y), tip(a, TIP_R, TIP_Y))}`;
|
|
34
|
+
const outline = `M${pts(...corners)}Z`;
|
|
35
|
+
const svg = line
|
|
36
|
+
? `<path d="${outline}${p.nylon ? "" : quill}"/>`
|
|
37
|
+
: `<path d="${outline}" fill="${fill}"${p.nylon ? ` fill-opacity=".9"` : ""} stroke="${mix(p.feather, -0.55)}" stroke-width="${num(Math.max(0.7, c.minWidth * 0.6), 2)}" stroke-linejoin="round"/>` +
|
|
38
|
+
(p.nylon ? "" : `<path d="${quill}" fill="none" stroke="${p.shaft}" stroke-width="${num(Math.max(0.45, c.minWidth * 0.5), 2)}" stroke-linecap="round" opacity=".8"/>`);
|
|
39
|
+
blades.push({ depth: m[2], svg });
|
|
40
|
+
}
|
|
41
|
+
blades.sort((x, y) => x.depth - y.depth);
|
|
42
|
+
const ring = (y, r) => {
|
|
43
|
+
const q = [];
|
|
44
|
+
for (let i = 0; i <= 36; i++)
|
|
45
|
+
q.push(`${i === 0 ? "M" : "L"}${pts(tip((i / 36) * 2 * Math.PI, r, y))}`);
|
|
46
|
+
return q.join("");
|
|
47
|
+
};
|
|
48
|
+
// Where the base is: below the skirt, so it is behind it when the tip leans toward you, in front of it when the cork leans toward you.
|
|
49
|
+
const base = c.at([0, ROOT_Y, 0]);
|
|
50
|
+
const top = c.at([0, TIP_Y, 0]);
|
|
51
|
+
const corkFirst = base[2] <= top[2];
|
|
52
|
+
const cx = c.at([0, ROOT_Y - 0.4, 0]);
|
|
53
|
+
const corkR = 46 * 0.43 * ROOT_R;
|
|
54
|
+
const defs = line
|
|
55
|
+
? ""
|
|
56
|
+
: `<radialGradient id="${c.id}k" cx=".36" cy=".3" r=".8"><stop offset="0" stop-color="${blend(p.cork, "#fff", 0.35)}"/><stop offset=".5" stop-color="${p.cork}"/><stop offset="1" stop-color="${mix(p.cork, -0.55)}"/></radialGradient>`;
|
|
57
|
+
const cork = line
|
|
58
|
+
? `<circle cx="${num(cx[0])}" cy="${num(cx[1])}" r="${num(corkR)}"/>`
|
|
59
|
+
: `<circle cx="${num(cx[0])}" cy="${num(cx[1])}" r="${num(corkR)}" fill="url(#${c.id}k)"/><path d="${ring(ROOT_Y + 0.02, ROOT_R)}" fill="none" stroke="${p.band}" stroke-width="${num(Math.max(1.4, c.minWidth), 2)}" opacity=".9"/>`;
|
|
60
|
+
const thread = `<path d="${ring(0.55, 0.72)}" fill="none" stroke="${line ? "currentColor" : p.thread}" stroke-width="${num(Math.max(0.5, c.minWidth * 0.7), 2)}"${line ? ' opacity=".7"' : ""}/>`;
|
|
61
|
+
const rim = `<path d="${ring(TIP_Y, TIP_R)}" fill="none" stroke="${line ? "currentColor" : mix(p.feather, -0.3)}" stroke-width="${num(Math.max(0.5, c.minWidth * 0.6), 2)}"${line ? ' opacity=".6"' : ' opacity=".5"'}/>`;
|
|
62
|
+
const feathers = blades.map((b) => b.svg).join("");
|
|
63
|
+
let body = corkFirst ? cork + feathers : feathers + cork;
|
|
64
|
+
body += thread;
|
|
65
|
+
if (line)
|
|
66
|
+
body = `<g fill="none" stroke="currentColor" stroke-width="${num(Math.max(2.4, c.minWidth * 1.4), 2)}" stroke-linejoin="round" stroke-linecap="round">${body}${rim}</g>`;
|
|
67
|
+
else
|
|
68
|
+
body += rim;
|
|
69
|
+
return { defs, body };
|
|
70
|
+
};
|
|
71
|
+
const VIEW = { yaw: 0, pitch: 22, roll: -32 };
|
|
72
|
+
export const BALL_SHUTTLECOCK_FEATHER = /* @__PURE__ */ defineObject({
|
|
73
|
+
id: "ball:shuttlecock-feather",
|
|
74
|
+
en: "Shuttlecock, feather",
|
|
75
|
+
ja: "水鳥シャトル",
|
|
76
|
+
size: { extentMm: 150, diameterMm: 63, lengthMm: 66, massG: [4.74, 5.5], rule: "BWF Laws of Badminton, Law 2 Shuttle (2.1 general, 2.2 Feathered shuttle 2.2.1-2.2.6, 2.3 Non-feathered shuttle, 2.4 modifications) and Laws 3 Testing a shuttle for speed", note: "62 to 70 mm long with the tips on a circle 58 to 68 mm across, on a base 25 to 28 mm across; the box is drawn at the scale of the shuttlecock, which fills a part of it." },
|
|
77
|
+
view: VIEW,
|
|
78
|
+
scale: 0.43,
|
|
79
|
+
shift: [0, 0.02, 0],
|
|
80
|
+
model: { feathers: FEATHERS },
|
|
81
|
+
draw: (c) => drawShuttle(c, { feather: "#fbfaf4", shaft: "#b5ac94", cork: "#c8925a", band: "#f6f2e8", thread: "#8a826a", nylon: false }),
|
|
82
|
+
});
|
|
83
|
+
export const BALL_SHUTTLECOCK_NYLON = /* @__PURE__ */ defineObject({
|
|
84
|
+
id: "ball:shuttlecock-nylon",
|
|
85
|
+
en: "Shuttlecock, nylon",
|
|
86
|
+
ja: "ナイロンシャトル",
|
|
87
|
+
size: { extentMm: 150, diameterMm: 63, lengthMm: 66, massG: [4.74, 5.5], rule: "BWF Laws of Badminton, Law 2 Shuttle (2.1 general, 2.2 Feathered shuttle 2.2.1-2.2.6, 2.3 Non-feathered shuttle, 2.4 modifications) and Laws 3 Testing a shuttle for speed", note: "A non-feathered shuttle follows the same measures, with a tolerance of 10 per cent (Law 2.3); the box is drawn at the scale of the shuttlecock, which fills a part of it." },
|
|
88
|
+
view: VIEW,
|
|
89
|
+
scale: 0.43,
|
|
90
|
+
shift: [0, 0.02, 0],
|
|
91
|
+
model: { feathers: FEATHERS },
|
|
92
|
+
draw: (c) => drawShuttle(c, { feather: "#f2f4f6", shaft: "#aab0b8", cork: "#f0eadd", band: "#e04a3c", thread: "#7a8088", nylon: true }),
|
|
93
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BALL_SLIOTAR: import("./ball.core.ts").Piece<import("./ball.engine.ts").BallSpec>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Sliotar: a cork-cored leather ball for hurling, with a raised rib along its seam.
|
|
2
|
+
import { seamedBall } from "./ball.family.seamed.js";
|
|
3
|
+
export const BALL_SLIOTAR = /* @__PURE__ */ seamedBall({
|
|
4
|
+
id: "ball:sliotar",
|
|
5
|
+
en: "Sliotar",
|
|
6
|
+
ja: "シリター",
|
|
7
|
+
size: { extentMm: 70.5, diameterMm: 70.5, massG: [110, 116], rule: "GAA Official Guide Part 2, Rules of Specification, Rule 4.4(i)", note: "The rule gives a diameter that leaves out the raised rib." },
|
|
8
|
+
base: "#efe8d4",
|
|
9
|
+
b: 0.36,
|
|
10
|
+
view: { yaw: 22, pitch: 34, roll: 8 },
|
|
11
|
+
mat: { gloss: 0.4, shade: "#4a3a20", grain: { f: 1.3, a: 0.2 } },
|
|
12
|
+
strip: { colour: "#ded4b6", width: 2.4, raised: true },
|
|
13
|
+
stitch: { colour: "#8a7a58", count: 90, half: 0.05, width: 0.6, lean: 0.0 },
|
|
14
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const BALL_LACROSSE: import("./ball.core.ts").Piece<import("./ball.engine.ts").BallSpec>;
|
|
2
|
+
export declare const BALL_RACQUETBALL: import("./ball.core.ts").Piece<import("./ball.engine.ts").BallSpec>;
|
|
3
|
+
export declare const BALL_TABLE_TENNIS: import("./ball.core.ts").Piece<import("./ball.engine.ts").BallSpec>;
|
|
4
|
+
export declare const BALL_SHOT: import("./ball.core.ts").Piece<import("./ball.engine.ts").BallSpec>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Plain round balls: the lacrosse ball, the racquetball, the table-tennis ball and the shot. A faint seam where a real one has it.
|
|
2
|
+
import { defineBall } from "./ball.engine.js";
|
|
3
|
+
import { greatCircle } from "./ball.math.js";
|
|
4
|
+
export const BALL_LACROSSE = /* @__PURE__ */ defineBall({
|
|
5
|
+
id: "ball:lacrosse",
|
|
6
|
+
en: "Lacrosse ball",
|
|
7
|
+
ja: "ラクロスボール",
|
|
8
|
+
size: { extentMm: 63.7, diameterMm: 63.7, circumferenceMm: 200.05, massG: [141.75, 148.83], rule: "World Lacrosse Rules of Men's Field Lacrosse 2025-2027 (Ver 1.0), Section 2 Equipment, Rule 14 The Ball, 14.1", note: "Diameter worked out from the middle of the circumference range." },
|
|
9
|
+
spec: {
|
|
10
|
+
view: { yaw: 0, pitch: 0, roll: 0 },
|
|
11
|
+
base: "#f2791c",
|
|
12
|
+
mat: { gloss: 0.5, shade: "#5a2208", grain: { f: 1.5, a: 0.14 } },
|
|
13
|
+
draw: () => "",
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
export const BALL_RACQUETBALL = /* @__PURE__ */ defineBall({
|
|
17
|
+
id: "ball:racquetball",
|
|
18
|
+
en: "Racquetball",
|
|
19
|
+
ja: "ラケットボール",
|
|
20
|
+
size: { extentMm: 57.1, diameterMm: 57.1, massG: [39.7, 39.7], rule: "USA Racquetball Rules, Rule 2.2 Ball Specifications (a)-(b); Rule 2.3 Ball Selection", note: "Nominal values; the rule gives no tolerance." },
|
|
21
|
+
spec: {
|
|
22
|
+
view: { yaw: 25, pitch: 30, roll: 0 },
|
|
23
|
+
base: "#2f63d2",
|
|
24
|
+
mat: { gloss: 0.55, shade: "#06143a", grain: { f: 1.5, a: 0.1 } },
|
|
25
|
+
draw: (s) => s.stroke(greatCircle([0.35, 0.9, 0.25], 72), "#10265e", 0.9, { closed: true, opacity: 0.5, deco: false }),
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
export const BALL_TABLE_TENNIS = /* @__PURE__ */ defineBall({
|
|
29
|
+
id: "ball:table-tennis",
|
|
30
|
+
en: "Table-tennis ball",
|
|
31
|
+
ja: "卓球ボール",
|
|
32
|
+
size: { extentMm: 40.0, diameterMm: 40.0, massG: [2.7, 2.7], rule: "Laws of Table Tennis, 2.3 The Ball, 2.3.1-2.3.3" },
|
|
33
|
+
spec: {
|
|
34
|
+
view: { yaw: 25, pitch: 30, roll: 0 },
|
|
35
|
+
base: "#f6f5f0",
|
|
36
|
+
mat: { gloss: 0.32, shade: "#2e3550", grain: { f: 2, a: 0.05 } },
|
|
37
|
+
draw: (s) => s.stroke(greatCircle([0.3, 0.8, 0.5], 72), "#9aa0ac", 0.45, { closed: true, opacity: 0.8 }),
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
export const BALL_SHOT = /* @__PURE__ */ defineBall({
|
|
41
|
+
id: "ball:shot",
|
|
42
|
+
en: "Shot",
|
|
43
|
+
ja: "砲丸",
|
|
44
|
+
size: { extentMm: 120, diameterMm: 120, massG: [7260, 7260], rule: "World Athletics Technical Rules (C2.1), Rule 33 Shot Put - implement specification ('Shot'); smooth finish N7 (Ra <= 1.6 micrometres)", note: "Men's shot, 110 to 130 mm across; 7.260 kg is a minimum." },
|
|
45
|
+
spec: {
|
|
46
|
+
view: { yaw: 0, pitch: 0, roll: 0 },
|
|
47
|
+
base: "#8c949e",
|
|
48
|
+
mat: { gloss: 0.95, shade: "#0c1018", metal: true, rim: 1 },
|
|
49
|
+
draw: () => "",
|
|
50
|
+
},
|
|
51
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// The classic soccer ball: 32 panels, twelve black pentagons and twenty white hexagons, laid on a truncated icosahedron; and a coloured one with a motif of our own (a triangle on each hexagon
|
|
2
|
+
// pointing at its three pentagons). No brand, no tournament's pattern.
|
|
3
|
+
import { defineBall } from "./ball.engine.js";
|
|
4
|
+
import { truncatedIcosahedron } from "./ball.polyhedra.js";
|
|
5
|
+
import { add, mul, norm } from "./ball.math.js";
|
|
6
|
+
import { blend, mix } from "./ball.core.js";
|
|
7
|
+
const SEAM = "#6b7180";
|
|
8
|
+
export const BALL_SOCCER = /* @__PURE__ */ defineBall({
|
|
9
|
+
id: "ball:soccer",
|
|
10
|
+
en: "Soccer ball",
|
|
11
|
+
ja: "サッカーボール",
|
|
12
|
+
size: { extentMm: 219.6, diameterMm: 219.6, circumferenceMm: 690.0, massG: [410, 450], rule: "IFAB Laws of the Game, Law 2 The Ball, section 2.1 Qualities and measurements", note: "Diameter worked out from the middle of the circumference range." },
|
|
13
|
+
spec: {
|
|
14
|
+
view: { yaw: 30, pitch: 24, roll: 8 },
|
|
15
|
+
base: "#1e2025",
|
|
16
|
+
ground: "#f8f8f6",
|
|
17
|
+
mat: { gloss: 0.8, shade: "#2a3450", grain: { f: 1.1, a: 0.16 } },
|
|
18
|
+
draw(s, base) {
|
|
19
|
+
const t = truncatedIcosahedron();
|
|
20
|
+
let out = "";
|
|
21
|
+
for (const p of t.pentagons)
|
|
22
|
+
out += s.panel(p, base, { ink: true });
|
|
23
|
+
out += s.strokes(t.edges, SEAM, 1.15);
|
|
24
|
+
out += s.strokes(t.edges, "#fff", 0.45, { deco: true, opacity: 0.5, dx: 0.3, dy: 0.35 });
|
|
25
|
+
return out;
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
export const BALL_SOCCER_COLOUR = /* @__PURE__ */ defineBall({
|
|
30
|
+
id: "ball:soccer-colour",
|
|
31
|
+
en: "Soccer ball, coloured",
|
|
32
|
+
ja: "サッカーボール(カラー)",
|
|
33
|
+
size: { extentMm: 219.6, diameterMm: 219.6, circumferenceMm: 690.0, massG: [410, 450], rule: "IFAB Laws of the Game, Law 2 The Ball, section 2.1 Qualities and measurements", note: "Diameter worked out from the middle of the circumference range." },
|
|
34
|
+
spec: {
|
|
35
|
+
view: { yaw: 30, pitch: 24, roll: 8 },
|
|
36
|
+
base: "#d4283c",
|
|
37
|
+
ground: "#f8f8f6",
|
|
38
|
+
mat: { gloss: 0.8, shade: "#3a2030", grain: { f: 1.1, a: 0.16 } },
|
|
39
|
+
draw(s, base) {
|
|
40
|
+
const t = truncatedIcosahedron();
|
|
41
|
+
const light = blend(base, "#ffffff", 0.45);
|
|
42
|
+
let out = "";
|
|
43
|
+
t.hexagons.forEach((_, i) => {
|
|
44
|
+
const c = t.hexagonCentres[i];
|
|
45
|
+
out += s.panel(t.hexagonPentagonSides[i].map((m) => norm(add(mul(c, 0.38), mul(m, 0.62)))), light, { n: 2 });
|
|
46
|
+
});
|
|
47
|
+
for (const p of t.pentagons)
|
|
48
|
+
out += s.panel(p, base, { ink: true });
|
|
49
|
+
out += s.strokes(t.edges, mix(base, -0.35), 1.1);
|
|
50
|
+
out += s.strokes(t.edges, "#fff", 0.45, { deco: true, opacity: 0.45, dx: 0.3, dy: 0.35 });
|
|
51
|
+
return out;
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BALL_SOFTBALL: import("./ball.core.ts").Piece<import("./ball.engine.ts").BallSpec>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Softball: an optic-yellow ball with red stitches along the seam (88 here, which the rule leaves free).
|
|
2
|
+
import { seamedBall } from "./ball.family.seamed.js";
|
|
3
|
+
export const BALL_SOFTBALL = /* @__PURE__ */ seamedBall({
|
|
4
|
+
id: "ball:softball",
|
|
5
|
+
en: "Softball",
|
|
6
|
+
ja: "ソフトボール",
|
|
7
|
+
size: { extentMm: 97.1, diameterMm: 97.1, circumferenceMm: 305.0, massG: [178.0, 198.4], rule: "WBSC Official Rules of Softball Slow Pitch 2026-2029, Appendix 3 (Ball Specifications), B. Dimensions and Specifications and 'Ball standards' table; Fast Pitch 2026-2029 Appendix 3 gives the same 12 in ball", note: "The 12 in ball (the 11 in ball is 279.5 mm round). Diameter worked out from the middle of the circumference range." },
|
|
8
|
+
base: "#d8e22a",
|
|
9
|
+
b: 0.4,
|
|
10
|
+
view: { yaw: 18, pitch: 28, roll: -10 },
|
|
11
|
+
mat: { gloss: 0.35, shade: "#4c5a10", grain: { f: 1.4, a: 0.12 } },
|
|
12
|
+
groove: "#8a9420",
|
|
13
|
+
stitch: { colour: "#d0262c", count: 88, half: 0.085, width: 0.95, lean: 0.04 },
|
|
14
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Piece } from "./ball.core.ts";
|
|
2
|
+
import type { BallSpec } from "./ball.engine.ts";
|
|
3
|
+
export declare const BALL_SQUASH_DOUBLE_YELLOW: Piece<BallSpec>;
|
|
4
|
+
export declare const BALL_SQUASH_YELLOW: Piece<BallSpec>;
|
|
5
|
+
export declare const BALL_SQUASH_RED: Piece<BallSpec>;
|
|
6
|
+
export declare const BALL_SQUASH_BLUE: Piece<BallSpec>;
|
|
7
|
+
export declare const BALL_SQUASH_GREEN: Piece<BallSpec>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Squash balls: small hollow black rubber balls with a coloured dot (or two) that says how lively the ball is: double yellow (the competition ball), yellow (club), green (high altitude), red
|
|
2
|
+
// (medium) and blue (fast). World Squash's specification recommends the dots; it does not require them.
|
|
3
|
+
import { defineBall } from "./ball.engine.js";
|
|
4
|
+
import { norm } from "./ball.math.js";
|
|
5
|
+
function squash(id, en, ja, colour, count, size) {
|
|
6
|
+
return defineBall({
|
|
7
|
+
id,
|
|
8
|
+
en,
|
|
9
|
+
ja,
|
|
10
|
+
size,
|
|
11
|
+
spec: {
|
|
12
|
+
view: { yaw: -18, pitch: 18, roll: 0 },
|
|
13
|
+
base: "#1f2023",
|
|
14
|
+
mat: { gloss: 0.5, shade: "#000000", grain: { f: 1.6, a: 0.12 } },
|
|
15
|
+
draw: (s) => {
|
|
16
|
+
const centres = count === 2 ? [norm([-0.28, 0.12, 1]), norm([0.34, 0.1, 1])] : [norm([0.04, 0.1, 1])];
|
|
17
|
+
return s.dots(centres, count === 2 ? 0.2 : 0.28, colour, { ink: true });
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
const SIZE = { extentMm: 40.0, diameterMm: 40.0, massG: [23.0, 25.0], rule: "World Squash 'Specifications for Squash Balls' (Recommended standards approved by the WSF; updated WSF AGM 2021, rebranded 2025), sections 1-3 and Notes 2-4", note: "Size and weight are set for the double yellow, yellow and green dot balls; the red and blue dot balls carry no limits in the specification." };
|
|
23
|
+
export const BALL_SQUASH_DOUBLE_YELLOW = /* @__PURE__ */ squash("ball:squash", "Squash ball, 2 yellow dots", "スカッシュ球(ダブルイエロー)", "#f4d41c", 2, SIZE);
|
|
24
|
+
export const BALL_SQUASH_YELLOW = /* @__PURE__ */ squash("ball:squash-yellow", "Squash ball, yellow dot", "スカッシュ球(黄色)", "#f4d41c", 1, SIZE);
|
|
25
|
+
export const BALL_SQUASH_RED = /* @__PURE__ */ squash("ball:squash-red", "Squash ball, red dot", "スカッシュ球(赤)", "#d9262c", 1, SIZE);
|
|
26
|
+
export const BALL_SQUASH_BLUE = /* @__PURE__ */ squash("ball:squash-blue", "Squash ball, blue dot", "スカッシュ球(青)", "#2b6fd6", 1, SIZE);
|
|
27
|
+
export const BALL_SQUASH_GREEN = /* @__PURE__ */ squash("ball:squash-green", "Squash ball, green dot", "スカッシュ球(緑)", "#2aa84a", 1, SIZE);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type ObjectContext } from "./ball.object.ts";
|
|
2
|
+
export interface Slice {
|
|
3
|
+
y0: number;
|
|
4
|
+
y1: number;
|
|
5
|
+
/** The radius at the lower end and at the upper end (one number for a plain cylinder). */
|
|
6
|
+
r: number | readonly [number, number];
|
|
7
|
+
colour: string;
|
|
8
|
+
/** Drawn in the line style (the others are left out so a line drawing keeps to the outline). */
|
|
9
|
+
outline?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface StackSpec {
|
|
12
|
+
slices: readonly Slice[];
|
|
13
|
+
top: string;
|
|
14
|
+
bottom: string;
|
|
15
|
+
gloss: number;
|
|
16
|
+
shade: string;
|
|
17
|
+
grain?: {
|
|
18
|
+
f: number;
|
|
19
|
+
a: number;
|
|
20
|
+
};
|
|
21
|
+
/** Lines down the side: how many round the whole slice, on the slices that have `grooved`. */
|
|
22
|
+
grooves?: {
|
|
23
|
+
count: number;
|
|
24
|
+
slices: readonly number[];
|
|
25
|
+
colour: string;
|
|
26
|
+
opacity: number;
|
|
27
|
+
};
|
|
28
|
+
/** A ring on the top face: radius as a fraction, colour. */
|
|
29
|
+
topRing?: {
|
|
30
|
+
r: number;
|
|
31
|
+
colour: string;
|
|
32
|
+
};
|
|
33
|
+
/** What lies in the bottom face when it faces you: a dish. */
|
|
34
|
+
dish?: {
|
|
35
|
+
r: number;
|
|
36
|
+
colour: string;
|
|
37
|
+
};
|
|
38
|
+
/** Drawn on top of the stack, in the stack's own space (a handle). `up` is the screen position of the top face's centre. */
|
|
39
|
+
extra?: (c: ObjectContext, top: {
|
|
40
|
+
cx: number;
|
|
41
|
+
cy: number;
|
|
42
|
+
nz: number;
|
|
43
|
+
}) => string;
|
|
44
|
+
}
|
|
45
|
+
export declare function drawStack(c: ObjectContext, spec: StackSpec): {
|
|
46
|
+
defs: string;
|
|
47
|
+
body: string;
|
|
48
|
+
};
|