visualbuilder/filament-screenshot-catalogue
| Install | |
|---|---|
composer require visualbuilder/filament-screenshot-catalogue |
|
| Latest Version: | 5.8.0 |
| PHP: | ^8.2 |
| License: | GPL-2.0-or-later |
| Last Updated: | Jul 12, 2026 |
| Links: | GitHub · Packagist |
Filament Panel Screenshot Catalogue
Capture every page of a Filament v5 panel — at desktop, tablet, and mobile breakpoints, in light and dark mode — upload to S3, and publish a browsable, link-shareable index. Designed as the data source for visual QA, design reviews, marketing assets, and AI-driven visual regression workflows.
What you get
php artisan panel:sitemap --panel=admin # discover every URL
php artisan screenshot:dispatch --panel=admin --tag=latest # queue per-page capture jobs
php artisan screenshot:capture --panel=admin --page=dashboard --tag=latest # one-off sync run
php artisan screenshot:rebuild-index --panel=admin --tag=latest # rebuild index.html only
The pipeline is:
- Sitemap generator walks the panel's resources, custom pages and auth screens, picks a representative record for
view/editURLs, and saves a JSON manifest tostorage/app/sitemap-{panel}.json. - Capture jobs drive Playwright through every entry × every viewport × every mode, save PNGs locally, and upload to your configured S3 disk.
- Index builder lists the run's S3 prefix and renders
index.htmlwith a sticky sidebar nav, scrollspy, lightbox, and one section per page. - Output lives at
s3://{disk}/{prefix}/{env}/{panel}/{version}/with a top-levelindex.htmland{slug}/{viewport}-{mode}.pngper shot.
Install
This is a development tool — most consumers will want it as a require-dev dependency so it never ships to production:
composer require --dev visualbuilder/filament-screenshot-catalogue
(If you genuinely need the artisan commands available in production — e.g. you run captures from a CI job that mounts production-like infrastructure — drop the --dev flag.)
The package's commands auto-register. Then make sure both Composer and Node prerequisites are in place:
| Dependency | Why it's needed | How to install |
|---|---|---|
aws/aws-sdk-php + an S3 disk |
Uploads + serves the catalogue | Already pulled in transitively. Configure an S3 disk in config/filesystems.php (default expected name: s3_public). |
| Node 18+ | Runs the Playwright runner | System-level (apt install nodejs / brew install node / etc.). |
| Playwright | Drives the headless browser | npm install playwright && npx playwright install chromium in the host project root. |
| A canonical "screenshot user" per panel | The runner logs in as this user and the sitemap generator uses them to find sample records | Seeded by the host (see Panel registration below). |
Optionally publish the config, the Node runner, or the bundled Claude Code skill:
php artisan vendor:publish --tag=filament-screenshot-catalogue-config # override defaults
php artisan vendor:publish --tag=filament-screenshot-catalogue-js # custom Playwright runner
php artisan vendor:publish --tag=filament-screenshot-catalogue-claude-skills # /screenshot-catalogue slash command
The Claude skill installs into the host's .claude/commands/screenshot-catalogue.md — gives Claude the full command surface, troubleshooting tips, and the PanelDescriptor registration pattern as context.
Panel registration
Hosts tell the package which panels to capture by registering a PanelDescriptor per panel — typically inside a small service provider:
namespace App\Providers;
use Filament\Facades\Filament;
use Illuminate\Support\ServiceProvider;
use Visualbuilder\FilamentScreenshotCatalogue\PanelDescriptor;
use Visualbuilder\FilamentScreenshotCatalogue\PanelRegistry;
class ScreenshotCatalogueServiceProvider extends ServiceProvider
{
public function boot(): void
{
PanelRegistry::register(new PanelDescriptor(
key: 'admin',
panelId: 'admin',
domain: env('ADMIN_DOMAIN'),
loginHeading: 'Admin Login',
email: env('SCREENSHOT_ADMIN_EMAIL'),
password: env('SCREENSHOT_ADMIN_PASSWORD'),
authenticator: static function (): void {
$user = \App\Models\User::where('email', config('catalogue.admin_email'))->first();
if ($user !== null) auth('web')->setUser($user);
},
));
}
}
Add the provider to bootstrap/providers.php. If you installed the package as require-dev (the default suggestion above), wrap the registration in a class_exists check so production — where the package isn't installed — silently skips it instead of crashing on a missing class import:
// bootstrap/providers.php
$providers = [
// ...your usual providers...
];
if (class_exists(\Visualbuilder\FilamentScreenshotCatalogue\PanelRegistry::class)) {
$providers[] = App\Providers\ScreenshotCatalogueServiceProvider::class;
}
return $providers;
If you installed as a regular require dependency, register the provider unconditionally.
Tenanted panels (Filament's tenancy enabled): set the active tenant inside authenticator:
authenticator: static function (): void {
$user = \App\Models\OrganisationUser::where('email', 'sample@example.com')->first();
if ($user !== null) {
auth('organisation_user')->setUser($user);
Filament::setTenant($user->organisation);
}
},
Configuration
Override defaults by publishing config/screenshot-catalogue.php. Common knobs:
return [
// S3 disk (must be configured in config/filesystems.php).
'disk' => 's3_public',
// Top-level S3 prefix.
'path_prefix' => 'screenshots',
// Capture viewports — name → { name, width, height }. Override to
// standardise on your own breakpoints.
'viewports' => [
'desktop' => ['name' => 'desktop', 'width' => 1280, 'height' => 800],
'tablet' => ['name' => 'tablet', 'width' => 768, 'height' => 1024],
'mobile' => ['name' => 'mobile', 'width' => 375, 'height' => 812],
],
// CSS injected into every page just before the screenshot fires —
// use this to lock host theme animations into a stable state. Empty
// by default.
//
// Example for a theme that animates its topbar on root scroll:
//
// 'capture_time_css' => '
// .fi-topbar { padding-block: 1rem !important; }
// .fi-main { padding-top: 7rem !important; }
// ',
'capture_time_css' => '',
// Sitemap entries to omit from the catalogue. Match the `slug` field
// in `storage/app/sitemap-{panel}.json` — Filament's `{resource}.{page}`
// form (e.g. `users.index`, `orders.edit`) for resource pages, or the
// page class slug for custom pages. NOT URL slugs.
'excluded_slugs' => [],
// Brand assets uploaded next to index.html so the catalogue's heading
// shows your wordmark + favicon. Both are optional.
'brand' => [
'name' => 'Panel Screenshots',
'logo' => public_path('media/your_logo_dark_mode.svg'),
'favicon' => public_path('media/your_favicon.svg'),
],
];
How the catalogue is laid out on S3
{prefix}/{env}/{panel}/{version}/ (env omitted in production)
├── index.html
├── favicon.svg
├── logo.svg
├── dashboard/
│ ├── desktop-light.png
│ ├── desktop-dark.png
│ ├── tablet-light.png
│ ├── tablet-dark.png
│ ├── mobile-light.png
│ └── mobile-dark.png
├── orders.index/
│ └── …
└── …
Tag-versioning: --tag=latest overwrites in place (continuous capture), any other tag (e.g. --tag=v2.5.0) is treated as immutable.
Commands
| Command | Use it for |
|---|---|
panel:sitemap --panel=KEY |
Generate sitemap-{panelId}.json for the panel. Re-run when routes change. |
screenshot:dispatch --panel=KEY --tag=latest |
Queue one CapturePageScreenshotsJob per sitemap entry plus a final RebuildScreenshotIndexJob. Use a queue worker. |
screenshot:capture --panel=KEY --page=SLUG --tag=latest |
Synchronous run, single page or a few. Useful for debug. |
screenshot:rebuild-index --panel=KEY --tag=latest |
Re-render index.html from the existing PNGs without re-capturing. |
All four accept --panel=KEY where KEY is the friendly CLI name registered in the descriptor (e.g. admin). The package translates to Filament's internal panel ID for URL/route resolution.
What's not in the package (host responsibilities)
- The seeded sample user(s) per panel — the package needs a real user to log in as, but creating one is host territory.
- Theme-specific tweaks beyond
capture_time_css(e.g. permanent CSS overrides for a custom design system) — keep those in your theme stylesheet. - Authentication wiring (tenants, magic links, 2FA dismissal) — the descriptor's
authenticatorclosure is the seam.
Production safety
The package refuses to run screenshot:capture and screenshot:dispatch when APP_ENV=production. The dispatch flow respects APP_DEBUG=true too — it bails out so the Laravel debug bar doesn't pollute every shot.
License
GPL-2.0-or-later.
Related Packages
Human QA review for Filament v5 screenshot catalogues — approve, request changes...
A Filament v5 design-system review panel and AI-friendly theme designer.
Lottie animation Schema component and Blade component for Filament panels.
Effortlessly manage revisions of your Eloquent models in Filament with polymorph...
Laravel artisan commands for YouTrack workflow automation — extracted so dev-age...