Lightweight library for adding YouTube-style ambient glow effects to HTML5 video elements
npm install video-ambient-glow


Inspired by YouTube's immersive glow, this tiny, zero-dependency library adds a smooth, color-reactive effect behind HTML5 videosβno thumbnails or spritesheets needed.
π¦ Install from npm
π¬ Live Example | Original on CodePen
- π¨ Extracts colors directly from the video
- π Smooth frame blending for natural transitions
- β‘ Small bundle size (~5.8KB minified, ~2.0KB gzipped)
- ποΈ Customizable blur, opacity, brightness, saturation
- π¦ Universal imports (ESM, CJS, UMD), auto-detects environment, tree-shakeable
- π Written in TypeScript with full types
- βΏ Accessible (canvas uses aria-hidden)
``bash`
npm install video-ambient-glow
The package automatically detects your environment and serves the optimal format:
#### ES Modules (Recommended)
`typescript`
import { AmbientGlow } from 'video-ambient-glow'
// TypeScript types included automatically
import type { GlowOptions } from 'video-ambient-glow'
#### CommonJS (Node.js)
`javascript`
const { AmbientGlow } = require('video-ambient-glow')
#### Script Tag / CDN
`html
`
#### Dynamic Import
`javascript`
const { AmbientGlow } = await import('video-ambient-glow')
> π‘ No configuration needed! Modern bundlers (Webpack 5+, Vite, Rollup, Parcel) automatically pick the best format based on your project setup.
`ts
import { AmbientGlow } from 'video-ambient-glow'
const video = document.querySelector('video')
const glow = new AmbientGlow(video, {
blur: 96,
opacity: 0.65,
brightness: 1.1,
saturate: 1.2
})
video.play()
// Cleanup
glow.destroy()
`
Creates a glow behind a video element.
video β target HTMLVideoElement
options β optional configuration
`ts`
interface GlowOptions {
blur?: number // default: 96
opacity?: number // 0β1, default: 0.65
brightness?: number // default: 1.1
saturate?: number // default: 1.2
scale?: number // canvas scale, default: 1.08
downscale?: number // sampling 0.01β0.5, default: 0.08
updateInterval?: number // in ms, default: 98
blendOld?: number // @deprecated Use responsiveness instead. Old frame weight, default: 0.85 (ignored if responsiveness is set)
blendNew?: number // @deprecated Use responsiveness instead. New frame weight, default: 0.15 (ignored if responsiveness is set)
responsiveness?: number // 0.0β1.0, simplified blending control, default: undefined. Higher = more responsive to changes. Overrides blendOld/blendNew when set.
}
`ts`
glow.updateOptions({ blur: 120, opacity: 0.8 }) // Update settings
glow.destroy() // Remove glow + listeners
`ts`
const glow = new AmbientGlow(document.querySelector('video'))
`ts`
const glow = new AmbientGlow(video, {
blur: 120,
opacity: 0.8,
brightness: 1.3,
saturate: 1.5,
updateInterval: 500
})
`ts`
glow.updateOptions({ opacity: 0.4, blur: 60 })
glow.updateOptions({ opacity: 0.9, blur: 150, saturate: 2.0 })
`tsx
import { useEffect, useRef } from 'react'
import { AmbientGlow } from 'video-ambient-glow'
export function VideoPlayer({ src }: { src: string }) {
const ref = useRef
useEffect(() => {
if (!ref.current) return
const glow = new AmbientGlow(ref.current, { blur: 96, opacity: 0.65 })
return () => glow.destroy()
}, [])
return
}
`
`svelte
`
`ts
import {
Component,
ViewChild,
AfterViewInit,
OnDestroy,
Input,
ElementRef
} from '@angular/core'
import { AmbientGlow } from 'video-ambient-glow'
@Component({
selector: 'app-video-player',
template: ''
})
export class VideoPlayerComponent implements AfterViewInit, OnDestroy {
@Input() src!: string
@ViewChild('video', { static: false })
videoElement!: ElementRef
private glow: AmbientGlow | null = null
ngAfterViewInit() {
if (this.videoElement?.nativeElement) {
this.glow = new AmbientGlow(this.videoElement.nativeElement, {
blur: 96,
opacity: 0.65
})
}
}
ngOnDestroy() {
this.glow?.destroy()
}
}
`
`vue
`
`bash`
cd example
npm install
npm run dev
Then open http://localhost:5173
1. Captures frames from the video (downscaled for speed)
2. Blends new and old frames for smooth transitions
3. Draws the result to a background canvas
4. Applies CSS filters (blur, brightness, saturation)
5. Uses requestAnimationFrame at a throttled rate for performance
Low update rates and small sampling keep it lightweight while still reactive.
- index.ts β Main classlib/
- β Internal modulescanvas.ts
- β Canvas creation and stylingframeProcessor.ts
- β Color extraction and blendingeventHandlers.ts
- β Safe event listenersconstants.ts
- β Default config valuestypes.ts
- β Type definitions
Modular, typed, and easy to extend.
- Lower downscale for faster performanceupdateInterval
- Increase to save CPUresponsiveness
- Use for blending control (recommended). blendOld/blendNew are deprecated.
- Auto-pauses when the video stops or scrolls out of view (uses IntersectionObserver)
| Script | Description |
| ----------------------- | ------------------------------------------ |
| npm run dev | Start development mode with watch (Rollup) |npm run build
| | Build the library for production |npm run build:example
| | Build library and example app |npm test
| | Run tests once |npm run test:watch
| | Run tests in watch mode |npm run lint
| | Format code and run ESLint |npm run format
| | Format code with Prettier |npm run format:check
| | Check code formatting without writing |
Uses Vitest + happy-dom.
`bash``
npm test
npm run test:watch