@johnmorrisdotca/dougu-sports 0.27.0 → 0.28.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 +31 -1
- package/README.md +3 -3
- package/dist/emblems/emblem.descriptions.js +15 -4
- package/dist/emblems/emblem.ids.d.ts +2 -2
- package/dist/emblems/emblem.ids.js +11 -0
- package/dist/emblems/emblem.lathe.d.ts +79 -8
- package/dist/emblems/emblem.lathe.js +21 -7
- package/dist/emblems/emblem.named.js +115 -5
- package/dist/emblems/emblem.registry.js +22 -0
- package/dist/emblems/lathe.ballrods.d.ts +2 -0
- package/dist/emblems/lathe.ballrods.js +155 -0
- package/dist/emblems/lathe.conference.d.ts +2 -0
- package/dist/emblems/lathe.conference.js +219 -0
- package/dist/emblems/lathe.extras.d.ts +3 -1
- package/dist/emblems/lathe.extras.js +77 -2
- package/dist/emblems/lathe.framed.d.ts +30 -0
- package/dist/emblems/lathe.framed.js +98 -0
- package/dist/emblems/lathe.sculpt.js +73 -20
- package/dist/emblems/nba.parts.d.ts +27 -0
- package/dist/emblems/nba.parts.js +34 -0
- package/dist/emblems/trophy/bill-russell-trophy.d.ts +1 -1
- package/dist/emblems/trophy/bill-russell-trophy.js +17 -13
- package/dist/emblems/trophy/bob-cousy-trophy.d.ts +2 -0
- package/dist/emblems/trophy/bob-cousy-trophy.js +18 -0
- package/dist/emblems/trophy/foundation-player-award.js +2 -0
- package/dist/emblems/trophy/george-halas-trophy.d.ts +2 -0
- package/dist/emblems/trophy/george-halas-trophy.js +6 -0
- package/dist/emblems/trophy/jackie-robinson-award.d.ts +2 -0
- package/dist/emblems/trophy/jackie-robinson-award.js +60 -0
- package/dist/emblems/trophy/lamar-hunt-trophy.d.ts +1 -1
- package/dist/emblems/trophy/lamar-hunt-trophy.js +5 -16
- package/dist/emblems/trophy/larry-bird-trophy.d.ts +2 -0
- package/dist/emblems/trophy/larry-bird-trophy.js +23 -0
- package/dist/emblems/trophy/larry-obrien-trophy-1977.d.ts +2 -0
- package/dist/emblems/trophy/larry-obrien-trophy-1977.js +23 -0
- package/dist/emblems/trophy/larry-obrien-trophy.d.ts +1 -1
- package/dist/emblems/trophy/larry-obrien-trophy.js +18 -11
- package/dist/emblems/trophy/magic-johnson-trophy.d.ts +2 -0
- package/dist/emblems/trophy/magic-johnson-trophy.js +20 -0
- package/dist/emblems/trophy/messier-leadership-award.d.ts +2 -0
- package/dist/emblems/trophy/messier-leadership-award.js +79 -0
- package/dist/emblems/trophy/nba-eastern-conference-2001.d.ts +2 -0
- package/dist/emblems/trophy/nba-eastern-conference-2001.js +18 -0
- package/dist/emblems/trophy/nba-western-conference-2001.d.ts +2 -0
- package/dist/emblems/trophy/nba-western-conference-2001.js +19 -0
- package/dist/emblems/trophy/oscar-robertson-trophy.d.ts +2 -0
- package/dist/emblems/trophy/oscar-robertson-trophy.js +19 -0
- package/dist/emblems/trophy/willie-oree-award.d.ts +2 -0
- package/dist/emblems/trophy/willie-oree-award.js +55 -0
- package/dist/emblems/trophy/wnba-championship-trophy.d.ts +1 -1
- package/dist/emblems/trophy/wnba-championship-trophy.js +6 -17
- package/dist/index.d.ts +11 -0
- package/dist/index.js +11 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ const pt = (x, y) => `${f(x)} ${f(y)}`;
|
|
|
9
9
|
export function LATHE_EXTRAS(c, d) {
|
|
10
10
|
const { p, solid, yaw, where, at } = c;
|
|
11
11
|
if (d[0] === "mesh") {
|
|
12
|
-
const [, y0, y1, n, rows] = d;
|
|
12
|
+
const [, y0, y1, n, rows, name, width = 0.55] = d;
|
|
13
13
|
let m = "";
|
|
14
14
|
for (let i = 0; i < n; i++) {
|
|
15
15
|
for (const way of [1, -1]) {
|
|
@@ -27,7 +27,13 @@ export function LATHE_EXTRAS(c, d) {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
if (m === "")
|
|
31
|
+
return "";
|
|
32
|
+
if (name === undefined)
|
|
33
|
+
return `<path d="${m}" stroke="${mix(c.base.rgb, 0.55)}" stroke-width=".55" stroke-opacity=".9"/>`;
|
|
34
|
+
// An etched net in a tone of its own: a dark line, then the tone laid on it a little to the side.
|
|
35
|
+
const t = c.tone(name);
|
|
36
|
+
return `<path d="${m}" transform="translate(.2 .25)" stroke="${mix(c.base.rgb, -0.6)}" stroke-width="${width}" stroke-opacity=".4"/><path d="${m}" stroke="${mix(t.rgb, 0.05)}" stroke-width="${width}"/>`;
|
|
31
37
|
}
|
|
32
38
|
if (d[0] === "patch") {
|
|
33
39
|
const [, y0, y1, deg0, deg1, name] = d;
|
|
@@ -57,3 +63,72 @@ export function LATHE_EXTRAS(c, d) {
|
|
|
57
63
|
};
|
|
58
64
|
return `<path d="M${lerp(y0, u0)}L${lerp(y0, u1)}L${lerp(y1, u1)}L${lerp(y1, u0)}z" fill="${t.fill}" stroke="${t.edge}" stroke-width=".5"/>`;
|
|
59
65
|
}
|
|
66
|
+
const rotate = (v, lz, lx, yaw) => {
|
|
67
|
+
const [x0, y0, z0] = v;
|
|
68
|
+
const x1 = x0 * Math.cos(lz) - y0 * Math.sin(lz);
|
|
69
|
+
const y1 = x0 * Math.sin(lz) + y0 * Math.cos(lz);
|
|
70
|
+
const y2 = y1 * Math.cos(lx) - z0 * Math.sin(lx);
|
|
71
|
+
const z2 = y1 * Math.sin(lx) + z0 * Math.cos(lx);
|
|
72
|
+
return [x1 * Math.cos(yaw) + z2 * Math.sin(yaw), y2, -x1 * Math.sin(yaw) + z2 * Math.cos(yaw)];
|
|
73
|
+
};
|
|
74
|
+
/** The great circles of a basketball's seams, by their normals: the equator, the meridian, and the two curved seams that run from pole to pole at 60 degrees either side of it. */
|
|
75
|
+
const SEAMS = [[0, 1, 0], [1, 0, 0], [Math.cos(Math.PI / 3), 0, -Math.sin(Math.PI / 3)], [Math.cos(Math.PI / 3), 0, Math.sin(Math.PI / 3)]];
|
|
76
|
+
/** Draws the seams of a basketball as grooves (each the front half of a great circle: one elliptical arc), and the specks of a grained finish. */
|
|
77
|
+
export function LATHE_BALL(c) {
|
|
78
|
+
const { ball, cx, cy } = c;
|
|
79
|
+
const r = ball.r;
|
|
80
|
+
const lz = ((ball.lean?.[0] ?? 0) * Math.PI) / 180;
|
|
81
|
+
const lx = ((ball.lean?.[1] ?? 0) * Math.PI) / 180;
|
|
82
|
+
const yaw = (c.yaw * Math.PI) / 180;
|
|
83
|
+
const e = (c.elevation * Math.PI) / 180;
|
|
84
|
+
const se = Math.sin(e);
|
|
85
|
+
const ce = Math.cos(e);
|
|
86
|
+
const view = [0, se, ce];
|
|
87
|
+
const screen = (v) => [v[0], -v[1] * ce + v[2] * se];
|
|
88
|
+
const t = c.tone(ball.tone);
|
|
89
|
+
let m = "";
|
|
90
|
+
for (const n0 of SEAMS) {
|
|
91
|
+
const n = rotate(n0, lz, lx, yaw);
|
|
92
|
+
const facing = n[0] * view[0] + n[1] * view[1] + n[2] * view[2];
|
|
93
|
+
const limb = [n[1] * view[2] - n[2] * view[1], n[2] * view[0] - n[0] * view[2], n[0] * view[1] - n[1] * view[0]];
|
|
94
|
+
const size = Math.hypot(...limb);
|
|
95
|
+
if (size < 0.02)
|
|
96
|
+
continue;
|
|
97
|
+
const a = screen([limb[0] / size, limb[1] / size, limb[2] / size]);
|
|
98
|
+
const near = [view[0] - facing * n[0], view[1] - facing * n[1], view[2] - facing * n[2]];
|
|
99
|
+
const k = Math.hypot(...near);
|
|
100
|
+
const mid = screen([near[0] / k, near[1] / k, near[2] / k]);
|
|
101
|
+
const sweep = a[0] * mid[1] - a[1] * mid[0] > 0 ? 1 : 0;
|
|
102
|
+
const angle = (Math.atan2(a[1], a[0]) * 180) / Math.PI;
|
|
103
|
+
m += `M${pt(cx + r * a[0], cy + r * a[1])}A${f(r)} ${f(Math.max(0.05, r * Math.abs(facing)))} ${f(angle)} 0 ${sweep} ${pt(cx - r * a[0], cy - r * a[1])}`;
|
|
104
|
+
}
|
|
105
|
+
let out = "";
|
|
106
|
+
if (m !== "") {
|
|
107
|
+
if (c.line)
|
|
108
|
+
out += `<path d="${m}" stroke-width="1.4"/>`;
|
|
109
|
+
else if (c.flat)
|
|
110
|
+
out += `<path d="${m}" stroke="${mix(t.rgb, -0.4)}" stroke-width="1"/>`;
|
|
111
|
+
else {
|
|
112
|
+
const inlay = ball.seam === undefined ? undefined : c.tone(ball.seam);
|
|
113
|
+
out += `<path d="${m}" stroke="${mix(t.rgb, -0.5)}" stroke-width="${inlay === undefined ? 0.75 : 0.85}"/>`;
|
|
114
|
+
out += inlay === undefined ? `<path d="${m}" transform="translate(.35 .4)" stroke="${mix(t.rgb, 0.55)}" stroke-width=".3" stroke-opacity=".8"/>` : `<path d="${m}" stroke="${mix(inlay.rgb, 0.1)}" stroke-width=".42"/>`;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const grain = ball.grain ?? 0;
|
|
118
|
+
if (grain > 0 && !c.line) {
|
|
119
|
+
let dots = "";
|
|
120
|
+
for (let i = 0; i < grain; i++) {
|
|
121
|
+
const y = 1 - (2 * (i + 0.5)) / grain;
|
|
122
|
+
const ring = Math.sqrt(1 - y * y);
|
|
123
|
+
const theta = i * 2.39996;
|
|
124
|
+
const p = rotate([ring * Math.cos(theta), y, ring * Math.sin(theta)], lz, lx, yaw);
|
|
125
|
+
if (p[0] * view[0] + p[1] * view[1] + p[2] * view[2] < 0.12)
|
|
126
|
+
continue;
|
|
127
|
+
const [sx, sy] = screen(p);
|
|
128
|
+
dots += `M${pt(cx + r * sx, cy + r * sy)}h0`;
|
|
129
|
+
}
|
|
130
|
+
if (dots !== "")
|
|
131
|
+
out += `<path d="${dots}" stroke="${mix(t.rgb, -0.5)}" stroke-width=".36" stroke-opacity=".6"/>`;
|
|
132
|
+
}
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Rgb } from "./emblem.core.ts";
|
|
2
|
+
import type { FramedCtx } from "./emblem.lathe.ts";
|
|
3
|
+
/** A point or a direction: x to the right, y down, z toward the eye at rest, in the lathe's units about the axis x = 0 (drawn at x = 32). */
|
|
4
|
+
export type V3 = readonly [x: number, y: number, z: number];
|
|
5
|
+
/** The turn and the eye of a drawing: rotate a point about the axis, place it on the page, and say how near the eye it is and whether a direction faces the eye. */
|
|
6
|
+
export declare function viewOf(c: Pick<FramedCtx, "yaw" | "s">): {
|
|
7
|
+
rot: (v: V3) => V3;
|
|
8
|
+
at: (r: V3) => readonly [number, number];
|
|
9
|
+
depth: (r: V3) => number;
|
|
10
|
+
facing: (n: V3) => number;
|
|
11
|
+
};
|
|
12
|
+
export declare const sub: (a: V3, b: V3) => V3;
|
|
13
|
+
export declare const cross: (a: V3, b: V3) => V3;
|
|
14
|
+
export declare const unit: (a: V3) => V3;
|
|
15
|
+
/** The normal of a facet from its first, middle and last points (a quadrilateral's diagonals). */
|
|
16
|
+
export declare const normalOf: (p: readonly V3[]) => V3;
|
|
17
|
+
/**
|
|
18
|
+
* How light polished metal is where a facet faces some way: -1 (black) to 1 (white), for a rotated, unit normal and the elevation of the eye `s`. Two sided, because a thin sheet is seen from either side. A polished
|
|
19
|
+
* surface shows what it mirrors, so the shade is read off a small room: a bright sky above, a dark band at the horizon, a mid floor and a bright window to the upper left. A facet that turns from the sky to the floor
|
|
20
|
+
* as a band twists runs from white through black to grey, the way chrome does.
|
|
21
|
+
*/
|
|
22
|
+
export declare function chrome(n: V3, s: number): number;
|
|
23
|
+
/** A colour for a shade from `chrome`, kept to a few steps so that neighbouring facets that differ by a hair are one colour. */
|
|
24
|
+
export declare const shadeOf: (rgb: Rgb, v: number, steps?: number) => string;
|
|
25
|
+
/** A smooth curve through a table of `[x, y]` points that never overshoots them (monotone cubic), as a function of x; outside the table it holds the end values. */
|
|
26
|
+
export declare function curve(table: readonly (readonly [number, number])[]): (x: number) => number;
|
|
27
|
+
/** A straight-line table: the value at x between the two points either side of it. */
|
|
28
|
+
export declare function lin(table: readonly (readonly [number, number])[]): (x: number) => number;
|
|
29
|
+
/** The points as a path: a closed polygon, or an open line. */
|
|
30
|
+
export declare const line: (pts: readonly (readonly [number, number])[], closed: boolean, digits?: 1 | 2) => string;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// The small 3D that a body of revolution's own `framed` drawer use (`FramedCtx` in emblem.lathe.ts): a point turned by the yaw and placed the way the body's surface is placed, a polished-metal shade for a facet from the way it
|
|
2
|
+
// faces, a smooth curve through a table of measurements, and the paths of polygons. Nothing here knows any one emblem; a body with no framed parts does not take this module. Imports only the core.
|
|
3
|
+
import { mix } from "./emblem.core.js";
|
|
4
|
+
const RAD = Math.PI / 180;
|
|
5
|
+
const one = (n) => String(Math.round(n * 10) / 10 + 0);
|
|
6
|
+
const two = (n) => String(Math.round(n * 100) / 100 + 0);
|
|
7
|
+
/** The turn and the eye of a drawing: rotate a point about the axis, place it on the page, and say how near the eye it is and whether a direction faces the eye. */
|
|
8
|
+
export function viewOf(c) {
|
|
9
|
+
const cy = Math.cos(c.yaw * RAD);
|
|
10
|
+
const sy = Math.sin(c.yaw * RAD);
|
|
11
|
+
const ce = Math.sqrt(1 - c.s * c.s);
|
|
12
|
+
return {
|
|
13
|
+
rot: (v) => [v[0] * cy + v[2] * sy, v[1], v[2] * cy - v[0] * sy],
|
|
14
|
+
at: (r) => [32 + r[0], r[1] + c.s * r[2]],
|
|
15
|
+
depth: (r) => r[2] * ce - r[1] * c.s,
|
|
16
|
+
facing: (n) => n[2] * ce - n[1] * c.s,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export const sub = (a, b) => [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
|
|
20
|
+
export const cross = (a, b) => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
|
|
21
|
+
export const unit = (a) => {
|
|
22
|
+
const m = Math.hypot(a[0], a[1], a[2]) || 1;
|
|
23
|
+
return [a[0] / m, a[1] / m, a[2] / m];
|
|
24
|
+
};
|
|
25
|
+
/** The normal of a facet from its first, middle and last points (a quadrilateral's diagonals). */
|
|
26
|
+
export const normalOf = (p) => unit(cross(sub(p[2], p[0]), sub(p[p.length - 1], p[1])));
|
|
27
|
+
const smooth = (x, a, b) => {
|
|
28
|
+
const t = Math.max(0, Math.min(1, (x - a) / (b - a)));
|
|
29
|
+
return t * t * (3 - 2 * t);
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* How light polished metal is where a facet faces some way: -1 (black) to 1 (white), for a rotated, unit normal and the elevation of the eye `s`. Two sided, because a thin sheet is seen from either side. A polished
|
|
33
|
+
* surface shows what it mirrors, so the shade is read off a small room: a bright sky above, a dark band at the horizon, a mid floor and a bright window to the upper left. A facet that turns from the sky to the floor
|
|
34
|
+
* as a band twists runs from white through black to grey, the way chrome does.
|
|
35
|
+
*/
|
|
36
|
+
export function chrome(n, s) {
|
|
37
|
+
const ce = Math.sqrt(1 - s * s);
|
|
38
|
+
const eye = [0, -s, ce];
|
|
39
|
+
let m = n;
|
|
40
|
+
let d = m[0] * eye[0] + m[1] * eye[1] + m[2] * eye[2];
|
|
41
|
+
if (d < 0) {
|
|
42
|
+
m = [-m[0], -m[1], -m[2]];
|
|
43
|
+
d = -d;
|
|
44
|
+
}
|
|
45
|
+
const r = [2 * d * m[0] - eye[0], 2 * d * m[1] - eye[1], 2 * d * m[2] - eye[2]];
|
|
46
|
+
const up = -r[1];
|
|
47
|
+
const window = r[2] > 0 ? Math.exp(-(((r[0] + 0.5) / 0.34) ** 2 + ((up - 0.4) / 0.3) ** 2)) : 0;
|
|
48
|
+
const v = -0.12 + 0.95 * smooth(up, -0.12, 0.4) - 0.6 * Math.exp(-(((up + 0.02) / 0.14) ** 2)) + 0.75 * window;
|
|
49
|
+
return Math.max(-0.72, Math.min(0.9, v));
|
|
50
|
+
}
|
|
51
|
+
/** A colour for a shade from `chrome`, kept to a few steps so that neighbouring facets that differ by a hair are one colour. */
|
|
52
|
+
export const shadeOf = (rgb, v, steps = 24) => mix(rgb, Math.round(v * steps) / steps);
|
|
53
|
+
/** A smooth curve through a table of `[x, y]` points that never overshoots them (monotone cubic), as a function of x; outside the table it holds the end values. */
|
|
54
|
+
export function curve(table) {
|
|
55
|
+
const n = table.length;
|
|
56
|
+
const dx = table.slice(1).map((p, i) => p[0] - table[i][0]);
|
|
57
|
+
const dy = table.slice(1).map((p, i) => p[1] - table[i][1]);
|
|
58
|
+
const m = dy.map((d, i) => d / dx[i]);
|
|
59
|
+
const t = table.map((_, i) => (i === 0 ? m[0] : i === n - 1 ? m[n - 2] : m[i - 1] * m[i] <= 0 ? 0 : (2 * m[i - 1] * m[i]) / (m[i - 1] + m[i])));
|
|
60
|
+
return (x) => {
|
|
61
|
+
const first = table[0];
|
|
62
|
+
const last = table[n - 1];
|
|
63
|
+
if (x <= first[0])
|
|
64
|
+
return first[1];
|
|
65
|
+
if (x >= last[0])
|
|
66
|
+
return last[1];
|
|
67
|
+
let i = 0;
|
|
68
|
+
while (x > table[i + 1][0])
|
|
69
|
+
i++;
|
|
70
|
+
const a = table[i];
|
|
71
|
+
const w = dx[i];
|
|
72
|
+
const u = (x - a[0]) / w;
|
|
73
|
+
const u2 = u * u;
|
|
74
|
+
const u3 = u2 * u;
|
|
75
|
+
return (2 * u3 - 3 * u2 + 1) * a[1] + (u3 - 2 * u2 + u) * w * t[i] + (-2 * u3 + 3 * u2) * table[i + 1][1] + (u3 - u2) * w * t[i + 1];
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** A straight-line table: the value at x between the two points either side of it. */
|
|
79
|
+
export function lin(table) {
|
|
80
|
+
return (x) => {
|
|
81
|
+
const first = table[0];
|
|
82
|
+
if (x <= first[0])
|
|
83
|
+
return first[1];
|
|
84
|
+
for (let i = 1; i < table.length; i++) {
|
|
85
|
+
const b = table[i];
|
|
86
|
+
if (x <= b[0]) {
|
|
87
|
+
const a = table[i - 1];
|
|
88
|
+
return a[1] + ((b[1] - a[1]) * (x - a[0])) / (b[0] - a[0]);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return table[table.length - 1][1];
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** The points as a path: a closed polygon, or an open line. */
|
|
95
|
+
export const line = (pts, closed, digits = 1) => {
|
|
96
|
+
const w = digits === 1 ? one : two;
|
|
97
|
+
return `M${pts.map((p) => `${w(p[0])} ${w(p[1])}`).join("L")}${closed ? "z" : ""}`;
|
|
98
|
+
};
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// as a solid edge, widest when it is edge on. A ribbon is a centre line with a width that turns about it, drawn as a strip of shaded quadrilaterals. A model that wants them sets `sculptor: LATHE_SCULPT`;
|
|
4
4
|
// one that does not never imports this file, so its bundle carries none of the code. Plain SVG.
|
|
5
5
|
import { mix } from "./emblem.core.js";
|
|
6
|
+
import { engravingInk, sideText } from "./emblem.engrave.js";
|
|
6
7
|
const CX = 32;
|
|
7
8
|
const RAD = Math.PI / 180;
|
|
8
9
|
const f = (n) => String(Math.round(n * 10) / 10 + 0);
|
|
@@ -55,8 +56,9 @@ function polys(d) {
|
|
|
55
56
|
}
|
|
56
57
|
else if (cmd === "Q") {
|
|
57
58
|
const [x1, y1, x2, y2] = [num(), num(), num(), num()];
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
const qn = Math.max(2, Math.min(5, Math.ceil(Math.hypot(x2 - x, y2 - y) / 3.4)));
|
|
60
|
+
for (let k = 1; k <= qn; k++) {
|
|
61
|
+
const u = k / qn;
|
|
60
62
|
cur.push([(1 - u) ** 2 * x + 2 * (1 - u) * u * x1 + u * u * x2, (1 - u) ** 2 * y + 2 * (1 - u) * u * y1 + u * u * y2]);
|
|
61
63
|
}
|
|
62
64
|
x = x2;
|
|
@@ -64,8 +66,9 @@ function polys(d) {
|
|
|
64
66
|
}
|
|
65
67
|
else if (cmd === "C") {
|
|
66
68
|
const [x1, y1, x2, y2, x3, y3] = [num(), num(), num(), num(), num(), num()];
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
const cn = Math.max(2, Math.min(6, Math.ceil(Math.hypot(x3 - x, y3 - y) / 3.3)));
|
|
70
|
+
for (let k = 1; k <= cn; k++) {
|
|
71
|
+
const u = k / cn;
|
|
69
72
|
const a = (1 - u) ** 3;
|
|
70
73
|
const b = 3 * (1 - u) ** 2 * u;
|
|
71
74
|
const c = 3 * (1 - u) * u * u;
|
|
@@ -84,8 +87,8 @@ function polys(d) {
|
|
|
84
87
|
CACHE.set(d, out);
|
|
85
88
|
return out;
|
|
86
89
|
}
|
|
87
|
-
function drawCut(c,
|
|
88
|
-
const { cut, ax, az, dy } =
|
|
90
|
+
function drawCut(c, stands) {
|
|
91
|
+
const { cut, ax, az, dy } = stands[0];
|
|
89
92
|
const { yaw, s, tone, line, flat } = c;
|
|
90
93
|
const th = yaw * RAD;
|
|
91
94
|
const phi = ((cut.rot ?? 0) + yaw) * RAD;
|
|
@@ -93,24 +96,30 @@ function drawCut(c, stand) {
|
|
|
93
96
|
const sinP = Math.sin(phi);
|
|
94
97
|
const A = ax * Math.cos(th) + az * Math.sin(th);
|
|
95
98
|
const B = az * Math.cos(th) - ax * Math.sin(th);
|
|
96
|
-
if (cut.decal === true && cosP <= 0.03)
|
|
99
|
+
if ((cut.decal === true && cosP <= 0.03) || (line && cut.fine === true))
|
|
97
100
|
return undefined;
|
|
98
101
|
const t = cut.t ?? 1;
|
|
99
102
|
const sign = cosP >= 0 ? 1 : -1;
|
|
100
|
-
const at = (px, py, d) => `${f(CX + A + (px - CX) * cosP + d * sinP)} ${f(py + dy + s * (B - (px - CX) * sinP + d * cosP))}`;
|
|
101
103
|
const path = (d, depth) => {
|
|
102
104
|
let out = "";
|
|
103
|
-
for (const
|
|
104
|
-
|
|
105
|
+
for (const st of stands) {
|
|
106
|
+
const sa = st.ax * Math.cos(th) + st.az * Math.sin(th);
|
|
107
|
+
const sb = st.az * Math.cos(th) - st.ax * Math.sin(th);
|
|
108
|
+
for (const poly of polys(d))
|
|
109
|
+
out += `M${poly.map(([px, py]) => `${f(CX + sa + (px - CX) * cosP + depth * sinP)} ${f(py + st.dy + s * (sb - (px - CX) * sinP + depth * cosP))}`).join("L")}Z`;
|
|
110
|
+
}
|
|
105
111
|
return out;
|
|
106
112
|
};
|
|
107
113
|
const near = (sign * t) / 2;
|
|
108
|
-
const first = cut.layers[0];
|
|
114
|
+
const first = cut.layers[0] ?? ["main", ""];
|
|
109
115
|
const base = tone(first[0]);
|
|
110
116
|
let svg = "";
|
|
111
117
|
const reach = t * Math.hypot(sinP, s * cosP);
|
|
112
118
|
const glass = first[2] === "gl";
|
|
113
|
-
if (
|
|
119
|
+
if (first[1] === "") {
|
|
120
|
+
// A text only: nothing is drawn but the engraving.
|
|
121
|
+
}
|
|
122
|
+
else if (line) {
|
|
114
123
|
if (reach > 1.3 && Math.abs(sinP) > 0.3)
|
|
115
124
|
svg += `<path d="${path(first[1], -near)}" stroke-opacity=".6"/>`;
|
|
116
125
|
}
|
|
@@ -131,7 +140,7 @@ function drawCut(c, stand) {
|
|
|
131
140
|
for (const [name, d, mode] of cut.layers) {
|
|
132
141
|
const q = tone(name);
|
|
133
142
|
if (line) {
|
|
134
|
-
if (mode === undefined || mode === "gl" || mode === "rf")
|
|
143
|
+
if (mode === undefined || mode === "gl" || mode === "rf" || mode === "fl")
|
|
135
144
|
svg += `<path d="${path(d, near)}"/>`;
|
|
136
145
|
else if (mode === "ln")
|
|
137
146
|
svg += `<path d="${path(d, near)}" stroke-width="1.1"/>`;
|
|
@@ -139,7 +148,7 @@ function drawCut(c, stand) {
|
|
|
139
148
|
}
|
|
140
149
|
const p = path(d, near);
|
|
141
150
|
if (mode === undefined)
|
|
142
|
-
svg += `<path d="${p}" fill="${q.fill}" stroke="${q.edge}"/>`;
|
|
151
|
+
svg += `<path d="${p}" fill="${q.fill}" stroke="${q.edge}" stroke-width=".3"/>`;
|
|
143
152
|
else if (mode === "dk")
|
|
144
153
|
svg += `<path d="${p}" fill="${mix(q.rgb, -0.55)}" fill-opacity=".5" stroke="none"/>`;
|
|
145
154
|
else if (mode === "lt")
|
|
@@ -148,13 +157,21 @@ function drawCut(c, stand) {
|
|
|
148
157
|
svg += `<path d="${p}" stroke="${q.edge}" stroke-width=".5"/>`;
|
|
149
158
|
else if (mode === "gl")
|
|
150
159
|
svg += `<path d="${p}" fill="${mix(q.rgb, 0.35)}" fill-opacity=".3" stroke="${q.edge}" stroke-width=".45"/>`;
|
|
160
|
+
else if (mode === "fl")
|
|
161
|
+
svg += `<path d="${p}" fill="${mix(q.rgb, 0.08)}" stroke="${q.edge}" stroke-width=".3"/>`;
|
|
151
162
|
else if (mode === "rf")
|
|
152
|
-
svg += `<path d="${p}" fill="${q.fill}" fill-opacity=".8" stroke="${q.edge}" stroke-width=".
|
|
163
|
+
svg += `<path d="${p}" fill="${q.fill}" fill-opacity=".8" stroke="${q.edge}" stroke-width=".3"/>`;
|
|
153
164
|
else
|
|
154
165
|
svg += `<path d="${p}" fill="#fff" fill-opacity=".6" stroke="none"/>`;
|
|
155
166
|
}
|
|
156
|
-
if (sign < 0 && !line)
|
|
167
|
+
if (sign < 0 && !line && first[1] !== "")
|
|
157
168
|
svg += `<path d="${path(first[1], near)}" fill="#000" fill-opacity=".22" stroke="none"/>`;
|
|
169
|
+
if (cut.plate !== undefined && c.words !== "") {
|
|
170
|
+
const [x0, x1, y0, y1] = cut.plate;
|
|
171
|
+
const y = (y0 + y1) / 2;
|
|
172
|
+
const end = (px) => [CX + A + (px - CX) * cosP + near * sinP, y + dy + s * (B - (px - CX) * sinP + near * cosP)];
|
|
173
|
+
svg += sideText(c.words, x1 - x0, y1 - y0, engravingInk(line ? "line" : flat ? "color" : "metal", base.rgb), end(x0), end(x1), cosP);
|
|
174
|
+
}
|
|
158
175
|
return { z: B, svg };
|
|
159
176
|
}
|
|
160
177
|
/** The convex hull of some points (Andrew's monotone chain), counter-clockwise. */
|
|
@@ -225,7 +242,7 @@ function drawRibbon(c, r) {
|
|
|
225
242
|
const nz = -ty * wx;
|
|
226
243
|
const nl = Math.hypot(nx, ny, nz) || 1;
|
|
227
244
|
const lambert = Math.abs((nx * L[0] + ny * L[1] + nz * L[2]) / (nl * len));
|
|
228
|
-
const bucket = Math.round(Math.max(-0.
|
|
245
|
+
const bucket = Math.round(Math.max(-0.45, Math.min(0.5, (lambert - 0.45) * 1.1)) * 10) / 10;
|
|
229
246
|
const colour = mix(base.rgb, bucket);
|
|
230
247
|
quads.push({ z: (p.pz + q.pz) / 2, d: `M${pt(p.px - p.wx, p.py, p.pz - p.wz)}L${pt(p.px + p.wx, p.py, p.pz + p.wz)}L${pt(q.px + q.wx, q.py, q.pz + q.wz)}L${pt(q.px - q.wx, q.py, q.pz - q.wz)}Z`, colour });
|
|
231
248
|
}
|
|
@@ -245,23 +262,59 @@ function drawRibbon(c, r) {
|
|
|
245
262
|
svg += `<path d="${run}" fill="${colour}" stroke="${colour}" stroke-width=".3"/>`;
|
|
246
263
|
return { z: turned.reduce((m, p) => m + p.pz, 0) / turned.length, svg };
|
|
247
264
|
}
|
|
265
|
+
function drawBlock(c, b) {
|
|
266
|
+
const { yaw, s, tone, line } = c;
|
|
267
|
+
const th = yaw * RAD;
|
|
268
|
+
const cos = Math.cos(th);
|
|
269
|
+
const sin = Math.sin(th);
|
|
270
|
+
const t = tone(b.tone);
|
|
271
|
+
const up = tone(b.top ?? b.tone);
|
|
272
|
+
const [x0, x1] = b.x;
|
|
273
|
+
const [y0, y1] = b.y;
|
|
274
|
+
const [z0, z1] = b.z;
|
|
275
|
+
const at = (x, y, z) => `${f(CX + x * cos + z * sin)} ${f(y + s * (z * cos - x * sin))}`;
|
|
276
|
+
let svg = "";
|
|
277
|
+
// The four sides, each by the way it faces: the ones that look toward the eye, lit from the left.
|
|
278
|
+
const faces = [
|
|
279
|
+
[0, 1, [x0, z1], [x1, z1]],
|
|
280
|
+
[1, 0, [x1, z1], [x1, z0]],
|
|
281
|
+
[0, -1, [x1, z0], [x0, z0]],
|
|
282
|
+
[-1, 0, [x0, z0], [x0, z1]],
|
|
283
|
+
];
|
|
284
|
+
for (const [nx, nz, a, e] of faces) {
|
|
285
|
+
const facing = nz * cos - nx * sin;
|
|
286
|
+
if (facing <= 0.01)
|
|
287
|
+
continue;
|
|
288
|
+
const lit = -(nx * cos + nz * sin);
|
|
289
|
+
svg += `<path d="M${at(a[0], y0, a[1])}L${at(e[0], y0, e[1])}L${at(e[0], y1, e[1])}L${at(a[0], y1, a[1])}Z" fill="${line ? "none" : mix(t.rgb, 0.05 + 0.27 * lit)}" stroke="${line ? "currentColor" : t.edge}"/>`;
|
|
290
|
+
}
|
|
291
|
+
if (s > 0.02)
|
|
292
|
+
svg += `<path d="M${at(x0, y0, z0)}L${at(x1, y0, z0)}L${at(x1, y0, z1)}L${at(x0, y0, z1)}Z" fill="${line ? "none" : mix(up.rgb, 0.3)}" stroke="${line ? "currentColor" : b.rim === undefined ? up.edge : mix(tone(b.rim).rgb, 0.2)}"${b.rim === undefined || line ? "" : ' stroke-width=".8"'}/>`;
|
|
293
|
+
return svg;
|
|
294
|
+
}
|
|
248
295
|
/** Draws the parts of a model: the ones that are `under` the bodies, and the rest, each group from far to near. */
|
|
249
296
|
export function LATHE_SCULPT(c, parts) {
|
|
250
297
|
const under = [];
|
|
251
298
|
const over = [];
|
|
299
|
+
const boxes = [];
|
|
252
300
|
for (const part of parts) {
|
|
301
|
+
if (part.kind === "box") {
|
|
302
|
+
boxes.push(drawBlock(c, part));
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
253
305
|
if (part.kind === "ribbon") {
|
|
254
306
|
(part.under === true ? under : over).push(drawRibbon(c, part));
|
|
255
307
|
continue;
|
|
256
308
|
}
|
|
257
309
|
const [x, z] = part.at ?? [0, 0];
|
|
258
310
|
const stands = [{ cut: part, ax: x, az: z, dy: part.y ?? 0 }, ...(part.copies ?? []).map(([cx, cz, cy]) => ({ cut: part, ax: x + cx, az: z + cz, dy: (part.y ?? 0) + (cy ?? 0) }))];
|
|
259
|
-
|
|
260
|
-
|
|
311
|
+
// The copies of a decal are one path (they lie on one face and cannot hide each other); those of a cut-out are drawn one by one, far to near.
|
|
312
|
+
for (const group of part.decal === true ? [stands] : stands.map((st) => [st])) {
|
|
313
|
+
const made = drawCut(c, group);
|
|
261
314
|
if (made !== undefined)
|
|
262
315
|
(part.under === true ? under : over).push(made);
|
|
263
316
|
}
|
|
264
317
|
}
|
|
265
318
|
const join = (list) => list.sort((a, b) => a.z - b.z).map((p) => p.svg).join("");
|
|
266
|
-
return { under: join(under), over: join(over) };
|
|
319
|
+
return { under: join(under), over: boxes.join("") + join(over) };
|
|
267
320
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Pt } from "./emblem.lathe.ts";
|
|
2
|
+
/** The tones the NBA's postseason trophies share: the ball's silver (and the frosted silver of the earlier conference balls), the black of the rings and feet, and the pale gold of the etched net. */
|
|
3
|
+
export declare const NBA_TONES: {
|
|
4
|
+
readonly silver: "#d3d8df";
|
|
5
|
+
readonly frost: "#e6e9ec";
|
|
6
|
+
readonly dark: "#16171b";
|
|
7
|
+
readonly etch: "#f0cf66";
|
|
8
|
+
};
|
|
9
|
+
/** The trumpet from its flange down to its foot, in the 64 unit box: the flange's rim is at 24.5 and the foot ends at 61.4. */
|
|
10
|
+
export declare const TRUMPET: readonly Pt[];
|
|
11
|
+
/** The ball's ring of the Western trophy: four bands that cross under the ball and rise round its lower half (the real ones are two rings). */
|
|
12
|
+
export declare const WEST_BAND: readonly [readonly [0, 38.2], readonly [4.2, 37.6], readonly [8.4, 36.2], readonly [12, 33.6], readonly [14.6, 30.4], readonly [15.5, 28.8]];
|
|
13
|
+
/** The Western base from the gold dome down: a black ring, a thin band, a flared black drum, a tall flared skirt and a black foot. In the earlier pair the thin band is black and the skirt polished silver. */
|
|
14
|
+
export declare const westBase: (earlier: boolean) => readonly Pt[];
|
|
15
|
+
/** The Eastern base from its plate down: a plate, three black tiers, a tall drum and a black foot. In the earlier pair the plate and the drum are polished silver. */
|
|
16
|
+
export declare const eastBase: (earlier: boolean) => readonly Pt[];
|
|
17
|
+
/** One of the three posts of the Eastern trophy and its stem and dish, as solids (the posts stand at 0, 120 and 240 degrees). */
|
|
18
|
+
export declare const eastTop: () => ({
|
|
19
|
+
at: readonly [12.2, number];
|
|
20
|
+
p: readonly [readonly [33.4, 0.9, 1], readonly [40.6, 0.9, 1]];
|
|
21
|
+
} | {
|
|
22
|
+
p: readonly [readonly [37.6, 1.2, 1], readonly [40.7, 1.4, 1]];
|
|
23
|
+
open?: undefined;
|
|
24
|
+
} | {
|
|
25
|
+
open: boolean;
|
|
26
|
+
p: readonly [readonly [33.2, 10, 1], readonly [34, 9.7], readonly [36, 7.2], readonly [37.6, 3.2], readonly [38.2, 1.3, 1]];
|
|
27
|
+
})[];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** The tones the NBA's postseason trophies share: the ball's silver (and the frosted silver of the earlier conference balls), the black of the rings and feet, and the pale gold of the etched net. */
|
|
2
|
+
export const NBA_TONES = { silver: "#d3d8df", frost: "#e6e9ec", dark: "#16171b", etch: "#f0cf66" };
|
|
3
|
+
/** The trumpet from its flange down to its foot, in the 64 unit box: the flange's rim is at 24.5 and the foot ends at 61.4. */
|
|
4
|
+
export const TRUMPET = [
|
|
5
|
+
[23, 10.3, 1], [23.2, 11.1], [24.3, 11.25, 1], [24.6, 11.2], [24.6, 9.95],
|
|
6
|
+
[26, 9.7], [28, 9.15], [30, 8.65], [32, 8.15], [34, 7.65], [36, 7.1], [38, 6.55], [40, 6.05], [42, 5.6], [44, 5.15], [46, 4.8], [48, 4.5], [49.4, 4.4], [50.6, 4.55], [51.8, 5.15], [52.8, 6.3], [53.7, 7.6], [54.4, 8.4], [54.8, 8.6, 1],
|
|
7
|
+
[54.8, 8.9, 1, "dark"], [56.4, 8.9, 1, "dark"], [56.4, 9.35, 1], [59.8, 9.4, 1], [59.8, 9.5, 1, "dark"], [61.4, 9.5, 1, "dark"],
|
|
8
|
+
];
|
|
9
|
+
/** The ball's ring of the Western trophy: four bands that cross under the ball and rise round its lower half (the real ones are two rings). */
|
|
10
|
+
export const WEST_BAND = [[0, 38.2], [4.2, 37.6], [8.4, 36.2], [12, 33.6], [14.6, 30.4], [15.5, 28.8]];
|
|
11
|
+
/** The Western base from the gold dome down: a black ring, a thin band, a flared black drum, a tall flared skirt and a black foot. In the earlier pair the thin band is black and the skirt polished silver. */
|
|
12
|
+
export const westBase = (earlier) => [
|
|
13
|
+
[38, 3, 1], [38.5, 8.6], [39.6, 11], [40, 11.4, 1],
|
|
14
|
+
[40, 13.4, 1, "dark"], [42.2, 13.8, 1, "dark"],
|
|
15
|
+
[42.2, 14.3, 1, earlier ? "dark" : "main"], [44.8, 14.6, 1, earlier ? "dark" : "main"],
|
|
16
|
+
[44.8, 15.3, 1, "dark"], [46, 16], [48, 17.6], [50.4, 20, 1, "dark"],
|
|
17
|
+
[50.4, 20.2, 1, earlier ? "silver" : "main"], [53, 21], [56, 22], [60.6, 23, 1, earlier ? "silver" : "main"],
|
|
18
|
+
[60.6, 23.3, 1, "dark"], [62.4, 23.4, 1, "dark"],
|
|
19
|
+
];
|
|
20
|
+
/** The Eastern base from its plate down: a plate, three black tiers, a tall drum and a black foot. In the earlier pair the plate and the drum are polished silver. */
|
|
21
|
+
export const eastBase = (earlier) => {
|
|
22
|
+
const light = earlier ? "silver" : "main";
|
|
23
|
+
return [
|
|
24
|
+
[40.6, 10.2, 1, light], [42.2, 10.4, 1, light],
|
|
25
|
+
[42.2, 12.2, 1, "dark"], [43.8, 12.2, 1, "dark"], [43.8, 14, 1, "dark"], [45.4, 14, 1, "dark"], [45.4, 15.8, 1, "dark"], [47, 15.8, 1, "dark"],
|
|
26
|
+
[47, 19.2, 1, light], [58.8, 19.5, 1, light],
|
|
27
|
+
[58.8, 20, 1, "dark"], [60.4, 20.6, 1, "dark"], [62.5, 20.9, 1, "dark"],
|
|
28
|
+
];
|
|
29
|
+
};
|
|
30
|
+
/** One of the three posts of the Eastern trophy and its stem and dish, as solids (the posts stand at 0, 120 and 240 degrees). */
|
|
31
|
+
export const eastTop = () => {
|
|
32
|
+
const post = (deg) => ({ at: [12.2, deg], p: [[33.4, 0.9, 1], [40.6, 0.9, 1]] });
|
|
33
|
+
return [{ p: [[37.6, 1.2, 1], [40.7, 1.4, 1]] }, { open: true, p: [[33.2, 10, 1], [34, 9.7], [36, 7.2], [37.6, 3.2], [38.2, 1.3, 1]] }, post(0), post(120), post(240)];
|
|
34
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/** The Bill Russell NBA Finals Most Valuable Player Trophy: a gold basketball
|
|
1
|
+
/** The Bill Russell NBA Finals Most Valuable Player Trophy: a gold basketball with silver seams in a net-etched gold trumpet over a stepped round foot. */
|
|
2
2
|
export declare const TROPHY_BILL_RUSSELL_TROPHY: import("../emblem.core.ts").Emblem<import("../emblem.lathe.ts").LatheModel>;
|
|
@@ -1,24 +1,28 @@
|
|
|
1
|
-
// A gold basketball seated
|
|
2
|
-
//
|
|
3
|
-
// the
|
|
1
|
+
// A gold basketball with grooved silver seams, seated in the mouth of a tall gold trumpet: the flange is wider than the body under it, the body narrows in a long smooth curve to a slim waist a little under half the
|
|
2
|
+
// body's width, flares into a round foot of two tiers, and is etched with a net of silver diamonds. Drawn for this package from photographs of the 2022 trophy standing beside the championship trophy and the conference finals
|
|
3
|
+
// MVP trophies (docs/likeness.md): the heights and radii are measured on a photograph of the whole row, the ball is a little under a third of the height, and the lettering on the foot's band and the ball's valve are left out
|
|
4
|
+
// (the band takes the engraving option).
|
|
4
5
|
import { defineLathe } from "../emblem.lathe.js";
|
|
5
|
-
import { LATHE_EXTRAS } from "../lathe.extras.js";
|
|
6
|
-
/** The Bill Russell NBA Finals Most Valuable Player Trophy: a gold basketball
|
|
6
|
+
import { LATHE_BALL, LATHE_EXTRAS } from "../lathe.extras.js";
|
|
7
|
+
/** The Bill Russell NBA Finals Most Valuable Player Trophy: a gold basketball with silver seams in a net-etched gold trumpet over a stepped round foot. */
|
|
7
8
|
export const TROPHY_BILL_RUSSELL_TROPHY = /* @__PURE__ */ defineLathe("trophy:bill-russell-trophy", "Bill Russell Trophy", "ビル・ラッセル・トロフィー", "ours", {
|
|
8
9
|
extras: LATHE_EXTRAS,
|
|
10
|
+
ballExtras: LATHE_BALL,
|
|
9
11
|
metal: "gold",
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
tones: { silver: "#cfd3d8" },
|
|
13
|
+
box: "-0.3 0 64.6 64.6",
|
|
14
|
+
turnBox: "-4.6 0 73.1 73.1",
|
|
15
|
+
tilt: 10,
|
|
12
16
|
solids: [
|
|
13
17
|
{
|
|
14
18
|
p: [
|
|
15
|
-
[22.
|
|
16
|
-
[
|
|
17
|
-
[
|
|
19
|
+
[22.8, 11, 1], [23, 12], [23.9, 12, 1], [24, 10.7, 1],
|
|
20
|
+
[25, 10.25], [27, 9.7], [29.3, 9.3], [31.4, 8.65], [33.5, 7.98], [35.7, 7.45], [37.8, 6.9], [39.9, 6.4], [42, 5.9], [44, 5.4], [45.5, 5.05], [47, 4.8], [50.5, 4.8], [51.6, 5.05], [52.7, 5.6], [53.7, 6.9], [54.8, 8.6], [55.9, 9.7, 1],
|
|
21
|
+
[55.9, 9.9, 1], [58, 10.4], [59.2, 10.7, 1], [59.2, 11, 1], [61.3, 11, 1],
|
|
18
22
|
],
|
|
19
|
-
decor: [["mesh", 25.
|
|
23
|
+
decor: [["mesh", 25.5, 46, 8, 5, "silver", 0.3], ["ring", 57.2]],
|
|
20
24
|
},
|
|
21
25
|
],
|
|
22
|
-
balls: [{ kind: "
|
|
23
|
-
plate: { y0:
|
|
26
|
+
balls: [{ kind: "plain", nba: true, cy: 13.3, r: 10.1, seam: "silver", lean: [-16, 22] }],
|
|
27
|
+
plate: { y0: 59.4, y1: 61 },
|
|
24
28
|
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// A large polished silver basketball with grooved seams on three slim gold posts over a small gold dish, on a round stepped base: a gold plate, three black tiers, a tall plain gold drum and a black foot. Drawn for this package
|
|
2
|
+
// from a photograph of the 2022 conference champions' trophies standing side by side (docs/likeness.md): the posts stand at the corners of a triangle a little wider than the dish, and the lettering on the drum and the ball's
|
|
3
|
+
// valve are left out (the drum is a plain band that takes the engraving option). The Western champions' trophy, the Oscar Robertson Trophy, holds the ball in crossed bands.
|
|
4
|
+
import { defineLathe } from "../emblem.lathe.js";
|
|
5
|
+
import { LATHE_BALL } from "../lathe.extras.js";
|
|
6
|
+
import { NBA_TONES, eastBase, eastTop } from "../nba.parts.js";
|
|
7
|
+
/** The Bob Cousy Trophy: the Eastern Conference champions' trophy, a silver ball on three gold posts over a round black and gold base. */
|
|
8
|
+
export const TROPHY_BOB_COUSY_TROPHY = /* @__PURE__ */ defineLathe("trophy:bob-cousy-trophy", "Bob Cousy Trophy", "ボブ・クージー・トロフィー", "ours", {
|
|
9
|
+
ballExtras: LATHE_BALL,
|
|
10
|
+
metal: "gold",
|
|
11
|
+
tones: NBA_TONES,
|
|
12
|
+
box: "-2.3 0 68.6 68.6",
|
|
13
|
+
turnBox: "-10.5 -1.1 85 85",
|
|
14
|
+
tilt: 13,
|
|
15
|
+
solids: [{ p: eastBase(false) }, ...eastTop()],
|
|
16
|
+
balls: [{ kind: "plain", nba: true, cy: 19.2, r: 17.3, tone: "silver", lean: [20, -16] }],
|
|
17
|
+
plate: { y0: 49, y1: 57 },
|
|
18
|
+
});
|
|
@@ -25,5 +25,7 @@ export const TROPHY_FOUNDATION_PLAYER_AWARD = /* @__PURE__ */ defineLathe("troph
|
|
|
25
25
|
["glass", "M19.2 61.8L20.6 60.4H43.4L44.8 61.8Z", "sh"],
|
|
26
26
|
],
|
|
27
27
|
},
|
|
28
|
+
// The text the `engrave` option cuts into the clear middle of the glass; plain glass without it.
|
|
29
|
+
{ kind: "cut", at: [0, 4.3], t: 0.1, decal: true, plate: [25.4, 38.6, 24, 38], layers: [] },
|
|
28
30
|
],
|
|
29
31
|
});
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/** The George Halas Trophy: an open football of polished silver, a laced ribbon in front and two curved bands behind, standing on its tip on a round flared base over a black foot. */
|
|
2
|
+
export declare const TROPHY_GEORGE_HALAS_TROPHY: import("../emblem.core.ts").Emblem<import("../emblem.lathe.ts").LatheModel>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// The George Halas Trophy: the trophy of the National Football Conference champion, drawn as one drawing with the Lamar Hunt Trophy (lathe.conference.ts). Drawn for this package from photographs (docs/likeness.md); the
|
|
2
|
+
// shield and the conference letters on the plate and the engraving on the base are left out.
|
|
3
|
+
import { defineLathe } from "../emblem.lathe.js";
|
|
4
|
+
import { NFL_CONFERENCE } from "../lathe.conference.js";
|
|
5
|
+
/** The George Halas Trophy: an open football of polished silver, a laced ribbon in front and two curved bands behind, standing on its tip on a round flared base over a black foot. */
|
|
6
|
+
export const TROPHY_GEORGE_HALAS_TROPHY = /* @__PURE__ */ defineLathe("trophy:george-halas-trophy", "George Halas Trophy", "ハラス・トロフィー", "ours", NFL_CONFERENCE);
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/** The Jackie Robinson Rookie of the Year Award: a walnut plaque with a black nameplate, a gold emblem, a bronze relief of a slide at the plate, a plate and a green pin. */
|
|
2
|
+
export declare const TROPHY_JACKIE_ROBINSON_AWARD: import("../emblem.core.ts").Emblem<import("../emblem.shapes.ts").FlatModel>;
|