martin6363/filament-click-spark
A Filament plugin that adds a playful click-spark animation to your admin panel's buttons and interactive elements, giving instant visual feedback on every click. Lightweight and easy to install, it brings a small touch of polish to the Filament UI with minimal configuration.
Install it and read vendor/ before you write a single line of app code. There is no README, so the vendor directory is the documentation. Pin the constraint explicitly — this is a 2-star, single-maintainer, front-end-only package with an auto-generated changelog; the version constraint is load-bearing.
composer require martin6363/filament-click-spark:^1.0
Then spend fifteen minutes in vendor/martin6363/filament-click-spark/ answering three questions that determine whether you can use it at all:
vendor/martin6363/filament-click-spark/
├── composer.json # which Filament majors + Livewire/PHP are allowed
├── src/ # plugin class + service provider — the real namespace
└── resources/ # dist/ (prebuilt JS/CSS) or js/ (Vite source you must build)
dist/ via FilamentAsset::register(), you get zero-config. If it ships Vite source, you need your own theme entry and this stops being free.prefers-reduced-motion guard? Grep for it. The answer decides whether you ship it to anyone outside the ops team.Register it on exactly one panel — the internal ops panel — first. Not globally, not in a shared base provider.
// app/Providers/Filament/InternalPanelProvider.php
use Martin6363\FilamentClickSpark\ClickSparkPlugin; // verify namespace in src/
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(ClickSparkPlugin::make());
}
Then run the asset pipeline as part of the same change, not as a manual step you'll forget:
php artisan filament:assets
php artisan view:clear
First use case worth doing: enable it on the internal ops panel behind a config flag defaulting to false, and clear three gates in one PR — (a) click once, see one burst; (b) click a wire:navigate link, come back, click again, still exactly one burst; (c) load the panel with your production CSP header applied and confirm zero blocked-script console errors. If any gate fails and the fix isn't under an hour, clone the ~60–120 line Alpine pattern in-house instead. That is a legitimate outcome, not a failure.
Gate registration behind config, so removal is a config change and not a code change.
// config/filament-click-spark.php
return [
'enabled' => env('FILAMENT_CLICK_SPARK_ENABLED', false),
// only pass these through if src/ actually exposes them
'colors' => ['#6366f1', '#22d3ee'],
];
// Panel provider — branch on the flag so you never depend on the
// plugin class having a ->visible()/->enabled() method of its own.
if (config('filament-click-spark.enabled')) {
$panel->plugin(ClickSparkPlugin::make());
}
return $panel;
Only reach for ->visible(...), ->colors(...), or similar fluent customizers after you've confirmed those methods exist in src/. Guessing at the API from the description is how you get a BadMethodCallException in a panel provider that breaks every page of the admin.
Wrap it in a one-file adapter. The realistic futures are a Filament major upgrade or upstream abandonment; both should touch exactly one file.
// app/Filament/Plugins/Spark.php
namespace App\Filament\Plugins;
use Filament\Panel;
use Martin6363\FilamentClickSpark\ClickSparkPlugin;
final class Spark
{
public static function register(Panel $panel): Panel
{
if (! config('filament-click-spark.enabled')) {
return $panel;
}
return $panel->plugin(ClickSparkPlugin::make());
}
}
Now composer remove or a vendor-fork swap is a single import change, and the panel providers stay clean. This is the highest-leverage thing you can do with a package of this maturity.
Register it in one block with your other cosmetic plugins. Reviewers should see the whole visual contract — spark, toast position, loading states, sidebar behaviour — as one diff. It also makes "is this panel carrying too much front-end weight?" answerable without archaeology.
Segment by panel deliberately, in writing, so it isn't re-litigated per engineer.
| Panel | Enable |
|---|---|
| Internal ops / support | Yes |
| Sales demo / brand-personality | Yes |
| Customer-facing portal | No |
| Regulated / public-sector / accessibility-audited | No |
Test SPA navigation explicitly — this is the realistic silent failure. Script it:
wire:navigate, click → still exactly one burst, not two.<canvas> nodes.If listeners accumulate, the fix is a document-level binding with an idempotency guard, or teardown on livewire:navigating. That's a small patch — but it means you now own a fork, so make that call consciously.
Check it under your real theme before the demo. Particle palettes are usually hard-coded. Open the panel in dark mode with your custom primary colour applied; if the sparks vanish against a light surface or clash with your brand, you need to know now, not in front of a stakeholder.
Ship it on a branch with a five-second screen capture and the decision gate in the PR description. Half-day spike, day-five verdict: adopt / fork / replicate. That framing is what makes a cosmetic dependency reviewable instead of a matter of taste.
The package metadata tells you nothing. v1.0.0 with an auto-generated changelog link, 2 stars, 0 dependents, no README. Every claim below the install line is something you verify against vendor/, not the repo page. Put that in the internal runbook so a teammate doesn't discover it accidentally in a panel provider.
A rendered panel with no sparks almost always means a Filament-version mismatch. It fails soft — no exception, no error, just nothing. Read the composer.json constraint in vendor/ and reconcile it with your lockfile before you start debugging your own JS.
php artisan filament:assets is a deploy step. If the pipeline doesn't run it, the bundle 404s in production while working perfectly on your machine. Put it next to filament:upgrade / optimize and verify the asset appears under public/.
CSP is the most common silent killer. An inline <script> in a shipped Blade view is blocked by any strict script-src without a nonce or hash. Symptom: no effect, a console error nobody reports, zero functional impact — so it lingers for months. Check with your production headers applied, not with php artisan serve.
prefers-reduced-motion is a hard gate. Particle bursts on every click are a vestibular concern, and an accessibility finding forces immediate removal anyway. If the package ships no guard, add one in your wrapper before enabling it anywhere:
@media (prefers-reduced-motion: reduce) {
[data-click-spark] { display: none !important; } /* match the real selector */
}
Better: patch the JS to bail at init on matchMedia('(prefers-reduced-motion: reduce)').matches. If neither is achievable in under an hour, replicate in-house.
Leaked canvases are the other silent failure. A <canvas> created on init and never removed, multiplied by wire:navigate transitions, is progressive CPU creep nobody notices until someone's been on the panel for six hours. After ten navigations, the DOM node count should be flat.
Debugging checklist when sparks don't appear:
grep -r "FilamentAsset\|register" vendor/martin6363/filament-click-spark/src — confirm the plugin actually returns assets from register()/boot().filament:assets wasn't run.false, or ->visible(false) — the most boring explanation and by far the most common.Extension points, in order of preference: the fluent plugin API (if src/ exposes one) → your own config file → your adapter class → a CSS override on the injected selector → a full vendor fork. Stop at the last one unless you've decided you're adopting it.
Pin it, name an owner, schedule the review. Zero dependents and one maintainer means no support tier. Budget a quarterly check against Filament upgrades — hours, not sprints, because the surface is one provider line and one asset bundle. Assume you'll vendor-fork it eventually; the only question is whether the adapter class is already in place when that day comes.
Set the sunset condition before adoption. No owner, no reduced-motion path, no confirmed Filament compatibility, or a major upgrade breaks it → remove and replicate in-house. And don't enable it on customer-facing or regulated panels, or claim it improves satisfaction or productivity. It's a cheap, visible, reversible experiment. If it needs more than a few hours of engineering attention to justify keeping, delete the provider line and spend the time where it compounds.
How can I help you explore Laravel packages today?