blemli/filament-audiofeedback

Delightful, unobtrusive audio feedback for Filament panels, powered by Cuelume.

Maintainers

Package info

github.com/blemli/filament-audiofeedback

pkg:composer/blemli/filament-audiofeedback

Transparency log

Fund package maintenance!

blemli

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.2.0 2026-07-28 09:14 UTC

This package is not auto-updated.

Last update: 2026-07-29 04:11:34 UTC


README

Latest Version on Packagist GitHub Tests Action Status Total Downloads

Delightful, unobtrusive audio feedback for Filament panels, powered by Cuelume — fourteen tiny interaction sounds synthesized live with the Web Audio API. No audio files, no npm install, nothing to configure unless you want to.

Deliberately not annoying: sounds play for toggles, notifications, form submits, sliders, login/logout, drag & drop, and a barely-there whisper on navigation hover. Users get a mute button, a master volume, and (optionally) their own per-sound settings on Filament Breezy's my-profile page — persisted to the database.

Installation

composer require blemli/filament-audiofeedback

Add the plugin to your panel — that's it:

use Blemli\AudioFeedback\AudioFeedbackPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->plugin(AudioFeedbackPlugin::make());
}

The Cuelume engine (~10 kB, MIT) is bundled with the plugin and registered through Filament's asset system. No Filament views are overridden — everything hooks into Livewire events, DOM roles and render hooks.

What plays when

Each event maps to the Cuelume sound designed for that exact moment:

Event Default sound Cuelume's description
Notification (success) success Warm three-note confirmation
Notification (danger) error Soft knock and descending refusal
Notification (warning) chime Soft two-note ascending bell
Notification (info / none) whisper Breathy quiet swell
Toggle switched toggle Mechanical click-clack
Toggle buttons changed toggle-buttonstick Crisp instant tick
Slider released / stepped slidertick Crisp instant tick
Navigation item hovered nav.hoverwhisper The quietest option, made for dense lists
Form submitted loading Brief unresolved rising shimmer
Login ready Focus tick with a harmonic bloom
Logout droplet Single note gliding down
Drag (grab a sortable item) press Dull muted knock
Drop (release it) release Brighter springy tick
Record deleted deletedroplet Single note gliding down

Configuration

Publish the config file if you want to change anything:

php artisan vendor:publish --tag="audiofeedback-config"
// config/audiofeedback.php
return [
    'enabled' => env('AUDIOFEEDBACK_ENABLED', true),

    // Master volume, 0–100. Users can pick their own (see below).
    'volume' => 50,

    // The mute button is shown by default; opt out with false.
    'mute_toggle' => true,

    // 'topbar-start', 'topbar-end', 'user-menu-before' or 'user-menu'.
    'mute_toggle_position' => 'user-menu-before',

    // Opt in to a per-user "Sounds" section on Breezy's my-profile page.
    'breezy_profile_section' => false,

    // Any of: chime, sparkle, droplet, bloom, whisper, tick, press,
    // release, toggle, success, error, page, loading, ready — or false.
    'sounds' => [
        'notification.success' => 'success',
        'toggle' => 'toggle',
        'nav.hover' => false, // silence a single event
        // ...
    ],
];

The same options are available fluently on the plugin:

AudioFeedbackPlugin::make()
    ->volume(25)
    ->sound('toggle', 'tick')
    ->disable('form.submit', 'drag', 'drop')
    ->muteToggle(position: 'topbar-end');

Or globally from your AppServiceProvider:

use Blemli\AudioFeedback\AudioFeedbackPlugin;

public function boot(): void
{
    AudioFeedbackPlugin::configureUsing(
        fn (AudioFeedbackPlugin $plugin) => $plugin->sound('login', 'bloom'),
    );
}

Precedence: config file → configureUsing() → fluent calls in the panel provider.

Notifications

Notifications automatically play the sound matching their status. Override or silence a single notification:

Notification::make()
    ->title('Saved')
    ->success()
    ->sound('sparkle') // override the status sound
    ->send();

Notification::make()
    ->title('Autosaved')
    ->silent() // no sound for this one
    ->send();

Notification::make()
    ->title('Gone')
    ->soundEvent('delete') // play a configured event's sound instead
    ->send();

Delete and force-delete actions (including bulk) automatically use the delete event's sound for their success notification instead of the generic success chime.

Mute button

A small speaker icon lets every user opt out. It is shown by default (opt out with ->muteToggle(false)) and can live in four places, matching Filament's render hooks:

use Blemli\AudioFeedback\MuteTogglePosition;

AudioFeedbackPlugin::make()->muteToggle(position: MuteTogglePosition::UserMenu);
Position Where
topbar-start Start of the topbar, after the logo
topbar-end End of the topbar, before the user menu area
user-menu-before Next to the user avatar (default)
user-menu An item inside the user dropdown

Per-user settings (Filament Breezy)

If your panel uses Filament Breezy, opt in to a "Sounds" section on the my-profile page:

AudioFeedbackPlugin::make()->breezyProfileSection();

The Sounds section on Breezy's my-profile page

The section is a native Filament form: a Toggle to mute everything, a Slider for the volume (with a pip marking the panel default and a Reset hint action), and a Select per event — every sound can be re-mapped to any of the fourteen cues, muted, or left at the panel default, with an instant preview on selection. When two events resolve to the same tune, the affected selects show a warning hint. The section only appears when the BreezyCore plugin is registered on the same panel; hide it per-panel with Breezy's ->withoutMyProfileComponents(['audiofeedback']).

To guard the section per user, pass a closure — it receives the authenticated user:

AudioFeedbackPlugin::make()->breezyProfileSection(
    fn (?User $user) => $user?->can('tune-sounds') ?? false,
);

Choices are saved to the audiofeedback_settings table (the migration ships with the package — just run php artisan migrate) and hydrated on every page, so they follow the user across browsers. The topbar mute button persists through a small authenticated endpoint; guests and apps without the table gracefully fall back to localStorage.

Translations

Ships in English, German, French, Italian and Spanish (en, de, fr, it, es) — the mute button and the profile section follow your app's locale automatically. To adjust strings or add a locale, publish the language files:

php artisan vendor:publish --tag="audiofeedback-translations"

The Cuelume sound names themselves (chime, sparkle, …) stay untranslated on purpose — they're identifiers, not copy.

Extras

  • Reduced motion — users with the OS-level "reduce motion" accessibility preference start muted; an explicit unmute (or saved per-user setting) still wins. Opt out of the hint with ->ignoreReducedMotion() or 'ignore_reduced_motion' => true.
  • Your own sounds — the script also honors plain Cuelume attributes in your views (<button data-cuelume-press>), and exposes window.audiofeedback.cue('toggle') / window.audiofeedback.play('sparkle') for custom JS.
  • Autoplay policy — browsers block audio before the first user interaction on a page. Cues that arrive earlier (e.g. right after the login redirect) are held and played on the first click or keypress.

Testing

composer test

Credits

License

The MIT License (MIT). Please see License File for more information.