@johnmorrisdotca/dougu-sports 0.4.1 → 0.5.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 +20 -1
- package/NOTICE.md +6 -4
- package/README.md +6 -5
- package/dist/emblems/ball/ball.baseball.vintage.d.ts +10 -0
- package/dist/emblems/ball/ball.baseball.vintage.js +70 -0
- package/dist/emblems/ball/ball.core.d.ts +4 -0
- package/dist/emblems/ball/ball.core.js +11 -1
- package/dist/emblems/ball/ball.decal.d.ts +56 -0
- package/dist/emblems/ball/ball.decal.js +146 -0
- package/dist/emblems/ball/ball.engine.d.ts +7 -1
- package/dist/emblems/ball/ball.engine.js +10 -2
- package/dist/emblems/ball/ball.family.panelled.d.ts +5 -0
- package/dist/emblems/ball/ball.family.panelled.js +12 -5
- package/dist/emblems/ball/ball.family.seamed.d.ts +8 -1
- package/dist/emblems/ball/ball.family.seamed.js +13 -3
- package/dist/emblems/ball/ball.index.js +6 -1
- package/dist/emblems/ball/ball.soccer.era.d.ts +23 -0
- package/dist/emblems/ball/ball.soccer.era.js +302 -0
- package/dist/emblems/ball/ball.soccer.store.d.ts +19 -0
- package/dist/emblems/ball/ball.soccer.store.js +176 -0
- package/dist/emblems/ball/ball.soccer.vintage.d.ts +11 -0
- package/dist/emblems/ball/ball.soccer.vintage.js +135 -0
- package/dist/emblems/ball/ball.tilings.d.ts +26 -0
- package/dist/emblems/ball/ball.tilings.js +87 -0
- package/dist/emblems/ball/ball.volleyball.flag.d.ts +12 -0
- package/dist/emblems/ball/ball.volleyball.flag.js +36 -0
- package/dist/emblems/emblem.core.d.ts +2 -0
- package/dist/emblems/emblem.descriptions.js +50 -0
- package/dist/emblems/emblem.ids.d.ts +2 -2
- package/dist/emblems/emblem.ids.js +3 -2
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Balls with the seam of a baseball or a tennis ball: one closed curve that winds twice round the sphere, x=(1-b)cos t + b cos 3t, y=(1-b)sin t - b sin 3t, z=2sqrt(b(1-b)) sin 2t.
|
|
2
2
|
// A baseball and a softball have red stitches that cross it in Vs; a tennis or padel ball has a white rubber strip along it; a sliotar a raised rib.
|
|
3
3
|
import { defineBall } from "./ball.engine.js";
|
|
4
|
+
import { mix } from "./ball.core.js";
|
|
5
|
+
import { scuffs } from "./ball.decal.js";
|
|
4
6
|
import { seamCurve } from "./ball.math.js";
|
|
5
7
|
import { stitches } from "./ball.stitch.js";
|
|
6
8
|
export function seamedBall(o) {
|
|
@@ -8,15 +10,23 @@ export function seamedBall(o) {
|
|
|
8
10
|
view: o.view ?? { yaw: 0, pitch: 0, roll: 0 },
|
|
9
11
|
base: o.base,
|
|
10
12
|
mat: o.mat,
|
|
11
|
-
draw: (s) => {
|
|
13
|
+
draw: (s, base) => {
|
|
12
14
|
const seam = seamCurve(o.b, 160);
|
|
13
15
|
let out = "";
|
|
14
16
|
if (o.groove !== undefined)
|
|
15
17
|
out += s.stroke(seam, o.groove, 0.8, { closed: true, opacity: 0.55 });
|
|
16
18
|
if (o.strip !== undefined)
|
|
17
19
|
out += o.strip.raised === true ? s.seam(seam, o.strip.colour, o.strip.width, { closed: true }) : s.stroke(seam, o.strip.colour, o.strip.width, { closed: true });
|
|
18
|
-
if (o.
|
|
19
|
-
out += s
|
|
20
|
+
if (o.wear !== undefined)
|
|
21
|
+
out += scuffs(s, mix(base, -0.55), mix(base, 0.6), { dark: o.wear.dark, pale: o.wear.pale, seed: o.wear.seed });
|
|
22
|
+
if (o.stitch !== undefined) {
|
|
23
|
+
const marks = stitches(seam, true, o.stitch.count, o.stitch.half, { v: true, lean: o.stitch.lean });
|
|
24
|
+
const second = o.stitch.colour2;
|
|
25
|
+
if (second === undefined)
|
|
26
|
+
out += s.strokes(marks, o.stitch.colour, o.stitch.width, { ink: false });
|
|
27
|
+
else
|
|
28
|
+
out += s.strokes(marks.filter((_, i) => i % 2 === 0), o.stitch.colour, o.stitch.width, { ink: false }) + s.strokes(marks.filter((_, i) => i % 2 === 1), second, o.stitch.width, { ink: false });
|
|
29
|
+
}
|
|
20
30
|
if (o.strip === undefined && o.stitch === undefined)
|
|
21
31
|
out += s.stroke(seam, "currentColor", 1.6, { closed: true });
|
|
22
32
|
return out;
|
|
@@ -27,13 +27,18 @@ import { BALL_SOCCER, BALL_SOCCER_COLOUR } from "./ball.soccer.js";
|
|
|
27
27
|
import { BALL_SOCCER_26, BALL_SOCCER_18, BALL_SOCCER_14, BALL_SOCCER_12, BALL_SOCCER_6, BALL_SOCCER_ORANGE, BALL_SOCCER_26_ORANGE, BALL_SOCCER_18_ORANGE, BALL_SOCCER_14_ORANGE, BALL_SOCCER_12_ORANGE, BALL_SOCCER_6_ORANGE, BALL_SOCCER_YELLOW, BALL_SOCCER_26_YELLOW, BALL_SOCCER_18_YELLOW, BALL_SOCCER_14_YELLOW, BALL_SOCCER_12_YELLOW, BALL_SOCCER_6_YELLOW } from "./ball.soccer.panels.js";
|
|
28
28
|
import { BALL_FUTSAL, BALL_BEACH_SOCCER } from "./ball.soccer.indoor.js";
|
|
29
29
|
import { BALL_SOFTBALL } from "./ball.softball.js";
|
|
30
|
+
import { BALL_SOCCER_1870_HAND_STITCHED, BALL_SOCCER_1900_LACED, BALL_SOCCER_1930_18_PANEL, BALL_SOCCER_1950_12_PANEL, BALL_SOCCER_1960_32_PANEL_LEATHER } from "./ball.soccer.vintage.js";
|
|
31
|
+
import { BALL_SOCCER_1970_BLACK_WHITE, BALL_SOCCER_1978_TRIAD, BALL_SOCCER_1986_DECORATED_TRIAD, BALL_SOCCER_1998_COLOURED_TRIAD, BALL_SOCCER_2002_TRIANGLE_SWEEP, BALL_SOCCER_2006_PROPELLER, BALL_SOCCER_2010_GROOVED, BALL_SOCCER_2014_RIBBON, BALL_SOCCER_2018_PIXEL, BALL_SOCCER_2022_SPEED_SHELL, BALL_SOCCER_TRAINING_HIGH_VIS } from "./ball.soccer.era.js";
|
|
32
|
+
import { BALL_SOCCER_STARS_BLUE, BALL_SOCCER_STARS_RED, BALL_SOCCER_STARS_NIGHT, BALL_SOCCER_HEXAGONS_CYAN, BALL_SOCCER_HEXAGONS_MAGENTA, BALL_SOCCER_HEXAGONS_LIME, BALL_SOCCER_FLAMES_FIRE, BALL_SOCCER_FLAMES_ICE, BALL_SOCCER_FLAMES_TOXIC, BALL_SOCCER_CHEVRONS_RED, BALL_SOCCER_CHEVRONS_GREEN, BALL_SOCCER_CHEVRONS_BLUE, BALL_SOCCER_SWIRL_BLUE, BALL_SOCCER_SWIRL_RED, BALL_SOCCER_SWIRL_TEAL, BALL_SOCCER_METALLIC_GOLD, BALL_SOCCER_METALLIC_SILVER, BALL_SOCCER_METALLIC_COBALT } from "./ball.soccer.store.js";
|
|
33
|
+
import { BALL_BASEBALL_LEMON_PEEL, BALL_BASEBALL_RED_BLUE, BALL_BASEBALL_BLACK_RED, BALL_BASEBALL_VINTAGE_LEATHER, BALL_SOFTBALL_11_OPTIC } from "./ball.baseball.vintage.js";
|
|
34
|
+
import { BALL_VOLLEYBALL_COLOURS, BALL_VOLLEYBALL_BRAZIL, BALL_VOLLEYBALL_JAPAN, BALL_VOLLEYBALL_CANADA, BALL_VOLLEYBALL_USA, BALL_VOLLEYBALL_ITALY, BALL_VOLLEYBALL_POLAND, BALL_VOLLEYBALL_FRANCE, BALL_VOLLEYBALL_SERBIA, BALL_VOLLEYBALL_NETHERLANDS, BALL_VOLLEYBALL_GERMANY } from "./ball.volleyball.flag.js";
|
|
30
35
|
import { BALL_SQUASH_DOUBLE_YELLOW, BALL_SQUASH_YELLOW, BALL_SQUASH_RED, BALL_SQUASH_BLUE, BALL_SQUASH_GREEN } from "./ball.squash.js";
|
|
31
36
|
import { BALL_TENNIS } from "./ball.tennis.js";
|
|
32
37
|
import { BALL_TEQBALL } from "./ball.teqball.js";
|
|
33
38
|
import { BALL_VOLLEYBALL, BALL_VOLLEYBALL_8, BALL_BEACH_VOLLEYBALL } from "./ball.volleyball.js";
|
|
34
39
|
import { BALL_WATER_POLO } from "./ball.waterpolo.js";
|
|
35
40
|
/** Every ball, in the order a gallery shows them. */
|
|
36
|
-
export const BALLS = [BALL_SOCCER, BALL_SOCCER_COLOUR, BALL_SOCCER_26, BALL_SOCCER_18, BALL_SOCCER_14, BALL_SOCCER_12, BALL_SOCCER_6, BALL_SOCCER_ORANGE, BALL_SOCCER_26_ORANGE, BALL_SOCCER_18_ORANGE, BALL_SOCCER_14_ORANGE, BALL_SOCCER_12_ORANGE, BALL_SOCCER_6_ORANGE, BALL_SOCCER_YELLOW, BALL_SOCCER_26_YELLOW, BALL_SOCCER_18_YELLOW, BALL_SOCCER_14_YELLOW, BALL_SOCCER_12_YELLOW, BALL_SOCCER_6_YELLOW, BALL_FUTSAL, BALL_BEACH_SOCCER, BALL_TEQBALL, BALL_BASKETBALL, BALL_BASKETBALL_6, BALL_BASKETBALL_3X3, BALL_BASEBALL, BALL_SOFTBALL, BALL_TENNIS, BALL_PADEL, BALL_SLIOTAR, BALL_VOLLEYBALL, BALL_VOLLEYBALL_8, BALL_BEACH_VOLLEYBALL, BALL_CRICKET_RED, BALL_CRICKET_WHITE, BALL_CRICKET_PINK, BALL_FOOTBALL, BALL_FOOTBALL_CFL, BALL_FOOTBALL_IFAF, BALL_RUGBY, BALL_AFL, BALL_GAELIC_FOOTBALL, BALL_NETBALL, BALL_PICKLEBALL_OUTDOOR, BALL_PICKLEBALL_INDOOR, BALL_SQUASH_DOUBLE_YELLOW, BALL_SQUASH_YELLOW, BALL_SQUASH_GREEN, BALL_SQUASH_RED, BALL_SQUASH_BLUE, BALL_RACQUETBALL, BALL_LACROSSE, BALL_FIELD_HOCKEY, BALL_TABLE_TENNIS, BALL_HANDBALL, BALL_WATER_POLO, BALL_GOLF, BALL_PUCK, BALL_CURLING_STONE, BALL_SHOT, BALL_DISCUS, BALL_HAMMER, BALL_SEPAK_TAKRAW, BALL_ROUNDNET, BALL_SHUTTLECOCK_FEATHER, BALL_SHUTTLECOCK_NYLON];
|
|
41
|
+
export const BALLS = [BALL_SOCCER, BALL_SOCCER_COLOUR, BALL_SOCCER_26, BALL_SOCCER_18, BALL_SOCCER_14, BALL_SOCCER_12, BALL_SOCCER_6, BALL_SOCCER_ORANGE, BALL_SOCCER_26_ORANGE, BALL_SOCCER_18_ORANGE, BALL_SOCCER_14_ORANGE, BALL_SOCCER_12_ORANGE, BALL_SOCCER_6_ORANGE, BALL_SOCCER_YELLOW, BALL_SOCCER_26_YELLOW, BALL_SOCCER_18_YELLOW, BALL_SOCCER_14_YELLOW, BALL_SOCCER_12_YELLOW, BALL_SOCCER_6_YELLOW, BALL_FUTSAL, BALL_BEACH_SOCCER, BALL_SOCCER_1870_HAND_STITCHED, BALL_SOCCER_1900_LACED, BALL_SOCCER_1930_18_PANEL, BALL_SOCCER_1950_12_PANEL, BALL_SOCCER_1960_32_PANEL_LEATHER, BALL_SOCCER_1970_BLACK_WHITE, BALL_SOCCER_1978_TRIAD, BALL_SOCCER_1986_DECORATED_TRIAD, BALL_SOCCER_1998_COLOURED_TRIAD, BALL_SOCCER_2002_TRIANGLE_SWEEP, BALL_SOCCER_2006_PROPELLER, BALL_SOCCER_2010_GROOVED, BALL_SOCCER_2014_RIBBON, BALL_SOCCER_2018_PIXEL, BALL_SOCCER_2022_SPEED_SHELL, BALL_SOCCER_TRAINING_HIGH_VIS, BALL_SOCCER_STARS_BLUE, BALL_SOCCER_STARS_RED, BALL_SOCCER_STARS_NIGHT, BALL_SOCCER_HEXAGONS_CYAN, BALL_SOCCER_HEXAGONS_MAGENTA, BALL_SOCCER_HEXAGONS_LIME, BALL_SOCCER_FLAMES_FIRE, BALL_SOCCER_FLAMES_ICE, BALL_SOCCER_FLAMES_TOXIC, BALL_SOCCER_CHEVRONS_RED, BALL_SOCCER_CHEVRONS_GREEN, BALL_SOCCER_CHEVRONS_BLUE, BALL_SOCCER_SWIRL_BLUE, BALL_SOCCER_SWIRL_RED, BALL_SOCCER_SWIRL_TEAL, BALL_SOCCER_METALLIC_GOLD, BALL_SOCCER_METALLIC_SILVER, BALL_SOCCER_METALLIC_COBALT, BALL_TEQBALL, BALL_BASKETBALL, BALL_BASKETBALL_6, BALL_BASKETBALL_3X3, BALL_BASEBALL, BALL_SOFTBALL, BALL_BASEBALL_LEMON_PEEL, BALL_BASEBALL_RED_BLUE, BALL_BASEBALL_BLACK_RED, BALL_BASEBALL_VINTAGE_LEATHER, BALL_SOFTBALL_11_OPTIC, BALL_TENNIS, BALL_PADEL, BALL_SLIOTAR, BALL_VOLLEYBALL, BALL_VOLLEYBALL_8, BALL_BEACH_VOLLEYBALL, BALL_VOLLEYBALL_COLOURS, BALL_VOLLEYBALL_BRAZIL, BALL_VOLLEYBALL_JAPAN, BALL_VOLLEYBALL_CANADA, BALL_VOLLEYBALL_USA, BALL_VOLLEYBALL_ITALY, BALL_VOLLEYBALL_POLAND, BALL_VOLLEYBALL_FRANCE, BALL_VOLLEYBALL_SERBIA, BALL_VOLLEYBALL_NETHERLANDS, BALL_VOLLEYBALL_GERMANY, BALL_CRICKET_RED, BALL_CRICKET_WHITE, BALL_CRICKET_PINK, BALL_FOOTBALL, BALL_FOOTBALL_CFL, BALL_FOOTBALL_IFAF, BALL_RUGBY, BALL_AFL, BALL_GAELIC_FOOTBALL, BALL_NETBALL, BALL_PICKLEBALL_OUTDOOR, BALL_PICKLEBALL_INDOOR, BALL_SQUASH_DOUBLE_YELLOW, BALL_SQUASH_YELLOW, BALL_SQUASH_GREEN, BALL_SQUASH_RED, BALL_SQUASH_BLUE, BALL_RACQUETBALL, BALL_LACROSSE, BALL_FIELD_HOCKEY, BALL_TABLE_TENNIS, BALL_HANDBALL, BALL_WATER_POLO, BALL_GOLF, BALL_PUCK, BALL_CURLING_STONE, BALL_SHOT, BALL_DISCUS, BALL_HAMMER, BALL_SEPAK_TAKRAW, BALL_ROUNDNET, BALL_SHUTTLECOCK_FEATHER, BALL_SHUTTLECOCK_NYLON];
|
|
37
42
|
/** The id of every ball: `"ball:soccer"`, `"ball:cricket-red"`. */
|
|
38
43
|
export const BALL_IDS = BALLS.map((b) => b.id);
|
|
39
44
|
const TABLE = new Map([...BALLS, ...PUCKS].map((b) => [b.id, b]));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type BallSpec } from "./ball.engine.ts";
|
|
2
|
+
/** The 1970s: twelve black pentagons with a white ring round a small boss, and twenty white hexagons that each hold a pale dished hexagon and a dot. */
|
|
3
|
+
export declare const BALL_SOCCER_1970_BLACK_WHITE: import("./ball.core.ts").Piece<BallSpec>;
|
|
4
|
+
/** The late 1970s: a pinwheel of three bold curved triangles on each of the twenty hexagons, black on white; their points meet round each of the twelve pentagons. */
|
|
5
|
+
export declare const BALL_SOCCER_1978_TRIAD: import("./ball.core.ts").Piece<BallSpec>;
|
|
6
|
+
/** The 1980s: the same triads in a warm clay, each blade ornamented with a row of white beads along its spine, and gold-ringed dark pentagons. */
|
|
7
|
+
export declare const BALL_SOCCER_1986_DECORATED_TRIAD: import("./ball.core.ts").Piece<BallSpec>;
|
|
8
|
+
/** The 1990s: the triads in three colours (blue, red and gold) on a white ground, with deep navy pentagons. */
|
|
9
|
+
export declare const BALL_SOCCER_1998_COLOURED_TRIAD: import("./ball.core.ts").Piece<BallSpec>;
|
|
10
|
+
/** The early 2000s: long thin triangles that sweep across each hexagon from one side to the next, in graphite and gold, with a red spark, over charcoal pentagons. */
|
|
11
|
+
export declare const BALL_SOCCER_2002_TRIANGLE_SWEEP: import("./ball.core.ts").Piece<BallSpec>;
|
|
12
|
+
/** The mid 2000s: the 14-panel propeller layout (six propellers and eight triangles), with a fine line following each curved seam inside the panel, and a small ring on each triangle. */
|
|
13
|
+
export declare const BALL_SOCCER_2006_PROPELLER: import("./ball.core.ts").Piece<BallSpec>;
|
|
14
|
+
/** The early 2010s: the 8-panel layout, an octahedron whose edges are bent into S curves, with grooves for seams and fine contour lines across each panel. */
|
|
15
|
+
export declare const BALL_SOCCER_2010_GROOVED: import("./ball.core.ts").Piece<BallSpec>;
|
|
16
|
+
/** The mid 2010s: six twisted panels in white, crossed by wide ribbons that swirl round the ball in teal, orange and violet. */
|
|
17
|
+
export declare const BALL_SOCCER_2014_RIBBON: import("./ball.core.ts").Piece<BallSpec>;
|
|
18
|
+
/** The late 2010s: six panels covered with square pixel blocks, thick where the ball is dark and thinning out toward the lighter side. */
|
|
19
|
+
export declare const BALL_SOCCER_2018_PIXEL: import("./ball.core.ts").Piece<BallSpec>;
|
|
20
|
+
/** The early 2020s: twenty triangles (an icosahedron) in three warm tones, each carrying a shell of nested edges and a trail of speed lines. */
|
|
21
|
+
export declare const BALL_SOCCER_2022_SPEED_SHELL: import("./ball.core.ts").Piece<BallSpec>;
|
|
22
|
+
/** A modern high-visibility training ball: 32 panels in fluorescent yellow-green, hot pink pentagons ringed in black, and three dark speed marks across each hexagon. */
|
|
23
|
+
export declare const BALL_SOCCER_TRAINING_HIGH_VIS: import("./ball.core.ts").Piece<BallSpec>;
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
// Soccer balls in the style of an era's match balls, each on the construction of its time and with graphics of our own that only evoke the period: the black and white 32 panels of the early 1970s, curved
|
|
2
|
+
// triangles in threes (late 1970s, 1980s and 1990s), a triangular sweep, the 14-panel propeller, the 8-panel grooved ball, 6 panels with ribbons, pixel blocks, 20 panels with a shell of lines, and a modern
|
|
3
|
+
// high-visibility training ball. The panel counts are facts of the constructions (docs/references.md); the drawings are not the real balls' and use none of their marks, names or patterns.
|
|
4
|
+
import { defineBall } from "./ball.engine.js";
|
|
5
|
+
import { mix } from "./ball.core.js";
|
|
6
|
+
import { frameAt, noise, place, spiral, tongue, turned } from "./ball.decal.js";
|
|
7
|
+
import { shrink, truncatedIcosahedron } from "./ball.polyhedra.js";
|
|
8
|
+
import { gorePoint, gores, icosahedron, octahedron8, propellers14 } from "./ball.tilings.js";
|
|
9
|
+
import { SOCCER_SIZE } from "./ball.soccer.size.js";
|
|
10
|
+
const INK = "#1b1d22";
|
|
11
|
+
const WHITE = "#f8f8f6";
|
|
12
|
+
const GREY = "#6b7180";
|
|
13
|
+
const VIEW = { yaw: 30, pitch: 24, roll: 8 };
|
|
14
|
+
const GLOSS = { gloss: 0.8, shade: "#2a3450", grain: { f: 1.1, a: 0.16 } };
|
|
15
|
+
/** The highlight laid on a seam, so that it reads as a raised edge. */
|
|
16
|
+
const lit = (s, seams, width = 0.45) => s.strokes(seams, "#fff", width, { deco: true, opacity: 0.45, dx: 0.3, dy: 0.35 });
|
|
17
|
+
const ball = (id, en, ja, spec) => defineBall({ id, en, ja, size: SOCCER_SIZE, spec });
|
|
18
|
+
/** What lies on the 32 panels: a frame at the middle of each hexagon, with x toward one of the three sides it shares with a pentagon. */
|
|
19
|
+
const hexFrames = (t) => t.hexagonCentres.map((c, i) => frameAt(c, t.hexagonPentagonSides[i][0]));
|
|
20
|
+
/** Three curved blades in a pinwheel about the middle of a hexagon (a triad): each is a leaf along a spiral, `sweep` radians of turn, `w` wide. */
|
|
21
|
+
const triad = (r0, r1, sweep, w, start = 0.5) => [0, 1, 2].map((k) => tongue(spiral(r0, r1, start + (2 * Math.PI * k) / 3, sweep), (u) => w * Math.min(1, u * 5) * (1 - u) ** 0.7, 5));
|
|
22
|
+
/** The hexagons of a 32-panel ball carrying a triad each, over a ground; `colours` has one fill for each blade. */
|
|
23
|
+
function laidTriads(s, t, frames, blades, colours, edge, ew = 0.5) {
|
|
24
|
+
let out = "";
|
|
25
|
+
for (let k = 0; k < blades.length; k++)
|
|
26
|
+
out += s.panels(frames.map((f) => place(f, blades[k])), colours[k % colours.length], { n: 1 });
|
|
27
|
+
// The colour drawing is filled and needs no outline; the line drawing is the outline alone.
|
|
28
|
+
if (s.line) {
|
|
29
|
+
const rings = [];
|
|
30
|
+
for (const f of frames)
|
|
31
|
+
for (const b of blades)
|
|
32
|
+
rings.push(place(f, b));
|
|
33
|
+
out += s.strokes(rings, edge, ew, { closed: true });
|
|
34
|
+
}
|
|
35
|
+
void t;
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
/** The 1970s: twelve black pentagons with a white ring round a small boss, and twenty white hexagons that each hold a pale dished hexagon and a dot. */
|
|
39
|
+
export const BALL_SOCCER_1970_BLACK_WHITE = /* @__PURE__ */ ball("ball:soccer-1970-black-white", "Soccer, 1970s black-white", "70年代風・白黒", {
|
|
40
|
+
view: VIEW,
|
|
41
|
+
base: INK,
|
|
42
|
+
ground: WHITE,
|
|
43
|
+
mat: GLOSS,
|
|
44
|
+
draw(s, base, accent) {
|
|
45
|
+
const t = truncatedIcosahedron();
|
|
46
|
+
let out = "";
|
|
47
|
+
t.hexagons.forEach((h, i) => {
|
|
48
|
+
out += s.panel(shrink(h, t.hexagonCentres[i], 0.5), accent ?? "#e4e5e1", { n: 2 });
|
|
49
|
+
});
|
|
50
|
+
for (const p of t.pentagons)
|
|
51
|
+
out += s.panel(p, base, { ink: true });
|
|
52
|
+
t.pentagons.forEach((p, i) => {
|
|
53
|
+
out += s.strokes([shrink(p, t.pentagonCentres[i], 0.45)], "#fff", 0.5, { closed: true, deco: true, opacity: 0.85 });
|
|
54
|
+
});
|
|
55
|
+
out += s.dots(t.hexagonCentres, 0.03, base, { light: false });
|
|
56
|
+
out += s.strokes(t.edges, GREY, 1.15);
|
|
57
|
+
return out + lit(s, t.edges);
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
/** The late 1970s: a pinwheel of three bold curved triangles on each of the twenty hexagons, black on white; their points meet round each of the twelve pentagons. */
|
|
61
|
+
export const BALL_SOCCER_1978_TRIAD = /* @__PURE__ */ ball("ball:soccer-1978-triad", "Soccer, late-1970s triads", "70年代後期風・三つ巴", {
|
|
62
|
+
view: VIEW,
|
|
63
|
+
base: INK,
|
|
64
|
+
ground: WHITE,
|
|
65
|
+
mat: GLOSS,
|
|
66
|
+
draw(s, base) {
|
|
67
|
+
const t = truncatedIcosahedron();
|
|
68
|
+
let out = laidTriads(s, t, hexFrames(t), triad(0.0, 0.32, -0.85, 0.17, 0.3), [base], base, 0.4);
|
|
69
|
+
out += s.strokes(t.edges, mix(base, 0.45), 0.8);
|
|
70
|
+
return out + lit(s, t.edges, 0.4);
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
/** The 1980s: the same triads in a warm clay, each blade ornamented with a row of white beads along its spine, and gold-ringed dark pentagons. */
|
|
74
|
+
export const BALL_SOCCER_1986_DECORATED_TRIAD = /* @__PURE__ */ ball("ball:soccer-1986-decorated-triad", "Soccer, decorated triads", "80年代風・飾り三つ巴", {
|
|
75
|
+
view: VIEW,
|
|
76
|
+
base: "#c4563a",
|
|
77
|
+
ground: WHITE,
|
|
78
|
+
mat: GLOSS,
|
|
79
|
+
draw(s, base, accent) {
|
|
80
|
+
const t = truncatedIcosahedron();
|
|
81
|
+
const hf = hexFrames(t);
|
|
82
|
+
const gold = accent ?? "#e0a526";
|
|
83
|
+
let out = "";
|
|
84
|
+
for (const p of t.pentagons)
|
|
85
|
+
out += s.panel(p, "#3a2a2c", { ink: true });
|
|
86
|
+
t.pentagons.forEach((p, i) => {
|
|
87
|
+
out += s.strokes([shrink(p, t.pentagonCentres[i], 0.4)], gold, 0.6, { closed: true, deco: true });
|
|
88
|
+
});
|
|
89
|
+
out += laidTriads(s, t, hf, triad(0.0, 0.31, -0.85, 0.16, 0.3), [base], mix(base, -0.45), 0.5);
|
|
90
|
+
const spines = [];
|
|
91
|
+
for (const f of hf)
|
|
92
|
+
for (let k = 0; k < 3; k++)
|
|
93
|
+
spines.push(Array.from({ length: 6 }, (_, j) => f(...spiral(0.06, 0.26, 0.3 + (2 * Math.PI * k) / 3, -0.85)(j / 5))));
|
|
94
|
+
out += s.strokes(spines, "#fff7e6", 1.1, { dash: "0 2.3", deco: true });
|
|
95
|
+
return out + s.strokes(t.edges, mix(base, -0.5), 1);
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
/** The 1990s: the triads in three colours (blue, red and gold) on a white ground, with deep navy pentagons. */
|
|
99
|
+
export const BALL_SOCCER_1998_COLOURED_TRIAD = /* @__PURE__ */ ball("ball:soccer-1998-coloured-triad", "Soccer, coloured triads", "90年代風・色つき三つ巴", {
|
|
100
|
+
view: VIEW,
|
|
101
|
+
base: "#1e56b8",
|
|
102
|
+
ground: WHITE,
|
|
103
|
+
mat: GLOSS,
|
|
104
|
+
draw(s, base, accent) {
|
|
105
|
+
const t = truncatedIcosahedron();
|
|
106
|
+
let out = "";
|
|
107
|
+
for (const p of t.pentagons)
|
|
108
|
+
out += s.panel(p, mix(base, -0.55), { ink: true });
|
|
109
|
+
out += laidTriads(s, t, hexFrames(t), triad(0.0, 0.31, 0.9, 0.16, 0.2), [base, "#d8322f", accent ?? "#f2bf1b"], "#ffffff", 0.35);
|
|
110
|
+
out += s.strokes(t.edges, GREY, 0.9);
|
|
111
|
+
return out + lit(s, t.edges, 0.4);
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
/** The early 2000s: long thin triangles that sweep across each hexagon from one side to the next, in graphite and gold, with a red spark, over charcoal pentagons. */
|
|
115
|
+
export const BALL_SOCCER_2002_TRIANGLE_SWEEP = /* @__PURE__ */ ball("ball:soccer-2002-triangle-sweep", "Soccer, triangle sweep", "00年代風・三角の流れ", {
|
|
116
|
+
view: VIEW,
|
|
117
|
+
base: "#4a4f5c",
|
|
118
|
+
ground: "#f3efe4",
|
|
119
|
+
mat: GLOSS,
|
|
120
|
+
draw(s, base, accent) {
|
|
121
|
+
const t = truncatedIcosahedron();
|
|
122
|
+
const gold = accent ?? "#d9a420";
|
|
123
|
+
let out = "";
|
|
124
|
+
for (const p of t.pentagons)
|
|
125
|
+
out += s.panel(p, mix(base, -0.45), { ink: true });
|
|
126
|
+
const big = [[0.3, -0.03], [0.02, 0.2], [-0.05, 0.04]];
|
|
127
|
+
const small = [[0.27, 0.035], [0.12, 0.16], [0.1, 0.07]];
|
|
128
|
+
const frames = hexFrames(t);
|
|
129
|
+
const turns = [0, 1, 2].map((k) => (2 * Math.PI * k) / 3);
|
|
130
|
+
out += s.panels(frames.flatMap((f) => turns.map((a) => place(f, turned(big, a)))), base, { n: 1 });
|
|
131
|
+
out += s.panels(frames.flatMap((f) => turns.map((a) => place(f, turned(small, a + 0.1)))), gold, { n: 1 });
|
|
132
|
+
out += s.strokes(t.edges, GREY, 0.9);
|
|
133
|
+
return out + lit(s, t.edges, 0.4);
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
/** The mid 2000s: the 14-panel propeller layout (six propellers and eight triangles), with a fine line following each curved seam inside the panel, and a small ring on each triangle. */
|
|
137
|
+
export const BALL_SOCCER_2006_PROPELLER = /* @__PURE__ */ ball("ball:soccer-2006-propeller", "Soccer, 14-panel propeller", "14枚貼り・プロペラ形", {
|
|
138
|
+
view: { yaw: 40, pitch: 36, roll: 0 },
|
|
139
|
+
base: "#1f232b",
|
|
140
|
+
ground: "#f4f2ea",
|
|
141
|
+
mat: GLOSS,
|
|
142
|
+
draw(s, base, accent) {
|
|
143
|
+
const g = propellers14();
|
|
144
|
+
const gold = accent ?? "#c9962b";
|
|
145
|
+
let out = "";
|
|
146
|
+
for (const p of g.triangles)
|
|
147
|
+
out += s.panel(p, base, { n: 6, ink: true });
|
|
148
|
+
g.triangles.forEach((p, i) => {
|
|
149
|
+
out += s.panel(shrink(p, g.triangleCentres[i], 0.55), gold, { n: 4 });
|
|
150
|
+
});
|
|
151
|
+
// A line a little inside each propeller, following its seam.
|
|
152
|
+
g.propellers.forEach((p, i) => {
|
|
153
|
+
out += s.strokes([shrink(p, g.propellerCentres[i], 0.16).filter((_, j) => j % 2 === 0)], gold, 0.55, { closed: true, deco: true, opacity: 0.95 });
|
|
154
|
+
});
|
|
155
|
+
out += s.strokes(g.seams, "#3a3f4a", 1.4);
|
|
156
|
+
return out + lit(s, g.seams);
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
/** The early 2010s: the 8-panel layout, an octahedron whose edges are bent into S curves, with grooves for seams and fine contour lines across each panel. */
|
|
160
|
+
export const BALL_SOCCER_2010_GROOVED = /* @__PURE__ */ ball("ball:soccer-2010-grooved", "Soccer, 8-panel grooved", "8枚貼り・溝つき", {
|
|
161
|
+
view: { yaw: 32, pitch: 26, roll: 0 },
|
|
162
|
+
base: "#e9ecee",
|
|
163
|
+
ground: "#eceff0",
|
|
164
|
+
mat: { gloss: 0.7, shade: "#33404c", grain: { f: 1.6, a: 0.2 } },
|
|
165
|
+
draw(s, base, accent) {
|
|
166
|
+
const g = octahedron8();
|
|
167
|
+
const tone = [base, accent ?? "#cfe3d6"];
|
|
168
|
+
let out = "";
|
|
169
|
+
g.panels.forEach((p, i) => {
|
|
170
|
+
if (g.parity[i] === 1)
|
|
171
|
+
out += s.panel(p, tone[1], { n: 1 });
|
|
172
|
+
});
|
|
173
|
+
const groove = "#3f4b57";
|
|
174
|
+
g.panels.forEach((p, i) => {
|
|
175
|
+
out += s.strokes([shrink(p, g.centres[i], 0.4).filter((_, j) => j % 2 === 0)], groove, 0.35, { closed: true, deco: true, opacity: 0.6 });
|
|
176
|
+
});
|
|
177
|
+
out += s.strokes(g.seams, groove, 1.8);
|
|
178
|
+
out += s.strokes(g.seams, "#fff", 0.55, { deco: true, opacity: 0.55, dx: 0.5, dy: 0.55 });
|
|
179
|
+
return out;
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
/** The six gores of the thermobonded layout (see ball.soccer.panels.ts), for the layers drawn on them: only the gores whose tone is not the ground's are painted. */
|
|
183
|
+
function sixGores(s, tilt, tone, twist = 180) {
|
|
184
|
+
const g = gores(6, twist, tilt);
|
|
185
|
+
let out = "";
|
|
186
|
+
for (const { ring, gore } of g.pieces) {
|
|
187
|
+
if (gore % 3 !== 1)
|
|
188
|
+
continue;
|
|
189
|
+
out += s.panel(ring, tone, { n: 1 });
|
|
190
|
+
out += s.strokes([ring], tone, 0.5, { closed: true, deco: true });
|
|
191
|
+
}
|
|
192
|
+
return { g, out };
|
|
193
|
+
}
|
|
194
|
+
/** The mid 2010s: six twisted panels in white, crossed by wide ribbons that swirl round the ball in teal, orange and violet. */
|
|
195
|
+
export const BALL_SOCCER_2014_RIBBON = /* @__PURE__ */ ball("ball:soccer-2014-ribbon", "Soccer, 6-panel ribbons", "6枚貼り・リボン柄", {
|
|
196
|
+
view: { yaw: 20, pitch: 22, roll: 0 },
|
|
197
|
+
base: "#14a7a0",
|
|
198
|
+
ground: "#f5f5f1",
|
|
199
|
+
mat: { gloss: 0.9, shade: "#2a3450", grain: { f: 0.7, a: 0.07 } },
|
|
200
|
+
draw(s, base, accent) {
|
|
201
|
+
const { g, out: panels } = sixGores(s, [0, 0, 28], "#ebebe5");
|
|
202
|
+
const at = gorePoint(6, 180, [0, 0, 28]);
|
|
203
|
+
const cols = [base, accent ?? "#f08a24", "#7a4bc2"];
|
|
204
|
+
let out = panels;
|
|
205
|
+
// Three ribbons on a gore, spiralling: each is a leaf whose spine follows a curve across the gore.
|
|
206
|
+
for (let i = 0; i < 6; i++) {
|
|
207
|
+
for (let k = 0; k < 2; k++) {
|
|
208
|
+
const c = cols[(i + k) % 3];
|
|
209
|
+
const left = [];
|
|
210
|
+
const right = [];
|
|
211
|
+
const s0 = -0.75 + k * 0.7 + (i % 2) * 0.12;
|
|
212
|
+
for (let j = 0; j <= 10; j++) {
|
|
213
|
+
const u = j / 10;
|
|
214
|
+
const lat = s0 + 0.5 * u;
|
|
215
|
+
const w = 0.1 + 0.16 * Math.sin(Math.PI * u) ** 0.8;
|
|
216
|
+
left.push(at(i, 0.12 + 0.76 * u, lat));
|
|
217
|
+
right.push(at(i, 0.12 + 0.76 * u, lat + w));
|
|
218
|
+
}
|
|
219
|
+
out += s.panel([...left, ...right.reverse()], c, { n: 1 });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
out += s.strokes(g.seams, GREY, 0.85);
|
|
223
|
+
return out + lit(s, g.seams, 0.5);
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
/** The late 2010s: six panels covered with square pixel blocks, thick where the ball is dark and thinning out toward the lighter side. */
|
|
227
|
+
export const BALL_SOCCER_2018_PIXEL = /* @__PURE__ */ ball("ball:soccer-2018-pixel", "Soccer, pixel blocks", "ピクセル柄", {
|
|
228
|
+
view: { yaw: 20, pitch: 22, roll: 0 },
|
|
229
|
+
base: "#2a2f3a",
|
|
230
|
+
ground: "#f2f2ee",
|
|
231
|
+
mat: { gloss: 0.9, shade: "#2a3450", grain: { f: 0.7, a: 0.07 } },
|
|
232
|
+
draw(s, base, accent) {
|
|
233
|
+
const { g, out: panels } = sixGores(s, [0, 0, 28], "#e7e7e1", 90);
|
|
234
|
+
const pal = [base, mix(base, 0.4), accent ?? "#d4472f", "#e6b53a", mix(base, 0.4)];
|
|
235
|
+
let out = panels;
|
|
236
|
+
const groups = pal.map(() => []);
|
|
237
|
+
const rows = 17, cols = 34;
|
|
238
|
+
for (let r = 1; r < rows - 1; r++) {
|
|
239
|
+
for (let c = 0; c < cols; c++) {
|
|
240
|
+
const lon = (2 * Math.PI * c) / cols, lat = Math.PI * (r / rows - 0.5);
|
|
241
|
+
// Dense on one side (longitude near 0.8 turns), a few scattered elsewhere.
|
|
242
|
+
const band = Math.cos(lon - 3.2 * lat - 4.1);
|
|
243
|
+
const density = band > 0 ? 0.04 + 0.8 * band ** 0.9 : 0.02;
|
|
244
|
+
if (noise(r, c) > density)
|
|
245
|
+
continue;
|
|
246
|
+
const d = (Math.PI / cols) * 1.7, e = (Math.PI / rows) * 0.85;
|
|
247
|
+
const corner = (a, b) => [Math.sin(lon + a) * Math.cos(lat + b), Math.sin(lat + b), Math.cos(lon + a) * Math.cos(lat + b)];
|
|
248
|
+
const k = Math.floor(noise(c, r + 50) * pal.length);
|
|
249
|
+
groups[k].push([corner(0, 0), corner(d, 0), corner(d, e), corner(0, e)]);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
pal.forEach((c, k) => {
|
|
253
|
+
out += s.panels(groups[k], c, { n: 1, ink: k === 0 });
|
|
254
|
+
});
|
|
255
|
+
out += s.strokes(g.seams, GREY, 0.85);
|
|
256
|
+
return out + lit(s, g.seams, 0.5);
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
/** The early 2020s: twenty triangles (an icosahedron) in three warm tones, each carrying a shell of nested edges and a trail of speed lines. */
|
|
260
|
+
export const BALL_SOCCER_2022_SPEED_SHELL = /* @__PURE__ */ ball("ball:soccer-2022-speed-shell", "Soccer, 20-panel shell", "20枚貼り・貝殻柄", {
|
|
261
|
+
view: { yaw: 30, pitch: 24, roll: 8 },
|
|
262
|
+
base: "#8c1d3b",
|
|
263
|
+
ground: "#f1ece0",
|
|
264
|
+
mat: GLOSS,
|
|
265
|
+
draw(s, base, accent) {
|
|
266
|
+
const g = icosahedron();
|
|
267
|
+
const gold = accent ?? "#d9a93a";
|
|
268
|
+
const fill = [mix(base, 0.0), "#f1ece0", gold, mix(base, 0.35)];
|
|
269
|
+
let out = "";
|
|
270
|
+
fill.forEach((c, k) => {
|
|
271
|
+
out += s.panels(g.panels.filter((_, i) => g.colour[i] === k), c, { n: 4, ink: k === 0 });
|
|
272
|
+
});
|
|
273
|
+
g.panels.forEach((p, i) => {
|
|
274
|
+
const inner = g.colour[i] === 0 ? "#f1ece0" : base;
|
|
275
|
+
for (const k of [0.3, 0.58])
|
|
276
|
+
out += s.strokes([shrink(p, g.centres[i], k)], inner, 0.45, { closed: true, deco: true, opacity: 0.85 });
|
|
277
|
+
});
|
|
278
|
+
out += s.strokes(g.seams, mix(base, -0.5), 1.1);
|
|
279
|
+
return out + lit(s, g.seams);
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
/** A modern high-visibility training ball: 32 panels in fluorescent yellow-green, hot pink pentagons ringed in black, and three dark speed marks across each hexagon. */
|
|
283
|
+
export const BALL_SOCCER_TRAINING_HIGH_VIS = /* @__PURE__ */ ball("ball:soccer-training-high-vis", "Soccer, high-vis training", "蛍光トレーニングボール", {
|
|
284
|
+
view: VIEW,
|
|
285
|
+
base: "#ff2f7d",
|
|
286
|
+
ground: "#d8f21f",
|
|
287
|
+
mat: { gloss: 0.7, shade: "#3a5010", grain: { f: 1.3, a: 0.2 } },
|
|
288
|
+
draw(s, base, accent) {
|
|
289
|
+
const t = truncatedIcosahedron();
|
|
290
|
+
let out = "";
|
|
291
|
+
for (const p of t.pentagons)
|
|
292
|
+
out += s.panel(p, base, { ink: true });
|
|
293
|
+
t.pentagons.forEach((p, i) => {
|
|
294
|
+
out += s.strokes([shrink(p, t.pentagonCentres[i], 0.4)], accent ?? INK, 0.7, { closed: true, deco: true });
|
|
295
|
+
});
|
|
296
|
+
const dash = [[-0.1, -0.06], [0.1, -0.06], [0.1, -0.035], [-0.1, -0.035]];
|
|
297
|
+
const moved = dash.map(([x, y]) => [x + 0.05, y - 0.04]);
|
|
298
|
+
out += s.panels(hexFrames(t).flatMap((f) => [0, 1, 2].map((k) => place(f, turned(moved, (2 * Math.PI * k) / 3 + 0.5)))), accent ?? INK, { n: 1 });
|
|
299
|
+
out += s.strokes(t.edges, "#6d8a10", 1.1);
|
|
300
|
+
return out + lit(s, t.edges);
|
|
301
|
+
},
|
|
302
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type BallSpec } from "./ball.engine.ts";
|
|
2
|
+
export declare const BALL_SOCCER_STARS_BLUE: import("./ball.core.ts").Piece<BallSpec>;
|
|
3
|
+
export declare const BALL_SOCCER_STARS_RED: import("./ball.core.ts").Piece<BallSpec>;
|
|
4
|
+
export declare const BALL_SOCCER_STARS_NIGHT: import("./ball.core.ts").Piece<BallSpec>;
|
|
5
|
+
export declare const BALL_SOCCER_HEXAGONS_CYAN: import("./ball.core.ts").Piece<BallSpec>;
|
|
6
|
+
export declare const BALL_SOCCER_HEXAGONS_MAGENTA: import("./ball.core.ts").Piece<BallSpec>;
|
|
7
|
+
export declare const BALL_SOCCER_HEXAGONS_LIME: import("./ball.core.ts").Piece<BallSpec>;
|
|
8
|
+
export declare const BALL_SOCCER_FLAMES_FIRE: import("./ball.core.ts").Piece<BallSpec>;
|
|
9
|
+
export declare const BALL_SOCCER_FLAMES_ICE: import("./ball.core.ts").Piece<BallSpec>;
|
|
10
|
+
export declare const BALL_SOCCER_FLAMES_TOXIC: import("./ball.core.ts").Piece<BallSpec>;
|
|
11
|
+
export declare const BALL_SOCCER_CHEVRONS_RED: import("./ball.core.ts").Piece<BallSpec>;
|
|
12
|
+
export declare const BALL_SOCCER_CHEVRONS_GREEN: import("./ball.core.ts").Piece<BallSpec>;
|
|
13
|
+
export declare const BALL_SOCCER_CHEVRONS_BLUE: import("./ball.core.ts").Piece<BallSpec>;
|
|
14
|
+
export declare const BALL_SOCCER_SWIRL_BLUE: import("./ball.core.ts").Piece<BallSpec>;
|
|
15
|
+
export declare const BALL_SOCCER_SWIRL_RED: import("./ball.core.ts").Piece<BallSpec>;
|
|
16
|
+
export declare const BALL_SOCCER_SWIRL_TEAL: import("./ball.core.ts").Piece<BallSpec>;
|
|
17
|
+
export declare const BALL_SOCCER_METALLIC_GOLD: import("./ball.core.ts").Piece<BallSpec>;
|
|
18
|
+
export declare const BALL_SOCCER_METALLIC_SILVER: import("./ball.core.ts").Piece<BallSpec>;
|
|
19
|
+
export declare const BALL_SOCCER_METALLIC_COBALT: import("./ball.core.ts").Piece<BallSpec>;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// Generic patterns of the kind a sports shop has on its wall, each in three colourways: stars, hexagon outlines, flames, chevrons, a two-tone swirl and a metallic glossy finish. Every pattern is our own
|
|
2
|
+
// drawing on a construction of the family (the 32 panels, or gores that run from pole to pole), and the balls are the size of an 11-a-side ball (IFAB Law 2). No logo, no brand, no team.
|
|
3
|
+
import { defineBall } from "./ball.engine.js";
|
|
4
|
+
import { mix } from "./ball.core.js";
|
|
5
|
+
import { frameAt, place, spiral, star, tongue, turned } from "./ball.decal.js";
|
|
6
|
+
import { shrink, truncatedIcosahedron } from "./ball.polyhedra.js";
|
|
7
|
+
import { gorePoint, gores } from "./ball.tilings.js";
|
|
8
|
+
import { SOCCER_SIZE } from "./ball.soccer.size.js";
|
|
9
|
+
const VIEW = { yaw: 30, pitch: 24, roll: 8 };
|
|
10
|
+
const GLOSS = { gloss: 0.8, shade: "#2a3450", grain: { f: 1.1, a: 0.16 } };
|
|
11
|
+
const lit = (s, seams, width = 0.45) => s.strokes(seams, "#fff", width, { deco: true, opacity: 0.45, dx: 0.3, dy: 0.35 });
|
|
12
|
+
const ball = (id, en, ja, spec) => defineBall({ id, en, ja, size: SOCCER_SIZE, spec });
|
|
13
|
+
// Stars: a five-pointed star on every panel, on a white or a night-blue ground.
|
|
14
|
+
const stars = (w) => ({
|
|
15
|
+
view: VIEW,
|
|
16
|
+
base: w.main,
|
|
17
|
+
ground: w.ground,
|
|
18
|
+
mat: GLOSS,
|
|
19
|
+
draw(s, base, accent) {
|
|
20
|
+
const t = truncatedIcosahedron();
|
|
21
|
+
const dark = accent ?? w.dark;
|
|
22
|
+
let out = "";
|
|
23
|
+
for (const p of t.pentagons)
|
|
24
|
+
out += s.panel(p, dark, { ink: true });
|
|
25
|
+
const big = star(5, 0.2, 0.09);
|
|
26
|
+
const small = star(5, 0.12, 0.054);
|
|
27
|
+
out += s.panels([
|
|
28
|
+
...t.hexagonCentres.map((c, i) => place(frameAt(c, t.hexagonPentagonSides[i][0]), turned(big, 0.35))),
|
|
29
|
+
...t.pentagonCentres.map((c, i) => place(frameAt(c, t.pentagons[i][0]), small)),
|
|
30
|
+
], base, { n: 1 });
|
|
31
|
+
out += s.strokes(t.edges, mix(dark, 0.2), 1.05);
|
|
32
|
+
return out + lit(s, t.edges);
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
// Hexagon outlines: two outlines inside each hexagon, one inside the other, like a honeycomb; the pentagons are solid.
|
|
36
|
+
const hexagons = (w) => ({
|
|
37
|
+
view: VIEW,
|
|
38
|
+
base: w.main,
|
|
39
|
+
ground: w.ground,
|
|
40
|
+
mat: GLOSS,
|
|
41
|
+
draw(s, base, accent) {
|
|
42
|
+
const t = truncatedIcosahedron();
|
|
43
|
+
const dark = accent ?? w.dark;
|
|
44
|
+
let out = "";
|
|
45
|
+
for (const p of t.pentagons)
|
|
46
|
+
out += s.panel(p, dark, { ink: true });
|
|
47
|
+
t.hexagons.forEach((h, i) => {
|
|
48
|
+
out += s.strokes([shrink(h, t.hexagonCentres[i], 0.28), shrink(h, t.hexagonCentres[i], 0.58)], base, 1.1, { closed: true });
|
|
49
|
+
});
|
|
50
|
+
out += s.strokes(t.edges, mix(dark, 0.2), 1.1);
|
|
51
|
+
return out + lit(s, t.edges);
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
// Flames: five tongues of flame leave each dark pentagon, an outer one and a lighter inner one.
|
|
55
|
+
const flames = (w, inner) => ({
|
|
56
|
+
view: VIEW,
|
|
57
|
+
base: w.main,
|
|
58
|
+
ground: w.ground,
|
|
59
|
+
mat: GLOSS,
|
|
60
|
+
draw(s, base, accent) {
|
|
61
|
+
const t = truncatedIcosahedron();
|
|
62
|
+
const core = accent ?? inner;
|
|
63
|
+
let out = "";
|
|
64
|
+
for (const p of t.pentagons)
|
|
65
|
+
out += s.panel(p, w.dark, { ink: true });
|
|
66
|
+
const flame = (r0, r1, a, wd) => tongue(spiral(r0, r1, a, 0.75), (u) => wd * Math.min(1, u * 6 + 0.3) * (1 - u) ** 0.75, 3);
|
|
67
|
+
const frames = t.pentagonCentres.map((c, i) => frameAt(c, t.pentagons[i][0]));
|
|
68
|
+
const rings = (r0, r1, da, wd) => frames.flatMap((f) => [0, 1, 2, 3, 4].map((k) => place(f, flame(r0, r1, Math.PI / 5 + (2 * Math.PI * k) / 5 + da, wd))));
|
|
69
|
+
out += s.panels(rings(0.19, 0.64, -0.1, 0.125), base, { n: 1 });
|
|
70
|
+
out += s.panels(rings(0.21, 0.45, -0.03, 0.06), core, { n: 1 });
|
|
71
|
+
return out + s.strokes(t.edges, mix(w.dark, 0.5), 1);
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
// Chevrons: eight gores from pole to pole, every other one coloured, crossed by three bands that bend into a V on each gore, so that round the ball they make a zigzag.
|
|
75
|
+
const chevrons = (w) => ({
|
|
76
|
+
view: { yaw: 24, pitch: 24, roll: 0 },
|
|
77
|
+
base: w.main,
|
|
78
|
+
ground: w.ground,
|
|
79
|
+
mat: GLOSS,
|
|
80
|
+
draw(s, base, accent) {
|
|
81
|
+
const dark = accent ?? w.dark;
|
|
82
|
+
const tilt = [0, 22, 0];
|
|
83
|
+
const g = gores(8, 0, tilt);
|
|
84
|
+
const at = gorePoint(8, 0, tilt);
|
|
85
|
+
let out = "";
|
|
86
|
+
for (let i = 0; i < 8; i += 2)
|
|
87
|
+
out += s.panel(g.panels[i], base, { n: 1 });
|
|
88
|
+
for (let i = 0; i < 8; i++) {
|
|
89
|
+
for (const s0 of [-0.28, 0.02, 0.32]) {
|
|
90
|
+
const upper = [], lower = [];
|
|
91
|
+
for (let j = 0; j <= 4; j++) {
|
|
92
|
+
const u = j / 4;
|
|
93
|
+
const dip = 0.34 * Math.abs(u - 0.5);
|
|
94
|
+
upper.push(at(i, u, s0 + 0.12 + dip));
|
|
95
|
+
lower.push(at(i, u, s0 + dip));
|
|
96
|
+
}
|
|
97
|
+
const band = [...lower, ...upper.reverse()];
|
|
98
|
+
out += s.panel(band, dark, { n: 2 });
|
|
99
|
+
if (s.line)
|
|
100
|
+
out += s.strokes([band], dark, 0.6, { closed: true });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
out += s.strokes(g.seams, mix(dark, 0.3), 0.7);
|
|
104
|
+
return out + lit(s, g.seams, 0.4);
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
// Swirl: four gores that twist round the ball, two of them in one colour and two in the other.
|
|
108
|
+
const swirl = (w) => ({
|
|
109
|
+
view: { yaw: 20, pitch: 24, roll: 0 },
|
|
110
|
+
base: w.main,
|
|
111
|
+
ground: w.ground,
|
|
112
|
+
mat: { gloss: 0.9, shade: "#2a3450", grain: { f: 0.8, a: 0.08 } },
|
|
113
|
+
draw(s, base) {
|
|
114
|
+
const g = gores(4, 330, [0, 24, 0], 24, 6);
|
|
115
|
+
let out = "";
|
|
116
|
+
for (const { ring, gore } of g.pieces) {
|
|
117
|
+
if (gore % 2 === 1)
|
|
118
|
+
continue;
|
|
119
|
+
out += s.panel(ring, base, { n: 4, ink: true });
|
|
120
|
+
out += s.strokes([ring], base, 0.5, { closed: true, deco: true });
|
|
121
|
+
}
|
|
122
|
+
out += s.strokes(g.seams, mix(w.dark, 0.2), 0.9);
|
|
123
|
+
return out + lit(s, g.seams, 0.5);
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
// Metallic: the 32 panels in a polished finish that mirrors the sky above and the ground below, a light metal on the hexagons and a dark one on the pentagons.
|
|
127
|
+
const metallic = (w) => ({
|
|
128
|
+
view: VIEW,
|
|
129
|
+
base: w.dark,
|
|
130
|
+
ground: w.main,
|
|
131
|
+
mat: { gloss: 1, metal: true, shade: mix(w.dark, -0.4), rim: 0.8 },
|
|
132
|
+
draw(s, base) {
|
|
133
|
+
const t = truncatedIcosahedron();
|
|
134
|
+
let out = "";
|
|
135
|
+
for (const p of t.pentagons)
|
|
136
|
+
out += s.panel(p, base, { ink: true });
|
|
137
|
+
out += s.strokes(t.edges, mix(base, -0.2), 1.1);
|
|
138
|
+
return out + lit(s, t.edges, 0.55);
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
const BLUE = { ground: "#f4f6fb", main: "#1f56c4", dark: "#12306f" };
|
|
142
|
+
const RED = { ground: "#f8f4f2", main: "#d8312f", dark: "#6e1313" };
|
|
143
|
+
const NIGHT = { ground: "#16275a", main: "#f2c230", dark: "#0a1230" };
|
|
144
|
+
const CYAN = { ground: "#f4f8fa", main: "#12a8c8", dark: "#143a52" };
|
|
145
|
+
const MAGENTA = { ground: "#faf4f8", main: "#d62a8c", dark: "#4a1a52" };
|
|
146
|
+
const LIME = { ground: "#f6f9ee", main: "#5fb81a", dark: "#1b3a12" };
|
|
147
|
+
const FIRE = { ground: "#f6f1e8", main: "#ff6a13", dark: "#1b1b1f" };
|
|
148
|
+
const ICE = { ground: "#f2f6fa", main: "#1e8cff", dark: "#0d1b3d" };
|
|
149
|
+
const TOXIC = { ground: "#f3f6ea", main: "#2bbf5a", dark: "#241a3a" };
|
|
150
|
+
const CHEV_RED = { ground: "#f8f6f2", main: "#d6312e", dark: "#1f2128" };
|
|
151
|
+
const CHEV_GREEN = { ground: "#f8f6ee", main: "#1fa65a", dark: "#f0c81c" };
|
|
152
|
+
const CHEV_BLUE = { ground: "#f6f7fa", main: "#1f5fbf", dark: "#f08a24" };
|
|
153
|
+
const SWIRL_BLUE = { ground: "#f6f6f2", main: "#1f5fbf", dark: "#143f86" };
|
|
154
|
+
const SWIRL_RED = { ground: "#1f2128", main: "#d6312e", dark: "#d6312e" };
|
|
155
|
+
const SWIRL_TEAL = { ground: "#14b0c8", main: "#f08a24", dark: "#0c6d80" };
|
|
156
|
+
const GOLD = { ground: "#e3b73a", main: "#e3b73a", dark: "#7a560f" };
|
|
157
|
+
const SILVER = { ground: "#cdd3db", main: "#cdd3db", dark: "#4d5662" };
|
|
158
|
+
const COBALT = { ground: "#5b93e0", main: "#5b93e0", dark: "#15306a" };
|
|
159
|
+
export const BALL_SOCCER_STARS_BLUE = /* @__PURE__ */ ball("ball:soccer-stars-blue", "Soccer, stars, blue", "星柄・青", stars(BLUE));
|
|
160
|
+
export const BALL_SOCCER_STARS_RED = /* @__PURE__ */ ball("ball:soccer-stars-red", "Soccer, stars, red", "星柄・赤", stars(RED));
|
|
161
|
+
export const BALL_SOCCER_STARS_NIGHT = /* @__PURE__ */ ball("ball:soccer-stars-night", "Soccer, stars, night", "星柄・夜空", stars(NIGHT));
|
|
162
|
+
export const BALL_SOCCER_HEXAGONS_CYAN = /* @__PURE__ */ ball("ball:soccer-hexagons-cyan", "Soccer, hexagons, cyan", "六角形柄・シアン", hexagons(CYAN));
|
|
163
|
+
export const BALL_SOCCER_HEXAGONS_MAGENTA = /* @__PURE__ */ ball("ball:soccer-hexagons-magenta", "Soccer, hexagons, magenta", "六角形柄・マゼンタ", hexagons(MAGENTA));
|
|
164
|
+
export const BALL_SOCCER_HEXAGONS_LIME = /* @__PURE__ */ ball("ball:soccer-hexagons-lime", "Soccer, hexagons, lime", "六角形柄・ライム", hexagons(LIME));
|
|
165
|
+
export const BALL_SOCCER_FLAMES_FIRE = /* @__PURE__ */ ball("ball:soccer-flames-fire", "Soccer, flames, fire", "炎柄・ファイア", flames(FIRE, "#ffd21f"));
|
|
166
|
+
export const BALL_SOCCER_FLAMES_ICE = /* @__PURE__ */ ball("ball:soccer-flames-ice", "Soccer, flames, ice", "炎柄・アイス", flames(ICE, "#c4e8ff"));
|
|
167
|
+
export const BALL_SOCCER_FLAMES_TOXIC = /* @__PURE__ */ ball("ball:soccer-flames-toxic", "Soccer, flames, toxic", "炎柄・トキシック", flames(TOXIC, "#dcf23a"));
|
|
168
|
+
export const BALL_SOCCER_CHEVRONS_RED = /* @__PURE__ */ ball("ball:soccer-chevrons-red", "Soccer, chevrons, red", "シェブロン柄・赤", chevrons(CHEV_RED));
|
|
169
|
+
export const BALL_SOCCER_CHEVRONS_GREEN = /* @__PURE__ */ ball("ball:soccer-chevrons-green", "Soccer, chevrons, green", "シェブロン柄・緑", chevrons(CHEV_GREEN));
|
|
170
|
+
export const BALL_SOCCER_CHEVRONS_BLUE = /* @__PURE__ */ ball("ball:soccer-chevrons-blue", "Soccer, chevrons, blue", "シェブロン柄・青", chevrons(CHEV_BLUE));
|
|
171
|
+
export const BALL_SOCCER_SWIRL_BLUE = /* @__PURE__ */ ball("ball:soccer-swirl-blue", "Soccer, swirl, blue", "渦巻き柄・青", swirl(SWIRL_BLUE));
|
|
172
|
+
export const BALL_SOCCER_SWIRL_RED = /* @__PURE__ */ ball("ball:soccer-swirl-red", "Soccer, swirl, red", "渦巻き柄・赤", swirl(SWIRL_RED));
|
|
173
|
+
export const BALL_SOCCER_SWIRL_TEAL = /* @__PURE__ */ ball("ball:soccer-swirl-teal", "Soccer, swirl, teal", "渦巻き柄・ティール", swirl(SWIRL_TEAL));
|
|
174
|
+
export const BALL_SOCCER_METALLIC_GOLD = /* @__PURE__ */ ball("ball:soccer-metallic-gold", "Soccer, metallic, gold", "メタリック・金", metallic(GOLD));
|
|
175
|
+
export const BALL_SOCCER_METALLIC_SILVER = /* @__PURE__ */ ball("ball:soccer-metallic-silver", "Soccer, metallic, silver", "メタリック・銀", metallic(SILVER));
|
|
176
|
+
export const BALL_SOCCER_METALLIC_COBALT = /* @__PURE__ */ ball("ball:soccer-metallic-cobalt", "Soccer, metallic, cobalt", "メタリック・コバルト", metallic(COBALT));
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type BallSpec } from "./ball.engine.ts";
|
|
2
|
+
/** The late 1800s: eight long panels sewn by hand with a visible cross of thread, and a button where they meet at each end. */
|
|
3
|
+
export declare const BALL_SOCCER_1870_HAND_STITCHED: import("./ball.core.ts").Piece<BallSpec>;
|
|
4
|
+
/** The 1900s: eight panels, a round cap at each end, and a slit across which a lace is drawn to shut the casing once the bladder is in. */
|
|
5
|
+
export declare const BALL_SOCCER_1900_LACED: import("./ball.core.ts").Piece<BallSpec>;
|
|
6
|
+
/** The 1930s: eighteen strips, six panels of three, in two tones of leather, the seams stitched in two rows. */
|
|
7
|
+
export declare const BALL_SOCCER_1930_18_PANEL: import("./ball.core.ts").Piece<BallSpec>;
|
|
8
|
+
/** The 1950s: twelve pentagons, in four tones of chestnut leather so that no two that touch match, the seams stitched. */
|
|
9
|
+
export declare const BALL_SOCCER_1950_12_PANEL: import("./ball.core.ts").Piece<BallSpec>;
|
|
10
|
+
/** The 1960s: the 32 panels (twelve pentagons and twenty hexagons) in leather, tan hexagons and chestnut pentagons, stitched along the seams. */
|
|
11
|
+
export declare const BALL_SOCCER_1960_32_PANEL_LEATHER: import("./ball.core.ts").Piece<BallSpec>;
|