@johnmorrisdotca/dougu-sports 0.13.0 → 0.15.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 +28 -0
- package/README.md +45 -23
- package/dist/emblems/ball/ball.engine.d.ts +6 -0
- package/dist/emblems/ball/ball.engine.js +4 -2
- package/dist/emblems/ball/ball.family.dotted.d.ts +3 -0
- package/dist/emblems/ball/ball.family.dotted.js +3 -0
- package/dist/emblems/ball/ball.holes.d.ts +18 -0
- package/dist/emblems/ball/ball.holes.js +88 -0
- package/dist/emblems/ball/ball.pickleball.js +3 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/turn-control.d.ts +13 -0
- package/dist/turn-control.js +15 -2
- package/dist/turn-entry.d.ts +2 -2
- package/dist/turn-entry.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,34 @@ All notable changes to this project are written here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.15.0] - 2026-10-21
|
|
10
|
+
|
|
11
|
+
The pickleballs get real holes: cut through the shell, with the inside of the ball behind them, and the page showing through where two holes line up.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **`ball:pickleball-outdoor` and `ball:pickleball-indoor` have real holes** (new module `src/emblems/ball/ball.holes.ts`, taken only by the pickleballs). Each hole on the near side is cut out of the shell by a mask, so its shading, highlight and grain are cut with it; behind it is the inside of the hollow ball (the far shell's inner surface, darker, lit low and to the right) with the far holes cut out of it, so where a near hole and a far hole line up the SVG is transparent and the page shows through, on any background. A hole is a cylinder along the line to the centre: near the edge it is a thin ellipse and the bore's wall shows as a crescent, toned by the light, and the cut edge carries a soft shadow and a thin lit rim (the thickness of the shell). It turns with `ballFrame`, `emblemFrame` and `bindTurn`; every turn has ids of its own. The line style still draws a mark for each hole, and the hole counts and sizes are unchanged (40 small, 26 large). A pickleball's drawing is about 8 kB where it was 3.7 kB (about 1.7 to 2 kB gzipped); its bundle is 8.0 kB gzipped (the other balls' are unchanged).
|
|
16
|
+
- Every other ball with round marks (a golf ball's and a field hockey ball's dimples, a squash ball's dots) is drawn exactly as before: `BallSpec` gained an optional `holes` function that only the pickleballs set, and `test/holes.test.ts` holds the drawings of 0.14.0 by hash.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **`docs/pickleball.md`**, with pictures of both balls at rest and turned, light and dark, and a turning picture (`pnpm animations`, scene `pickleball-turn`; `pnpm screenshots`, sheet `pickleball`). The README shows the still picture under "The best of it", and the balls sheet is redrawn with the new hole.
|
|
21
|
+
- **`e2e/holes.demo.ts`**: in a real browser, a pixel seen through a near hole and the far hole behind it is transparent and equals the page's own on four page colours; the shell round a hole is solid; a turned ball shows the dark inside; a turning pickleball has open holes at some angle and a golf ball never does.
|
|
22
|
+
|
|
23
|
+
## [0.14.0] - 2026-10-21
|
|
24
|
+
|
|
25
|
+
The auto-turn can go either way, and the pictures and the demo are slower and wait for the pointer.
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- **`direction` for the auto-turn**: `bindTurn(container, emblem, { direction: "clockwise" })` (seen from above; the default, `"counterclockwise"`, is how it has always turned, the front swinging to the viewer's right). `controller.setDirection(direction)` changes it while it turns without stopping it, `controller.direction()` reads it, and `turnDirection(value)` is the check the option goes through (exported from `./turn` and the main entry, with the `TurnDirection` type). `update` keeps the direction unless it names one. A drag, the keys and `setAngles` are not reversed. Tests: `test/turn-control.test.ts` and the demo's.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- **README: it opens on the still pictures again** (the balls, the vintage balls, the trophies, the famous trophies and the gear, with the turned and phone pictures), as before 0.12.1. The turning pictures sit lower, each beside its own point of "The best of it" (the famous trophies, the balls, the medals and crests), never stacked.
|
|
34
|
+
- **The turning pictures run at half the speed** (`pnpm animations` shows each frame 140 ms, it was 70; `DELAY=70` for the old pace).
|
|
35
|
+
- **Demo: the emblem waits still and turns while the mouse is over it.** Leaving stops it where it is; a tap on a phone turns it and a second tap holds it (a drag turns it by hand as before). Auto-turn keeps it going wherever the pointer is, and `?turn=1` starts it with the page. The speed buttons are Slow 9, Medium 18 (the default, half of the old 36) and Fast 45 degrees a second; addresses with `speed=18`, `36` or `90` still mean those speeds. A **Reverse** button (`逆回転`, "reverse rotation", with the label `逆向きに回す`, "Turn the other way") turns it the other way, kept in the address as `dir=cw`. The trophy case waits still too and turns an emblem while the pointer is over it or after a tap, at 22 degrees a second (it was 45). A reader who prefers reduced motion is never turned for by the pointer. The package's own default speed (36) is unchanged.
|
|
36
|
+
|
|
9
37
|
## [0.13.0] - 2026-10-20
|
|
10
38
|
|
|
11
39
|
Four combat sports get their pictograms, so a page that lists MMA, boxing, wrestling or professional wrestling no longer borrows the judo or karate suit.
|
package/README.md
CHANGED
|
@@ -15,29 +15,25 @@ The ball and the gear of every sport, trophies, medals, crests and the icon of e
|
|
|
15
15
|
|
|
16
16
|
<p align="center">
|
|
17
17
|
<picture>
|
|
18
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/
|
|
19
|
-
<img alt="
|
|
18
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/balls-desk-dark.webp">
|
|
19
|
+
<img alt="Thirty-six balls and pucks drawn in 3D under floodlights, in four rows of nine: soccer balls of several constructions and colours, then basketball, the 3x3 ball, baseball, softball, a football, a rugby ball, an Australian football and two volleyballs, then tennis, padel, pickleball with its holes, squash with its two dots, racquetball, golf, red and pink cricket and water polo, and last sepak takraw, a shuttlecock, a puck, a curling stone, lacrosse, handball, table tennis, a sliotar and a roundnet ball." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/balls-desk-light.webp" width="760">
|
|
20
20
|
</picture>
|
|
21
21
|
</p>
|
|
22
22
|
|
|
23
23
|
<p align="center">
|
|
24
24
|
<picture>
|
|
25
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/
|
|
26
|
-
<img alt="
|
|
25
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/vintage-desk-dark.webp">
|
|
26
|
+
<img alt="Eighteen more balls on a warm sunburst, in two rows of nine: five vintage leather soccer balls (hand-stitched, laced, 18 strips, 12 panels, 32 panels), a lemon-peel baseball, two baseballs stitched in two colours and an aged baseball, then nine soccer balls in the style of an era, with patterns of pentagons, leaves, a rosette, a star, a pinwheel and kites, a double border and plain white panels." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/vintage-desk-light.webp" width="760">
|
|
27
27
|
</picture>
|
|
28
28
|
</p>
|
|
29
29
|
|
|
30
30
|
<p align="center">
|
|
31
31
|
<picture>
|
|
32
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/
|
|
33
|
-
<img alt="
|
|
32
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/hero-desk-dark.webp">
|
|
33
|
+
<img alt="Trophies, medals and crests, in four rows of nine: nine famous cups, then a gilded cup, a phoenix-handle cup, a soccer ball trophy, a wreath, a rosette, a belt, a banner, a ring and a plaque, then three medals, three place badges and three crests, and last three cups each in metal, line and colour." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/hero-desk-light.webp" width="760">
|
|
34
34
|
</picture>
|
|
35
35
|
</p>
|
|
36
36
|
|
|
37
|
-
## The best of it
|
|
38
|
-
|
|
39
|
-
- **47 famous trophies**, each a close likeness measured on a photograph and carrying no lettering, logo or mark: the Stanley Cup, the FIFA World Cup, the Lombardi Trophy, the Larry O'Brien trophy, the Grey Cup and the rest ([famous trophies](./docs/famous-trophies.md)).
|
|
40
|
-
|
|
41
37
|
<p align="center">
|
|
42
38
|
<picture>
|
|
43
39
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/famous-desk-dark.webp">
|
|
@@ -45,41 +41,66 @@ The ball and the gear of every sport, trophies, medals, crests and the icon of e
|
|
|
45
41
|
</picture>
|
|
46
42
|
</p>
|
|
47
43
|
|
|
48
|
-
|
|
44
|
+
<p align="center">
|
|
45
|
+
<picture>
|
|
46
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/gear-desk-dark.webp">
|
|
47
|
+
<img alt="Thirty-six pieces of gear in four rows of nine: hockey stick and skate, a goalie mask, field hockey, lacrosse and hurling sticks, a cricket bat and wicket, a baseball bat and glove, a football helmet and goalposts, a basketball hoop, a volleyball net, rackets and paddles, a curling broom, skates, swim goggles, starting blocks, a baton, a javelin, a hurdle, and the kendo, sumo, judo, kyudo and karate gear of Japan." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/gear-desk-light.webp" width="760">
|
|
48
|
+
</picture>
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<table align="center">
|
|
52
|
+
<tr>
|
|
53
|
+
<td align="center" valign="top">
|
|
54
|
+
<img alt="A two-handled cup, a medal, a soccer ball and a championship banner each turned through seven angles: the cup keeps its outline and moves its light and handles, the medal and the banner flip like a coin to show their plain backs, and the ball rolls." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/turn-desk.webp" width="470"><br><em>Turned: a ball rolls, a medal flips</em>
|
|
55
|
+
</td>
|
|
56
|
+
<td align="center" valign="top">
|
|
57
|
+
<img alt="Cups, a medal, balls and gear on a phone, three to a row." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/phone-light.webp" width="200"><br><em>On a phone</em>
|
|
58
|
+
</td>
|
|
59
|
+
</tr>
|
|
60
|
+
</table>
|
|
61
|
+
|
|
62
|
+
## The best of it
|
|
63
|
+
|
|
64
|
+
- **47 famous trophies**, each a close likeness measured on a photograph and carrying no lettering, logo or mark: the Stanley Cup, the FIFA World Cup, the Lombardi Trophy, the Larry O'Brien trophy, the Grey Cup and the rest ([famous trophies](./docs/famous-trophies.md)).
|
|
49
65
|
|
|
50
66
|
<p align="center">
|
|
51
67
|
<picture>
|
|
52
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/
|
|
53
|
-
<img alt="
|
|
68
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/trophies-turn-dark.webp">
|
|
69
|
+
<img alt="Five famous trophies turning in 3D on royal purple, each a little behind the one before: the Stanley Cup first, then the FIFA World Cup, the Lombardi Trophy, the Larry O'Brien trophy and the Webb Ellis Cup. Each keeps its outline while its light and its handles move." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/trophies-turn-light.webp" width="760">
|
|
54
70
|
</picture>
|
|
55
71
|
</p>
|
|
56
72
|
|
|
57
|
-
- **
|
|
73
|
+
- **117 balls and implements in 3D**, from the 32-panel soccer ball to the pucks and the curling stone, that roll as they turn ([gallery](./docs/gallery.md), [vintage and era-style balls](./docs/vintage-balls.md)).
|
|
58
74
|
|
|
59
75
|
<p align="center">
|
|
60
76
|
<picture>
|
|
61
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/
|
|
62
|
-
<img alt="
|
|
77
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/balls-turn-dark.webp">
|
|
78
|
+
<img alt="Seven balls rolling under floodlights: a soccer ball, a basketball, a baseball, a rugby ball, a volleyball, a tennis ball and a golf ball, each turned a little differently so that the seams and panels travel across them." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/balls-turn-light.webp" width="760">
|
|
63
79
|
</picture>
|
|
64
80
|
</p>
|
|
65
81
|
|
|
66
|
-
- **
|
|
82
|
+
- **Pickleballs with real holes**: the holes are cut through the shell, so you see the dark inside of the ball and, where a near hole and a far one line up, the page itself ([pickleballs](./docs/pickleball.md)).
|
|
67
83
|
|
|
68
84
|
<p align="center">
|
|
69
85
|
<picture>
|
|
70
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/
|
|
71
|
-
<img alt="
|
|
86
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/pickleball-dark.webp">
|
|
87
|
+
<img alt="Two pickleballs, the yellow outdoor ball with its 40 small holes above and the white indoor ball with its 26 large ones below, each at rest and at three turns: through each hole the dark inside of the ball shows, and where a hole in the near side lines up with one in the far side the background shows through." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/pickleball-light.webp" width="760">
|
|
72
88
|
</picture>
|
|
73
89
|
</p>
|
|
74
90
|
|
|
75
|
-
- **
|
|
91
|
+
- **Trophies, medals, crests and the icon of every sport**, in metal, one line or flat colour, light and dark.
|
|
76
92
|
|
|
77
93
|
<p align="center">
|
|
78
94
|
<picture>
|
|
79
|
-
<
|
|
95
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/flips-turn-dark.webp">
|
|
96
|
+
<img alt="A gold and a silver medal, a championship banner, a crest, a hockey skate and a baseball glove flipping like coins on royal purple: each shows its face, then its edge, then its plain back." src="https://raw.githubusercontent.com/johnmorrisdotca/dougu-sports/main/docs/images/flips-turn-light.webp" width="760">
|
|
80
97
|
</picture>
|
|
81
98
|
</p>
|
|
82
99
|
|
|
100
|
+
- **70 pieces of gear**, among them the Japanese sports and budo ([Japanese sports](./docs/japanese-sports.md)).
|
|
101
|
+
|
|
102
|
+
- **On a phone**, and **turned by hand**: drag, arrow keys or the automatic turn ([turning](./docs/turning.md)).
|
|
103
|
+
|
|
83
104
|
> **Status: preview.** 325 emblems: 71 trophies, 6 awards, 6 medals, 4 crests, a pictogram for each of the 42 sports, 117 balls and implements drawn in 3D, 8 printed pucks ([docs/pucks.md](./docs/pucks.md)), 70 pieces of gear (among them the Japanese sports and budo, [docs/japanese-sports.md](./docs/japanese-sports.md)) and a championship pennant; [docs/layout.md](./docs/layout.md) says where each goes. All of it is drawn for this package: no art is copied from another project.
|
|
84
105
|
|
|
85
106
|
## In 30 seconds
|
|
@@ -394,9 +415,10 @@ import { TROPHY_TENNIS_CUP } from "@johnmorrisdotca/dougu-sports/trophy/tennis-c
|
|
|
394
415
|
|
|
395
416
|
const turner = bindTurn(document.getElementById("cup"), TROPHY_TENNIS_CUP, { size: 160, speed: 36 });
|
|
396
417
|
document.getElementById("spin").onclick = () => turner.togglePlay();
|
|
418
|
+
turner.setDirection("clockwise"); // seen from above: the other way (the default, `"counterclockwise"`, swings the front to the viewer's right)
|
|
397
419
|
```
|
|
398
420
|
|
|
399
|
-
A drag turns it, the arrow keys turn it, Space starts and stops an auto-turn, and nothing moves until you ask. Pass the emblem itself and the page carries the turning and that one emblem and nothing else (a cup and the turning are about 9 kB gzipped); pass an id, `"trophy:tennis-cup"`, and the registry is loaded when it is needed. See [docs/turning.md](./docs/turning.md).
|
|
421
|
+
`direction` is `"counterclockwise"` (how it has always turned) or `"clockwise"`, and `turnDirection(value)` is the check it goes through (anything but `"clockwise"` is counterclockwise). A drag turns it, the arrow keys turn it, Space starts and stops an auto-turn, and nothing moves until you ask. Pass the emblem itself and the page carries the turning and that one emblem and nothing else (a cup and the turning are about 9 kB gzipped); pass an id, `"trophy:tennis-cup"`, and the registry is loaded when it is needed. See [docs/turning.md](./docs/turning.md).
|
|
400
422
|
|
|
401
423
|
### In React, Vue and the rest
|
|
402
424
|
|
|
@@ -645,7 +667,7 @@ Bug reports and ideas go in the [issues](https://github.com/johnmorrisdotca/doug
|
|
|
645
667
|
|
|
646
668
|
## Changes
|
|
647
669
|
|
|
648
|
-
See [CHANGELOG.md](./CHANGELOG.md). 0.13.0 adds a pictogram for each of four combat sports, MMA (a cage), boxing (a glove), wrestling (two wrestlers on the mat) and professional wrestling (a ring with ropes), in the three styles (325 emblems); 0.12.0 adds forty-seven named trophies, each a close likeness measured on a photograph (321 emblems); 0.11.0 gives the era soccer balls neutral ids (the old ones stay as aliases), new looks and a second 1980s ball (274 emblems); 0.10.0 adds a standalone ribbon and the nets and posts of sepak takraw, netball and teqball from their rulebooks' sizes (273 emblems); 0.9.0 lets the baseball, the softball and the classic soccer balls be painted and printed: solid and two-tone colours, a logo of your own wrapped onto the ball, stamped text, an original cursive word and a small mark, all turning with the ball ([docs/custom-balls.md](./docs/custom-balls.md)); 0.8.0 makes `bindTurn` light: it takes an emblem object and then needs no registry, so a turnable cup is about 9.4 kB gzipped instead of about 81 kB, and an id loads the registry on demand; 0.7.3 turns the build, docs and picture scripts, the browser tests and the demo's source from JavaScript into TypeScript, with no change to the package; 0.7.2 makes every docs page single-language (a page in Japanese beside each page that had Japanese words in it, and a test that holds them apart), with no change to the pictures; 0.7.1 puts real countries (Canada, Japan) in the crest and puck examples in place of made-up teams, with no change to the code; 0.7.0 gives the national volleyballs layouts that tell them apart (Japan a crimson band, Poland white above and red below, the USA a navy field), strengthens the 2010-style grooved soccer ball, and adds six pictures of how the judo belt is tied, `gear:obi-step-1` to `gear:obi-step-6` (269 emblems: [docs/obi-steps.md](./docs/obi-steps.md)); 0.6.0 gives the judo suit and the karate suit their sleeves (a judogi has no short ones: they reach the wrist) and adds the judogi seen from behind with the IJF-style back number, a family name and a country code on a patch, with a `backnumber` option (269 emblems: [docs/judogi-back.md](./docs/judogi-back.md)); 0.5.1 redraws the judo suit, the belt and the football pictograms and adds the blue and folded suits and the belts of every grade (261 emblems: [docs/japanese-sports.md](./docs/japanese-sports.md)); 0.5.0 adds fifty balls: vintage leather soccer balls, era-style and shop-wall soccer balls, baseballs of other threads and volleyballs in national colours, with a `colors` option (244 emblems: [docs/vintage-balls.md](./docs/vintage-balls.md)); 0.4.0 adds eight printed pucks and a `face` option (194 emblems: [docs/pucks.md](./docs/pucks.md)); 0.3.0 adds nineteen soccer balls (26, 18, 14, 12 and 6 panels, winter orange and high-visibility yellow, futsal and beach soccer: 186 emblems); 0.2.1 draws every ball and implement to the rulebook's proportions; 0.2.0 is 167 emblems, every one drawn here, with the Japanese sports, engraving, a turn for every emblem and the compose helpers; 0.1.0 brought the first full set of 148; 0.0.1 was the first preview.
|
|
670
|
+
See [CHANGELOG.md](./CHANGELOG.md). 0.15.0 gives the pickleballs real holes, cut through the shell and drawn with the inside of the ball behind them, so the page shows through where two holes line up ([docs/pickleball.md](./docs/pickleball.md)); 0.14.0 lets the auto-turn go either way (`direction: "clockwise"` or `"counterclockwise"`, `setDirection()`); 0.13.0 adds a pictogram for each of four combat sports, MMA (a cage), boxing (a glove), wrestling (two wrestlers on the mat) and professional wrestling (a ring with ropes), in the three styles (325 emblems); 0.12.0 adds forty-seven named trophies, each a close likeness measured on a photograph (321 emblems); 0.11.0 gives the era soccer balls neutral ids (the old ones stay as aliases), new looks and a second 1980s ball (274 emblems); 0.10.0 adds a standalone ribbon and the nets and posts of sepak takraw, netball and teqball from their rulebooks' sizes (273 emblems); 0.9.0 lets the baseball, the softball and the classic soccer balls be painted and printed: solid and two-tone colours, a logo of your own wrapped onto the ball, stamped text, an original cursive word and a small mark, all turning with the ball ([docs/custom-balls.md](./docs/custom-balls.md)); 0.8.0 makes `bindTurn` light: it takes an emblem object and then needs no registry, so a turnable cup is about 9.4 kB gzipped instead of about 81 kB, and an id loads the registry on demand; 0.7.3 turns the build, docs and picture scripts, the browser tests and the demo's source from JavaScript into TypeScript, with no change to the package; 0.7.2 makes every docs page single-language (a page in Japanese beside each page that had Japanese words in it, and a test that holds them apart), with no change to the pictures; 0.7.1 puts real countries (Canada, Japan) in the crest and puck examples in place of made-up teams, with no change to the code; 0.7.0 gives the national volleyballs layouts that tell them apart (Japan a crimson band, Poland white above and red below, the USA a navy field), strengthens the 2010-style grooved soccer ball, and adds six pictures of how the judo belt is tied, `gear:obi-step-1` to `gear:obi-step-6` (269 emblems: [docs/obi-steps.md](./docs/obi-steps.md)); 0.6.0 gives the judo suit and the karate suit their sleeves (a judogi has no short ones: they reach the wrist) and adds the judogi seen from behind with the IJF-style back number, a family name and a country code on a patch, with a `backnumber` option (269 emblems: [docs/judogi-back.md](./docs/judogi-back.md)); 0.5.1 redraws the judo suit, the belt and the football pictograms and adds the blue and folded suits and the belts of every grade (261 emblems: [docs/japanese-sports.md](./docs/japanese-sports.md)); 0.5.0 adds fifty balls: vintage leather soccer balls, era-style and shop-wall soccer balls, baseballs of other threads and volleyballs in national colours, with a `colors` option (244 emblems: [docs/vintage-balls.md](./docs/vintage-balls.md)); 0.4.0 adds eight printed pucks and a `face` option (194 emblems: [docs/pucks.md](./docs/pucks.md)); 0.3.0 adds nineteen soccer balls (26, 18, 14, 12 and 6 panels, winter orange and high-visibility yellow, futsal and beach soccer: 186 emblems); 0.2.1 draws every ball and implement to the rulebook's proportions; 0.2.0 is 167 emblems, every one drawn here, with the Japanese sports, engraving, a turn for every emblem and the compose helpers; 0.1.0 brought the first full set of 148; 0.0.1 was the first preview.
|
|
649
671
|
|
|
650
672
|
## Credits
|
|
651
673
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Piece, type PieceSize, type PrintOptions, type PrintRenderer, type ResolvedOptions, type ResolvedPaint } from "./ball.core.ts";
|
|
2
|
+
import type { HoleLayers } from "./ball.holes.ts";
|
|
2
3
|
import { type M3, type V3 } from "./ball.math.ts";
|
|
3
4
|
/** How a ball takes the light. */
|
|
4
5
|
export interface Material {
|
|
@@ -121,6 +122,11 @@ export interface BallSpec {
|
|
|
121
122
|
at?: V3;
|
|
122
123
|
/** The fraction of the box's radius the ball takes (1 by default): a hammer's head is small, to leave room for its wire. */
|
|
123
124
|
fit?: number;
|
|
125
|
+
/**
|
|
126
|
+
* A ball with real holes (a pickleball), drilled through its shell: each near hole is cut out and shows the inside of the ball, and where a near and a far hole line up the page shows through.
|
|
127
|
+
* It is a function (`drillHoles` in ball.holes.ts, bound to the hole centres) so that a ball without holes does not carry the code. The line style does not call it (a `draw` that wants marks there draws them).
|
|
128
|
+
*/
|
|
129
|
+
holes?: (s: Surface, id: string, base: string, shape: (attrs: string) => string, minWidth: number) => HoleLayers;
|
|
124
130
|
/** What is attached to the ball and sticks out of it (a hammer's wire and handle): drawn behind the ball or in front of it, by what is nearer to you. */
|
|
125
131
|
attach?: (s: Surface, base: string) => {
|
|
126
132
|
behind: string;
|
|
@@ -363,11 +363,13 @@ export function drawBall(title, key, spec, opts, turn, turning) {
|
|
|
363
363
|
(gr === undefined
|
|
364
364
|
? ""
|
|
365
365
|
: grainDef(id, gr.f, gr.a, gr.seed));
|
|
366
|
-
const
|
|
366
|
+
const hol = spec.holes?.(surface, id, base, shape, minWidth);
|
|
367
|
+
const inner = `<g clip-path="url(#${id}c)"${gr === undefined ? "" : ` filter="url(#${id}n)"`}>${shape(`fill="${ground ?? spec.ground ?? base}"`)}${layers}${hol?.edge ?? ""}</g>`;
|
|
367
368
|
const metal = m.metal === true ? shape(`fill="url(#${id}m)"`) : "";
|
|
368
369
|
const overlays = shape(`fill="url(#${id}d)"`) + metal + shape(`fill="url(#${id}b)"`) + shape(`fill="url(#${id}h)"`);
|
|
369
370
|
const at = spec.attach?.(surface, base);
|
|
370
|
-
|
|
371
|
+
const shell = hol?.mask === undefined ? `${inner}${overlays}` : `<g mask="url(#${hol.mask})">${inner}${overlays}</g>`;
|
|
372
|
+
return wrapPiece({ title, size: opts.size, theme: opts.theme, defs: defs + (hol?.defs ?? "") + metalDef(id, m.metal === true), body: `${at?.behind ?? ""}${hol?.behind ?? ""}${shell}${at?.front ?? ""}` });
|
|
371
373
|
}
|
|
372
374
|
/** A ball's label area as a surface sees it: the middle, the right-hand and the upward direction, orthogonal, and how far it reaches. */
|
|
373
375
|
function homeOf(spec) {
|
|
@@ -2,6 +2,7 @@ import { type BallDef } from "./ball.engine.ts";
|
|
|
2
2
|
import { type V3 } from "./ball.math.ts";
|
|
3
3
|
import type { Piece } from "./ball.core.ts";
|
|
4
4
|
import type { BallSpec } from "./ball.engine.ts";
|
|
5
|
+
import type { Drill } from "./ball.holes.ts";
|
|
5
6
|
export interface DottedOptions {
|
|
6
7
|
id: string;
|
|
7
8
|
en: string;
|
|
@@ -19,6 +20,8 @@ export interface DottedOptions {
|
|
|
19
20
|
mark?: string;
|
|
20
21
|
/** A lit rim on each mark (not for a dimple pattern of two hundred, which is large enough already). */
|
|
21
22
|
light?: boolean;
|
|
23
|
+
/** Real holes through the shell, not marks on it (`holeLayers` from ball.holes.ts, taken by the pickleball only): the near ones are cut out and show the inside of the ball, and where two line up the page shows through. The line style still draws marks. */
|
|
24
|
+
hollow?: Drill;
|
|
22
25
|
/** Turns the spread, so a ball does not show its spiral's pole straight on. */
|
|
23
26
|
phase?: number;
|
|
24
27
|
}
|
|
@@ -13,8 +13,11 @@ export function dottedBall(o) {
|
|
|
13
13
|
mat: o.mat,
|
|
14
14
|
draw: (s, base) => {
|
|
15
15
|
const mark = o.mark ?? mix(base, -0.55);
|
|
16
|
+
if (o.hollow !== undefined && !s.line)
|
|
17
|
+
return "";
|
|
16
18
|
return s.dots(centres, o.radius, mark, { opacity: o.depth ?? 0.55, ink: true, light: o.light ?? true });
|
|
17
19
|
},
|
|
20
|
+
holes: o.hollow === undefined ? undefined : (s, id, base, shape, minWidth) => o.hollow(s, id, { centres, radius: o.radius }, base, shape, minWidth),
|
|
18
21
|
};
|
|
19
22
|
return defineBall({ id: o.id, en: o.en, ja: o.ja, spec, size: o.size });
|
|
20
23
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Surface } from "./ball.engine.ts";
|
|
2
|
+
import { type V3 } from "./ball.math.ts";
|
|
3
|
+
/** Where a ball is drilled: the hole centres on the unit sphere, a hole's radius as the angle of its cap in radians, and the shell's thickness as a fraction of the ball's radius (0.05 by default). */
|
|
4
|
+
export interface Holes {
|
|
5
|
+
centres: readonly V3[];
|
|
6
|
+
radius: number;
|
|
7
|
+
wall?: number;
|
|
8
|
+
}
|
|
9
|
+
/** What `holeLayers` makes: the definitions, the inside of the ball (drawn first), the edges drawn on the shell, and the mask that cuts the near holes out of everything on the shell, if there is one. */
|
|
10
|
+
export interface HoleLayers {
|
|
11
|
+
defs: string;
|
|
12
|
+
behind: string;
|
|
13
|
+
edge: string;
|
|
14
|
+
mask: string | undefined;
|
|
15
|
+
}
|
|
16
|
+
/** The signature of `holeLayers`, which a ball is handed so that its own module is the only one that carries the code. */
|
|
17
|
+
export type Drill = (s: Surface, id: string, holes: Holes, base: string, shape: (attrs: string) => string, minWidth: number) => HoleLayers;
|
|
18
|
+
export declare const holeLayers: Drill;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { hashOf, mix, num } from "./ball.core.js";
|
|
2
|
+
import { basis, ellipseOf, mul } from "./ball.math.js";
|
|
3
|
+
/** The circle of the hole's bore at `depth` below the surface (0 on the outside), as the ellipse it makes on the screen; undefined where it is too thin to draw. */
|
|
4
|
+
function bore(s, m, radius, depth) {
|
|
5
|
+
const [t1, t2] = basis(m);
|
|
6
|
+
const sr = Math.sin(radius), cr = Math.cos(radius) - depth;
|
|
7
|
+
const c = s.project(mul(m, cr));
|
|
8
|
+
const o = s.project([0, 0, 0]);
|
|
9
|
+
const pa = s.project(mul(t1, sr));
|
|
10
|
+
const pb = s.project(mul(t2, sr));
|
|
11
|
+
const da = [pa[0] - o[0], pa[1] - o[1]];
|
|
12
|
+
const db = [pb[0] - o[0], pb[1] - o[1]];
|
|
13
|
+
const { rx, ry, angle } = ellipseOf([[da[0], db[0], 0], [da[1], db[1], 0]]);
|
|
14
|
+
if (rx < 0.05)
|
|
15
|
+
return undefined;
|
|
16
|
+
return { x: c[0], y: c[1], rx, ry: Math.max(ry, 0.05), deg: (angle * 180) / Math.PI, ax: Math.cos(angle) * rx, ay: Math.sin(angle) * rx, facing: s.facing(m) };
|
|
17
|
+
}
|
|
18
|
+
const ellipse = (e) => {
|
|
19
|
+
const arcs = `a${num(e.rx)} ${num(e.ry)} ${num(e.deg, 0)} 1 0`;
|
|
20
|
+
return `M${num(e.x + e.ax)} ${num(e.y + e.ay)}${arcs}${num(-2 * e.ax)} ${num(-2 * e.ay)}${arcs}${num(2 * e.ax)} ${num(2 * e.ay)}`;
|
|
21
|
+
};
|
|
22
|
+
/** The light comes from the upper left, as it does everywhere else in the engine. */
|
|
23
|
+
const LIGHT = [-0.62, -0.78];
|
|
24
|
+
/** The tones a wall is drawn in, darkest first, as amounts of the ball's colour mixed toward black. */
|
|
25
|
+
const TONES = [-0.6, -0.45, -0.3, -0.15];
|
|
26
|
+
export const holeLayers = (s, id, holes, base, shape, minWidth) => {
|
|
27
|
+
const thick = holes.wall ?? 0.05;
|
|
28
|
+
const front = [];
|
|
29
|
+
const backOut = [];
|
|
30
|
+
const backIn = [];
|
|
31
|
+
for (const m of holes.centres) {
|
|
32
|
+
const f = s.facing(m);
|
|
33
|
+
if (f >= 0.08) {
|
|
34
|
+
const out = bore(s, m, holes.radius, 0);
|
|
35
|
+
if (out !== undefined)
|
|
36
|
+
front.push({ out, inn: bore(s, m, holes.radius, thick) });
|
|
37
|
+
}
|
|
38
|
+
else if (f <= -0.08) {
|
|
39
|
+
const out = bore(s, m, holes.radius, 0);
|
|
40
|
+
const inn = bore(s, m, holes.radius, thick);
|
|
41
|
+
if (out !== undefined && inn !== undefined) {
|
|
42
|
+
backOut.push(out);
|
|
43
|
+
backIn.push(inn);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (front.length === 0 && backOut.length === 0)
|
|
48
|
+
return { defs: "", behind: "", edge: "", mask: undefined };
|
|
49
|
+
const frontPath = front.map((h) => ellipse(h.out)).join("");
|
|
50
|
+
const backOutPath = backOut.map(ellipse).join("");
|
|
51
|
+
const backInPath = backIn.map(ellipse).join("");
|
|
52
|
+
const key = hashOf(frontPath + "|" + backOutPath + "|" + backInPath);
|
|
53
|
+
// The inside of the ball: lit a little where the light that comes through the near holes lands (low and to the right), dark toward the edge.
|
|
54
|
+
let defs = `<radialGradient id="${id}i" cx=".62" cy=".66" r=".62"><stop offset="0" stop-color="${mix(base, -0.36)}"/><stop offset="1" stop-color="${mix(base, -0.72)}"/></radialGradient>`;
|
|
55
|
+
let disc = shape(`fill="url(#${id}i)"`);
|
|
56
|
+
if (backOut.length > 0) {
|
|
57
|
+
// A far hole is open where its inner opening and its outer opening overlap: the bore leans away from you, so a hole near the far edge is a slit.
|
|
58
|
+
defs += `<clipPath id="${id}o${key}"><path d="${backOutPath}"/></clipPath><mask id="${id}b${key}" maskUnits="userSpaceOnUse" x="0" y="0" width="100" height="100"><rect width="100" height="100" fill="#fff"/><path d="${backInPath}" fill="#000" clip-path="url(#${id}o${key})"/></mask>`;
|
|
59
|
+
disc = shape(`fill="url(#${id}i)" mask="url(#${id}b${key})"`);
|
|
60
|
+
}
|
|
61
|
+
// The wall of each near hole: what is inside the outer opening and outside the inner one (the part of the bore that faces you), toned by whether it faces the light and how near the edge it is.
|
|
62
|
+
const o = s.project([0, 0, 0]);
|
|
63
|
+
const buckets = TONES.map(() => []);
|
|
64
|
+
for (const h of front) {
|
|
65
|
+
if (h.inn === undefined)
|
|
66
|
+
continue;
|
|
67
|
+
const dx = h.out.x - o[0], dy = h.out.y - o[1];
|
|
68
|
+
const d = Math.hypot(dx, dy) || 1;
|
|
69
|
+
// The wall you see is the one on the far side of the hole, facing the middle of the ball on the screen.
|
|
70
|
+
const lit = (-dx / d) * LIGHT[0] + (-dy / d) * LIGHT[1];
|
|
71
|
+
const k = -0.3 + 0.2 * lit - 0.25 * (1 - h.out.facing);
|
|
72
|
+
let best = 0;
|
|
73
|
+
for (let i = 1; i < TONES.length; i++)
|
|
74
|
+
if (Math.abs(TONES[i] - k) < Math.abs(TONES[best] - k))
|
|
75
|
+
best = i;
|
|
76
|
+
buckets[best].push(ellipse(h.out) + ellipse(h.inn));
|
|
77
|
+
}
|
|
78
|
+
const walls = buckets.map((b, i) => (b.length === 0 ? "" : `<path d="${b.join("")}" fill="${mix(base, TONES[i])}" fill-rule="evenodd"/>`)).join("");
|
|
79
|
+
const behind = `<g clip-path="url(#${id}c)">${disc}${walls}</g>`;
|
|
80
|
+
if (front.length === 0)
|
|
81
|
+
return { defs, behind, edge: "", mask: undefined };
|
|
82
|
+
// The outline of the near holes is written once and used three times.
|
|
83
|
+
defs += `<path id="${id}f${key}" d="${frontPath}"/><mask id="${id}k${key}" maskUnits="userSpaceOnUse" x="0" y="0" width="100" height="100"><rect width="100" height="100" fill="#fff"/><use href="#${id}f${key}" fill="#000"/></mask>`;
|
|
84
|
+
// On the shell, round each cut: a soft shadow where the plastic turns in, and a thin lit edge (the cut face of the shell). Half of each stroke lies inside the cut and is masked away.
|
|
85
|
+
const edge = `<use href="#${id}f${key}" fill="none" stroke="${mix(base, -0.6)}" stroke-width="${num(Math.max(1.1, minWidth * 0.8), 2)}" opacity=".22"/>` +
|
|
86
|
+
`<use href="#${id}f${key}" fill="none" stroke="${mix(base, 0.5)}" stroke-width="${num(Math.max(0.3, minWidth * 0.3), 2)}" opacity=".5"/>`;
|
|
87
|
+
return { defs, behind, edge, mask: `${id}k${key}` };
|
|
88
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
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
2
|
import { dottedBall } from "./ball.family.dotted.js";
|
|
3
|
+
import { holeLayers } from "./ball.holes.js";
|
|
3
4
|
export const BALL_PICKLEBALL_OUTDOOR = /* @__PURE__ */ dottedBall({
|
|
4
5
|
id: "ball:pickleball-outdoor",
|
|
5
6
|
en: "Pickleball, outdoor",
|
|
@@ -11,6 +12,7 @@ export const BALL_PICKLEBALL_OUTDOOR = /* @__PURE__ */ dottedBall({
|
|
|
11
12
|
mat: { gloss: 0.55, shade: "#4a5008", grain: { f: 1.4, a: 0.1 } },
|
|
12
13
|
mark: "#454b0e",
|
|
13
14
|
depth: 0.75,
|
|
15
|
+
hollow: holeLayers,
|
|
14
16
|
});
|
|
15
17
|
export const BALL_PICKLEBALL_INDOOR = /* @__PURE__ */ dottedBall({
|
|
16
18
|
id: "ball:pickleball-indoor",
|
|
@@ -23,4 +25,5 @@ export const BALL_PICKLEBALL_INDOOR = /* @__PURE__ */ dottedBall({
|
|
|
23
25
|
mat: { gloss: 0.6, shade: "#3a3a40", grain: { f: 1.4, a: 0.08 } },
|
|
24
26
|
mark: "#3d3d44",
|
|
25
27
|
depth: 0.7,
|
|
28
|
+
hollow: holeLayers,
|
|
26
29
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export * from "./emblems-entry.ts";
|
|
2
2
|
export { ballFrame, emblemFrame } from "./emblems/emblem.api.ts";
|
|
3
3
|
export { bindTurn } from "./turn-full.ts";
|
|
4
|
-
export
|
|
4
|
+
export { turnDirection } from "./turn-control.ts";
|
|
5
|
+
export type { TurnAngles, TurnContainer, TurnControlOptions, TurnController, TurnDirection, TurnEvent } from "./turn-control.ts";
|
|
5
6
|
export { EMBLEM_TABLE } from "./emblems/emblem.registry.ts";
|
|
6
7
|
export { AWARD_MEDAL } from "./emblems/award/medal.ts";
|
|
7
8
|
export { AWARD_BADGE } from "./emblems/award/badge.ts";
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
export * from "./emblems-entry.js";
|
|
4
4
|
export { ballFrame, emblemFrame } from "./emblems/emblem.api.js";
|
|
5
5
|
export { bindTurn } from "./turn-full.js";
|
|
6
|
+
export { turnDirection } from "./turn-control.js";
|
|
6
7
|
export { EMBLEM_TABLE } from "./emblems/emblem.registry.js";
|
|
7
8
|
export { AWARD_MEDAL } from "./emblems/award/medal.js";
|
|
8
9
|
export { AWARD_BADGE } from "./emblems/award/badge.js";
|
package/dist/turn-control.d.ts
CHANGED
|
@@ -8,6 +8,13 @@ export interface TurnRegistry {
|
|
|
8
8
|
renderEmblem(ref: EmblemRef, options?: FrameOptions): string;
|
|
9
9
|
emblemFrame(ref: EmblemRef, options?: FrameOptions): string;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Which way the auto-turn goes, seen from above. `"counterclockwise"` is how it has always turned: the front swings to the viewer's right. `"clockwise"` is the other way: the front swings to the viewer's left.
|
|
13
|
+
* A drag, the arrow keys and `setAngles` are not reversed.
|
|
14
|
+
*/
|
|
15
|
+
export type TurnDirection = "clockwise" | "counterclockwise";
|
|
16
|
+
/** A direction from anything: `"clockwise"` is clockwise, and everything else is the default, `"counterclockwise"`. */
|
|
17
|
+
export declare function turnDirection(value: unknown): TurnDirection;
|
|
11
18
|
/** The three angles of a turn, in degrees. */
|
|
12
19
|
export interface TurnAngles {
|
|
13
20
|
/** About the vertical axis, from -180 (excluded) to 180. */
|
|
@@ -34,6 +41,8 @@ export interface TurnControlOptions extends FrameOptions {
|
|
|
34
41
|
autoPlay?: boolean | "force";
|
|
35
42
|
/** Degrees of yaw each second the auto-turn advances (36 by default; negative turns the other way). */
|
|
36
43
|
speed?: number;
|
|
44
|
+
/** Which way the auto-turn goes (`"counterclockwise"`, the way it has always turned, by default). `update` keeps the direction unless it names one; a negative `speed` reverses it. */
|
|
45
|
+
direction?: TurnDirection;
|
|
37
46
|
/** When true (the default), a drag holds the auto-turn while the pointer is down, and an arrow key, Home or `setAngles` pauses it. When false nothing but `pause()` stops it. */
|
|
38
47
|
pauseOnInteract?: boolean;
|
|
39
48
|
/** Called with `true` when the auto-turn starts and `false` when it stops, whatever stopped it. */
|
|
@@ -60,6 +69,10 @@ export interface TurnController {
|
|
|
60
69
|
play(): boolean;
|
|
61
70
|
/** Stops the auto-turn. */
|
|
62
71
|
pause(): void;
|
|
72
|
+
/** Which way the auto-turn goes. */
|
|
73
|
+
direction(): TurnDirection;
|
|
74
|
+
/** Changes which way the auto-turn goes, at once and without stopping it. */
|
|
75
|
+
setDirection(direction: TurnDirection): void;
|
|
63
76
|
/** Starts or stops the auto-turn and gives the new state; `false` for an emblem that cannot turn. */
|
|
64
77
|
togglePlay(): boolean;
|
|
65
78
|
/** Removes the listeners and the attributes and styles `bindTurn` added; the last drawing stays. */
|
package/dist/turn-control.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/** A direction from anything: `"clockwise"` is clockwise, and everything else is the default, `"counterclockwise"`. */
|
|
2
|
+
export function turnDirection(value) {
|
|
3
|
+
return value === "clockwise" ? "clockwise" : "counterclockwise";
|
|
4
|
+
}
|
|
1
5
|
const WORDS = {
|
|
2
6
|
en: { role: "turnable emblem", hint: "Drag, or use the arrow keys, to turn it. Space starts and stops the turning." },
|
|
3
7
|
ja: { role: "回せるエンブレム", hint: "ドラッグするか矢印キーで回せます。スペースキーで自動回転を始めたり止めたりできます。" },
|
|
@@ -63,6 +67,7 @@ export function bindTurnWith(registry, container, ref, options = {}) {
|
|
|
63
67
|
let range = [-60, 60];
|
|
64
68
|
let keyStep = 5;
|
|
65
69
|
let speed = 36;
|
|
70
|
+
let way = turnDirection(options.direction);
|
|
66
71
|
let pauseOnInteract = true;
|
|
67
72
|
let locale = "en";
|
|
68
73
|
let onTurn;
|
|
@@ -86,12 +91,14 @@ export function bindTurnWith(registry, container, ref, options = {}) {
|
|
|
86
91
|
range = low <= high ? [low, high] : [high, low];
|
|
87
92
|
keyStep = clamp(finite(o.keyStep, 5), 0.5, 90);
|
|
88
93
|
speed = clamp(finite(o.speed, 36), -720, 720);
|
|
94
|
+
if (o.direction !== undefined)
|
|
95
|
+
way = turnDirection(o.direction);
|
|
89
96
|
pauseOnInteract = o.pauseOnInteract !== false;
|
|
90
97
|
locale = o.locale === "ja" ? "ja" : "en";
|
|
91
98
|
onTurn = typeof o.onTurn === "function" ? o.onTurn : undefined;
|
|
92
99
|
onPlayChange = typeof o.onPlayChange === "function" ? o.onPlayChange : undefined;
|
|
93
100
|
const rest = { ...o };
|
|
94
|
-
for (const name of ["sensitivity", "pitchRange", "keyStep", "onTurn", "autoPlay", "speed", "pauseOnInteract", "onPlayChange", "yaw", "pitch", "roll"])
|
|
101
|
+
for (const name of ["sensitivity", "pitchRange", "keyStep", "onTurn", "autoPlay", "speed", "direction", "pauseOnInteract", "onPlayChange", "yaw", "pitch", "roll"])
|
|
95
102
|
delete rest[name];
|
|
96
103
|
frame = rest;
|
|
97
104
|
};
|
|
@@ -156,7 +163,7 @@ export function bindTurnWith(registry, container, ref, options = {}) {
|
|
|
156
163
|
const dt = last === undefined ? 0 : clamp((time - last) / 1000, 0, 0.1);
|
|
157
164
|
last = time;
|
|
158
165
|
if (!held && dt > 0) {
|
|
159
|
-
place({ yaw: angles.yaw + speed * dt });
|
|
166
|
+
place({ yaw: angles.yaw + (way === "clockwise" ? -1 : 1) * speed * dt });
|
|
160
167
|
draw();
|
|
161
168
|
onTurn?.(copy());
|
|
162
169
|
}
|
|
@@ -378,6 +385,12 @@ export function bindTurnWith(registry, container, ref, options = {}) {
|
|
|
378
385
|
if (pending === undefined)
|
|
379
386
|
draw();
|
|
380
387
|
},
|
|
388
|
+
direction() {
|
|
389
|
+
return way;
|
|
390
|
+
},
|
|
391
|
+
setDirection(next) {
|
|
392
|
+
way = turnDirection(next);
|
|
393
|
+
},
|
|
381
394
|
play() {
|
|
382
395
|
if (!turnable || destroyed)
|
|
383
396
|
return false;
|
package/dist/turn-entry.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { ballFrame, emblemFrame } from "./emblems/emblem.api.ts";
|
|
2
2
|
export type { FrameOptions } from "./emblems/emblem.core.ts";
|
|
3
|
-
export { bindTurn } from "./turn-control.ts";
|
|
4
|
-
export type { TurnAngles, TurnContainer, TurnControlOptions, TurnController, TurnEvent } from "./turn-control.ts";
|
|
3
|
+
export { bindTurn, turnDirection } from "./turn-control.ts";
|
|
4
|
+
export type { TurnAngles, TurnContainer, TurnControlOptions, TurnController, TurnDirection, TurnEvent } from "./turn-control.ts";
|
package/dist/turn-entry.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// The turning entry point: an emblem at an angle. `emblemFrame` turns any emblem about its vertical axis and tilts it; `ballFrame` rolls a ball. Each frame is plain SVG, so a turn is a loop over
|
|
2
2
|
// the angle, drawn by the caller (a slider, a requestAnimationFrame, a CSS-free animation).
|
|
3
3
|
export { ballFrame, emblemFrame } from "./emblems/emblem.api.js";
|
|
4
|
-
export { bindTurn } from "./turn-control.js";
|
|
4
|
+
export { bindTurn, turnDirection } from "./turn-control.js";
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.15.0";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.
|
|
1
|
+
export const VERSION = "0.15.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnmorrisdotca/dougu-sports",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Dougu Sports 道具, sports emblems as SVG strings: trophies, medals, crests, sport icons, and the ball and gear of every sport, in metal, line or flat colour, with optional 3D turning. Light and dark, accessible, tree-shakeable. Zero dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sports",
|