npm package: @smartimpact-it/modern-video-embed
Description: Modern YouTube and Vimeo embed web components with lazy loading, accessibility, quality control, and comprehensive API
Author: Smart Impact IT
Latest version: 2.0.9

# Video Embed Components

Modern, performant YouTube, Vimeo, and HTML5 video embed web components with lazy loading, event-driven architecture, and comprehensive API control.

## 📋 Quick Reference

| Component         | Best For           | Bundle Size (Min) | External API       |
| ----------------- | ------------------ | ----------------- | ------------------ |
| `<youtube-embed>` | YouTube videos     | 15KB              | YouTube iframe API |
| `<vimeo-embed>`   | Vimeo videos       | 14KB              | Vimeo Player API   |
| `<video-embed>`   | Self-hosted videos | 12KB              | Native HTML5       |

**Need help?** See [AI Instructions](.ai-instructions.md) for development guidance.

## ✨ Features

- **🎮 Full Control API** - Play, pause, stop, mute, and load videos programmatically
- **📡 Event-Driven** - Listen to player events (ready, play, pause, error, etc.)
- **⚡ Lazy Loading** - Improve performance with poster images and on-demand loading
- **🔗 Flexible URLs** - Support for full URLs, short links, and video IDs
- **📱 Responsive** - Mobile-first design with touch-friendly controls
- **♿ Accessible** - Keyboard navigation and screen reader support
- **🎨 Customizable** - Custom overlay controls or native player controls
- **🎬 Multi-Platform** - YouTube, Vimeo, and self-hosted HTML5 video support

## � Project Structure

```
si_video_embed/
├── src/
│   ├── components/          # Web Components
│   │   ├── BaseVideoEmbed.ts       # Abstract base class (shared functionality)
│   │   ├── YouTubeEmbed.ts         # YouTube iframe component
│   │   ├── VimeoEmbed.ts           # Vimeo iframe component
│   │   └── VideoEmbed.ts           # Native HTML5 video component
│   ├── types/               # TypeScript type definitions
│   └── styles/              # SCSS stylesheets
│       ├── _shared-functions.scss  # Reusable SVG encoding functions
│       ├── _embed-base.scss        # Shared component mixins
│       ├── youtube-embed.scss      # YouTube-specific styles
│       ├── vimeo-embed.scss        # Vimeo-specific styles
│       └── video-embed.scss        # Video-specific styles
├── dist/                    # Compiled output (auto-generated)
│   ├── index.js/.min.js     # Full bundle (YouTube + Vimeo + Video)
│   ├── youtube-only.js      # YouTube-only bundle (15KB min)
│   ├── vimeo-only.js        # Vimeo-only bundle (14KB min)
│   ├── video-only.js        # Native video-only bundle (12KB min)
│   └── css/                 # Compiled styles
├── examples/                # Live demos and usage examples
├── test/                    # Automated test suite (67+ tests)
└── scripts/                 # Build validation and cache-busting scripts
```

**Key Files:**

- `.ai-instructions.md` - Development guide for AI agents and contributors
- `package.json` - NPM scripts and dependencies
- `tsconfig.json` - TypeScript configuration (strict mode)

## �🚀 Quick Start

### Installation

#### Via NPM (recommended for projects)

```bash
npm install @smartimpact-it/modern-video-embed
```

#### Via CDN (for quick prototypes)

```html |
| ----------------- | ------------------------- | ---------- | ----------- |
----------------------- | | **Full** | `dist/index.js` | 58KB | **29KB** | All
three components | | **YouTube Only** | `dist/youtube-only.js` | 29KB | **15KB**
| Only YouTube embeds | | **Vimeo Only** | `dist/vimeo-only.js` | 29KB |
**14KB** | Only Vimeo embeds | | **Video Only** | `dist/video-only.js` | 24KB |
**12KB** | Only HTML5 video embeds | | **Styles (Core)** |
`dist/css/components.css` | 9KB | **7KB** | Component styles only | | **Styles
(Full)** | `dist/css/main.css` | 276KB | **224KB** | With Bootstrap (demos)
href="https://unpkg.com/@smartimpact-it/modern-video-embed@latest/dist/css/components.css"
/>
```

#### Manual Build

```bash
git clone https://github.com/siit-dev/si_video_embed.git
cd si_video_embed
npm install
npm run build
```

### Bundle Options

Choose the right bundle for your needs:

| Bundle            | File                      | Size (Dev) | Size (Prod) | Use Case               |
| ----------------- | ------------------------- | ---------- | ----------- | ---------------------- |
| **Full**          | `dist/index.js`           | 58KB       | **29KB**    | Both YouTube and Vimeo |
| **YouTube Only**  | `dist/youtube-only.js`    | 29KB       | **15KB**    | Only YouTube embeds    |
| **Vimeo Only**    | `dist/vimeo-only.js`      | 29KB       | **14KB**    | Only Vimeo embeds      |
| **Styles (Core)** | `dist/css/components.css` | 9KB        | **7KB**     | Component styles only  |
| **Styles (Full)** | `dist/css/main.css`       | 276KB      | **224KB**   | With Bootstrap (demos) |

**Production Files** use minified versions (`.min.js` / `.min.css`) for ~50% size reduction.

**Recommended for Production:**

- Use **YouTube-only** or **Vimeo-only** bundles when possible (~14-15KB minified)
- Use **Core styles** (`components.css`) instead of full Bootstrap (~7KB minified)
- Enable gzip compression on your server (reduces size by additional 60-70%)

### Basic Usage

#### Include Required Files

**For Production** (recommended - use minified files):

```html
<!-- Full bundle: Both YouTube and Vimeo (29KB minified) -->
<script type="module" src="dist/index.min.js"></script>
<link rel="stylesheet" href="dist/css/components.min.css" />

<!-- OR YouTube only (15KB minified) -->
<script type="module" src="dist/youtube-only.min.js"></script>
<link rel="stylesheet" href="dist/css/components.min.css" />

<!-- OR Vimeo only (14KB minified) -->
<script type="module" src="dist/vimeo-only.min.js"></script>
<link rel="stylesheet" href="dist/css/components.min.css" />
```

**For Development** (use unminified files for debugging):

```html
<!-- Full bundle: Both YouTube and Vimeo -->
<script type="module" src="dist/index.js"></script>

<!-- OR YouTube only (smaller) -->
<script type="module" src="dist/youtube-only.js"></script>

<!-- OR Vimeo only (smaller) -->
<script type="module" src="dist/vimeo-only.js"></script>

<!-- Component CSS only -->
<link rel="stylesheet" href="dist/css/components.css" />
```

**For Demos/Examples** (includes Bootstrap):

```html
<!-- Component JavaScript -->
<script type="module" src="dist/index.js"></script>

<!-- Full CSS with Bootstrap (~276KB) -->
<link rel="stylesheet" href="dist/css/main.css" />
```

#### YouTube

```html
<!-- Use in HTML -->
<youtube-embed url="https://www.youtube.com/watch?v=dQw4w9WgXcQ" controls>
</youtube-embed>
```

#### Vimeo

```html
<!-- Use in HTML -->
<vimeo-embed url="https://vimeo.com/76979871" controls> </vimeo-embed>
```

# HTML5 Video (Self-hosted)

```html
<!-- Use in HTML with self-hosted videos -->
<video-embed
  url="https://example.com/videos/demo.mp4"
  controls
  poster="thumbnail.jpg"
>
</video-embed>
```

###

### Advanced Usage

#### YouTube

```html
<!-- Lazy loading with custom poster -->
<youtube-embed
  video-id="dQw4w9WgXcQ"
  lazy
  autoplay
  muted
  poster="custom-poster.jpg"
>
</youtube-embed>
```

#### Vimeo

````html
<!-- Lazy loading with custom poster -->
<vimeo-embed
  ## HTML5 Video

```html
<!-- Self-hostedAll Components)

| Attribute     | Type    | YouTube | Vimeo | Video | Description                                  |
| ------------- | ------- | ------- | ----- | ----- | -------------------------------------------- |
| `url`         | String  | ✅      | ✅    | ✅    | Full video URL                               |
| `video-id`    | String  | ✅      | ✅    | ❌    | Video ID (YouTube: 11 chars, Vimeo: numeric) |
| `autoplay`    | Boolean | ✅      | ✅    | ✅    | Auto-play video when loaded                  |
| `controls`    | Boolean | ✅      | ✅    | ✅    | Show native player controls                  |
| `lazy`        | Boolean | ✅      | ✅    | ✅    | Enable lazy loading with poster              |
| `muted`       | Boolean | ✅      | ✅    | ✅    | Start video muted                            |
| `poster`      | String  | ✅      | ✅    | ✅    | Custom poster image URL                      |
| `background`  | Boolean | ✅      | ✅    | ✅    | Enable background video mode                 |
| `player-vars` | JSON    | ✅      | ✅    | ❌    | JSON object of extra player parameters       |
| `loop`        | Boolean | ❌      | ❌    | ✅    | Loop video (native video only)               |
| `preload`     | String  | ❌      | ❌    | ✅    | Preload strategy: "none", "metadata", "auto"
  lazy
  autoplay
  muted
  poster="custom-poster.jpg"
>
</vimeo-embed>
````

## 📖 API Reference

### Attributes (Both Components)

| Attribute     | Type    | Description                                  |
| ------------- | ------- | -------------------------------------------- |
| `url`         | String  | Full video URL                               |
| `video-id`    | String  | Video ID (YouTube: 11 chars, Vimeo: numeric) |
| `autoplay`    | Boolean | Auto-play video when loaded                  |
| `controls`    | Boolean | Show native player controls                  |
| `lazy`        | Boolean | Enable lazy loading with poster              |
| `muted`       | Boolean | Start video muted                            |
| `poster`      | String  | Custom poster image URL                      |
| `background`  | Boolean | Enable background video mode                 |
| `player-vars` | JSON    | JSON object of extra player parameters       |

### Methods

#### YouTube Embed

```javascript
const embed = document.querySelector("youtube-embed");

// Playback control (wraps YouTube IFrame API Player methods)
// Reference: https://developers.google.com/youtube/iframe_api_reference#Playback_controls
embed.play(); // ▶️ Play video (calls playVideo())
embed.pause(); // ⏸️ Pause video (calls pauseVideo())
embed.stopVideo(); // ⏹️ Stop video (calls stopVideo())
embed.togglePlay(); // ⏯️ Toggle play/pause

// Audio control
// Reference: https://developers.google.com/youtube/iframe_api_reference#Playback_volume
embed.mute(); // 🔇 Mute audio (calls mute())
embed.unmute(); // 🔊 Unmute audio (calls unMute())
embed.toggleMute(); // 🔇 Toggle mute
const isMuted = embed.isMuted(); // Check if muted (calls isMuted())

// Playback time control
// Reference: https://developers.google.com/youtube/iframe_api_reference#Playback_status
const currentTime = embed.getCurrentTime(); // Get current time in seconds (calls getCurrentTime())
embed.seekTo(30); // Seek to 30 seconds (calls seekTo())
embed.currentTime = 45; // Seek to 45 seconds using property setter

// Video management
embed.loadVideo("dQw4w9WgXcQ"); // Load by video ID
embed.loadVideo("https://youtu.be/dQw4w9WgXcQ"); // Load by URL

// State inspection
const state = embed.getPlayerState();
// Returns: { playing: boolean, muted: boolean, videoId: string, ready: boolean, initialized: boolean }

// Quality control (DEPRECATED as of October 2019 - YouTube controls quality automatically)
// Reference: https://developers.google.com/youtube/iframe_api_reference#Playback_quality
// WARNING: These methods are NO-OPS and have no effect on YouTube videos
const qualities = embed.getAvailableQualities(); // ⚠️ DEPRECATED - Returns empty array
const current = embed.getCurrentQuality(); // ⚠️ DEPRECATED - Returns "auto"
embed.setQuality("hd1080"); // ⚠️ DEPRECATED - Does nothing (no-op function)

// Fullscreen control
embed.enterFullscreen(); // Enter fullscreen mode
embed.exitFullscreen(); // Exit fullscreen mode
embed.toggleFullscreen(); // Toggle fullscreen
const isFs = embed.isFullscreen(); // Check fullscreen state

// Set extra player parameters
// Reference: https://developers.google.com/youtube/player_parameters
embed.playerVars = { loop: 1, playlist: "dQw4w9WgXcQ" };
```

**Passing Extra Parameters:**

You can pass additional parameters to the YouTube or Vimeo player using the `player-vars` attribute or `playerVars` property.

For YouTube, see the [YouTube Player Parameters Reference](https://developers.google.com/youtube/player_parameters) for all available options.

```html
<!-- YouTube: Loop a video -->
<youtube-embed
  video-id="dQw4w9WgXcQ"
  player-vars='{"loop": 1, "playlist": "dQw4w9WgXcQ"}'
></youtube-embed>

<!-- YouTube: Custom start time and quality -->
<youtube-embed
  video-id="dQw4w9WgXcQ"
  player-vars='{"start": 30, "end": 90, "quality": "hd720"}'
></youtube-embed>
```

```javascript
// Set via JavaScript
const embed = document.querySelector("youtube-embed");
embed.playerVars = {
  loop: 1,
  playlist: "dQw4w9WgXcQ", // Required for loop to work
  start: 10, // Start at 10 seconds
  modestbranding: 1, // Minimal YouTube branding
  rel: 0, // Don't show related videos
};
```

See [YouTube Player Parameters](https://developers.google.com/youtube/player_parameters) for all available options.

#### Vimeo Embed

```javascript
const embed = document.querySelector("vimeo-embed");

// Playback control
embed.play(); // ▶️ Play video
embed.pause(); // ⏸️ Pause video
embed.stopVideo(); // ⏹️ Stop video
embed.togglePlay(); // ⏯️ Toggle play/pause

// Audio control
embed.mute(); // 🔇 Mute audio
embed.unmute(); // 🔊 Unmute audio
embed.toggleMute(); // 🔇 Toggle mute

// Video management
embed.loadVideo("123456789"); // Load by video ID
embed.loadVideo("https://vimeo.com/123456789"); // Load by URL

// State inspection
const state = embed.getPlayerState();
// Returns: { playing: boolean, muted: boolean, videoId: string, ready: boolean, initialized: boolean }

// Async methods
const currentTime = await embed.getCurrentTime();
const isMuted = await embed.isMuted();

// Quality control (async)
const qualities = await embed.getAvailableQualities(); // Get available quality levels
const current = await embed.getCurrentQuality(); // Get current quality
await embed.setQuality("720p"); // Set quality to 720p

// Fullscreen control
await embed.enterFullscreen(); // Enter fullscreen mode
await embed.exitFullscreen(); // Exit fullscreen mode
await embed.toggleFullscreen(); // Toggle fullscreen
const isFs = embed.isFullscreen(); // Check fullscreen state
```

**Passing Extra Parameters:**

You can pass additional parameters to the Vimeo player using the `player-vars` attribute or `playerVars` property:

````html
<!-- Vimeo: Loop a video -->
<vimeo-embed video-id="76979871" player-vars='{"loop": true}'></vimeo-embed>

<!-- Vimeo: Custom color and quality -->
<vimeo-embed
  video-id="76979871"
  player-vars='{"color": "ff0000", "quality": "720p"}'
></vimeo-embed>

<!-- Vimeo: Privacy and customization -->
<vimeo-embed
  video-id="76979871"
  player-vars='{"dnt": true, "title": false, "byline": false, "portrait": false}'
></vimeo-embed>
```# Video Embed (HTML5) All three components support the same event interface:
```javascript // Listen to player events (works for youtube-embed, vimeo-embed,
and video-embed) embed.addEventListener("ready", () => console.log("Player
ready")); embed.addEventListener("play", () => console.log("Playing"));
embed.addEventListener("pause", () => console.log("Paused"));
embed.addEventListener("ended", () => console.log("Video ended"));
embed.addEventListener("error", (e) => console.error("Error:", e.detail));
embed.addEventListener("qualitychange", (e) => { console.log( "Quality
changed:", e.detail.oldQuality, "→", e.detail.newQuality, );
console.log("Available qualities:", e.detail.availableQualities); });
````

**Supported Events:**

- `ready` - Player initialized and ready to use (wraps YouTube's [`onReady`](https://developers.google.com/youtube/iframe_api_reference#onReady))
- `play` - Video playback started (wraps YouTube's [`onStateChange`](https://developers.google.com/youtube/iframe_api_reference#onStateChange) with state `YT.PlayerState.PLAYING`)
- `pause` - Video playback paused (wraps `onStateChange` with state `YT.PlayerState.PAUSED`)
- `stop` - Video playback stopped
- `ended` - Video playback finished (wraps `onStateChange` with state `YT.PlayerState.ENDED`)
- `error` - An error occurred (wraps YouTube's [`onError`](https://developers.google.com/youtube/iframe_api_reference#onError), check `event.detail` for details)
- `timeupdate` - Current time position updated
- `qualitychange` - Video quality level changed (wraps YouTube's [`onPlaybackQualityChange`](https://developers.google.com/youtube/iframe_api_reference#onPlaybackQualityChange))
- `loadstart` - Video loading started (native video)
- `connected` - Component connected to DOM
- `disconnected` - Component disconnected from DOMst state = embed.getPlayerState();
  // Returns: { playing: boolean, muted: boolean, videoId: string, ready: boolean, initialized: boolean }

const currentTime = embed.getCurrentTime();
const isMuted = embed.isMuted();

// Native video attributes
embed.loop = true; // Enable looping
embed.preload = "metadata"; // Set preload strategy

````

**Native HTML5 Video Attributes:**

```html
<!-- HTML5-specific attributes -->
<video-embed
  url="video.mp4"
  loop
  preload="metadata"
  controls
  poster="thumb.jpg"
>
</video-embed>
````

###

```javascript
// Set via JavaScript
const embed = document.querySelector("vimeo-embed");
embed.playerVars = {
  loop: true, // Enable looping
  color: "00adef", // Custom player color (hex without #)
  title: false, // Hide video title
  byline: false, // Hide author
  portrait: false, // Hide author portrait
  dnt: true, // Do Not Track
};
```

See [Vimeo Embed Options](https://developer.vimeo.com/player/sdk/embed) for all available options.

### Events

Both components support the same event interface:

```javascript
// Listen to player events
embed.addEventListener("ready", () => console.log("Player ready"));
embed.addEventListener("play", () => console.log("Playing"));
embed.addEventListener("pause", () => console.log("Paused"));
embed.addEventListener("ended", () => console.log("Video ended"));
embed.addEventListener("error", (e) => console.error("Error:", e.detail));
embed.addEventListener("qualitychange", (e) => {
  console.log(
    "Quality changed:",
    e.detail.oldQuality,
    "→",
    e.detail.newQuality,
  );
  console.log("Available qualities:", e.detail.availableQualities);
});
```

### Video Quality

Both components support programmatic quality control and emit events when quality changes.

**⚠️ IMPORTANT: YouTube Quality APIs Deprecated (October 2019)**

YouTube deprecated manual quality control methods as of October 24, 2019. The quality methods for YouTube (`getAvailableQualities()`, `getCurrentQuality()`, `setQuality()`) are **no-op functions** that have no effect. YouTube now automatically adjusts quality based on network conditions. See the [YouTube Help Center](https://support.google.com/youtube/answer/91449) for details.

**Use Vimeo or HTML5 Video if you need manual quality control.**

#### YouTube Quality Levels (Reference Only - APIs Deprecated)

| Quality Level | Resolution | Description         |
| ------------- | ---------- | ------------------- |
| `tiny`        | 144p       | Lowest quality      |
| `small`       | 240p       | Low quality         |
| `medium`      | 360p       | Medium quality      |
| `large`       | 480p       | Standard quality    |
| `hd720`       | 720p       | HD quality          |
| `hd1080`      | 1080p      | Full HD             |
| `hd1440`      | 1440p      | 2K quality          |
| `hd2160`      | 2160p      | 4K quality          |
| `highres`     | >1080p     | Highest available   |
| `auto`        | Auto       | Automatic selection |

#### Vimeo Quality Levels

| Quality Level | Resolution | Description         |
| ------------- | ---------- | ------------------- |
| `240p`        | 240p       | Low quality         |
| `360p`        | 360p       | Medium quality      |
| `540p`        | 540p       | Standard quality    |
| `720p`        | 720p       | HD quality          |
| `1080p`       | 1080p      | Full HD             |
| `2k`          | 1440p      | 2K quality          |
| `4k`          | 2160p      | 4K quality          |
| `auto`        | Auto       | Automatic selection |

#### Usage Examples

```html
<!-- Set initial quality via attribute -->
<!-- WARNING: YouTube quality attribute is ignored (APIs deprecated Oct 2019) -->
<youtube-embed video-id="dQw4w9WgXcQ" quality="hd1080"></youtube-embed>
<!-- Vimeo quality control works normally -->
<vimeo-embed video-id="76979871" quality="720p"></vimeo-embed>
```

```javascript
// YouTube quality control (DEPRECATED - These are no-op functions)
const ytEmbed = document.querySelector("youtube-embed");
const qualities = ytEmbed.getAvailableQualities(); // ⚠️ Returns empty array - DEPRECATED
const current = ytEmbed.getCurrentQuality(); // ⚠️ Returns "auto" - DEPRECATED
ytEmbed.setQuality("hd1080"); // ⚠️ Does nothing - DEPRECATED (no-op)

// Vimeo quality control (Works normally - async)
const vimeoEmbed = document.querySelector("vimeo-embed");
const qualities = await vimeoEmbed.getAvailableQualities(); // ["auto", "1080p", "720p", "540p"]
const current = await vimeoEmbed.getCurrentQuality(); // "720p"
await vimeoEmbed.setQuality("1080p"); // Switch to 1080p
```

#### Quality Change Event

```javascript
embed.addEventListener("qualitychange", (event) => {
  const { oldQuality, newQuality, availableQualities } = event.detail;
  console.log(`Quality changed from ${oldQuality} to ${newQuality}`);
  console.log(`Available: ${availableQualities.join(", ")}`);
});
```

**⚠️ CRITICAL: YouTube Quality Control APIs Are DEPRECATED (October 2019)**

As of **October 24, 2019**, YouTube deprecated all manual quality control functions. According to the [official documentation update](https://developers.google.com/youtube/iframe_api_reference#Revision_History):

**These methods are NO LONGER FUNCTIONAL:**

- [`getPlaybackQuality()`](https://developers.google.com/youtube/iframe_api_reference#getPlaybackQuality) - No longer returns accurate quality information
- [`setPlaybackQuality()`](https://developers.google.com/youtube/iframe_api_reference#setPlaybackQuality) - **No-op function** (does nothing)
- [`getAvailableQualityLevels()`](https://developers.google.com/youtube/iframe_api_reference#getAvailableQualityLevels) - No longer returns quality options

**Why these were deprecated:**
YouTube now automatically adjusts video quality based on viewing conditions (network bandwidth, device capabilities, viewport size) to provide the best viewing experience. Manual quality selection interferes with YouTube's adaptive streaming algorithms.

**What still works:**

- [`onPlaybackQualityChange`](https://developers.google.com/youtube/iframe_api_reference#onPlaybackQualityChange) event - Still fires when YouTube automatically changes quality
- The `qualitychange` event in this library still works and reports YouTube's automatic quality changes

**For developers:**
The quality methods (`getAvailableQualities()`, `getCurrentQuality()`, `setQuality()`) are kept in this library for API compatibility but **have no effect** on YouTube videos. They are maintained only to prevent breaking existing code. Use the Vimeo or native HTML5 video components if manual quality control is required.

**Official YouTube Help Article:**
[Why does YouTube adjust video quality?](https://support.google.com/youtube/answer/91449)

Vimeo's quality control is more reliable and respects quality changes consistently.

### Error Handling

Components include comprehensive error handling with automatic retry and user-friendly feedback:

#### Features

- **Automatic Retry**: API loads retry up to 3 times with 2-second delays
- **Timeout Protection**: 10-second timeout prevents indefinite waiting
- **Visual Feedback**: Error UI with descriptive messages and retry button
- **Event Notifications**: Detailed error events with codes and retry status

#### Error Event Details

```javascript
embed.addEventListener("error", (e) => {
  console.log(e.detail.message); // Human-readable error message
  console.log(e.detail.code); // Error code (e.g., "API_LOAD_ERROR")
  console.log(e.detail.retryable); // Whether error is retryable
});
```

#### Common Error Scenarios

| Error Type         | Cause                      | Solution                             |
| ------------------ | -------------------------- | ------------------------------------ |
| API Load Timeout   | Ad blocker or slow network | Disable ad blocker, check connection |
| Script Load Failed | Network issue or CORS      | Verify internet connection           |
| Video Not Found    | Invalid video ID           | Check video ID/URL                   |

| EmHTML5 Video Demos:\*\*

- `video-basic-demo.html` - Self-hosted video usage
- `video-lazy-loading-demo.html` - Native video lazy loading
- `video-background-demo.html` - Background video patterns
- **`platform-comparison-demo.html`** - Side-by-side platform comparison
- **`quality-control-demo.html`** - Quality selection and switching
- **`fullscreen-accessibility-demo.html`** - Fullscreen and accessibility featureso |

### Accessibility

Both components are fully accessible with keyboard navigation and screen reader support:

#### Keyboard Shortcuts

| Key               | Action                     |
| ----------------- | -------------------------- |
| `Tab`             | Focus player               |
| `Enter` / `Space` | Activate lazy-loaded video |
| `k` / `Space`     | Play/Pause video           |
| `m`               | Mute/Unmute                |
| `f`               | Toggle fullscreen          |

#### ARIA Support

- **ARIA Roles**: Components use `role="region"` with `aria-label="Video player"`
- **Live Regions**: Screen reader announcements for state changes (playing, paused, muted, etc.)
- **Button Labels**: Play buttons have descriptive `aria-label` attributes
- **Focus Management**: Proper `tabindex` and focus indicators
- **Keyboard Accessible**: All interactive elements support keyboard navigation

```html
<!-- Example: Accessible video embed -->
<youtube-embed
  url="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  controls
  aria-label="Product demo video"
  tabindex="0"
>
</youtube-embed>
```

### Properties

All attributes are accessible as JavaScript properties:

```javascript
embed.autoplay = true; // Enable autoplay
embed.muted = false; // Unmute video
embed.url = "https://..."; // Change video URL
console.log(embed.playing); // Get current playing state
```

## 🎯 Examples

Comprehensive examples are available in the `examples/` directory:

- **`examples/index.html`** - Overview and navigation to all demos
- **YouTube Demos:**
  - `youtube-basic-demo.html` - Basic usage patterns and modal integration
  - `youtube-lazy-loading-demo.html` - Performance optimization techniques
  - `youtube-background-demo.html` - Background video integration
- **Vimeo Demos:**
  - `vimeo-basic-demo.html` - Comprehensive Vimeo features
  - `vimeo-lazy-loading-demo.html` - Performance-focused lazy loading
  - `vimeo-background-demo.html` - Full-screen background videos
  - `vimeo-demo.html` - Original Vimeo integration demo
- **`platform-comparison-demo.html`** - Side-by-side platform comparison

### Running Examples

1. Build the component: `npm run build`
2. Open `examples/index.html` in your browser
3. Explore different usage patterns and features

## 🧪 Testing

This component includes a comprehensive automated test suite to ensure reliability, performance, and correct functionality.

### Running Tests

1. **Quick Access**: Visit `test/index.html` in your browser
2. **From Examples**: Navigate to the test suite from `examples/index.html`
3. **Direct URL**: `http://localhost:8000/test/` (when serving locally)

### Test Categories

#### 🔧 **Unit Tests** (20+ tests)

- Component creation and initialization
- Attribute parsing and validation
- Video ID extraction from various URL formats
- Method availability and error handling
- DOM structure verification

#### ⏳ **Lazy Loading Tests** (15+ tests)

- Poster image display and interaction
- Deferred iframe creation
- Click-to-load functionality
- Performance benefit verification
- Resource optimization testing

#### ▶️ **Player State Tests** (12+ tests)

- Play/pause/stop operations
- State transitions and reporting
- Mute/unmute functionality
- Custom vs native controls
- Error recovery mechanisms

#### 🔗 **Integration Tests** (10+ tests)

- YouTube/Vimeo iframe API loading
- Real player initialization and events
- Cross-origin and security features
- Browser compatibility verification
- Multiple instance handling

#### ⚡ **Performance Tests** (10+ tests)

- Initialization speed benchmarks (< 200ms target)
- Memory leak detection
- Resource build:cache-bust`| Update cache-busting params    | Updates query strings in files  |
|`npm run test:build`    | Build + ready message            | One-command test preparation    |
|`npm run test:validate` | Build + comprehensive check      | Full environment validation     |
|`npm run watch`         | Watch mode (TypeScript + SCSS)   | Auto-rebuild during development |
|`npm run examples` | Build + examples ready | Prepare examples for viewing |

#### Build Scripts

The project includes helper scripts in the `scripts/` directory:

- **`verify-build.js`** - Validates that all required build outputs exist and are valid
  - Checks for compiled JS files (index.js, youtube-only.js, vimeo-only.js, video-only.js)
  - Verifies CSS compilation (main.css, components.css)
  - Ensures test files are accessible
  - Automatically run as part of `npm run build`

- **`update-cache-busters.js`** - Updates cache-busting query parameters in built files
  - Appends version-based timestamps to asset references
  - Ensures browsers load fresh assets after updates
  - Automatically run as part of `npm run build`

### Test Framework Features

- **Visual Progress Tracking** - Real-time progress bars and statistics
- **Console Capture** - All logs displayed in beautiful interface
- **Test Filtering** - Run specific suites or filter by pass/fail
- **Results Export** - Download detailed JSON reports
- **Performance Monitoring** - Automatic timing and memory tracking

### Example Test Usage

```javascript
// Run all tests
runAllTests();

// Run specific test suites
runTestSuite("unit"); // Unit tests only
runTestSuite("lazy"); // Lazy loading tests
runTestSuite("integration"); // Integration tests
runTestSuite("performance"); // Performance tests
```

### Test Results Interpretation

- **90%+ Success Rate** - Excellent, production ready
- **70-89% Success Rate** - Good, minor issues may exist
- **< 70% Success Rate** - Issues need investigation

Common test failures in browser environments:

- YouTube/Vimeo API loading delays
- Network connectivity issues
- Browser security restrictions
- Timing-sensitive operations

## ⚡ Performance Benefits

### Lazy Loading

- **Faster initial page loads** - Videos load on-demand
- **Reduced bandwidth** - Only loads when user wants to watch
- **Better Core Web Vitals** - Improved LCP scores
- **Mobile optimization** - Data usage conscious

### Event-Driven Architecture

- **Efficient updates** - React to state changes without polling
- **Better UX** - Responsive to user interactions
- **Easy integration** - Standard event listeners

## 🛠️ Development

### Build Process

#### Available Build Scripts

| Script                   | Purpose                          | Usage                           |
| ------------------------ | -------------------------------- | ------------------------------- |
| `npm run build`          | Full clean build with validation | Always run before testing       |
| `npm run build:clean`    | Clean dist directory             | Removes old build artifacts     |
| `npm run build:ts`       | Compile TypeScript only          | Quick TypeScript updates        |
| `npm run build:css`      | Compile SCSS only                | Quick style updates             |
| `npm run build:validate` | Verify build integrity           | Checks all required files       |
| `npm run test:build`     | Build + ready message            | One-command test preparation    |
| `npm run test:validate`  | Build + comprehensive check      | Full environment validation     |
| `npm run watch`          | Watch mode (TypeScript + SCSS)   | Auto-rebuild during development |
| `npm run examples`       | Build + examples ready           | Prepare examples for viewing    |

#### Quick Start

```bash
# Initial setup (one time)
npm install

# Development workflow (recommended)
npm run watch              # Auto-rebuild on changes

# OR manual builds
npm run build             # Full clean build
npm run test:validate     # Build + validate everything
```

#### Build Validation

The build process includes automatic validation that checks:

- ✅ **TypeScript compilation** - `dist/index.js` and component files
- ✅ **SCSS compilation** - `dist/css/main.css` with proper styling
- ✅ **Test file integrity** - All test files present and accessible
- ✅ **Documentation** - README and guides are available

### Testing Workflow

#### Quick Testing Guide

1. **Build the component** (required):

   ```bash
   npm run build
   ```

2. **Start watch mode** (recommended for development):

   ```bash
   npm run watch
   ```

3. **Open the test suite**:
   - Navigate to `test/index.html` in your browser
   - Or serve via local server: `python -m http.server 8000`
   - Visit: `http://localhost:8000/test/`

#### Development Workflow with Tests

When using `npm run watch`, the system will:

- ✅ Automatically compile TypeScript changes to JavaScript
- ✅ Automatically compile SCSS changes to CSS
- ✅ Keep compiled files up to date

**Workflow:**

1. Start watch mode: `npm run watch`
2. Make changes to TypeScript or SCSS files
3. Refresh the test page to see updates
4. Tests automatically use latest compiled code

#### Test Features

- ✅ **67+ comprehensive tests** across 5 categories (YouTube) + 5 categories (Vimeo)
- ✅ **Automatic component detection** and loading
- ✅ **Real-time console output** with colored messages
- ✅ **Progress tracking** and detailed statistics
- ✅ **JSON export** for results documentation
- ✅ **Individual test suite** execution
- ✅ **Component demo** integration

#### Troubleshooting Tests

**Component Not Loading:**

- Error: "Component not registered"
- Solution: Run `npm run build` or `npm run watch` first

**CORS Issues:**

- Error: Module loading fails
- Solution: Serve files via HTTP server instead of file:// protocol

**Outdated Tests:**

- Error: Tests show old behavior
- Solution: Ensure watch mode is running or rebuild manually

For detailed testing documentation, see `test/README.md`.

## 🌐 Browser Support

- Modern browsers with Web Components support
- ES6+ JavaScript features
- YouTube IFrame API integration ([API Reference](https://developers.google.com/youtube/iframe_api_reference))
- Vimeo Player API integration ([API Reference](https://developer.vimeo.com/player/sdk/reference))

### YouTube IFrame API Integration

The `<youtube-embed>` component wraps the [YouTube IFrame Player API](https://developers.google.com/youtube/iframe_api_reference) to provide a consistent, web-component-based interface.

**API Loading:**

- Dynamically loads `https://www.youtube.com/iframe_api`
- Implements retry mechanism (up to 3 attempts) for reliability
- Handles API initialization via `onYouTubeIframeAPIReady` callback
- 10-second timeout protection against blocked scripts

**Player Methods Used:**

- [`playVideo()`](https://developers.google.com/youtube/iframe_api_reference#playVideo) - Start video playback ✅
- [`pauseVideo()`](https://developers.google.com/youtube/iframe_api_reference#pauseVideo) - Pause video playback ✅
- [`stopVideo()`](https://developers.google.com/youtube/iframe_api_reference#stopVideo) - Stop video and reset ✅
- [`seekTo(seconds, allowSeekAhead)`](https://developers.google.com/youtube/iframe_api_reference#seekTo) - Seek to specific time ✅
- [`mute()`](https://developers.google.com/youtube/iframe_api_reference#mute) - Mute the player ✅
- [`unMute()`](https://developers.google.com/youtube/iframe_api_reference#unMute) - Unmute the player ✅
- [`isMuted()`](https://developers.google.com/youtube/iframe_api_reference#isMuted) - Check mute state ✅
- [`getCurrentTime()`](https://developers.google.com/youtube/iframe_api_reference#getCurrentTime) - Get current playback time ✅
- ~~[`getPlaybackQuality()`](https://developers.google.com/youtube/iframe_api_reference#getPlaybackQuality)~~ - ⚠️ **DEPRECATED Oct 2019** - No longer functional
- ~~[`setPlaybackQuality(suggestedQuality)`](https://developers.google.com/youtube/iframe_api_reference#setPlaybackQuality)~~ - ⚠️ **DEPRECATED Oct 2019** - No-op function
- ~~[`getAvailableQualityLevels()`](https://developers.google.com/youtube/iframe_api_reference#getAvailableQualityLevels)~~ - ⚠️ **DEPRECATED Oct 2019** - No longer returns data

**Event Handlers:**

- [`onReady`](https://developers.google.com/youtube/iframe_api_reference#onReady) - Player is ready
- [`onStateChange`](https://developers.google.com/youtube/iframe_api_reference#onStateChange) - Player state changed (playing, paused, ended, etc.)
- [`onPlaybackQualityChange`](https://developers.google.com/youtube/iframe_api_reference#onPlaybackQualityChange) - Quality level changed
- [`onError`](https://developers.google.com/youtube/iframe_api_reference#onError) - Error occurred

**Player Parameters:**
Supports all [YouTube Player Parameters](https://developers.google.com/youtube/player_parameters) via the `player-vars` attribute, including `autoplay`, `loop`, `controls`, `modestbranding`, `rel`, `showinfo`, and more.

## 📝 Migration Guide

### From Standard iframes to Web Components

Migrating from traditional iframe embeds is straightforward:

#### Before (Standard iframe):

```html
<iframe
  width="560"
  height="315"
  src="https://www.youtube.com/embed/dQw4w9WgXcQ"
  frameborder="0"
  allow="autoplay; encrypted-media"
  allowfullscreen
></iframe>
```

#### After (Web Component):

```html
<youtube-embed video-id="dQw4w9WgXcQ" controls></youtube-embed>
```

**Benefits of Migration:**

- ✅ Lazy loading support (faster page loads)
- ✅ Programmatic control (play, pause, mute, etc.)
- ✅ Event handling (ready, play, pause, ended, error)
- ✅ Quality control (set preferred video quality)
- ✅ Fullscreen API (enter/exit fullscreen programmatically)
- ✅ Accessibility features (keyboard shortcuts, ARIA support)
- ✅ Error handling with retry mechanism
- ✅ Responsive by default

### From Previous Versions

- `pause()` now pauses instead of stopping (use `stopVideo()` to stop)
- Boolean attributes work correctly (presence = true, absence = false)
- Event-based architecture replaces callbacks
- `video-id` attribute supported alongside `url`

### Event Migration

```javascript
// Old approach
embed.onReady = () => {
  /* ... */
};

// New approach
embed.addEventListener("ready", () => {
  /* ... */
});
```

## 🔧 Troubleshooting

### Common Issues and Solutions

#### Video Not Loading

**Problem**: Video doesn't load or shows error message

**Solutions**:

1. **Check Video ID**: Ensure the video ID is correct and publicly accessible
2. **Disable Ad Blockers**: Some ad blockers prevent video APIs from loading
3. **Check Network**: Verify internet connection and firewall settings
4. **CORS Issues**: Ensure your domain is allowed (usually not an issue with official APIs)

```javascript
// Listen for error events
embed.addEventListener("error", (e) => {
  console.log("Error details:", e.detail);
  // e.detail.message - Human-readable error
  // e.detail.code - Error code (e.g., "API_LOAD_ERROR")
  // e.detail.retryable - Whether automatic retry will occur
});
```

#### Autoplay Not Working

**Problem**: Video doesn't autoplay even with `autoplay` attribute

**Solutions**:

1. **Add `muted` attribute**: Most browsers require videos to be muted for autoplay
2. **User Interaction**: Some browsers require user interaction before autoplay

```html
<!-- Correct autoplay setup -->
<youtube-embed video-id="VIDEO_ID" autoplay muted></youtube-embed>
```

#### Lazy Loading Not Triggering

**Problem**: Video doesn't load when scrolled into view

**Solutions**:

1. **Check `lazy` attribute**: Ensure the `lazy` attribute is present
2. **Viewport Visibility**: Element must be within viewport threshold (50px)
3. **Browser Support**: Ensure browser supports Intersection Observer API

```javascript
// Debug lazy loading
const embed = document.querySelector("youtube-embed");
console.log("Lazy enabled:", embed.hasAttribute("lazy"));
console.log(
  "In viewport:",
  embed.getBoundingClientRect().top < window.innerHeight,
);
```

#### Keyboard Shortcuts Not Working

**Problem**: Pressing 'k', 'm', or 'f' doesn't control the video

**Solutions**:

1. **Focus Element**: Click on the video component to focus it first
2. **Check Conflicts**: Ensure no other scripts are intercepting keyboard events
3. **Browser Compatibility**: Some browsers may restrict keyboard events

**Available Shortcuts**:

- `k` - Play/Pause toggle
- `m` - Mute/Unmute toggle
- `f` - Fullscreen toggle

#### Quality Selection Issues

**Problem**: Cannot change video quality or quality selector shows no options

**Solutions**:

1. **Wait for Ready Event**: Quality info only available after player is ready
2. **Video Support**: Not all videos have multiple quality levels
3. **API Limitations**: Platform APIs may not expose all quality levels immediately

```javascript
embed.addEventListener("ready", async () => {
  // For YouTube
  const qualities = embed.getAvailableQualities();
  console.log("Available:", qualities);

  // For Vimeo (async)
  const qualities = await embed.getAvailableQualities();
  console.log("Available:", qualities);
});
```

## 🌐 Browser Compatibility

### Minimum Requirements

| Feature                   | Chrome | Firefox | Safari | Edge |
| ------------------------- | ------ | ------- | ------ | ---- |
| **Web Components**        | 67+    | 63+     | 10.1+  | 79+  |
| **Custom Elements**       | 67+    | 63+     | 10.1+  | 79+  |
| **Shadow DOM**            | 53+    | 63+     | 10.1+  | 79+  |
| **ES6 Modules**           | 61+    | 60+     | 10.1+  | 79+  |
| **Intersection Observer** | 58+    | 55+     | 12.1+  | 79+  |
| **Fullscreen API**        | 71+    | 64+     | 5.1+   | 79+  |

### Feature Support

| Feature            | Support            | Polyfill Available | Notes                                 |
| ------------------ | ------------------ | ------------------ | ------------------------------------- |
| Lazy Loading       | Modern Browsers    | ✅                 | Falls back to immediate load          |
| Keyboard Shortcuts | All Browsers       | N/A                | Browser-dependent focus behavior      |
| Fullscreen API     | Modern Browsers    | ❌                 | Vendor prefixes handled automatically |
| Quality Control    | Platform-dependent | N/A                | Depends on YouTube/Vimeo API support  |
| ARIA Support       | All Browsers       | N/A                | Screen reader compatibility           |

### Polyfills

For older browser support, include these polyfills:

```html
<!-- Web Components Polyfills -->
<script src="https://unpkg.com/@webcomponents/webcomponentsjs@2.8.0/webcomponents-loader.js"></script>

<!-- Intersection Observer Polyfill -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver"></script>
```

## 💡 Advanced Usage Examples

### Playlist Implementation

```html
<div id="playlist-container"></div>

<script type="module">
  const videos = ["dQw4w9WgXcQ", "ScMzIvxBSi4", "M7lc1UVf-VE"];

  let currentIndex = 0;
  const container = document.getElementById("playlist-container");

  function loadVideo(index) {
    container.innerHTML = "";
    const embed = document.createElement("youtube-embed");
    embed.setAttribute("video-id", videos[index]);
    embed.setAttribute("autoplay", "");

    embed.addEventListener("ended", () => {
      currentIndex = (currentIndex + 1) % videos.length;
      loadVideo(currentIndex);
    });

    container.appendChild(embed);
  }

  loadVideo(0);
</script>
```

### Custom Styling

```html
<style>
  youtube-embed {
    --embed-border-radius: 16px;
    --embed-max-width: 800px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  }

  youtube-embed::part(container) {
    border-radius: var(--embed-border-radius);
  }
</style>

<youtube-embed video-id="dQw4w9WgXcQ" controls></youtube-embed>
```

### Dynamic Quality Selection

```html
<youtube-embed id="player" video-id="dQw4w9WgXcQ"></youtube-embed>

<select id="quality-selector">
  <option value="auto">Auto</option>
</select>

<script type="module">
  const player = document.getElementById("player");
  const selector = document.getElementById("quality-selector");

  player.addEventListener("ready", () => {
    const qualities = player.getAvailableQualities();

    // Populate selector
    qualities.forEach((quality) => {
      if (quality !== "auto") {
        const option = document.createElement("option");
        option.value = quality;
        option.textContent = quality.toUpperCase();
        selector.appendChild(option);
      }
    });
  });

  selector.addEventListener("change", (e) => {
    player.setQuality(e.target.value);
  });

  player.addEventListener("qualitychange", (e) => {
    console.log(
      `Quality changed: ${e.detail.oldQuality} → ${e.detail.newQuality}`,
    );
  });
</script>
```

### Event Logger

```html
<youtube-embed id="player" video-id="dQw4w9WgXcQ"></youtube-embed>
<div id="event-log"></div>

<script type="module">
  const player = document.getElementById("player");
  const log = document.getElementById("event-log");

  const events = [
    "ready",
    "play",
    "pause",
    "ended",
    "error",
    "timeupdate",
    "qualitychange",
  ];

  events.forEach((eventName) => {
    player.addEventListener(eventName, (e) => {
      const entry = document.createElement("div");
      entry.textContent = `${new Date().toLocaleTimeString()} - ${eventName}: ${JSON.stringify(
        e.detail || {},
      )}`;
      log.prepend(entry);
    });
  });
</script>
```

### Responsive Aspect Ratio

```html
<style>
  .video-wrapper {
    position: relative;
    width: 100%;
    padding-bottom: 56.25%; /* 16:9 aspect ratio */
  }

  .video-wrapper youtube-embed {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
</style>

<div class="video-wrapper">
  <youtube-embed video-id="dQw4w9WgXcQ" controls></youtube-embed>
</div>
```

## 📦 Build & Distribution

### Development Build

```bash
# Standard build (unminified for debugging)
npm run build

# Watch mode for development
npm run dev

# Validate build integrity
npm run build:validate
```

### Production Build

```bash
# Production build with minification (~50% size reduction)
npm run build:prod
```

This creates optimized `.min.js` and `.min.css` files with:

- **Terser** minification for JavaScript (removes whitespace, shortens variable names)
- **CSSO** opt (all three components)
  import "@smartimpact-it/modern-video-embed";

// YouTube only
import "@smartimpact-it/modern-video-embed/dist/youtube-only.js";

// Vimeo only
import "@smartimpact-it/modern-video-embed/dist/vimeo-only.js";

// Native video only
import "@smartimpact-it/modern-video-embed/dist/vidKB)
├── index.min.js # Full bundle minified (29KB) ⭐ Production
├── youtube-only.js # YouTube bundle (29KB)
├── youtube-only.min.js # YouTube minified (15KB) ⭐ Production
├── vimeo-only.js # Vimeo bundle (29KB)
├── vimeo-only.min.js # Vimeo minified (14KB) ⭐ Production
├── components/
│ ├── YouTubeEmbed.js # YouTube component (58KB)
│ ├── YouTubeEmbed.min.js # YouTube minified (29KB)
│ ├── VimeoEmbed.js # Vimeo component (49KB)
│ └── VimeoEmbed.min.js # Vimeo minified (27KB)
├── css/
│ ├── components.css # Core styles (9KB)
│ ├── components.min.css # Core minified (7KB) ⭐ Production
│ ├── main.css # With Bootstrap (276KB)
│ └── main.min.css # Bootstrap minified (224KB)
└── types/ # TypeScript declarations

````

### Performance Optimization

**Bundle Size Comparison:**

| Configuration        | Size (Dev) | Size (Prod) | With gzip\* |
| -------------------- | ---------- | ----------- | ----------- |
We welcome contributions! Here's how to get started:

1. **Read the docs**: Check [`.ai-instructions.md`](.ai-instructions.md) for development guidelines
2. **Fork the repository**: Create your own fork on GitHub
3. **Create a feature branch**: `git checkout -b feature/your-feature-name`
4. **Make your changes**: Follow TypeScript strict mode and existing patterns
5. **Build and test**: Run `npm run build` and test with `test/index.html`
6. **Update documentation**: Update README and type definitions if needed
7. **Submit a pull request**: Include a clear description of changes

**Development Checklist:**
- ✅ Code follows existing patterns and conventions
- ✅ TypeScript compiles without errors (strict mode)
- ✅ All tests pass in `test/index.html`
- ✅ Type definitions updated if API changed
- ✅ README updated for user-facing changes
- ✅ Examples added/updated if needed
\*Estimated with gzip compression enabled on server

**Optimization Tips:**

1. ✅ **Use minified files** (`.min.js` / `.min.css`) in production - saves ~50%
2. ✅ **Choose platform-specific bundles** when possible - saves ~50%
3. ✅ **Use core CSS** instead of Bootstrap - saves ~97%
4. ✅ **Enable gzip/brotli** on your server - saves additional ~70%
5. ✅ **Lazy loading is built-in** - videos only load when visible

**Best Configuration for Production:**

```html
<!-- YouTube only: 22KB total (7KB gzipped) -->
<script type="module" src="dist/youtube-only.min.js"></script>
<link rel="stylesheet" href="dist/css/components.min.css" />
````

### Bundle Sizes

| File              | Uncompressed | Gzipped | Description                      |
| ----------------- | ------------ | ------- | -------------------------------- |
| `index.js`        | 58KB         | ~15KB   | Full bundle with both components |
| `youtube-only.js` | 29KB         | ~8KB    | YouTube component only           |
| `vimeo-only.js`   | 29KB         | ~8KB    | Vimeo component only             |
| `components.css`  | 15KB         | ~3KB    | Core component styles            |
| `main.css`        | 276KB        | ~35KB   | Full styles with Bootstrap       |

### Publishing to NPM

```bash
# Update version in package.json
npm version patch|minor|major

# Build and publish
npm publish
```

### Using in Your Project

#### ES Modules

```javascript
// Full bundle
import "@smartimpact-it/modern-video-embed";

// YouTube only
import "@smartimpact-it/modern-video-embed/dist/youtube-only.js";

// Vimeo only
import "@smartimpact-it/modern-video-embed/dist/vimeo-only.js";
```

#### With Bundlers (Webpack, Vite, etc.)

```javascript
// Install
npm install @smartimpact-it/modern-video-embed

// Import in your app
import '@smartimpact-it/modern-video-embed';
import '@smartimpact-it/modern-video-embed/dist/css/components.css';

// Use in your HTML/JSX
<youtube-embed video-id="dQw4w9WgXcQ" controls></youtube-embed>
```

#### TypeScript Support

```typescript
import { YouTubeEmbed } from "@smartimpact-it/modern-video-embed";

const embed = document.querySelector("youtube-embed") as YouTubeEmbed;
embed.play();
```

## 🤝 Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Test with the examples
5. Submit a pull request

## 📄 License

This project is open source. See the LICENSE file for details.

---

**Built with vanilla JavaScript • Web Components • TypeScript ready**