axstack 0.36.1 → 0.37.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/README.md +3 -2
- package/bin/axstack.js +4 -18
- package/docs/getting-started.md +6 -6
- package/docs/installation.md +20 -41
- package/docs/workflows.md +12 -9
- package/package.json +1 -1
- package/profiles/presets/claude-only.json +3 -3
- package/profiles/presets/codex-only.json +3 -3
- package/profiles/presets/mixed.json +5 -4
- package/skills/axstack/references/role-roster.md +5 -3
- package/skills/axstack/references/ui-verification.md +6 -10
- package/skills/axstack-anatomy/ANATOMY.md +172 -0
- package/skills/axstack-anatomy/CHANGELOG.md +70 -0
- package/skills/axstack-anatomy/LICENSE +21 -0
- package/skills/axstack-anatomy/PROVENANCE.md +21 -0
- package/skills/axstack-anatomy/README.md +316 -0
- package/skills/axstack-anatomy/SKILL.md +74 -0
- package/skills/axstack-anatomy/SOURCE-PROOF.json +107 -0
- package/skills/axstack-anatomy/examples/arcade-cabinet/arcade-cabinet.css +44 -0
- package/skills/axstack-anatomy/examples/arcade-cabinet/build.mjs +714 -0
- package/skills/axstack-anatomy/examples/arcade-cabinet/live.js +597 -0
- package/skills/axstack-anatomy/examples/arcade-cabinet/parts.mjs +89 -0
- package/skills/axstack-anatomy/examples/arcade-cabinet/screen.mjs +114 -0
- package/skills/axstack-anatomy/examples/desk-computer/build.mjs +435 -0
- package/skills/axstack-anatomy/examples/dial-indicator/build.mjs +275 -0
- package/skills/axstack-anatomy/examples/raptor-engine/build.mjs +938 -0
- package/skills/axstack-anatomy/examples/raptor-engine/live.js +907 -0
- package/skills/axstack-anatomy/examples/raptor-engine/raptor.css +359 -0
- package/skills/axstack-anatomy/examples/ripple-tank/build.mjs +558 -0
- package/skills/axstack-anatomy/examples/ripple-tank/live.js +579 -0
- package/skills/axstack-anatomy/examples/ripple-tank/model.mjs +131 -0
- package/skills/axstack-anatomy/examples/ripple-tank/ripple.css +103 -0
- package/skills/axstack-anatomy/examples/spot-plate/art.tsx +110 -0
- package/skills/axstack-anatomy/examples/spot-plate/drops.ts +541 -0
- package/skills/axstack-anatomy/examples/spot-plate/fan.ts +84 -0
- package/skills/axstack-anatomy/examples/spot-plate/figure.tsx +25 -0
- package/skills/axstack-anatomy/examples/spot-plate/geometry.ts +280 -0
- package/skills/axstack-anatomy/examples/spot-plate/live.tsx +339 -0
- package/skills/axstack-anatomy/examples/spot-plate/rig.ts +230 -0
- package/skills/axstack-anatomy/examples/spot-plate/spot-plate.css +92 -0
- package/skills/axstack-anatomy/examples/test-rig/art.tsx +196 -0
- package/skills/axstack-anatomy/examples/test-rig/figure.tsx +23 -0
- package/skills/axstack-anatomy/examples/test-rig/geometry.ts +305 -0
- package/skills/axstack-anatomy/examples/test-rig/live.tsx +511 -0
- package/skills/axstack-anatomy/examples/test-rig/pose.ts +107 -0
- package/skills/axstack-anatomy/examples/test-rig/rig.ts +170 -0
- package/skills/axstack-anatomy/examples/test-rig/stretch.css +80 -0
- package/skills/axstack-anatomy/examples/test-rig/view.ts +99 -0
- package/skills/axstack-anatomy/examples/turning-dial/build.mjs +479 -0
- package/skills/axstack-anatomy/examples/turning-dial/dial.css +10 -0
- package/skills/axstack-anatomy/examples/turning-dial/live.js +342 -0
- package/skills/axstack-anatomy/examples/turning-dial/stress.mjs +269 -0
- package/skills/axstack-anatomy/kit/audit.mjs +1913 -0
- package/skills/axstack-anatomy/kit/canvas-painter.mjs +722 -0
- package/skills/axstack-anatomy/kit/gl-shared.mjs +184 -0
- package/skills/axstack-anatomy/kit/gl.mjs +184 -0
- package/skills/axstack-anatomy/kit/iso-kit.mjs +674 -0
- package/skills/axstack-anatomy/kit/iso-kit.ts +842 -0
- package/skills/axstack-anatomy/kit/iso.css +106 -0
- package/skills/axstack-anatomy/kit/lathe.mjs +1184 -0
- package/skills/axstack-anatomy/kit/react/draw.tsx +205 -0
- package/skills/axstack-anatomy/kit/react/live.tsx +140 -0
- package/skills/axstack-anatomy/kit/tube.mjs +306 -0
- package/skills/axstack-anatomy/kit/turn-audit.mjs +1096 -0
- package/skills/axstack-anatomy/kit/turn-build.mjs +1355 -0
- package/skills/axstack-anatomy/kit/turn-fixed.mjs +3800 -0
- package/skills/axstack-anatomy/kit/turn.mjs +3610 -0
- package/skills/axstack-anatomy/references/3d.md +352 -0
- package/skills/axstack-anatomy/references/craft.md +325 -0
- package/skills/axstack-anatomy/references/kit.md +419 -0
- package/skills/axstack-anatomy/references/motion.md +165 -0
- package/skills/axstack-anatomy/references/react.md +42 -0
- package/skills/axstack-anatomy/references/verify.md +351 -0
- package/skills/axstack-anatomy/references/walkthrough.md +75 -0
- package/skills/axstack-anatomy/references/webgl.md +473 -0
- package/skills/axstack-anatomy/scripts/audit-affine-bounds.test.mjs +54 -0
- package/skills/axstack-anatomy/scripts/audit-cache.test.mjs +37 -0
- package/skills/axstack-anatomy/scripts/audit-clearance-envelope.test.mjs +39 -0
- package/skills/axstack-anatomy/scripts/audit-empty-clipping.test.mjs +38 -0
- package/skills/axstack-anatomy/scripts/audit-order-convergence.test.mjs +55 -0
- package/skills/axstack-anatomy/scripts/audit-path-origin.test.mjs +26 -0
- package/skills/axstack-anatomy/scripts/audit-profile.test.mjs +41 -0
- package/skills/axstack-anatomy/scripts/audit-projection.test.mjs +36 -0
- package/skills/axstack-anatomy/scripts/audit-slide-clearance.test.mjs +58 -0
- package/skills/axstack-anatomy/scripts/audit-svg-attributes.test.mjs +46 -0
- package/skills/axstack-anatomy/scripts/audit-taper.test.mjs +29 -0
- package/skills/axstack-anatomy/scripts/capture-selector.test.mjs +131 -0
- package/skills/axstack-anatomy/scripts/capture.mjs +228 -0
- package/skills/axstack-anatomy/scripts/capture.test.mjs +42 -0
- package/skills/axstack-anatomy/scripts/chrome-port.mjs +36 -0
- package/skills/axstack-anatomy/scripts/chrome-startup.test.mjs +38 -0
- package/skills/axstack-anatomy/scripts/drive-actions.test.mjs +46 -0
- package/skills/axstack-anatomy/scripts/drive.mjs +302 -0
- package/skills/axstack-anatomy/scripts/drive.test.mjs +72 -0
- package/skills/axstack-anatomy/scripts/enter-key.test.mjs +38 -0
- package/skills/axstack-anatomy/scripts/fidelity-cut.test.mjs +54 -0
- package/skills/axstack-anatomy/scripts/fidelity-tube-coverage.test.mjs +40 -0
- package/skills/axstack-anatomy/scripts/inline-kit.mjs +26 -0
- package/skills/axstack-anatomy/scripts/line-ends.mjs +306 -0
- package/skills/axstack-anatomy/scripts/lines-arcs.test.mjs +50 -0
- package/skills/axstack-anatomy/scripts/lines-bezier.test.mjs +28 -0
- package/skills/axstack-anatomy/scripts/lines-round.test.mjs +56 -0
- package/skills/axstack-anatomy/scripts/lines-rounded-rect.test.mjs +32 -0
- package/skills/axstack-anatomy/scripts/lines.mjs +31 -0
- package/skills/axstack-anatomy/scripts/lines.test.mjs +38 -0
- package/skills/axstack-anatomy/scripts/navigation.test.mjs +55 -0
- package/skills/axstack-anatomy/scripts/orbit-sampling.test.mjs +50 -0
- package/skills/axstack-anatomy/scripts/react-dots-opacity.test.mjs +51 -0
- package/skills/axstack-anatomy/scripts/react-readout-first-write.test.mjs +37 -0
- package/skills/axstack-anatomy/scripts/react-solid-seamless.test.mjs +47 -0
- package/skills/axstack-anatomy/scripts/react-visibility-target.test.mjs +38 -0
- package/skills/axstack-anatomy/scripts/turn-bench.mjs +74 -0
- package/skills/axstack-anatomy/scripts/turn-check.mjs +641 -0
- package/skills/axstack-anatomy/scripts/turn-fidelity.mjs +413 -0
- package/skills/axstack-anatomy/scripts/turn-group-reference.test.mjs +40 -0
- package/skills/axstack-anatomy/scripts/turn-split-owner.test.mjs +62 -0
- package/skills/axstack-anatomy/theme.js +56 -0
- package/skills/axstack-explain/SKILL.md +28 -15
- package/skills/axstack-explain/references/delivery.md +22 -0
- package/skills/{axstack-diagram → axstack-explain}/references/fidelity.md +1 -7
- package/skills/axstack-explain/references/inline-pages.md +8 -8
- package/skills/axstack-explain/references/visual-qa.md +3 -5
- package/skills/axstack-explain/references/whiteboard-defense.md +59 -0
- package/src/archify-legacy.js +70 -0
- package/src/capabilities.js +1 -29
- package/src/installer.js +11 -31
- package/skills/axstack-diagram/SKILL.md +0 -28
- package/skills/axstack-diagram/references/archify.md +0 -76
- package/src/archify-pin.js +0 -5
- package/src/archify.js +0 -151
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { circleRing, extrude, insetPlan, onTop, pathOf, planOutline, slabOf, topMatrix, type Flat, type Plan, type Plane, type Point3 } from "../../kit/iso-kit";
|
|
2
|
+
import {
|
|
3
|
+
BAR,
|
|
4
|
+
BAR_H,
|
|
5
|
+
BASE,
|
|
6
|
+
BASE_H,
|
|
7
|
+
BUSH_D,
|
|
8
|
+
BUSH_END,
|
|
9
|
+
BUSH_W,
|
|
10
|
+
CARRIAGE,
|
|
11
|
+
CARRIAGE_H,
|
|
12
|
+
CARRIAGE_TOP,
|
|
13
|
+
CARRIAGE_Z,
|
|
14
|
+
DIAL,
|
|
15
|
+
DIAL_H,
|
|
16
|
+
DIAL_R,
|
|
17
|
+
DIAL_SPAN,
|
|
18
|
+
DIAL_TOP,
|
|
19
|
+
DIAL_Z,
|
|
20
|
+
FOOT_H,
|
|
21
|
+
FRAME_X,
|
|
22
|
+
FRAME_Y,
|
|
23
|
+
GLASS_TOP,
|
|
24
|
+
HOUSING_H,
|
|
25
|
+
HOUSING_R,
|
|
26
|
+
HOUSING_Z,
|
|
27
|
+
P,
|
|
28
|
+
PAD_H,
|
|
29
|
+
PAD_R,
|
|
30
|
+
PLUNGER_Z,
|
|
31
|
+
POST,
|
|
32
|
+
POST_L,
|
|
33
|
+
POST_R,
|
|
34
|
+
PROBE_HOME,
|
|
35
|
+
RAIL_D,
|
|
36
|
+
RAIL_H,
|
|
37
|
+
RAIL_Y,
|
|
38
|
+
RAIL_Z,
|
|
39
|
+
ROD_HALF,
|
|
40
|
+
ROD_Y,
|
|
41
|
+
ROD_Z,
|
|
42
|
+
STEM,
|
|
43
|
+
at,
|
|
44
|
+
} from "./view";
|
|
45
|
+
|
|
46
|
+
const solid = (plan: Plan, z: number, h: number, steps = 6, bevel = 0) => slabOf(plan, z, h, P, steps, bevel);
|
|
47
|
+
const cylinder = (cx: number, cy: number, r: number, z: number, h: number, steps = 32) => extrude(circleRing(cx, cy, r, steps), z, h, P, { convex: true });
|
|
48
|
+
const ring = (cx: number, cy: number, r: number, z: number, steps = 40) => onTop(circleRing(cx, cy, r, steps), z, P, true);
|
|
49
|
+
const segment = (a: Point3, b: Point3) => pathOf([at(a), at(b)]);
|
|
50
|
+
const join = (paths: string[]) => paths.join("");
|
|
51
|
+
const RADIANS = Math.PI / 180;
|
|
52
|
+
|
|
53
|
+
function knurl(cx: number, cy: number, r: number, z0: number, z1: number, count: number) {
|
|
54
|
+
const lines: string[] = [];
|
|
55
|
+
for (let index = 0; index < count; index++) {
|
|
56
|
+
const angle = (index / count) * Math.PI * 2;
|
|
57
|
+
const nx = Math.cos(angle);
|
|
58
|
+
const ny = Math.sin(angle);
|
|
59
|
+
if (nx * Math.cos(57 * RADIANS) + ny * Math.sin(57 * RADIANS) < 0.15) continue;
|
|
60
|
+
lines.push(segment([cx + r * nx, cy + r * ny, z0 + 0.4], [cx + r * nx, cy + r * ny, z1 - 0.4]));
|
|
61
|
+
}
|
|
62
|
+
return join(lines);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function sideArc(cx: number, cy: number, r: number, z: number, steps = 24) {
|
|
66
|
+
const points: Flat[] = [];
|
|
67
|
+
for (let step = 0; step <= steps; step++) {
|
|
68
|
+
const angle = (57 - 90 + (step / steps) * 180) * RADIANS;
|
|
69
|
+
points.push(at([cx + r * Math.cos(angle), cy + r * Math.sin(angle), z]));
|
|
70
|
+
}
|
|
71
|
+
return pathOf(points);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function faceRing(x: number, cy: number, cz: number, r: number, steps = 20) {
|
|
75
|
+
const points: Flat[] = [];
|
|
76
|
+
for (let step = 0; step < steps; step++) {
|
|
77
|
+
const angle = (step / steps) * Math.PI * 2;
|
|
78
|
+
points.push(at([x, cy + r * Math.cos(angle), cz + r * Math.sin(angle)]));
|
|
79
|
+
}
|
|
80
|
+
return pathOf(points, true);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const FEET: Plane[] = [
|
|
84
|
+
[BASE.x + 18, BASE.y + 16],
|
|
85
|
+
[BASE.x + BASE.w - 18, BASE.y + 16],
|
|
86
|
+
[BASE.x + 18, BASE.y + BASE.d - 16],
|
|
87
|
+
[BASE.x + BASE.w - 18, BASE.y + BASE.d - 16],
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
const BASE_SCREWS: Plane[] = [
|
|
91
|
+
[BASE.x + 8, BASE.y + 8],
|
|
92
|
+
[BASE.x + BASE.w - 8, BASE.y + 8],
|
|
93
|
+
[BASE.x + 8, BASE.y + BASE.d - 8],
|
|
94
|
+
[BASE.x + BASE.w - 8, BASE.y + BASE.d - 8],
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
const PLATE: Plan = { x: BASE.x + 20, y: FRAME_Y + BAR + 6, w: 56, d: 11, r: 2 };
|
|
98
|
+
|
|
99
|
+
export const BASE_ART = {
|
|
100
|
+
halo: solid(BASE, -BASE_H - FOOT_H, BASE_H).fill,
|
|
101
|
+
feet: FEET.map(([x, y]) => [cylinder(x, y, 7, -BASE_H - FOOT_H, 1.6), cylinder(x, y, 5.5, -BASE_H - FOOT_H + 1.6, FOOT_H - 1.6)]),
|
|
102
|
+
slab: solid(BASE, -BASE_H, BASE_H, 8, 1.6),
|
|
103
|
+
groove: planOutline(insetPlan(BASE, 4.5), 0, P),
|
|
104
|
+
screws: BASE_SCREWS.map(([x, y]) => at([x, y, 0])),
|
|
105
|
+
screwRings: join(BASE_SCREWS.map(([x, y]) => ring(x, y, 2.2, 0, 16))),
|
|
106
|
+
plate: solid(PLATE, 0, 0.8, 4),
|
|
107
|
+
plateLine: planOutline(insetPlan(PLATE, 1.6), 0.8, P),
|
|
108
|
+
plateScrews: [at([PLATE.x + 3.5, PLATE.y + PLATE.d / 2, 0.8]), at([PLATE.x + PLATE.w - 3.5, PLATE.y + PLATE.d / 2, 0.8])],
|
|
109
|
+
plateRule: join([0, 1, 2].map((row) => onTop([[PLATE.x + 8, PLATE.y + 3.4 + row * 2.1], [PLATE.x + (row === 1 ? 34 : 44), PLATE.y + 3.4 + row * 2.1]], 0.8, P))),
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const POST_PLANS: Plan[] = [POST_L, POST_R].map((x) => ({ x, y: RAIL_Y - POST / 2, w: POST, d: POST, r: 2 }));
|
|
113
|
+
const RAIL: Plan = { x: POST_L - 5, y: RAIL_Y - RAIL_D / 2, w: POST_R + POST - POST_L + 10, d: RAIL_D, r: 2 };
|
|
114
|
+
const RAIL_FACE = RAIL_Y + RAIL_D / 2;
|
|
115
|
+
const RAIL_TOP = RAIL_Z + RAIL_H;
|
|
116
|
+
const RULE_FROM = POST_L + POST + 4;
|
|
117
|
+
const RULE_TO = POST_R - 4;
|
|
118
|
+
|
|
119
|
+
function ruler() {
|
|
120
|
+
const minor: string[] = [];
|
|
121
|
+
const major: string[] = [];
|
|
122
|
+
for (let x = Math.ceil(RULE_FROM / 5) * 5; x <= RULE_TO; x += 5) {
|
|
123
|
+
const big = x % 25 === 0;
|
|
124
|
+
(big ? major : minor).push(segment([x, RAIL_FACE, RAIL_TOP - 1.2], [x, RAIL_FACE, RAIL_TOP - (big ? 5 : 3)]));
|
|
125
|
+
}
|
|
126
|
+
return { minor: join(minor), major: join(major) };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const RULE = ruler();
|
|
130
|
+
|
|
131
|
+
export const RAIL_ART = {
|
|
132
|
+
feet: POST_PLANS.map((plan) => solid(insetPlan(plan, -3), 0, 2, 4)),
|
|
133
|
+
footScrews: POST_PLANS.flatMap((plan) => [at([plan.x - 1, plan.y + POST / 2, 2]), at([plan.x + POST + 1, plan.y + POST / 2, 2])]),
|
|
134
|
+
posts: POST_PLANS.map((plan) => solid(plan, 2, RAIL_Z - 2, 4)),
|
|
135
|
+
postLines: join(POST_PLANS.map((plan) => segment([plan.x + POST, plan.y + POST, 6], [plan.x + POST, plan.y + POST, RAIL_Z - 4]))),
|
|
136
|
+
rail: solid(RAIL, RAIL_Z, RAIL_H, 4, 0.8),
|
|
137
|
+
railScrews: POST_PLANS.map((plan) => at([plan.x + POST / 2, RAIL_Y, RAIL_TOP])),
|
|
138
|
+
ruleMinor: RULE.minor,
|
|
139
|
+
ruleMajor: RULE.major,
|
|
140
|
+
ruleBase: segment([RULE_FROM, RAIL_FACE, RAIL_TOP - 1.2], [RULE_TO, RAIL_FACE, RAIL_TOP - 1.2]),
|
|
141
|
+
stops: [RULE_FROM - 2, RULE_TO + 2].map((x) => solid({ x: x - 1.5, y: RAIL_Y - RAIL_D / 2 - 0.5, w: 3, d: RAIL_D + 1, r: 0.8 }, RAIL_TOP, 2.2, 3)),
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export const RIDER = {
|
|
145
|
+
body: solid({ x: -1.6, y: RAIL_Y - RAIL_D / 2 - 0.6, w: 3.2, d: RAIL_D + 1.2, r: 0.8 }, RAIL_TOP, 1.4, 3),
|
|
146
|
+
tick: segment([0, RAIL_FACE + 0.6, RAIL_TOP + 1.4], [0, RAIL_FACE + 0.6, RAIL_TOP - 3]),
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const H = PROBE_HOME;
|
|
150
|
+
const BLOCK: Plan = { x: H - 11, y: RAIL_Y - 7, w: 22, d: 14, r: 2.5 };
|
|
151
|
+
const BLOCK_Z = RAIL_TOP;
|
|
152
|
+
const BLOCK_H = 9;
|
|
153
|
+
const ARM_Z = BLOCK_Z + 3;
|
|
154
|
+
const ARM_H = 5;
|
|
155
|
+
const ARM: Plan = { x: H - 3.5, y: BLOCK.y + BLOCK.d - 1, w: 7, d: -(BLOCK.y + BLOCK.d - 1) + 2, r: 1.5 };
|
|
156
|
+
|
|
157
|
+
export const PROBE_ART = {
|
|
158
|
+
block: solid(BLOCK, BLOCK_Z, BLOCK_H, 5, 0.8),
|
|
159
|
+
blockLine: planOutline(insetPlan(BLOCK, 2), BLOCK_Z + BLOCK_H, P),
|
|
160
|
+
blockScrews: [at([BLOCK.x + 3, BLOCK.y + 3, BLOCK_Z + BLOCK_H]), at([BLOCK.x + BLOCK.w - 3, BLOCK.y + 3, BLOCK_Z + BLOCK_H])],
|
|
161
|
+
thumb: cylinder(H - 5, RAIL_Y - 1, 2.6, BLOCK_Z + BLOCK_H, 3.2, 20),
|
|
162
|
+
thumbKnurl: knurl(H - 5, RAIL_Y - 1, 2.6, BLOCK_Z + BLOCK_H, BLOCK_Z + BLOCK_H + 3.2, 16),
|
|
163
|
+
pointer: solid({ x: H - 2, y: BLOCK.y + BLOCK.d, w: 4, d: 1, r: 0.4 }, RAIL_TOP - 4, 4 + 2, 2),
|
|
164
|
+
index: segment([H, BLOCK.y + BLOCK.d + 1, RAIL_TOP + 1.5], [H, BLOCK.y + BLOCK.d + 1, RAIL_TOP - 3.6]),
|
|
165
|
+
arm: solid(ARM, ARM_Z, ARM_H, 4, 0.6),
|
|
166
|
+
armLine: onTop([[H, ARM.y + 3], [H, -9]], ARM_Z + ARM_H, P),
|
|
167
|
+
armScrews: [at([H, ARM.y + 2, ARM_Z + ARM_H]), at([H, -2, ARM_Z + ARM_H])],
|
|
168
|
+
housing: cylinder(H, 0, HOUSING_R, HOUSING_Z, HOUSING_H - 2, 32),
|
|
169
|
+
cap: cylinder(H, 0, HOUSING_R + 0.8, HOUSING_Z + HOUSING_H - 2, 2, 32),
|
|
170
|
+
collar: cylinder(H, 0, HOUSING_R + 0.8, HOUSING_Z, 2.4, 32),
|
|
171
|
+
housingSeam: join([HOUSING_Z + 6, HOUSING_Z + 11].map((z) => sideArc(H, 0, HOUSING_R, z))),
|
|
172
|
+
lock: solid({ x: H - 1.6, y: HOUSING_R - 0.5, w: 3.2, d: 3.5, r: 0.8 }, HOUSING_Z + 8, 3.2, 2),
|
|
173
|
+
lockHead: cylinder(H, HOUSING_R + 4.4, 2.2, HOUSING_Z + 7.4, 4.4, 16),
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const PAD_Z = GLASS_TOP;
|
|
177
|
+
export const FINGER_ART = {
|
|
178
|
+
stem: cylinder(H, 0, 1.5, PAD_Z + PAD_H + 2, STEM, 16),
|
|
179
|
+
stemMarks: join([8, 11, 14].map((rise) => sideArc(H, 0, 1.5, PAD_Z + PAD_H + 2 + rise, 12))),
|
|
180
|
+
collar: cylinder(H, 0, 2.6, PAD_Z + PAD_H, 2, 20),
|
|
181
|
+
pad: cylinder(H, 0, PAD_R, PAD_Z, PAD_H, 32),
|
|
182
|
+
padRing: ring(H, 0, PAD_R - 1.2, PAD_Z + PAD_H, 28),
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const BARS: Plan[] = [
|
|
186
|
+
{ x: -FRAME_X - BAR, y: -FRAME_Y - BAR, w: (FRAME_X + BAR) * 2, d: BAR, r: 1.5 },
|
|
187
|
+
{ x: -FRAME_X - BAR, y: -FRAME_Y, w: BAR, d: FRAME_Y * 2, r: 0.6 },
|
|
188
|
+
{ x: FRAME_X, y: -FRAME_Y, w: BAR, d: FRAME_Y * 2, r: 0.6 },
|
|
189
|
+
{ x: -FRAME_X - BAR, y: FRAME_Y, w: (FRAME_X + BAR) * 2, d: BAR, r: 1.5 },
|
|
190
|
+
];
|
|
191
|
+
|
|
192
|
+
const barScrews = (plan: Plan): Flat[] =>
|
|
193
|
+
plan.w > plan.d
|
|
194
|
+
? [-1, 1].map((side) => at([side * (FRAME_X + BAR / 2), plan.y + BAR / 2, BAR_H]))
|
|
195
|
+
: [-1, 1].map((side) => at([plan.x + BAR / 2, side * (FRAME_Y - 6), BAR_H]));
|
|
196
|
+
|
|
197
|
+
const FLOOR: Plan = { x: -FRAME_X, y: -FRAME_Y, w: FRAME_X * 2, d: FRAME_Y * 2, r: 0 };
|
|
198
|
+
|
|
199
|
+
function floorGrid() {
|
|
200
|
+
const lines: string[] = [];
|
|
201
|
+
for (let x = -FRAME_X + 10; x < FRAME_X; x += 10) lines.push(onTop([[x, -FRAME_Y], [x, FRAME_Y]], 0.8, P));
|
|
202
|
+
for (let y = -FRAME_Y + 7.4; y < FRAME_Y; y += 7.4) lines.push(onTop([[-FRAME_X, y], [FRAME_X, y]], 0.8, P));
|
|
203
|
+
return join(lines);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function barTicks() {
|
|
207
|
+
const minor: string[] = [];
|
|
208
|
+
const major: string[] = [];
|
|
209
|
+
const y = FRAME_Y + 1;
|
|
210
|
+
for (let x = -40; x <= 40; x += 2) {
|
|
211
|
+
const big = x % 10 === 0;
|
|
212
|
+
(big ? major : minor).push(onTop([[x, y], [x, y + (big ? 3.2 : 1.8)]], BAR_H, P));
|
|
213
|
+
}
|
|
214
|
+
return { minor: join(minor), major: join(major) };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const TICKS = barTicks();
|
|
218
|
+
|
|
219
|
+
export const FRAME_ART = {
|
|
220
|
+
back: solid(BARS[0]!, 0, BAR_H, 4, 0.8),
|
|
221
|
+
left: solid(BARS[1]!, 0, BAR_H, 3, 0.8),
|
|
222
|
+
right: solid(BARS[2]!, 0, BAR_H, 3, 0.8),
|
|
223
|
+
front: solid(BARS[3]!, 0, BAR_H, 4, 0.8),
|
|
224
|
+
backScrews: barScrews(BARS[0]!),
|
|
225
|
+
leftScrews: barScrews(BARS[1]!),
|
|
226
|
+
rightScrews: barScrews(BARS[2]!),
|
|
227
|
+
frontScrews: barScrews(BARS[3]!),
|
|
228
|
+
floor: solid(FLOOR, 0, 0.8, 2),
|
|
229
|
+
grid: floorGrid(),
|
|
230
|
+
ticksMinor: TICKS.minor,
|
|
231
|
+
ticksMajor: TICKS.major,
|
|
232
|
+
zero: onTop([[0, FRAME_Y + 0.6], [0, FRAME_Y + BAR - 0.6]], BAR_H, P),
|
|
233
|
+
rodEnds: join([-ROD_Y, ROD_Y].map((y) => faceRing(FRAME_X + BAR, y, ROD_Z, 3, 16))),
|
|
234
|
+
rodNuts: [-ROD_Y, ROD_Y].map((y) => at([FRAME_X + BAR, y, ROD_Z])),
|
|
235
|
+
bore: faceRing(FRAME_X + BAR, 0, PLUNGER_Z, 2.2, 14),
|
|
236
|
+
leftBores: join([-ROD_Y, ROD_Y].map((y) => faceRing(-FRAME_X, y, ROD_Z, 3, 16))),
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
export const RODS = [-ROD_Y, ROD_Y].map((y) => solid({ x: -FRAME_X, y: y - ROD_HALF, w: FRAME_X * 2, d: ROD_HALF * 2, r: ROD_HALF - 0.2 }, ROD_Z - ROD_HALF, ROD_HALF * 2, 3));
|
|
240
|
+
|
|
241
|
+
const SEAT: Plan = { x: -63, y: -18, w: 126, d: 36, r: 18 };
|
|
242
|
+
const BUSHES: Plan[] = [-1, 1].flatMap((side) =>
|
|
243
|
+
[-ROD_Y, ROD_Y].map((y) => ({ x: side < 0 ? -BUSH_END : BUSH_END - BUSH_W, y: y - BUSH_D / 2, w: BUSH_W, d: BUSH_D, r: 2 })),
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
export const CARRIAGE_ART = {
|
|
247
|
+
halo: solid(insetPlan(CARRIAGE, 3), 0.8, 0.1).fill,
|
|
248
|
+
plate: solid(CARRIAGE, CARRIAGE_Z, CARRIAGE_H, 6, 0.8),
|
|
249
|
+
seat: planOutline(SEAT, CARRIAGE_TOP, P, 10),
|
|
250
|
+
seatInner: planOutline(insetPlan(SEAT, 2.4), CARRIAGE_TOP, P, 10),
|
|
251
|
+
bushes: BUSHES.map((plan) => solid(plan, CARRIAGE_Z - 1, CARRIAGE_H + 4, 3, 0.6)),
|
|
252
|
+
bushScrews: BUSHES.flatMap((plan) => [at([plan.x + 3, plan.y + plan.d / 2, CARRIAGE_TOP + 3]), at([plan.x + plan.w - 3, plan.y + plan.d / 2, CARRIAGE_TOP + 3])]),
|
|
253
|
+
bushBores: join([-ROD_Y, ROD_Y].map((y) => faceRing(BUSH_END, y, ROD_Z, 2.8, 14))),
|
|
254
|
+
contact: solid({ x: BUSH_END - 8, y: -4, w: 8, d: 8, r: 2 }, CARRIAGE_Z, CARRIAGE_H, 3, 0.4),
|
|
255
|
+
rivets: [-56, -28, 0, 28, 56].map((x) => at([x, CARRIAGE.y + CARRIAGE.d - 2.4, CARRIAGE_TOP])),
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
export const PLUNGER_ART = {
|
|
259
|
+
rod: solid({ x: BUSH_END, y: -1.1, w: 44, d: 2.2, r: 1 }, PLUNGER_Z - 1.1, 2.2, 3),
|
|
260
|
+
collar: solid({ x: BUSH_END + 0.4, y: -2.2, w: 2.4, d: 4.4, r: 1 }, PLUNGER_Z - 2.2, 4.4, 3, 0.3),
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const [DX, DY] = DIAL;
|
|
264
|
+
const STAND: Plan = { x: DX - 15, y: DY - 14, w: 30, d: 28, r: 3 };
|
|
265
|
+
|
|
266
|
+
function dialTicks() {
|
|
267
|
+
const minor: string[] = [];
|
|
268
|
+
const major: string[] = [];
|
|
269
|
+
for (let step = 0; step < DIAL_SPAN; step++) {
|
|
270
|
+
const angle = (step / DIAL_SPAN) * Math.PI * 2;
|
|
271
|
+
const big = step % 5 === 0;
|
|
272
|
+
const sx = Math.sin(angle);
|
|
273
|
+
const sy = -Math.cos(angle);
|
|
274
|
+
const outer = DIAL_R - 2.4;
|
|
275
|
+
const inner = outer - (big ? 2.6 : 1.4);
|
|
276
|
+
(big ? major : minor).push(onTop([[DX + sx * inner, DY + sy * inner], [DX + sx * outer, DY + sy * outer]], DIAL_TOP, P));
|
|
277
|
+
}
|
|
278
|
+
return { minor: join(minor), major: join(major) };
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const DIAL_TICKS = dialTicks();
|
|
282
|
+
const GIVE_ANGLE = (14 / DIAL_SPAN) * Math.PI * 2;
|
|
283
|
+
const R_GIVE = DIAL_R - 1.4;
|
|
284
|
+
|
|
285
|
+
export const DIAL_ART = {
|
|
286
|
+
stand: solid(STAND, 0, DIAL_Z, 4, 0.6),
|
|
287
|
+
standScrews: [at([STAND.x + 3.4, STAND.y + 3.4, DIAL_Z]), at([STAND.x + STAND.w - 3.4, STAND.y + STAND.d - 3.4, DIAL_Z]), at([STAND.x + 3.4, STAND.y + STAND.d - 3.4, DIAL_Z]), at([STAND.x + STAND.w - 3.4, STAND.y + 3.4, DIAL_Z])],
|
|
288
|
+
sleeve: solid({ x: FRAME_X + BAR, y: -2.6, w: DX - DIAL_R - FRAME_X - BAR + 0.6, d: 5.2, r: 1 }, PLUNGER_Z - 2.6, 5.2, 3),
|
|
289
|
+
clamp: cylinder(FRAME_X + BAR + 3.2, 0, 1.6, PLUNGER_Z + 2.6, 2, 12),
|
|
290
|
+
puck: cylinder(DX, DY, DIAL_R, DIAL_Z, DIAL_H, 56),
|
|
291
|
+
bezel: ring(DX, DY, DIAL_R - 1, DIAL_TOP, 56),
|
|
292
|
+
face: ring(DX, DY, DIAL_R - 2.4, DIAL_TOP, 56),
|
|
293
|
+
knurl: knurl(DX, DY, DIAL_R, DIAL_Z + DIAL_H - 3, DIAL_Z + DIAL_H, 56),
|
|
294
|
+
band: sideArc(DX, DY, DIAL_R, DIAL_Z + DIAL_H - 3, 40),
|
|
295
|
+
minor: DIAL_TICKS.minor,
|
|
296
|
+
major: DIAL_TICKS.major,
|
|
297
|
+
give: [-1, 1].map((side) => at([DX + Math.sin(side * GIVE_ANGLE) * R_GIVE, DY - Math.cos(side * GIVE_ANGLE) * R_GIVE, DIAL_TOP])),
|
|
298
|
+
crown: solid({ x: DX + DIAL_R - 0.6, y: -2.4, w: 4.4, d: 4.8, r: 1.2 }, DIAL_Z + 2, 4, 3),
|
|
299
|
+
crownCap: solid({ x: DX + DIAL_R + 3.6, y: -3.2, w: 2.6, d: 6.4, r: 1.2 }, DIAL_Z + 1.2, 5.6, 3),
|
|
300
|
+
lug: solid({ x: DX - 3, y: DY - DIAL_R - 3.4, w: 6, d: 4, r: 1.2 }, DIAL_Z + 1.5, 5, 3),
|
|
301
|
+
label: topMatrix([DX, DY + 5.2], DIAL_TOP, P, "x"),
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
const REST_GLASS = { x: -60, y: -16, w: 120, d: 32, r: 16 };
|
|
305
|
+
export const REST_OUTLINE = planOutline(REST_GLASS, GLASS_TOP, P, 12);
|