Help us improve
Share bugs, ideas, or general feedback.
From progressive-web-app
Builds Progressive Web Apps with service workers for offline caching, web manifests for installability, install prompts, and push notifications. Use for adding native-like features or fixing service worker/manifest errors.
npx claudepluginhub secondsky/claude-skills --plugin progressive-web-appHow this skill is triggered — by the user, by Claude, or both
Slash command
/progressive-web-app:progressive-web-appThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Build web applications that work like native apps with offline support and installability.
Builds Progressive Web Apps with service workers for offline caching, web app manifests for installability, and strategies like Workbox for resilient web experiences.
Adds or reviews PWA capabilities: installability, manifest metadata, Service Worker registration, Workbox caching, offline fallback, app update prompts, maskable icons, and iOS PWA compatibility.
Guides Service Worker API implementation: registration, lifecycle, caching strategies (cache-first, network-first), push notifications, background sync, and debugging sw.js files.
Share bugs, ideas, or general feedback.
Build web applications that work like native apps with offline support and installability.
{
"name": "My Application",
"short_name": "MyApp",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#000000",
"icons": [
{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" }
]
}
const CACHE_NAME = 'app-v1';
const STATIC_ASSETS = ['/', '/index.html', '/styles.css', '/app.js'];
// Install
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME).then(cache => cache.addAll(STATIC_ASSETS))
);
});
// Fetch with cache-first strategy
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cached => {
if (cached) return cached;
return fetch(event.request).then(response => {
if (response.status === 200) {
const clone = response.clone();
caches.open(CACHE_NAME).then(cache => cache.put(event.request, clone));
}
return response;
});
})
);
});
let deferredPrompt;
window.addEventListener('beforeinstallprompt', e => {
e.preventDefault();
deferredPrompt = e;
showInstallButton();
});
async function installApp() {
if (!deferredPrompt) return;
deferredPrompt.prompt();
const { outcome } = await deferredPrompt.userChoice;
console.log('Install outcome:', outcome);
deferredPrompt = null;
}
async function subscribeToPush() {
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: VAPID_PUBLIC_KEY
});
await sendSubscriptionToServer(subscription);
}