Elysia Tools

Durchsuche Tools, Beispiele, visuelle Erklärungen und Themenguides an einem klaren Ort.

Beliebte Kategorien

Themen

Sprache
ZHESPTRUFRDEEN

Elysia Tools

Mobile Navigation

Webtechnologien

Service Workers für Offline Web Apps

Service Workers für Offline-Funktionalität, Hintergrund-Synchronisation und Netzwerk-Interceptierung

Beispiele

Einträge in dieser Sammlung

QuellcodejavascriptEinfach

Basis Service Worker Setup

Service Worker registrieren und Offline-Cache aktivieren

Schwierigkeit

3/10

Geschätzte Zeit

15 min

Schlagwörter

service worker, offline, cache, pwa

Voraussetzungen

JavaScript, Basic web development

javascript
// Basic Service Worker Setup
// service-worker.js
const CACHE_NAME = 'my-app-v1';
const urlsToCache = [
  '/',
  '/index.html',
  '/styles.css',
  '/app.js',
  '/icon.png'
];

// Install event - cache files
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});

// Fetch event - serve from cache when offline
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        // Cache hit - return response
        if (response) {
          return response;
        }

        // Clone the request
        const fetchRequest = event.request.clone();

        return fetch(fetchRequest).then(response => {
          // Check if valid response
          if(!response || response.status !== 200 || response.type !== 'basic') {
            return response;
          }

          // Clone the response
          const responseToCache = response.clone();

          caches.open(CACHE_NAME)
            .then(cache => {
              cache.put(event.request, responseToCache);
            });

          return response;
        });
      })
  );
});

// Activate event - clean up old caches
self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          if (cacheName !== CACHE_NAME) {
            console.log('Deleting old cache:', cacheName);
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

// main.js - Register service worker
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js')
      .then(registration => {
        console.log('ServiceWorker registration successful with scope: ', registration.scope);

        // Check for updates
        registration.addEventListener('updatefound', () => {
          const newWorker = registration.installing;

          newWorker.addEventListener('statechange', () => {
            if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
              // New content is available, show update notification
              if (confirm('New version available! Reload to update?')) {
                window.location.reload();
              }
            }
          });
        });

      })
      .catch(err => {
        console.log('ServiceWorker registration failed: ', err);
      });
  });

  // Listen for controlling service worker
  navigator.serviceWorker.addEventListener('controllerchange', () => {
    console.log('ServiceWorker controller changed');
    window.location.reload();
  });
}
QuellcodejavascriptMittel

Hintergrund-Synchronisation

Daten synchronisieren wenn die Netzwerkverbindung wiederhergestellt ist

Schwierigkeit

6/10

Geschätzte Zeit

25 min

Schlagwörter

background sync, offline, pwa, indexeddb

Voraussetzungen

JavaScript, Service Workers, IndexedDB

javascript
// Background Sync Service Worker
// service-worker.js
self.addEventListener('sync', event => {
  if (event.tag === 'background-sync') {
    event.waitUntil(syncData());
  }
});

async function syncData() {
  try {
    // Get all pending sync requests from IndexedDB
    const pendingRequests = await getPendingRequests();

    for (const request of pendingRequests) {
      try {
        const response = await fetch(request.url, {
          method: request.method,
          headers: request.headers,
          body: request.body
        });

        if (response.ok) {
          // Remove successful request from pending
          await removePendingRequest(request.id);
          console.log('Sync successful for request:', request.id);
        } else {
          console.error('Sync failed for request:', request.id);
        }
      } catch (error) {
        console.error('Network error during sync:', error);
        throw error; // This will retry the sync
      }
    }

    // Show notification if sync completed
    if (await getPendingRequestsCount() === 0) {
      self.registration.showNotification('Sync Complete', {
        body: 'All your data has been synchronized',
        icon: '/sync-icon.png'
      });
    }
  } catch (error) {
    console.error('Background sync failed:', error);
  }
}

// IndexedDB helpers for pending requests
async function getPendingRequests() {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open('sync-db', 1);

    request.onerror = () => reject(request.error);
    request.onsuccess = () => {
      const db = request.result;
      const transaction = db.transaction(['requests'], 'readonly');
      const store = transaction.objectStore('requests');
      const getAll = store.getAll();

      getAll.onsuccess = () => resolve(getAll.result);
      getAll.onerror = () => reject(getAll.error);
    };

    request.onupgradeneeded = () => {
      const db = request.result;
      db.createObjectStore('requests', { keyPath: 'id' });
    };
  });
}

async function removePendingRequest(id) {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open('sync-db', 1);

    request.onerror = () => reject(request.error);
    request.onsuccess = () => {
      const db = request.result;
      const transaction = db.transaction(['requests'], 'readwrite');
      const store = transaction.objectStore('requests');
      const deleteRequest = store.delete(id);

      deleteRequest.onsuccess = () => resolve();
      deleteRequest.onerror = () => reject(deleteRequest.error);
    };
  });
}

// main.js - Register background sync
class BackgroundSyncManager {
  constructor() {
    this.registration = null;
  }

  async init() {
    this.registration = await navigator.serviceWorker.ready;
  }

  async registerSync() {
    if ('serviceWorker' in navigator &&
        typeof ServiceWorkerRegistration !== 'undefined' &&
        'sync' in ServiceWorkerRegistration.prototype) {
      try {
        await this.registration.sync.register('background-sync');
        console.log('Background sync registered');
        return true;
      } catch (error) {
        console.error('Background sync registration failed:', error);
        return false;
      }
    } else {
      console.warn('Background sync not supported');
      return false;
    }
  }

  async addPendingRequest(requestData) {
    const request = {
      id: Date.now().toString(),
      ...requestData,
      timestamp: Date.now()
    };

    // Save to IndexedDB
    const db = await this.openDB();
    const transaction = db.transaction(['requests'], 'readwrite');
    const store = transaction.objectStore('requests');
    await store.add(request);

    // Try to register background sync
    const syncRegistered = await this.registerSync();

    if (!syncRegistered) {
      // Fallback: try immediate sync
      this.tryImmediateSync(request);
    }

    return request.id;
  }

  async openDB() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open('sync-db', 1);

      request.onerror = () => reject(request.error);
      request.onsuccess = () => resolve(request.result);

      request.onupgradeneeded = () => {
        const db = request.result;
        db.createObjectStore('requests', { keyPath: 'id' });
      };
    });
  }

  async tryImmediateSync(request) {
    try {
      const response = await fetch(request.url, {
        method: request.method,
        headers: request.headers,
        body: request.body
      });

      if (response.ok) {
        await this.removePendingRequest(request.id);
        console.log('Immediate sync successful');
      } else {
        console.log('Immediate sync failed, keeping in pending queue');
      }
    } catch (error) {
      console.log('Network unavailable, keeping in pending queue');
    }
  }
}

// Usage example
const syncManager = new BackgroundSyncManager();

// Initialize when app loads
window.addEventListener('load', async () => {
  await syncManager.init();
});

// Example: Save data with background sync
async function saveDataOffline(data) {
  const requestData = {
    url: '/api/save',
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
  };

  const requestId = await syncManager.addPendingRequest(requestData);

  // Show user that data will be synced
  alert('Your data will be synced when you're back online');
}
QuellcodejavascriptMittel

Push-Benachrichtigungen

Push-Benachrichtigungen mit Service Workers empfangen und verarbeiten

Schwierigkeit

7/10

Geschätzte Zeit

30 min

Schlagwörter

push notifications, pwa, service worker, messaging

Voraussetzungen

JavaScript, Service Workers, HTTPS setup

javascript
// Push Notifications with Service Worker
// service-worker.js
self.addEventListener('push', event => {
  const options = {
    body: event.data ? event.data.text() : 'New notification',
    icon: '/notification-icon.png',
    badge: '/notification-badge.png',
    vibrate: [100, 50, 100],
    data: {
      dateOfArrival: Date.now(),
      primaryKey: 1
    },
    actions: [
      {
        action: 'explore',
        title: 'Explore this new world',
        icon: '/images/checkmark.png'
      },
      {
        action: 'close',
        title: 'Close notification',
        icon: '/images/xmark.png'
      }
    ]
  };

  event.waitUntil(
    self.registration.showNotification('Push Notification', options)
  );
});

// Handle notification clicks
self.addEventListener('notificationclick', event => {
  event.notification.close();

  if (event.action === 'explore') {
    // Open the app to specific page
    event.waitUntil(
      clients.openWindow('/explore')
    );
  } else if (event.action === 'close') {
    // Just close the notification
    console.log('Notification closed');
  } else {
    // Default action - open main app
    event.waitUntil(
      clients.matchAll().then(clientList => {
        for (const client of clientList) {
          if (client.url === '/' && 'focus' in client) {
            return client.focus();
          }
        }
        if (clients.openWindow) {
          return clients.openWindow('/');
        }
      })
    );
  }
});

// Handle notification close
self.addEventListener('notificationclose', event => {
  console.log('Notification closed:', event.notification);
});

// main.js - Push notification subscription
class PushNotificationManager {
  constructor() {
    this.subscription = null;
    this.publicKey = 'YOUR_VAPID_PUBLIC_KEY';
  }

  async init() {
    // Check for service worker support
    if (!('serviceWorker' in navigator)) {
      console.error('Service Worker not supported');
      return false;
    }

    // Check for push notification support
    if (!('PushManager' in window)) {
      console.error('Push notifications not supported');
      return false;
    }

    // Register service worker
    const registration = await navigator.serviceWorker.register('/push-service-worker.js');
    console.log('Service Worker registered');

    this.registration = registration;
    return true;
  }

  async subscribeToPush() {
    try {
      // Subscribe to push notifications
      this.subscription = await this.registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: this.urlBase64ToUint8Array(this.publicKey)
      });

      console.log('User is subscribed:', this.subscription);

      // Send subscription to server
      await this.sendSubscriptionToServer(this.subscription);

      return this.subscription;
    } catch (error) {
      console.error('Failed to subscribe to push notifications:', error);
      return null;
    }
  }

  async unsubscribeFromPush() {
    try {
      const result = await this.subscription.unsubscribe();
      console.log('Unsubscribed:', result);

      // Remove subscription from server
      await this.removeSubscriptionFromServer(this.subscription);

      this.subscription = null;
      return result;
    } catch (error) {
      console.error('Failed to unsubscribe:', error);
      return false;
    }
  }

  async sendSubscriptionToServer(subscription) {
    try {
      const response = await fetch('/api/subscribe', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(subscription)
      });

      if (!response.ok) {
        throw new Error('Failed to send subscription to server');
      }

      return await response.json();
    } catch (error) {
      console.error('Error sending subscription to server:', error);
      throw error;
    }
  }

  async removeSubscriptionFromServer(subscription) {
    try {
      const response = await fetch('/api/unsubscribe', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(subscription)
      });

      if (!response.ok) {
        throw new Error('Failed to remove subscription from server');
      }
    } catch (error) {
      console.error('Error removing subscription from server:', error);
      throw error;
    }
  }

  async requestNotificationPermission() {
    const permission = await Notification.requestPermission();

    if (permission === 'granted') {
      console.log('Notification permission granted');
      return true;
    } else {
      console.log('Notification permission denied');
      return false;
    }
  }

  // Helper function to convert VAPID key
  urlBase64ToUint8Array(base64String) {
    const padding = '='.repeat((4 - base64String.length % 4) % 4);
    const base64 = (base64String + padding)
      .replace(/-/g, '+')
      .replace(/_/g, '/');

    const rawData = window.atob(base64);
    const outputArray = new Uint8Array(rawData.length);

    for (let i = 0; i < rawData.length; ++i) {
      outputArray[i] = rawData.charCodeAt(i);
    }

    return outputArray;
  }

  async checkSubscriptionStatus() {
    this.subscription = await this.registration.pushManager.getSubscription();

    if (this.subscription) {
      console.log('User is already subscribed');
      return this.subscription;
    } else {
      console.log('User is not subscribed');
      return null;
    }
  }
}

// Usage example
const pushManager = new PushNotificationManager();

// Initialize push notifications
async function initPushNotifications() {
  const initialized = await pushManager.init();
  if (!initialized) return;

  // Request permission
  const permissionGranted = await pushManager.requestNotificationPermission();
  if (!permissionGranted) return;

  // Check if already subscribed
  const existingSubscription = await pushManager.checkSubscriptionStatus();

  if (!existingSubscription) {
    // Subscribe to push notifications
    await pushManager.subscribeToPush();
  }
}

// Subscribe button handler
document.getElementById('subscribe-btn').addEventListener('click', async () => {
  await initPushNotifications();
});

// Unsubscribe button handler
document.getElementById('unsubscribe-btn').addEventListener('click', async () => {
  await pushManager.unsubscribeFromPush();
});

// Test local notification
document.getElementById('test-notification').addEventListener('click', async () => {
  if (Notification.permission === 'granted') {
    new Notification('Test Notification', {
      body: 'This is a test notification!',
      icon: '/icon.png'
    });
  } else {
    console.log('Notification permission not granted');
  }
});
QuellcodejavascriptMittel

Erweiterte Caching-Strategien

Verschiedene Caching-Strategien für optimale Leistung implementieren

Schwierigkeit

8/10

Geschätzte Zeit

35 min

Schlagwörter

caching, performance, offline, pwa, strategies

Voraussetzungen

JavaScript, Service Workers, Performance optimization

javascript
// Advanced Service Worker Caching Strategies
// service-worker.js

// Different cache strategies
class CacheStrategies {
  // Cache First - try cache first, fallback to network
  static cacheFirst(request) {
    return caches.match(request)
      .then(response => {
        return response || fetch(request);
      });
  }

  // Network First - try network first, fallback to cache
  static networkFirst(request) {
    return fetch(request)
      .then(response => {
        // Cache successful responses
        if (response.status === 200) {
          const responseClone = response.clone();
          caches.open('dynamic-cache-v1')
            .then(cache => cache.put(request, responseClone));
        }
        return response;
      })
      .catch(() => {
        // Fallback to cache
        return caches.match(request);
      });
  }

  // Stale While Revalidate - serve from cache, update in background
  static staleWhileRevalidate(request) {
    const cachePromise = caches.match(request);
    const networkPromise = fetch(request)
      .then(response => {
        const responseClone = response.clone();
        caches.open('dynamic-cache-v1')
          .then(cache => cache.put(request, responseClone));
        return response;
      });

    return cachePromise
      .then(response => response || networkPromise)
      .catch(() => networkPromise);
  }

  // Network Only - always fetch from network
  static networkOnly(request) {
    return fetch(request);
  }

  // Cache Only - always serve from cache
  static cacheOnly(request) {
    return caches.match(request);
  }
}

// Cache management
class CacheManager {
  constructor() {
    this.caches = {
      static: 'static-cache-v1',
      dynamic: 'dynamic-cache-v1',
      api: 'api-cache-v1',
      images: 'images-cache-v1'
    };

    this.cacheRules = [
      // Static assets - cache first
      {
        match: request =>
          request.destination === 'script' ||
          request.destination === 'style' ||
          request.destination === 'font',
        strategy: 'cacheFirst',
        cacheName: this.caches.static
      },

      // Images - stale while revalidate
      {
        match: request => request.destination === 'image',
        strategy: 'staleWhileRevalidate',
        cacheName: this.caches.images,
        maxEntries: 100,
        maxAge: 30 * 24 * 60 * 60 * 1000 // 30 days
      },

      // API calls - network first with timeout
      {
        match: request => request.url.includes('/api/'),
        strategy: 'networkFirst',
        cacheName: this.caches.api,
        timeout: 3000, // 3 seconds
        maxEntries: 50
      },

      // HTML pages - network first
      {
        match: request =>
          request.destination === 'document' ||
          request.mode === 'navigate',
        strategy: 'networkFirst',
        cacheName: this.caches.dynamic
      },

      // External CDN - cache first
      {
        match: request =>
          request.url.includes('cdn.jsdelivr.net') ||
          request.url.includes('cdnjs.cloudflare.com'),
        strategy: 'cacheFirst',
        cacheName: this.caches.static
      }
    ];
  }

  async handleRequest(request) {
    const rule = this.findMatchingRule(request);

    if (!rule) {
      return fetch(request);
    }

    try {
      // Apply strategy with timeout if specified
      if (rule.timeout) {
        return await this.withTimeout(
          CacheStrategies[rule.strategy](request),
          rule.timeout,
          caches.match(request)
        );
      } else {
        const response = await CacheStrategies[rule.strategy](request);

        // Apply cache management rules
        if (response && response.ok && rule.cacheName) {
          await this.manageCache(rule.cacheName, request, rule);
        }

        return response;
      }
    } catch (error) {
      console.error('Cache strategy failed:', error);

      // Fallback to cache if available
      return caches.match(request) || new Response('Offline', {
        status: 503,
        statusText: 'Service Unavailable'
      });
    }
  }

  findMatchingRule(request) {
    return this.cacheRules.find(rule => rule.match(request));
  }

  async withTimeout(promise, timeout, fallback) {
    return Promise.race([
      promise,
      new Promise((_, reject) =>
        setTimeout(() => reject(new Error('Timeout')), timeout)
      )
    ]).catch(error => {
      if (fallback) return fallback;
      throw error;
    });
  }

  async manageCache(cacheName, request, rule) {
    if (rule.maxEntries || rule.maxAge) {
      const cache = await caches.open(cacheName);
      const requests = await cache.keys();

      // Remove old entries if maxEntries exceeded
      if (rule.maxEntries && requests.length > rule.maxEntries) {
        const toDelete = requests.slice(0, requests.length - rule.maxEntries);
        await Promise.all(toDelete.map(req => cache.delete(req)));
      }

      // Remove old entries based on age
      if (rule.maxAge) {
        const now = Date.now();
        for (const cacheRequest of requests) {
          const response = await cache.match(cacheRequest);
          const dateHeader = response.headers.get('date');
          if (dateHeader && (now - new Date(dateHeader).getTime()) > rule.maxAge) {
            cache.delete(cacheRequest);
          }
        }
      }
    }
  }
}

// Initialize cache manager
const cacheManager = new CacheManager();

// Service worker event handlers
self.addEventListener('fetch', event => {
  event.respondWith(cacheManager.handleRequest(event.request));
});

// Install event - precache critical assets
self.addEventListener('install', event => {
  const staticAssets = [
    '/',
    '/index.html',
    '/offline.html',
    '/styles/main.css',
    '/scripts/app.js',
    '/images/logo.png'
  ];

  event.waitUntil(
    caches.open(cacheManager.caches.static)
      .then(cache => cache.addAll(staticAssets))
  );
});

// Activate event - clean up old caches
self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames
          .filter(name => !Object.values(cacheManager.caches).includes(name))
          .map(name => caches.delete(name))
      );
    })
  );
});

// Background sync for offline analytics
self.addEventListener('sync', event => {
  if (event.tag === 'analytics-sync') {
    event.waitUntil(syncAnalytics());
  }
});

async function syncAnalytics() {
  const offlineData = await getOfflineAnalytics();

  for (const data of offlineData) {
    try {
      await fetch('/api/analytics', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data)
      });

      await removeOfflineAnalytics(data.id);
    } catch (error) {
      console.error('Failed to sync analytics:', error);
      break;
    }
  }
}

// IndexedDB helpers for offline analytics
async function getOfflineAnalytics() {
  // Implementation for getting analytics from IndexedDB
  return [];
}

async function removeOfflineAnalytics(id) {
  // Implementation for removing analytics from IndexedDB
}

// main.js - Client-side analytics that works offline
class OfflineAnalytics {
  constructor() {
    this.db = null;
  }

  async init() {
    this.db = await this.openDB();
  }

  async openDB() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open('analytics-db', 1);

      request.onerror = () => reject(request.error);
      request.onsuccess = () => resolve(request.result);

      request.onupgradeneeded = () => {
        const db = request.result;
        db.createObjectStore('events', { keyPath: 'id', autoIncrement: true });
      };
    });
  }

  async track(eventName, properties = {}) {
    const event = {
      name: eventName,
      properties: {
        ...properties,
        timestamp: Date.now(),
        url: window.location.href,
        userAgent: navigator.userAgent
      }
    };

    try {
      // Try to send immediately
      const response = await fetch('/api/analytics', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(event)
      });

      if (!response.ok) throw new Error('Analytics request failed');

    } catch (error) {
      // Store offline
      await this.storeOffline(event);

      // Register background sync if available
      if ('serviceWorker' in navigator &&
          typeof ServiceWorkerRegistration !== 'undefined' &&
          'sync' in ServiceWorkerRegistration.prototype) {
        const registration = await navigator.serviceWorker.ready;
        registration.sync.register('analytics-sync');
      }
    }
  }

  async storeOffline(event) {
    const transaction = this.db.transaction(['events'], 'readwrite');
    const store = transaction.objectStore('events');
    await store.add(event);
  }
}

// Usage
const analytics = new OfflineAnalytics();
analytics.init();

// Track page view
analytics.track('page_view', {
  page: window.location.pathname,
  title: document.title
});

// Track user interaction
document.getElementById('cta-button').addEventListener('click', () => {
  analytics.track('cta_clicked', {
    button_text: 'Get Started',
    location: 'homepage'
  });
});

Werkzeuge

Tools, die oft mit diesem Beispiel genutzt werden

Verwandt

Verwandte Beispielsammlungen

Leitfaden zur Tool-Nutzung

Kontext zum Verständnis dieser Beispielsammlung

Titel

Service Workers für Offline Web Apps

Beschreibung

Service Workers für Offline-Funktionalität, Hintergrund-Synchronisation und Netzwerk-Interceptierung

Überblick

Service Workers für Offline-Funktionalität, Hintergrund-Synchronisation und Netzwerk-Interceptierung

Wann verwenden

  • Use this sample set when you want reference inputs for Service Workers für Offline Web Apps.
  • Use it to preview output formats and compare related sample variants.

So funktioniert es

  1. 1Open a sample entry to inspect the prepared example payload or asset.
  2. 2Compare it with related tools to understand how the workflow connects.

Anwendungsfälle

  • Basis Service Worker Setup
  • Hintergrund-Synchronisation
  • Push-Benachrichtigungen
  • Erweiterte Caching-Strategien

FAQ

What is included in Service Workers für Offline Web Apps?

This page includes curated sample entries, related tools, and neighboring sample collections for Service Workers für Offline Web Apps.

Start
Werkzeuge3197
Beispiele593
Visualisierungen461
Dateibetrachter103
Themen229
Schlagwörter333
Bilder, Audio & Video655

Werkzeuge für Bild-, Audio- und Videobearbeitung, Konvertierung und Optimierung

Mathe, Datum & Finanzen644

Rechner, Zahlenwerkzeuge, Datumslogik, Statistik und Finanztools

Design & Farbe296

Werkzeuge für Farben, Layouts, Grafiken, visuelle Gestaltung und Designhilfen

Text & Schreiben209

Werkzeuge für Schreiben, Bereinigung, Formatierung, Extraktion und Textanalyse

Entwicklung & Web193

Entwicklerwerkzeuge, Netzwerk-Utilities, Web-Debugging und Automatisierungshelfer

Konvertierung & Kodierung175

Werkzeuge für Format-, Datei-, Archiv-, Einheiten- und Kodierungskonvertierung

UI-Screenshot strukturieren, prüfen und an die Entwicklung übergeben
Klavierskizze erstellen, MIDI prüfen und Hördemo übergeben
Retro-Spieltexturen prüfen und Ressourcen übergeben
Screenshot-Anleitungen prüfen und Schulungsunterlagen übergeben
Responsive Seitenänderungen prüfen und Bildnachweise übergeben

© 2026 Elysia Tools. Alle Rechte vorbehalten.

DokumentationTarifeÜber unsNutzungsbedingungenDatenschutzerklärungCookiesKontakt

Media

Chrome Web Store Screenshots angepasst

Bilder an Chrome Web Store Screenshot-Größen anpassen (1280x800 oder 640x400) für Extension- und App-Listings

Security

ReDoS-Scanner fuer Regex

Prueft Regex-Muster auf katastrophales Backtracking, simuliert boesartige Eingaben und schlaegt sichere Alternativen vor

Security

Offline TOTP / HOTP Code-Generator

Erzeugt Einmalpasswörter TOTP RFC 6238 (6/8 Ziffern, 30/60 s) und HOTP RFC 4226 (zählerbasiert) aus einem base32-Secret, offline, mit HMAC-SHA1/256/512, und exportiert eine otpauth://-URI

Format Conversion

Web-Push-Encoder: RFC-8030-Anfrage + VAPID + RFC-8291-Verschlüsselung

Kodiert einen vollständigen Web-Push-Versand: aes128gcm-Verschlüsselung nach RFC 8291, VAPID-ES256-JWT nach RFC 8292, RFC-8030-Header, APNs/FCM-Zuordnung und Entschlüsselungs-Roundtrip-Verifikation.

Web & Internet

Websuche (SearXNG-JSON)

Durchsucht das Web über die SearXNG-Instanz s.stdlang.com und liefert JSON für Automatisierung und Folgetools.

Design

Web-Schrift-Pairing-Labor

Vorschau eines Google-Fonts-Pairings (Überschrift + Fließtext) mit Gewicht- und Zeilenhöhe-Reglern und kopierfertigem CSS-@import-+-Variablen-Snippet. Kuratierte 22-Schrift-Registry und 7 Presets.

Webtechnologien

Progressive Web Apps (PWA)

Moderne, zuverlässige und ansprechende Progressive Web Apps mit Offline-Fähigkeiten erstellen

Webtechnologien

WebRTC Echtzeitkommunikation Beispiele

Umfassende WebRTC-Beispiele für P2P Audio/Video-Kommunikation, Datenkanäle, Bildschirmfreigabe und Signalisierungsserver