Skip to content

Commit 1487836

Browse files
committed
Add visible Audio SFX style ranges and slider hints - PR_26145_010-audio-sfx-visible-style-ranges-and-slider-hints
1 parent 02f6a7e commit 1487836

4 files changed

Lines changed: 122 additions & 13 deletions

File tree

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# PR_26145_010 Audio SFX Visible Style Ranges
2+
3+
## Scope
4+
5+
- Updated `tools/audio-sfx-playground-v2` only.
6+
- Made Sound Style clamp ranges visible in each slider value output.
7+
- Added help text clarifying that Sound Style changes recommended operating ranges and clamps current values, while waveform options remain selectable.
8+
- Preserved external CSS/JS only; no inline event handlers or style/script blocks were added.
9+
10+
## Targeted Static Validation
11+
12+
PASS:
13+
14+
- `Get-ChildItem -Recurse -File tools/audio-sfx-playground-v2/js -Filter *.js | ForEach-Object { node --check $_.FullName }`
15+
- HTML/CSS guard:
16+
- no `<style>` blocks in `tools/audio-sfx-playground-v2/index.html`
17+
- no inline `<script>` blocks
18+
- no inline event handlers
19+
- Sound Style tooltip includes range and waveform guidance
20+
- Wave tooltip confirms every waveform remains selectable
21+
- density CSS reserves the compact slider/range output layout
22+
- `git diff --check -- tools/audio-sfx-playground-v2`
23+
- PASS with Git LF/CRLF warnings only for `index.html` and `audioSfxLayoutDensity.css`.
24+
25+
## Focused Playwright Validation
26+
27+
PASS using a local repo HTTP server and Chromium:
28+
29+
- Audio / SFX Playground V2 launched at `/tools/audio-sfx-playground-v2/index.html`.
30+
- No console errors and no page errors on launch or during style/slider interactions.
31+
- Initial range labels rendered:
32+
- Frequency: `880 Hz [20-20000 Hz]`
33+
- Sweep: `700 cents [-1200-1200 cents]`
34+
- Selecting Atari-style updated visible and DOM slider ranges:
35+
- Frequency range label: `[40-4000 Hz]`
36+
- Frequency min/max attributes: `40` / `4000`
37+
- Sweep range label: `[-1200-1200 cents]`
38+
- Brightness range label: `[400-7000 Hz]`
39+
- Switching from Pure Tone after setting Frequency to `20000 Hz` visibly changed the value after selecting Atari-style:
40+
- Before: `20000 Hz [20-20000 Hz]`
41+
- After: `520 Hz [40-4000 Hz]`
42+
- Selecting TTL Arcade updated Frequency to `1180 Hz [80-2500 Hz]`.
43+
- All waveform options remained enabled, including `noise`.
44+
- Slider focus retention passed:
45+
- Clicking `#durationInput` left focus on `durationInput`.
46+
- `ArrowRight` changed duration from `380` to `385`, preserving the 5 ms step.
47+
- All 9 density slider rows kept label, slider, and value output on one aligned row without overlap.
48+
49+
V8 coverage entry captured:
50+
51+
- `tools/audio-sfx-playground-v2/js/controls/SfxControlPanel.js`
52+
53+
## Workspace V2 Validation
54+
55+
Command:
56+
57+
```powershell
58+
$env:PLAYWRIGHT_BROWSERS_PATH='.ms-playwright'; npm.cmd run test:workspace-v2
59+
```
60+
61+
Result:
62+
63+
- 69 passed
64+
- 3 failed
65+
66+
Failures observed outside Audio / SFX Playground V2 scope:
67+
68+
- `Workspace Manager V2 bootstrap > shows Object Vector Studio V2 layout shell and schema-only palette gate`
69+
- Expected status log to contain `OK Applied transparent fill to shape row 1 by right-click.`
70+
- `Workspace Manager V2 bootstrap > compacts Object Vector Studio V2 geometry layouts and selected palette state`
71+
- Expected selected palette outline width `>= 3`; received `2.8`.
72+
- `Workspace Manager V2 bootstrap > owns temporary UAT manifest seeding and launches Asset Manager V2 through session context`
73+
- Timed out at 120000 ms, then coverage stop reported the target page/context/browser had closed.
74+
75+
## Full Samples Smoke
76+
77+
Skipped per BUILD request because this PR only impacts Audio / SFX Playground V2 UI behavior.

tools/audio-sfx-playground-v2/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ <h2 class="tools-platform-frame__eyebrow">First-Class Tools Surface V2</h2>
6868
<button id="deleteSfxButton" type="button" aria-label="Delete selected SFX">&#128465;</button>
6969
</div>
7070
<label class="tool-starter__field" for="styleProfileSelect">
71-
<span class="audio-sfx__label-tip" tabindex="0" data-tooltip="Applies a profile of default SFX ranges without saving the style name into toolState.">Sound Style</span>
71+
<span class="audio-sfx__label-tip" tabindex="0" data-tooltip="Changes recommended slider operating ranges and clamps current values; waveform choices are never disabled by style.">Sound Style</span>
7272
<select id="styleProfileSelect">
7373
<option value="custom">Custom</option>
7474
<option value="pure-tone">Pure Tone</option>
@@ -84,7 +84,7 @@ <h2 class="tools-platform-frame__eyebrow">First-Class Tools Surface V2</h2>
8484
</select>
8585
</label>
8686
<label class="tool-starter__field" for="waveformSelect">
87-
<span class="audio-sfx__label-tip" tabindex="0" data-tooltip="Chooses the oscillator shape or noise source that defines the sound character.">Wave</span>
87+
<span class="audio-sfx__label-tip" tabindex="0" data-tooltip="Chooses the oscillator shape or noise source; every waveform remains selectable for every Sound Style.">Wave</span>
8888
<select id="waveformSelect">
8989
<option value="sine">Sine</option>
9090
<option value="square">Square</option>

tools/audio-sfx-playground-v2/js/controls/SfxControlPanel.js

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ const SLIDER_INPUTS = Object.freeze([
2222
Object.freeze({ soundKey: "volume", inputProperty: "volumeInput" })
2323
]);
2424

25+
const SLIDER_RANGE_UNITS = Object.freeze({
26+
attackMs: "ms",
27+
durationMs: "ms",
28+
frequencyHz: "Hz",
29+
noiseAmount: "",
30+
noiseDecayMs: "ms",
31+
noiseFilterHz: "Hz",
32+
pitchSweepCents: "cents",
33+
releaseMs: "ms",
34+
volume: ""
35+
});
36+
2537
const STYLE_CLAMPS = Object.freeze({
2638
"pure-tone": Object.freeze({
2739
attackMs: Object.freeze({ min: 0, max: 120 }),
@@ -273,6 +285,13 @@ function readRange(input, limits) {
273285
return { ok: true, value };
274286
}
275287

288+
function formatRangeNumber(soundKey, value) {
289+
if (soundKey === "noiseAmount" || soundKey === "volume") {
290+
return value.toFixed(2);
291+
}
292+
return String(Math.round(value));
293+
}
294+
276295
export class SfxControlPanel {
277296
constructor({
278297
addButton,
@@ -464,15 +483,26 @@ export class SfxControlPanel {
464483
}
465484

466485
syncOutputs() {
467-
this.attackValue.textContent = `${Math.round(toNumber(this.attackInput))} ms`;
468-
this.durationValue.textContent = `${Math.round(toNumber(this.durationInput))} ms`;
469-
this.frequencyValue.textContent = `${Math.round(toNumber(this.frequencyInput))} Hz`;
470-
this.noiseAmountValue.textContent = toNumber(this.noiseAmountInput).toFixed(2);
471-
this.noiseDecayValue.textContent = `${Math.round(toNumber(this.noiseDecayInput))} ms`;
472-
this.noiseFilterValue.textContent = `${Math.round(toNumber(this.noiseFilterInput))} Hz`;
473-
this.pitchSweepValue.textContent = `${Math.round(toNumber(this.pitchSweepInput))} cents`;
474-
this.releaseValue.textContent = `${Math.round(toNumber(this.releaseInput))} ms`;
475-
this.volumeValue.textContent = toNumber(this.volumeInput).toFixed(2);
486+
this.attackValue.textContent = this.valueWithRange("attackMs", `${Math.round(toNumber(this.attackInput))} ms`);
487+
this.durationValue.textContent = this.valueWithRange("durationMs", `${Math.round(toNumber(this.durationInput))} ms`);
488+
this.frequencyValue.textContent = this.valueWithRange("frequencyHz", `${Math.round(toNumber(this.frequencyInput))} Hz`);
489+
this.noiseAmountValue.textContent = this.valueWithRange("noiseAmount", toNumber(this.noiseAmountInput).toFixed(2));
490+
this.noiseDecayValue.textContent = this.valueWithRange("noiseDecayMs", `${Math.round(toNumber(this.noiseDecayInput))} ms`);
491+
this.noiseFilterValue.textContent = this.valueWithRange("noiseFilterHz", `${Math.round(toNumber(this.noiseFilterInput))} Hz`);
492+
this.pitchSweepValue.textContent = this.valueWithRange("pitchSweepCents", `${Math.round(toNumber(this.pitchSweepInput))} cents`);
493+
this.releaseValue.textContent = this.valueWithRange("releaseMs", `${Math.round(toNumber(this.releaseInput))} ms`);
494+
this.volumeValue.textContent = this.valueWithRange("volume", toNumber(this.volumeInput).toFixed(2));
495+
}
496+
497+
valueWithRange(soundKey, valueText) {
498+
return `${valueText} [${this.rangeText(soundKey)}]`;
499+
}
500+
501+
rangeText(soundKey) {
502+
const limits = this.activeSliderLimits[soundKey];
503+
const unit = SLIDER_RANGE_UNITS[soundKey];
504+
const range = `${formatRangeNumber(soundKey, limits.min)}-${formatRangeNumber(soundKey, limits.max)}`;
505+
return unit ? `${range} ${unit}` : range;
476506
}
477507

478508
validate() {

tools/audio-sfx-playground-v2/styles/audioSfxLayoutDensity.css

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ body[data-tool-id="audio-sfx-playground-v2"] #sfxShapeContent .tool-starter__fie
3636
body[data-tool-id="audio-sfx-playground-v2"] #sfxShapeContent .tool-starter__field[data-density-control] {
3737
align-items: center;
3838
column-gap: 8px;
39-
grid-template-columns: 74px minmax(0, 1fr) minmax(64px, max-content);
39+
grid-template-columns: 74px minmax(48px, 1fr) minmax(118px, max-content);
4040
min-height: 28px;
4141
}
4242

@@ -52,7 +52,9 @@ body[data-tool-id="audio-sfx-playground-v2"] #sfxShapeContent .tool-starter__fie
5252
}
5353

5454
body[data-tool-id="audio-sfx-playground-v2"] #sfxShapeContent .tool-starter__field[data-density-control] output {
55-
min-width: 64px;
55+
color: var(--tool-starter-muted);
56+
font-size: 0.78rem;
57+
min-width: 118px;
5658
justify-self: end;
5759
text-align: right;
5860
white-space: nowrap;

0 commit comments

Comments
 (0)