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.
Architecture fit. This is the lowest-risk integration class available: a front-end-only Filament plugin that injects CSS/JS, registers through the standard ->plugin() panel API, and touches no models, migrations, queues, jobs, auth, or business logic. Blast radius on correctness is effectively zero. The relevant architectural question isn't "will it break something," it's "are we accumulating unreviewed front-end weight in the admin surface our operations actually run on." That framing should drive the decision, not the code review.
Integration feasibility. High on paper, unverifiable from metadata. There is no README, no meaningful changelog (v1.0.0 ships an auto-generated commit link), no declared Filament major, 2 stars, 0 dependents, and a single maintainer. The compatibility answer lives in vendor/martin6363/filament-click-spark/composer.json and nowhere else. Budget a half-day spike, not a planning cycle — and be honest that the diligence costs more than the artifact (a click listener plus a short-lived particle animation is roughly 60–120 lines of Alpine).
Technical risk. Low severity, medium probability, and consistently silent. This package fails soft: no sparks, no exception, no functional impact, nobody files a ticket. The enumerable risks:
| Risk | Symptom | Detection |
|---|---|---|
CSP blocks shipped inline <script> |
No effect; console error users ignore | DevTools under production CSP header |
filament:assets missing from deploy |
404 in prod, works locally | Network tab; asset present under public/ |
No prefers-reduced-motion guard |
Vestibular accessibility finding → forced removal | Read source; treat as hard gate |
Duplicate listeners on wire:navigate |
Two bursts per click | Navigate 5×, click, count |
Leaked <canvas> across SPA nav |
Progressive CPU creep on long shifts | DOM node count flat after 10 navigations |
| Filament v3 vs v4 asset-registration mismatch | Renders, no sparks | Match vendor constraint to lockfile |
| Hard-coded palette | Sparks vanish in dark mode / clash with brand | Check under real theme before demo |
Key questions a TPM must get answered before adoption. (1) Which Filament majors does the vendor composer.json allow, and does that match our lockfile? (2) Are assets served from a prebuilt dist/ bundle via FilamentAsset::register(), or do they need a Vite entry in our theme? (3) Is there any reduced-motion short-circuit — and if not, can we add one in under an hour? (4) Who is the named owner? (5) Which panels are in scope — decided in writing, once? If any of these is unanswered, the decision is "replicate in-house," because the honest competitor is a small first-party Alpine component that eliminates the supply-chain question entirely.
Stack fit. Laravel + Filament + Livewire, no additional dependencies, panel-scoped by design. That last property is the most useful thing about the package from a product standpoint: it makes surface segmentation a configuration decision rather than an engineering debate.
Migration path. Pin the constraint as load-bearing, not decorative:
composer require martin6363/filament-click-spark:^1.0
# commit composer.json AND composer.lock
Then wrap it in a one-file adapter so that removal, or a vendor fork, is a single import change:
// app/Filament/Plugins/Spark.php
public static function register(Panel $panel): Panel
{
if (! config('filament-click-spark.enabled')) {
return $panel; // removal is a config change, not a code change
}
return $panel->plugin(ClickSparkPlugin::make());
}
Ship with the flag defaulting to false. Registration goes in exactly one PanelProvider — not a shared base provider, not globally.
Compatibility. Verify the vendor constraint against the lockfile before writing the provider line, because v3 and v4 differ materially in FilamentAsset::register() behaviour, Alpine component loading, and the filament:assets pipeline. The failure mode for a mismatch is "renders fine, no sparks," which is precisely why it survives to production unnoticed.
Sequencing. Deliberately front-loaded so a "no" is cheap:
php artisan filament:assets next to optimize/filament:upgrade. Not a manual step.wire:navigate → back → click = still one burst; (c) zero CSP console errors under the production header; (d) reduced-motion path verified.Panel segmentation — decide once, in writing. Internal ops/support: yes. Sales demo/brand-personality: yes. Customer-facing portal: no. Regulated, public-sector, or accessibility-audited: no. Publishing this table is worth more than the package, because it stops the decision being relitigated by every engineer who touches a PanelProvider.
Also worth doing while you're here: write the cosmetic-dependency policy once — named owner, reduced-motion support, global kill switch, pinned version, scheduled review. That policy outlives this package by years.
Maintenance. There is no support tier. Zero dependents, one maintainer, an empty changelog, no README. Plan for a named owner and a quarterly check against Filament upgrades — hours per check, not sprints, because the surface is one provider line and one asset bundle. Assume a vendor fork is coming; the only question is whether the adapter class is already in place when it does.
Support. Cosmetic failures generate no tickets and no telemetry. Write a debug runbook into the internal docs — grep the plugin class for asset registration; check the network tab for a 404; check console for CSP/JS/Alpine errors; disable other cosmetic plugins to rule out conflicting document-level click listeners; check the config flag first. Do not let a teammate discover any of this by accident inside a PanelProvider.
Scaling. Per-click cost is negligible. The scaling concern is longitudinal: a canvas created on init and never torn down, multiplied by wire:navigate transitions, produces progressive CPU creep that surfaces as "the ops panel feels sluggish" on a long shift rather than as a bug. Verify DOM node count is flat after ten navigations. If listeners accumulate, the patch is a document-level binding with an idempotency guard or teardown on livewire:navigating — small, but it means you now own a fork, so make that call consciously rather than by drift.
Failure modes and responses.
| Failure | Business consequence | Response |
|---|---|---|
| CSP blocks the script | None functionally; invisible dead dependency | Fix nonce/hash path or remove |
filament:assets not in pipeline |
404 in prod only | Add to deploy, verify asset in public/ |
| No reduced-motion path | Accessibility finding forces immediate removal | Patch first, or don't enable |
| Duplicate bursts after SPA nav | Perceived jank on the flagship interaction | Fork and patch, or remove |
| Filament major upgrade breaks it | Silent no-op | Review cycle catches it; replicate in-house |
Ramp-up. Engineering: half a day. Organisation: near-zero — no training, no workflow change, no user-facing behaviour beyond an animation. Resist any temptation to claim it improves satisfaction, adoption, or productivity; if you want to test that hypothesis, define the signal before shipping, because a cosmetic probe with no one reading the result is just front-end weight with extra steps.
Pre-committed sunset criteria — set these before adoption, not after. Remove if: no named owner exists; no reduced-motion path; Filament compatibility cannot be confirmed against our lockfile; a Filament major upgrade breaks it; or it consumes more than a few hours of engineering attention to justify. Removal is a config flag plus a provider line. A cosmetic dependency without exit criteria is how front-end weight accumulates — and deleting it should feel easier than defending it.
How can I help you explore Laravel packages today?