@vessel-dsp/stompbox 0.6.4
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/LICENSE.md +21 -0
- package/README.md +471 -0
- package/assets/cad/parts/box-125b/.tayda-a7244.step.glb +0 -0
- package/assets/cad/parts/box-125b/tayda-a7244.step +3588 -0
- package/assets/cad/parts/box-1590b/.tayda-a6619.step.glb +0 -0
- package/assets/cad/parts/box-1590b/tayda-a6619.step +3587 -0
- package/assets/cad/parts/box-1590bb/.tayda-a5880.step.glb +0 -0
- package/assets/cad/parts/box-1590bb/tayda-a5880.step +3589 -0
- package/assets/cad/parts/box-hammond-diecast-stompbox-series/.hammond-1590a.step.glb +0 -0
- package/assets/cad/parts/box-hammond-diecast-stompbox-series/.hammond-1590n1.step.glb +0 -0
- package/assets/cad/parts/box-hammond-diecast-stompbox-series/.hammond-1590xx.step.glb +0 -0
- package/assets/cad/parts/box-hammond-diecast-stompbox-series/hammond-1590a.step +3587 -0
- package/assets/cad/parts/box-hammond-diecast-stompbox-series/hammond-1590n1.step +3589 -0
- package/assets/cad/parts/box-hammond-diecast-stompbox-series/hammond-1590xx.step +3589 -0
- package/assets/cad/parts/dc-socket-dc099/.dc099.step.glb +0 -0
- package/assets/cad/parts/dc-socket-dc099/dc099.step +261 -0
- package/assets/cad/parts/jack-ts-pj629han/.pj-629han-05.step.glb +0 -0
- package/assets/cad/parts/jack-ts-pj629han/pj-629han-05.step +261 -0
- package/assets/cad/parts/knob-chickenhead-lms-30mm/.lovemyswitches-chicken-head-30mm.step.glb +0 -0
- package/assets/cad/parts/knob-chickenhead-lms-30mm/lovemyswitches-chicken-head-30mm.step +535 -0
- package/assets/cad/parts/knob-cm42-bb/.tayda-a6078-cm42-bb.step.glb +0 -0
- package/assets/cad/parts/knob-cm42-bb/tayda-a6078-cm42-bb.step +535 -0
- package/assets/cad/parts/knob-davies-instrument-series/.davies-1100.step.glb +0 -0
- package/assets/cad/parts/knob-davies-instrument-series/.davies-1105.step.glb +0 -0
- package/assets/cad/parts/knob-davies-instrument-series/.davies-1110.step.glb +0 -0
- package/assets/cad/parts/knob-davies-instrument-series/.davies-1120.step.glb +0 -0
- package/assets/cad/parts/knob-davies-instrument-series/.davies-1510bg.step.glb +0 -0
- package/assets/cad/parts/knob-davies-instrument-series/.davies-1550ag.step.glb +0 -0
- package/assets/cad/parts/knob-davies-instrument-series/.davies-1900.step.glb +0 -0
- package/assets/cad/parts/knob-davies-instrument-series/davies-1100.step +7781 -0
- package/assets/cad/parts/knob-davies-instrument-series/davies-1105.step +7975 -0
- package/assets/cad/parts/knob-davies-instrument-series/davies-1110.step +8754 -0
- package/assets/cad/parts/knob-davies-instrument-series/davies-1120.step +8570 -0
- package/assets/cad/parts/knob-davies-instrument-series/davies-1510bg.step +1686 -0
- package/assets/cad/parts/knob-davies-instrument-series/davies-1550ag.step +3137 -0
- package/assets/cad/parts/knob-davies-instrument-series/davies-1900.step +19769 -0
- package/assets/cad/parts/knob-mxr-style-fluted/.daier-mf-b01.step.glb +0 -0
- package/assets/cad/parts/knob-mxr-style-fluted/.daier-mf-b02.step.glb +0 -0
- package/assets/cad/parts/knob-mxr-style-fluted/.daier-mf-b03.step.glb +0 -0
- package/assets/cad/parts/knob-mxr-style-fluted/.tayda-a1829-tymf-b00.step.glb +0 -0
- package/assets/cad/parts/knob-mxr-style-fluted/daier-mf-b01.step +4277 -0
- package/assets/cad/parts/knob-mxr-style-fluted/daier-mf-b02.step +4318 -0
- package/assets/cad/parts/knob-mxr-style-fluted/daier-mf-b03.step +4577 -0
- package/assets/cad/parts/knob-mxr-style-fluted/tayda-a1829-tymf-b00.step +535 -0
- package/assets/cad/parts/led-5mm-red-kento-5408urc/.kento-5408urc.step.glb +0 -0
- package/assets/cad/parts/led-5mm-red-kento-5408urc/kento-5408urc.step +384 -0
- package/assets/cad/parts/led-bezel-lh5/.pedal-parts-and-kits-bzl-5mm-p.step.glb +0 -0
- package/assets/cad/parts/led-bezel-lh5/pedal-parts-and-kits-bzl-5mm-p.step +469 -0
- package/assets/cad/parts/switch-3pdt-pic-pbs24302/.pic-pbs24302.step.glb +0 -0
- package/assets/cad/parts/switch-3pdt-pic-pbs24302/pic-pbs24302.step +435 -0
- package/assets/cad/parts/switch-toggle-reference-series/.toggle-switch-dpdt-pcb.step.glb +0 -0
- package/assets/cad/parts/switch-toggle-reference-series/.toggle-switch-mounting-plate.step.glb +0 -0
- package/assets/cad/parts/switch-toggle-reference-series/.toggle-switch-spdt-pcb.step.glb +0 -0
- package/assets/cad/parts/switch-toggle-reference-series/.toggle-switch-spst-13x7.step.glb +0 -0
- package/assets/cad/parts/switch-toggle-reference-series/toggle-switch-dpdt-pcb.step +2860 -0
- package/assets/cad/parts/switch-toggle-reference-series/toggle-switch-mounting-plate.step +1090 -0
- package/assets/cad/parts/switch-toggle-reference-series/toggle-switch-spdt-pcb.step +1749 -0
- package/assets/cad/parts/switch-toggle-reference-series/toggle-switch-spst-13x7.step +1608 -0
- package/dist/index.d.ts +714 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4462 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) VesselDSP contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
# @vessel-dsp/stompbox
|
|
2
|
+
|
|
3
|
+
Headless stompbox drill-layout and preview manifest helpers for `.vdsp`
|
|
4
|
+
documents parsed by `@vessel-dsp/core`.
|
|
5
|
+
|
|
6
|
+
This package does not render UI. It emits headless artifacts that downstream
|
|
7
|
+
tools can display or save:
|
|
8
|
+
|
|
9
|
+
- drill-layout manifests;
|
|
10
|
+
- drill-template SVG strings in `preview` and A4 `print` modes;
|
|
11
|
+
- mesh-backed stompbox preview GLB bytes assembled from caller-provided CAD
|
|
12
|
+
part GLBs and STEP companions via `hardwareProfile` plus `basePath`;
|
|
13
|
+
- orthographic preview SVG views for `top`, `bottom`, `left`, `right`, and
|
|
14
|
+
`back`;
|
|
15
|
+
- optional text, SVG, or image decals for brand/model/custom sticker artwork;
|
|
16
|
+
- headless pedal state, interaction, and preview-patch helpers for live
|
|
17
|
+
stompbox previews.
|
|
18
|
+
|
|
19
|
+
Applications own production part profiles, enclosure profiles, and asset roots.
|
|
20
|
+
Keep named style presets in your application or docs layer and pass them through
|
|
21
|
+
`styleProfile` when you want preset-specific default parts or placement rules.
|
|
22
|
+
|
|
23
|
+
Drill-template holes are fabrication holes: their circle diameters come from
|
|
24
|
+
each part profile's panel drill clearance, such as the PJ-629HAN 9.5 mm drill
|
|
25
|
+
and the DC099 8 mm barrel opening. Preview views and collision checks may use
|
|
26
|
+
larger visible exterior geometry, such as jack rings, bushings, nuts, and
|
|
27
|
+
bezels.
|
|
28
|
+
|
|
29
|
+
When `.vdsp` physical placement is present, stompbox preserves it as
|
|
30
|
+
`vdsp-declared`. When placement or common enclosure hardware is absent, stompbox
|
|
31
|
+
generates deterministic `auto-generated` placements for knobs, status LED,
|
|
32
|
+
bypass footswitch, input/output jacks, and the 9V connector. Set
|
|
33
|
+
`includePowerJack: false` to omit the synthesized 9V connector.
|
|
34
|
+
|
|
35
|
+
Pass `decals` to preview or drill-template helpers to place custom text, SVG,
|
|
36
|
+
or image artwork on the enclosure. Preview SVG views render the decal content
|
|
37
|
+
on the box, preview GLB output includes decal plane nodes with sticker metadata,
|
|
38
|
+
drill template preview mode shows decal outlines, and A4 print mode places the
|
|
39
|
+
decals in a separate sticker sheet area.
|
|
40
|
+
|
|
41
|
+
Decals can target the `top`, `left`, `right`, `back`, or `bottom` plane. Use
|
|
42
|
+
`placement: { kind: "grid" }` when the sticker should snap to the center of a
|
|
43
|
+
face grid cell. The grid uses the requested `columns` and `rows`, capped so
|
|
44
|
+
each cell remains at least 12 mm wide or tall. For example, a 40 mm wide face
|
|
45
|
+
can address at most 3 columns.
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const decals = [
|
|
49
|
+
{
|
|
50
|
+
id: "brand-label",
|
|
51
|
+
kind: "text",
|
|
52
|
+
text: "FUZZ LAB",
|
|
53
|
+
face: "top",
|
|
54
|
+
color: "#2563eb",
|
|
55
|
+
fontFamily: '"Roboto", sans-serif',
|
|
56
|
+
placement: { kind: "grid", columns: 4, rows: 4, column: 4, row: 2 },
|
|
57
|
+
sizeMm: { widthMm: 28, heightMm: 7 },
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: "side-vector",
|
|
61
|
+
kind: "svg",
|
|
62
|
+
face: "left",
|
|
63
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><path d="M1 5 H9" stroke="currentColor"/></svg>',
|
|
64
|
+
color: "#ef4444",
|
|
65
|
+
placement: { kind: "grid", columns: 2, rows: 4, column: 2, row: 3 },
|
|
66
|
+
sizeMm: { widthMm: 10, heightMm: 8 },
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: "back-image",
|
|
70
|
+
kind: "image",
|
|
71
|
+
face: "back",
|
|
72
|
+
href: "/artwork/sticker.png",
|
|
73
|
+
placement: { kind: "grid", columns: 4, rows: 1, column: 4, row: 1 },
|
|
74
|
+
sizeMm: { widthMm: 16, heightMm: 8 },
|
|
75
|
+
},
|
|
76
|
+
] as const;
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Helper map
|
|
80
|
+
|
|
81
|
+
Use `FromVdsp` helpers when the caller has serialized `.vdsp` text. Use the
|
|
82
|
+
document helpers when the caller has already parsed or edited a
|
|
83
|
+
`CircuitDocument`.
|
|
84
|
+
|
|
85
|
+
| Need | `.vdsp` helper | `CircuitDocument` helper |
|
|
86
|
+
| --- | --- | --- |
|
|
87
|
+
| Drill hole coordinates and diagnostics | `createStompboxDrillLayoutFromVdsp` | `createStompboxDrillLayout` |
|
|
88
|
+
| Drill-template manifest | `createStompboxDrillTemplateFromVdsp` | `createStompboxDrillTemplate` |
|
|
89
|
+
| Drill-template SVG string | `createStompboxDrillTemplateSvgFromVdsp` | `createStompboxDrillTemplateSvg` |
|
|
90
|
+
| Preview manifest | `createStompboxPreviewFromVdsp` | `createStompboxPreview` |
|
|
91
|
+
| Orthographic 2D SVG views | `createStompboxPreviewSvgViewsFromVdsp` | `createStompboxPreviewSvgViews` |
|
|
92
|
+
| Mesh-backed 3D GLB bytes | `createStompboxPreviewGlbFromVdsp` | `createStompboxPreviewGlb` |
|
|
93
|
+
| Frontend recolor patch | `createStompboxAppearancePatch` | `createStompboxAppearancePatch` |
|
|
94
|
+
| Resolved appearance alias | `resolveStompboxAppearance` | `resolveStompboxAppearance` |
|
|
95
|
+
| Source/compiled control surface | `parseCircuitDocumentFile` then `createStompboxControlSurface` | `createStompboxControlSurface` |
|
|
96
|
+
| Default live pedal state | `createDefaultStompboxPedalStateFromVdsp` | `createDefaultStompboxPedalState` |
|
|
97
|
+
| Headless live state store | `createStompboxPedalStateStore` | `createStompboxPedalStateStore` |
|
|
98
|
+
| Preview state patch | `createStompboxPreviewStatePatch` | `createStompboxPreviewStatePatch` |
|
|
99
|
+
|
|
100
|
+
Generated docs examples are published at:
|
|
101
|
+
|
|
102
|
+
- 2D preview SVG: `/core/examples/stompbox-mxr-style-preview-top.svg`
|
|
103
|
+
- 3D preview GLB: `/core/examples/stompbox-mxr-style-preview.glb`
|
|
104
|
+
- Drill-template preview SVG: `/core/examples/stompbox-mxr-style-drill-template-preview.svg`
|
|
105
|
+
- Drill-layout JSON: `/core/examples/stompbox-mxr-style-drill-layout.json`
|
|
106
|
+
|
|
107
|
+
## Providing CAD assets for 3D preview
|
|
108
|
+
|
|
109
|
+
`createStompboxPreviewGlbFromVdsp()` and `createStompboxPreviewGlb()` read GLB
|
|
110
|
+
files from disk. Put each part and enclosure GLB under an application-owned
|
|
111
|
+
asset root, reference those files from `hardwareProfile`, and pass that root as
|
|
112
|
+
`basePath`.
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import {
|
|
116
|
+
createStompboxPreviewGlbFromVdsp,
|
|
117
|
+
type StompboxHardwareProfile,
|
|
118
|
+
} from "@vessel-dsp/stompbox";
|
|
119
|
+
|
|
120
|
+
const hardwareProfile: StompboxHardwareProfile = {
|
|
121
|
+
id: "my-app-hardware",
|
|
122
|
+
label: "My app hardware",
|
|
123
|
+
defaultEnclosureId: "box-1590b",
|
|
124
|
+
defaultPartIds: {
|
|
125
|
+
knob: "my-knob",
|
|
126
|
+
largeKnob: "my-knob",
|
|
127
|
+
smallKnob: "my-knob",
|
|
128
|
+
led: "my-led",
|
|
129
|
+
footswitch: "my-footswitch",
|
|
130
|
+
audioJack: "my-audio-jack",
|
|
131
|
+
dcJack: "my-dc-jack",
|
|
132
|
+
},
|
|
133
|
+
enclosureProfiles: {
|
|
134
|
+
"box-1590b": {
|
|
135
|
+
variantId: "box-1590b",
|
|
136
|
+
label: "1590B enclosure",
|
|
137
|
+
dimensionsMm: { widthMm: 60.5, lengthMm: 111.5, depthMm: 31 },
|
|
138
|
+
topFace: { usableRectMm: { x: -29.25, y: -54.75, width: 58.5, height: 109.5 } },
|
|
139
|
+
assets: {
|
|
140
|
+
glbRelativePath: "enclosures/1590b.glb",
|
|
141
|
+
stepRelativePath: "enclosures/1590b.step",
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
partProfiles: {
|
|
146
|
+
"my-knob": {
|
|
147
|
+
id: "my-knob",
|
|
148
|
+
label: "My knob",
|
|
149
|
+
family: "knob",
|
|
150
|
+
level: "exterior",
|
|
151
|
+
status: "generated-stub",
|
|
152
|
+
panelHoleDrillMm: 7.14375,
|
|
153
|
+
drillHoleProfileId: "sixteen-mm-pot-9-32",
|
|
154
|
+
geometry: { kind: "knob", diameterMm: 20, depthMm: 11, shaftDiameterMm: 6.35 },
|
|
155
|
+
assets: {
|
|
156
|
+
glbRelativePath: "parts/my-knob.glb",
|
|
157
|
+
stepRelativePath: "parts/my-knob.step",
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
// Add my-led, my-footswitch, my-audio-jack, and my-dc-jack.
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const glb = createStompboxPreviewGlbFromVdsp(vdspSource, {
|
|
165
|
+
hardwareProfile,
|
|
166
|
+
basePath: "/absolute/path/to/cad-assets",
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The example above reads `/absolute/path/to/cad-assets/parts/my-knob.glb` and
|
|
171
|
+
`/absolute/path/to/cad-assets/enclosures/1590b.glb`. Use `baseUrl` for served
|
|
172
|
+
preview references; use `basePath` when assembling a GLB because the files are
|
|
173
|
+
read from the filesystem.
|
|
174
|
+
|
|
175
|
+
## Live pedal state
|
|
176
|
+
|
|
177
|
+
Stompbox can manage preview state for a pedal instance without owning the UI or
|
|
178
|
+
audio runtime. Use the state helpers to rotate knobs, light LEDs, depress
|
|
179
|
+
footswitches, and drive synthesized bypass hardware in the generated preview.
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import {
|
|
183
|
+
createDefaultStompboxPedalStateFromVdsp,
|
|
184
|
+
createStompboxControlSurface,
|
|
185
|
+
createStompboxPedalStateStore,
|
|
186
|
+
createStompboxPreviewFromVdsp,
|
|
187
|
+
} from "@vessel-dsp/stompbox";
|
|
188
|
+
import { parseCircuitDocumentFile } from "@vessel-dsp/core";
|
|
189
|
+
|
|
190
|
+
const document = parseCircuitDocumentFile(vdspSource, { filename: "pedal.vdsp" });
|
|
191
|
+
const surface = createStompboxControlSurface(document, {
|
|
192
|
+
pedalId: "stage-1",
|
|
193
|
+
compiledControls: runtimeControlsFromYourCompiler,
|
|
194
|
+
});
|
|
195
|
+
const preview = createStompboxPreviewFromVdsp(vdspSource, { hardwareProfile });
|
|
196
|
+
const state = createDefaultStompboxPedalStateFromVdsp(vdspSource, {
|
|
197
|
+
pedalId: "stage-1",
|
|
198
|
+
});
|
|
199
|
+
const store = createStompboxPedalStateStore(state, { preview });
|
|
200
|
+
|
|
201
|
+
store.subscribePreviewPatch((patch) => {
|
|
202
|
+
// Apply patch.parts["part-knob-GAIN"], patch.parts["part-led-status"], etc.
|
|
203
|
+
// to your SVG elements or loaded GLB node/material objects.
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
store.turnKnob("GAIN", 0.82);
|
|
207
|
+
store.pressFootswitch("switch-bypass", true);
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
`compiledControls` is optional. When present, pass a downstream compiler output
|
|
211
|
+
shaped like `{ id, sourceComponentId, name, kind, value, min, max, step }` plus
|
|
212
|
+
optional `unit`, `sweep`, `options`, and `targets`. Stompbox uses it only to
|
|
213
|
+
merge audio-bound control metadata with `.vdsp` source-panel order and to
|
|
214
|
+
return headless runtime command descriptions. It does not compile `.vdsp` or
|
|
215
|
+
send worklet messages.
|
|
216
|
+
|
|
217
|
+
Live GLB previews require semantic state targets on user-provided LED and
|
|
218
|
+
footswitch part assets. Declare those targets in the part profile so renderers
|
|
219
|
+
can affect the LED lens and the moving footswitch actuator instead of guessing
|
|
220
|
+
against the whole part assembly:
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
const ledPartProfile = {
|
|
224
|
+
// ...
|
|
225
|
+
stateTargets: {
|
|
226
|
+
led: {
|
|
227
|
+
lens: {
|
|
228
|
+
selector: {
|
|
229
|
+
nodeName: "o1.2",
|
|
230
|
+
meshNameIncludes: "5mm_led_lens",
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const footswitchPartProfile = {
|
|
238
|
+
// ...
|
|
239
|
+
stateTargets: {
|
|
240
|
+
footswitch: {
|
|
241
|
+
actuator: {
|
|
242
|
+
selector: {
|
|
243
|
+
nodeName: "o1.3",
|
|
244
|
+
meshNameIncludes: "plunger",
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
travelAxis: "z",
|
|
248
|
+
travelMm: 1.2,
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Validate caller-provided GLBs before using them for live state:
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
import {
|
|
258
|
+
validateStompboxGlbAssetFile,
|
|
259
|
+
validateStompboxHardwareProfileAssets,
|
|
260
|
+
} from "@vessel-dsp/stompbox";
|
|
261
|
+
|
|
262
|
+
const ledValidation = validateStompboxGlbAssetFile(
|
|
263
|
+
"/cad/parts/led-bezel-lh5/led.step.glb",
|
|
264
|
+
ledPartProfile,
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
const profileValidation = validateStompboxHardwareProfileAssets(hardwareProfile, {
|
|
268
|
+
basePath: "/cad/parts",
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Missing or ambiguous live targets produce diagnostics such as
|
|
273
|
+
`missing-state-target-contract`, `missing-state-target`, and
|
|
274
|
+
`ambiguous-state-target`. Static drill layouts and static SVG previews can still
|
|
275
|
+
be generated; live GLB preview code should treat those diagnostics as a signal
|
|
276
|
+
to avoid whole-part recolor or movement guesses.
|
|
277
|
+
|
|
278
|
+
For pointer interaction, convert viewer events into state commands, then apply
|
|
279
|
+
the resulting patch in your renderer:
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
import {
|
|
283
|
+
applyStompboxPreviewInteraction,
|
|
284
|
+
createStompboxFootswitchPressCommand,
|
|
285
|
+
createStompboxKnobTurnCommand,
|
|
286
|
+
createStompboxPreviewStatePatch,
|
|
287
|
+
} from "@vessel-dsp/stompbox";
|
|
288
|
+
|
|
289
|
+
const knobCommand = createStompboxKnobTurnCommand(surface, {
|
|
290
|
+
controlId: "GAIN",
|
|
291
|
+
position: 0.65,
|
|
292
|
+
});
|
|
293
|
+
const nextState = applyStompboxPreviewInteraction(store.getSnapshot(), knobCommand);
|
|
294
|
+
const patch = createStompboxPreviewStatePatch(preview, nextState, store.getSnapshot());
|
|
295
|
+
|
|
296
|
+
store.dispatch(knobCommand);
|
|
297
|
+
applyPatchToYourViewer(patch);
|
|
298
|
+
|
|
299
|
+
const bypassCommand = createStompboxFootswitchPressCommand(surface, {
|
|
300
|
+
partId: "switch-bypass",
|
|
301
|
+
pressed: true,
|
|
302
|
+
});
|
|
303
|
+
store.dispatch(bypassCommand);
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Synthesized `switch-bypass` and `led-status` follow the pedal-level `enabled`
|
|
307
|
+
state. Source-declared knobs, switches, and LEDs follow their `ControlState`
|
|
308
|
+
entries. A 9V connector is still generated by default for pedal previews and can
|
|
309
|
+
be omitted with `includePowerJack: false`.
|
|
310
|
+
|
|
311
|
+
React context, hooks, pointer handlers, SVG mutation, Three.js node updates,
|
|
312
|
+
and audio/worklet routing remain downstream responsibilities. A React app can
|
|
313
|
+
wrap `createStompboxPedalStateStore()` with its own context and
|
|
314
|
+
`useSyncExternalStore`, but `@vessel-dsp/stompbox` stays framework-neutral.
|
|
315
|
+
|
|
316
|
+
## 2D and 3D preview viewers
|
|
317
|
+
|
|
318
|
+
For static 2D previews, use `createStompboxPreviewSvgViewsFromVdsp()` or
|
|
319
|
+
`createStompboxPreviewSvgViews()` and display the returned `top`, `bottom`,
|
|
320
|
+
`left`, `right`, or `back` SVG string directly in the consuming app.
|
|
321
|
+
|
|
322
|
+
For model-backed 2D or interactive 3D previews, keep Three.js in the consuming
|
|
323
|
+
app. `@vessel-dsp/stompbox` should only create the preview GLB bytes and
|
|
324
|
+
metadata; the app can load that GLB, choose a camera, and add viewer-only
|
|
325
|
+
effects such as CAD-style linework.
|
|
326
|
+
|
|
327
|
+
```ts
|
|
328
|
+
import * as THREE from "three";
|
|
329
|
+
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
|
330
|
+
import { createStompboxPreviewGlbFromVdsp } from "@vessel-dsp/stompbox";
|
|
331
|
+
|
|
332
|
+
const assembly = createStompboxPreviewGlbFromVdsp(vdspSource, {
|
|
333
|
+
hardwareProfile,
|
|
334
|
+
basePath: "/absolute/path/to/cad-assets",
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
const previewUrl = URL.createObjectURL(
|
|
338
|
+
new Blob([assembly.bytes], { type: assembly.mimeType }),
|
|
339
|
+
);
|
|
340
|
+
const gltf = await new GLTFLoader().loadAsync(previewUrl);
|
|
341
|
+
scene.add(gltf.scene);
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Use a perspective camera and orbit controls for a 3D preview. For a 2D
|
|
345
|
+
model-backed preview, use an orthographic camera aimed at the desired face.
|
|
346
|
+
The assembled GLB uses millimeters and stable node names such as
|
|
347
|
+
`enclosure-box-1590b`, `part-knob-GAIN`, and `hole-backing-jack-IN`, so the
|
|
348
|
+
viewer can frame or select individual parts without parsing source documents.
|
|
349
|
+
|
|
350
|
+
```ts
|
|
351
|
+
function setTopPreviewCamera(
|
|
352
|
+
camera: THREE.OrthographicCamera,
|
|
353
|
+
dimensionsMm: { widthMm: number; lengthMm: number },
|
|
354
|
+
) {
|
|
355
|
+
const marginMm = 12;
|
|
356
|
+
|
|
357
|
+
camera.left = -dimensionsMm.widthMm / 2 - marginMm;
|
|
358
|
+
camera.right = dimensionsMm.widthMm / 2 + marginMm;
|
|
359
|
+
camera.top = dimensionsMm.lengthMm / 2 + marginMm;
|
|
360
|
+
camera.bottom = -dimensionsMm.lengthMm / 2 - marginMm;
|
|
361
|
+
camera.near = 0.1;
|
|
362
|
+
camera.far = 500;
|
|
363
|
+
camera.position.set(0, 0, 220);
|
|
364
|
+
camera.up.set(0, 1, 0);
|
|
365
|
+
camera.lookAt(0, 0, 0);
|
|
366
|
+
camera.updateProjectionMatrix();
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
setTopPreviewCamera(camera, assembly.preview.enclosure.dimensionsMm);
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
To render CAD-style border linework, expose a viewer option such as `linework`
|
|
373
|
+
and `lineworkColor`, then add an `EdgesGeometry` overlay after loading the GLB.
|
|
374
|
+
This is a display-only effect and should not be written back into the stompbox
|
|
375
|
+
artifact.
|
|
376
|
+
|
|
377
|
+
```ts
|
|
378
|
+
function addCadLinework(root: THREE.Object3D, lineworkColor = "#111827") {
|
|
379
|
+
const meshes: THREE.Mesh[] = [];
|
|
380
|
+
const material = new THREE.LineBasicMaterial({
|
|
381
|
+
color: new THREE.Color(lineworkColor),
|
|
382
|
+
transparent: true,
|
|
383
|
+
opacity: 0.85,
|
|
384
|
+
depthTest: true,
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
root.traverse((object) => {
|
|
388
|
+
if (object instanceof THREE.Mesh) {
|
|
389
|
+
meshes.push(object);
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
for (const object of meshes) {
|
|
394
|
+
if (!(object.geometry instanceof THREE.BufferGeometry)) continue;
|
|
395
|
+
const edges = new THREE.EdgesGeometry(object.geometry, 35);
|
|
396
|
+
const lines = new THREE.LineSegments(edges, material);
|
|
397
|
+
|
|
398
|
+
lines.name = `${object.name || "mesh"}-cad-linework`;
|
|
399
|
+
lines.renderOrder = 10;
|
|
400
|
+
object.add(lines);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const linework = true;
|
|
405
|
+
const lineworkColor = "#eb7223";
|
|
406
|
+
|
|
407
|
+
if (linework) {
|
|
408
|
+
addCadLinework(gltf.scene, lineworkColor);
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
`LineBasicMaterial` is usually limited to one device pixel in WebGL. If the
|
|
413
|
+
viewer needs heavier strokes, use Three.js `LineSegments2` and `LineMaterial`
|
|
414
|
+
from `three/addons/lines` in the application layer.
|
|
415
|
+
|
|
416
|
+
## Appearance customization
|
|
417
|
+
|
|
418
|
+
Pass `appearance` to preview, GLB, SVG-view, or drill-template helpers to style
|
|
419
|
+
the generated artifacts without changing `.vdsp` placement data. `state` remains
|
|
420
|
+
for live values such as knob position, LED on/off, and footswitch pressed state;
|
|
421
|
+
`appearance` is for enclosure, LED, label, template, and non-knob material
|
|
422
|
+
hints. Knob bodies keep the material colors from their imported CAD/GLB assets.
|
|
423
|
+
|
|
424
|
+
```ts
|
|
425
|
+
import {
|
|
426
|
+
createStompboxAppearancePatch,
|
|
427
|
+
createStompboxPreviewFromVdsp,
|
|
428
|
+
createStompboxPreviewSvgViewsFromVdsp,
|
|
429
|
+
} from "@vessel-dsp/stompbox";
|
|
430
|
+
|
|
431
|
+
const appearance = {
|
|
432
|
+
enclosure: { color: "#f97316", strokeColor: "#7c2d12", roughnessFactor: 0.45 },
|
|
433
|
+
template: {
|
|
434
|
+
guideColor: "#0ea5e9",
|
|
435
|
+
foldColor: "#334155",
|
|
436
|
+
holeStrokeColor: "#7c3aed",
|
|
437
|
+
holeFillColor: "#faf5ff",
|
|
438
|
+
centerDotColor: "#581c87",
|
|
439
|
+
},
|
|
440
|
+
defaults: {
|
|
441
|
+
led: { color: "#ef4444", offColor: "#fee2e2" },
|
|
442
|
+
label: { color: "#111827" },
|
|
443
|
+
},
|
|
444
|
+
controls: {
|
|
445
|
+
GAIN: {
|
|
446
|
+
label: { text: "DRIVE", color: "#ffffff" },
|
|
447
|
+
},
|
|
448
|
+
LED1: {
|
|
449
|
+
led: { color: "#22c55e", offColor: "#064e3b" },
|
|
450
|
+
label: { text: "READY", color: "#16a34a" },
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
} as const;
|
|
454
|
+
|
|
455
|
+
const preview = createStompboxPreviewFromVdsp(vdspSource, {
|
|
456
|
+
hardwareProfile,
|
|
457
|
+
appearance,
|
|
458
|
+
});
|
|
459
|
+
const views = createStompboxPreviewSvgViewsFromVdsp(vdspSource, {
|
|
460
|
+
hardwareProfile,
|
|
461
|
+
appearance,
|
|
462
|
+
});
|
|
463
|
+
const patch = createStompboxAppearancePatch(preview);
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
Preview SVG output includes stable hooks such as `data-control-id`,
|
|
467
|
+
`data-part-family`, `.knob-body`, `.knob-indicator`, `.led-lens`, `.label-text`,
|
|
468
|
+
`.top-panel`, `.hole`, `.drill-hole-center-dot`, `.fold-line`, and
|
|
469
|
+
`.guide-line`. Preview GLB output bakes available material colors into copied
|
|
470
|
+
GLB materials and writes the same frontend-friendly patch into
|
|
471
|
+
`asset.extras.appearance`. Knob GLB materials are left as imported.
|
|
Binary file
|