Skip to content
Design
Skill

/sounds-on-the-web

Audit UI code for audio feedback best practices. Use when reviewing sound implementation, checking audio UX decisions, or auditing accessibility. Outputs file:line findings.

BOOST
From plugin
raphaelsalaja-skill
417 skills
Install
$ npx -y skills add raphaelsalaja/skill --skill sounds-on-the-web --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/sounds-on-the-web

Context preview

The summary Claude sees to decide when to auto-load this skill.

Audit UI code for audio feedback best practices. Use when reviewing sound implementation, checking audio UX decisions, or auditing accessibility. Outputs file:line findings.

SKILL.md

sounds-on-the-web.SKILL.md
name: sounds-on-the-web
description: Audit UI code for audio feedback best practices. Use when reviewing sound implementation, checking audio UX decisions, or auditing accessibility. Outputs file:line findings.
license: MIT
metadata:
  author: raphael-salaja
  version: "2.0.0"
  source: /content/sounds-on-the-web/index.mdx

Sounds on the Web

Review UI code for audio feedback best practices and accessibility.

How It Works

1. Read the specified files (or prompt user for files/pattern) 2. Check against all rules below 3. Output findings in `file:line` format

Rule Categories

| Priority | Category | Prefix | |----------|----------|--------| | 1 | Accessibility | `a11y-` | | 2 | Appropriateness | `appropriate-` | | 3 | Implementation | `impl-` | | 4 | Weight Matching | `weight-` |

Rules

Accessibility Rules

`a11y-visual-equivalent`

Every audio cue must have a visual equivalent; sound never replaces visual feedback.

**Fail:**

function SubmitButton({ onClick }) {
  const handleClick = () => {
    playSound("success");
    onClick(); // No visual confirmation
  };
}

**Pass:**

function SubmitButton({ onClick }) {
  const [status, setStatus] = useState("idle");
  
  const handleClick = () => {
    playSound("success");
    setStatus("success"); // Visual feedback too
    onClick();
  };
  
  return <button data-status={status}>Submit</button>;
}

`a11y-toggle-setting`

Provide explicit toggle to disable sounds in settings.

**Fail:**

// No way to disable sounds
function App() {
  return <SoundProvider>{children}</SoundProvider>;
}

**Pass:**

function App() {
  const { soundEnabled } = usePreferences();
  return (
    <SoundProvider enabled={soundEnabled}>
      {children}
    </SoundProvider>
  );
}

`a11y-reduced-motion-check`

Respect prefers-reduced-motion as proxy for sound sensitivity.

**Fail:**

function playSound(name: string) {
  audio.play(); // Plays regardless of preferences
}

**Pass:**

function playSound(name: string) {
  const prefersReducedMotion = window.matchMedia(
    "(prefers-reduced-motion: reduce)"
  ).matches;
  
  if (prefersReducedMotion) return;
  audio.play();
}

`a11y-volume-control`

Allow volume adjustment independent of system volume.

**Fail:**

function playSound() {
  audio.volume = 1; // Always full volume
  audio.play();
}

**Pass:**

function playSound() {
  const { volume } = usePreferences();
  audio.volume = volume; // User-controlled
  audio.play();
}

Appropriateness Rules

`appropriate-no-high-frequency`

Do not add sound to high-frequency interactions (typing, keyboard navigation).

**Fail:**

function Input({ onChange }) {
  const handleChange = (e) => {
    playSound("keystroke"); // Annoying on every keystroke
    onChange(e);
  };
}

**Pass:**

function Input({ onChange }) {
  // No sound on typing - visual feedback only
  return <input onChange={onChange} />;
}

`appropriate-confirmations-only`

Sound is appropriate for confirmations: payments, uploads, form submissions.

**Pass:**

async function handlePayment() {
  await processPayment();
  playSound("success"); // Appropriate - significant action
  showConfirmation();
}

`appropriate-errors-warnings`

Sound is appropriate for errors and warnings that can't be overlooked.

**Pass:**

function handleError(error: Error) {
  playSound("error"); // Appropriate - needs attention
  showErrorToast(error.message);
}

`appropriate-no-decorative`

Do not add sound to decorative moments with no informational value.

**Fail:**

function Card({ onHover }) {
  return (
    <div onMouseEnter={() => playSound("hover")}> {/* Decorative, no value */}
      {children}
    </div>
  );
}

`appropriate-no-punishing`

Sound should inform, not punish; avoid harsh sounds for user mistakes.

**Fail:**

function ValidationError() {
  playSound("loud-buzzer"); // Punishing
  return <span>Invalid input</span>;
}

**Pass:**

function ValidationError() {
  playSound("gentle-alert"); // Informative but not harsh
  return <span>Invalid input</span>;
}

Implementation Rules

`impl-preload-audio`

Preload audio files to avoid playback delay.

**Fail:**

function playSound(name: string) {
  const audio = new Audio(`/sounds/${name}.mp3`); // Loads on demand
  audio.play();
}

**Pass:**

const sounds = {
  success: new Audio("/sounds/success.mp3"),
  error: new Audio("/sounds/error.mp3"),
};

// Preload on app init
Object.values(sounds).forEach(audio => audio.load());

function playSound(name: keyof typeof sounds) {
  sounds[name].currentTime = 0;
  sounds[name].play();
}

`impl-default-subtle`

Default volume should be subtle, not loud.

**Fail:**

const DEFAULT_VOLUME = 1.0; // Too loud

**Pass:**

const DEFAULT_VOLUME = 0.3; // Subtle default

`impl-reset-current-time`

Reset audio currentTime before replay to allow rapid triggering.

**Fail:**

function playSound() {
  audio.play(); // Won't replay if already playing
}

**Pass:**

function playSound() {
  audio.currentTime = 0;
  audio.play();
}

Weight Matching Rules

`weight-match-action`

Sound weight should match action importance.

**Fail:**

// Loud fanfare for minor action
function handleToggle() {
  playSound("triumphant-fanfare");
  setEnabled(!enabled);
}

**Pass:**

// Subtle click for minor action
function handleToggle() {
  playSound("soft-click");
  setEnabled(!enabled);
}

// Richer sound for significant action
function handlePurchase() {
  playSound("success-chime");
  completePurchase();
}

`weight-duration-matches-action`

Sound duration should match action duration.

**Fail:**

// 2-second sound for instant action
function handleClick() {
  playSound("long-whoosh"); // 2000ms
  // Action completes immediately
}

**Pass:**

Read more
Ships withraphaelsalaja-skill

A skill file based on the articles written on userinterface.wiki. Designed for designers and engineers to help them build better user interfaces.

Get the whole plugin

Other skills on raphaelsalaja-skill.