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
aria-hidden)npm install video-ambient-glow
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()
new AmbientGlow(video, options?)Creates a glow behind a video element.
video β target HTMLVideoElement
options β optional configuration
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: 450
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.
}
glow.updateOptions({ blur: 120, opacity: 0.8 }) // Update settings
glow.destroy() // Remove glow + listeners
const glow = new AmbientGlow(document.querySelector('video'))
const glow = new AmbientGlow(video, {
blur: 120,
opacity: 0.8,
brightness: 1.3,
saturate: 1.5,
updateInterval: 500
})
glow.updateOptions({ opacity: 0.4, blur: 60 })
glow.updateOptions({ opacity: 0.9, blur: 150, saturate: 2.0 })
import { useEffect, useRef } from 'react'
import { AmbientGlow } from 'video-ambient-glow'
export function VideoPlayer({ src }: { src: string }) {
const ref = useRef<HTMLVideoElement>(null)
useEffect(() => {
if (!ref.current) return
const glow = new AmbientGlow(ref.current, { blur: 96, opacity: 0.65 })
return () => glow.destroy()
}, [])
return <video ref={ref} src={src} controls />
}
<script lang="ts">
import { onMount, onDestroy } from 'svelte'
import { AmbientGlow } from 'video-ambient-glow'
export let src: string
let videoElement: HTMLVideoElement
let glow: AmbientGlow | null = null
onMount(() => {
if (videoElement) {
glow = new AmbientGlow(videoElement, { blur: 96, opacity: 0.65 })
}
})
onDestroy(() => {
glow?.destroy()
})
</script>
<video bind:this={videoElement} {src} controls />
import {
Component,
ViewChild,
AfterViewInit,
OnDestroy,
Input,
ElementRef
} from '@angular/core'
import { AmbientGlow } from 'video-ambient-glow'
@Component({
selector: 'app-video-player',
template: '<video #video [src]="src" controls></video>'
})
export class VideoPlayerComponent implements AfterViewInit, OnDestroy {
@Input() src!: string
@ViewChild('video', { static: false })
videoElement!: ElementRef<HTMLVideoElement>
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()
}
}
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { AmbientGlow } from 'video-ambient-glow'
interface Props {
src: string
}
const props = defineProps<Props>()
const videoElement = ref<HTMLVideoElement | null>(null)
let glow: AmbientGlow | null = null
onMounted(() => {
if (videoElement.value) {
glow = new AmbientGlow(videoElement.value, { blur: 96, opacity: 0.65 })
}
})
onUnmounted(() => {
glow?.destroy()
})
</script>
<template>
<video ref="videoElement" :src="src" controls />
</template>
cd example
npm install
npm run dev
Then open http://localhost:5173
requestAnimationFrame at a throttled rate for performanceLow 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 definitionsModular, typed, and easy to extend.
downscale for faster performanceupdateInterval to save CPUresponsiveness for blending control (recommended). blendOld/blendNew are deprecated.| 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.
npm test
npm run test:watch