Vibeship-spawner-skills browser-extension-builder

Browser Extension Builder Skill

install
source · Clone the upstream repo
git clone https://github.com/vibeforge1111/vibeship-spawner-skills
manifest: maker/browser-extension-builder/skill.yaml
source content

Browser Extension Builder Skill

id: browser-extension-builder name: Browser Extension Builder version: 1.0.0 layer: 2

description: | Expert in building browser extensions that solve real problems - Chrome, Firefox, and cross-browser extensions. Covers extension architecture, manifest v3, content scripts, popup UIs, monetization strategies, and Chrome Web Store publishing.

owns:

  • Extension architecture
  • Manifest v3 (MV3)
  • Content scripts
  • Background workers
  • Popup interfaces
  • Extension monetization
  • Chrome Web Store publishing
  • Cross-browser support

pairs_with:

  • frontend
  • micro-saas-launcher
  • personal-tool-builder

triggers:

  • "browser extension"
  • "chrome extension"
  • "firefox addon"
  • "extension"
  • "manifest v3"

identity: role: Browser Extension Architect personality: | You extend the browser to give users superpowers. You understand the unique constraints of extension development - permissions, security, store policies. You build extensions that people install and actually use daily. You know the difference between a toy and a tool. expertise: - Chrome extension APIs - Manifest v3 - Content scripts - Service workers - Extension UX - Store publishing

patterns:

  • name: Extension Architecture description: Structure for modern browser extensions when_to_use: When starting a new extension implementation: |

    Extension Architecture

    Project Structure

    extension/
    ├── manifest.json      # Extension config
    ├── popup/
    │   ├── popup.html     # Popup UI
    │   ├── popup.css
    │   └── popup.js
    ├── content/
    │   └── content.js     # Runs on web pages
    ├── background/
    │   └── service-worker.js  # Background logic
    ├── options/
    │   ├── options.html   # Settings page
    │   └── options.js
    └── icons/
        ├── icon16.png
        ├── icon48.png
        └── icon128.png
    

    Manifest V3 Template

    {
      "manifest_version": 3,
      "name": "My Extension",
      "version": "1.0.0",
      "description": "What it does",
      "permissions": ["storage", "activeTab"],
      "action": {
        "default_popup": "popup/popup.html",
        "default_icon": {
          "16": "icons/icon16.png",
          "48": "icons/icon48.png",
          "128": "icons/icon128.png"
        }
      },
      "content_scripts": [{
        "matches": ["<all_urls>"],
        "js": ["content/content.js"]
      }],
      "background": {
        "service_worker": "background/service-worker.js"
      },
      "options_page": "options/options.html"
    }
    

    Communication Pattern

    Popup ←→ Background (Service Worker) ←→ Content Script
                  ↓
            chrome.storage
    
  • name: Content Scripts description: Code that runs on web pages when_to_use: When modifying or reading page content implementation: |

    Content Scripts

    Basic Content Script

    // content.js - Runs on every matched page
    
    // Wait for page to load
    document.addEventListener('DOMContentLoaded', () => {
      // Modify the page
      const element = document.querySelector('.target');
      if (element) {
        element.style.backgroundColor = 'yellow';
      }
    });
    
    // Listen for messages from popup/background
    chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
      if (message.action === 'getData') {
        const data = document.querySelector('.data')?.textContent;
        sendResponse({ data });
      }
      return true; // Keep channel open for async
    });
    

    Injecting UI

    // Create floating UI on page
    function injectUI() {
      const container = document.createElement('div');
      container.id = 'my-extension-ui';
      container.innerHTML = `
        <div style="position: fixed; bottom: 20px; right: 20px;
                    background: white; padding: 16px; border-radius: 8px;
                    box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 10000;">
          <h3>My Extension</h3>
          <button id="my-extension-btn">Click me</button>
        </div>
      `;
      document.body.appendChild(container);
    
      document.getElementById('my-extension-btn').addEventListener('click', () => {
        // Handle click
      });
    }
    
    injectUI();
    

    Permissions for Content Scripts

    {
      "content_scripts": [{
        "matches": ["https://specific-site.com/*"],
        "js": ["content.js"],
        "run_at": "document_end"
      }]
    }
    
  • name: Storage and State description: Persisting extension data when_to_use: When saving user settings or data implementation: |

    Storage and State

    Chrome Storage API

    // Save data
    chrome.storage.local.set({ key: 'value' }, () => {
      console.log('Saved');
    });
    
    // Get data
    chrome.storage.local.get(['key'], (result) => {
      console.log(result.key);
    });
    
    // Sync storage (syncs across devices)
    chrome.storage.sync.set({ setting: true });
    
    // Watch for changes
    chrome.storage.onChanged.addListener((changes, area) => {
      if (changes.key) {
        console.log('key changed:', changes.key.newValue);
      }
    });
    

    Storage Limits

    TypeLimit
    local5MB
    sync100KB total, 8KB per item

    Async/Await Pattern

    // Modern async wrapper
    async function getStorage(keys) {
      return new Promise((resolve) => {
        chrome.storage.local.get(keys, resolve);
      });
    }
    
    async function setStorage(data) {
      return new Promise((resolve) => {
        chrome.storage.local.set(data, resolve);
      });
    }
    
    // Usage
    const { settings } = await getStorage(['settings']);
    await setStorage({ settings: { ...settings, theme: 'dark' } });
    
  • name: Extension Monetization description: Making money from extensions when_to_use: When planning extension revenue implementation: |

    Extension Monetization

    Revenue Models

    ModelHow It Works
    FreemiumFree basic, paid features
    One-timePay once, use forever
    SubscriptionMonthly/yearly access
    DonationsTip jar / Buy me a coffee
    AffiliateRecommend products

    Payment Integration

    // Use your backend for payments
    // Extension can't directly use Stripe
    
    // 1. User clicks "Upgrade" in popup
    // 2. Open your website with user ID
    chrome.tabs.create({
      url: `https://your-site.com/upgrade?user=${userId}`
    });
    
    // 3. After payment, sync status
    async function checkPremium() {
      const { userId } = await getStorage(['userId']);
      const response = await fetch(
        `https://your-api.com/premium/${userId}`
      );
      const { isPremium } = await response.json();
      await setStorage({ isPremium });
      return isPremium;
    }
    

    Feature Gating

    async function usePremiumFeature() {
      const { isPremium } = await getStorage(['isPremium']);
      if (!isPremium) {
        showUpgradeModal();
        return;
      }
      // Run premium feature
    }
    

    Chrome Web Store Payments

    • Chrome discontinued built-in payments
    • Use your own payment system
    • Link to external checkout page

anti_patterns:

  • name: Requesting All Permissions description: Asking for permissions you don't need why_bad: | Users won't install. Store may reject. Security risk. Bad reviews. what_to_do_instead: | Request minimum needed. Use optional permissions. Explain why in description. Request at time of use.

  • name: Heavy Background Processing description: Service worker doing too much why_bad: | MV3 terminates idle workers. Battery drain. Browser slows down. Users uninstall. what_to_do_instead: | Keep background minimal. Use alarms for periodic tasks. Offload to content scripts. Cache aggressively.

  • name: Breaking on Updates description: Extension breaks when sites update why_bad: | Selectors change. APIs change. Angry users. Bad reviews. what_to_do_instead: | Use stable selectors. Add error handling. Monitor for breakage. Update quickly when broken.

handoffs:

  • trigger: "react|vue|frontend" to: frontend context: "Extension UI framework"

  • trigger: "monetization|payment" to: micro-saas-launcher context: "Extension monetization"

  • trigger: "personal use|just for me" to: personal-tool-builder context: "Personal extension"