matheusmarnt / ghostwire
Automatic runtime skeleton loaders for Livewire β synthesized from your live DOM, zero markup.
Package info
github.com/matheusmarnt/ghostwire
Language:JavaScript
pkg:composer/matheusmarnt/ghostwire
Requires
- php: ^8.2
- illuminate/support: ^12.0|^13.0
- livewire/livewire: ^3.6|^4.0
Requires (Dev)
- laravel/pint: ^1.14
- orchestra/testbench: ^10.0|^11.0
- pestphp/pest: ^3.0|^4.0
- pestphp/pest-plugin-browser: ^4.0
- pestphp/pest-plugin-laravel: ^3.0|^4.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- dev-release-please--branches--main--components--ghostwire
- dev-worktree-m7-learning
- dev-fix/issue-2-ci-phpunit-config
- dev-worktree-fix-issues-drop-laravel11
- dev-worktree-logo-update
- dev-worktree-m6-v1-launch
- dev-worktree-m5-theme-a11y
- dev-worktree-m4-ghost-attribute
- dev-worktree-m3-robustez
- dev-worktree-worktree-m2-synthesizer
- dev-worktree-m1-ghost-layer
This package is auto-updated.
Last update: 2026-09-12 04:54:35 UTC
README
Ghostwire
Automatic runtime skeleton loaders for Livewire β synthesized from your live DOM, zero markup.
π Documentation: https://matheusmarnt.github.io/ghostwire/ Β· π§π· PortuguΓͺs Β· πͺπΈ EspaΓ±ol
Add wire:ghost to any element (or #[Ghost] to a component class, with zero view changes) and Ghostwire synthesizes a matching skeleton from the live DOM the instant a Livewire request starts β no hand-written placeholder markup, no layout shift, and it works identically whether your app runs Livewire 3.6+ or 4.x.
Features
- Zero-markup synthesis β walks the live DOM, classifies text/heading/media/control/container nodes, and emits a matching Bone Tree, all in one batched read pass (no forced reflow)
- Dual Livewire bridge β Livewire 3.6+ and 4.x supported from the same package, selected by runtime feature detection (never a version-string check)
- Morph-safe β the Ghost Layer mounts outside Livewire's reconciled tree; concealment uses only
visibility/opacity/pointer-events, never a structural DOM change freezemode β dims and disables the live host in place, for layouts synthesis can't safely cover#[Ghost]attribute β class- or method-level, a 7-level precedence cascade (directive modifier β directive expression β method β class β inherited β config β package default), zero view changes required- Silence by default β sync-only and polling messages never trigger a ghost, so background updates stay invisible
- Repeat-sibling sampling, scrollable clipping, sticky/fixed geometry β real layouts (paginated tables, kanban boards, scrollable panels) synthesize correctly, not just simple cards
- Theming β shimmer/pulse/wave animations, automatic dark mode,
prefers-reduced-motionsupport, all pure CSS behind data/CSS-variable tokens - Accessibility β
aria-busy, focus preservation across the ghost window, a shared live region announcing loading/idle state; axe-core clean at the strictest level - CSP-safe β runs under a strict Content-Security-Policy (no inline scripts, no
eval); stylesheet nonce support built in php artisan ghost:inspectβ see exactly which precedence level decided each component's configuration- Learning β remembers a component's synthesized skeleton locally (opt-in, refused in production) so a lazy-loaded component's first paint on a later visit already has a matching placeholder β export it with
php artisan ghost:exportas a static Blade@placeholder
Requirements & compatibility
| Supported | |
|---|---|
| PHP | 8.2, 8.3, 8.4 |
| Laravel | 12.x, 13.x |
| Livewire | 3.6+, 4.x |
Tier matrix (FR-81)
Bridge selection is runtime feature detection, never a version string. Everything below is verified on both lines in CI.
| Tier | Capabilities |
|---|---|
| A β identical | Directive + every modifier except .island Β· #[Ghost] in full (class, method, inheritance, precedence) Β· synthesis Β· freeze Β· timing (delay/hold/timeout) Β· sync silence Β· theme & tokens Β· accessibility Β· morph coexistence |
| B β degraded on 3.x | Post-paint removal (emulated via double requestAnimationFrame) Β· finalization (composed from multiple hooks) Β· cancellation (resolved as finalization) Β· poll detection (origin heuristic) Β· per-action interception (bridge-level filter β same observable behavior) |
| C β 4.x only | Island scoping (.island) Β· message-skip handling |
Full detail: /docs/compat.
Installation
composer require matheusmarnt/ghostwire
<div wire:ghost> {{-- your existing Livewire markup, unchanged --}} </div>
See /docs/install for the full first-effect walkthrough, and /playground to try synthesis on your own markup without installing anything.
Learning
Ghostwire can remember a component's synthesized skeleton locally in the browser and reuse it the next time that component is about to lazy-load β so a later visit's first lazy paint already has a matching skeleton, not a blank placeholder. Off by default, and refused server-side in production regardless of config.
GHOSTWIRE_LEARNING=true
#[Ghost(lazy: true)] class OrdersTable extends Component { // ... }
Ghostwire.exportLearned() // in the browser: downloads ghostwire-learned.json
php artisan ghost:export --component=orders-table --breakpoint=lg --from=~/Downloads/ghostwire-learned.json
Full walkthrough, storage/privacy details, and the export command's security posture: /docs/learning.
Documentation
Full docs, live playground, and gallery: https://matheusmarnt.github.io/ghostwire/
/docs/wire-ghostβ directive & modifiers/docs/ghost-attributeβ#[Ghost]attribute & precedence/docs/learningβ local persistence, lazy skeletons,ghost:export/docs/choosingβ directive vs. attribute/docs/compatβ Livewire 3/4 tier matrix/docs/themingβ tokens, dark mode, animation/docs/how-it-worksβ the synthesis algorithm/docs/securityβ CSP, transport, supply chain/docs/testingβ Pest helpers & browser tests/docs/interopβ@placeholder, Wirebones, Flux, livecharts, scoutify
Security
See SECURITY.md and /docs/security. No DOM data ever leaves the browser; learning is local-only; zero telemetry (FR-93).
Other packages by the author
License
MIT Β© Matheus Mariano. See LICENSE.md.
