floating-ad-player-sdk-stupa
v1.0.0
Published
Framework-agnostic floating ad video player SDK
Maintainers
Readme
Floating Ad Player SDK
Lightweight, framework-agnostic ad video SDK that renders a floating mini-player via a single script import and exposes a clean event API.
1) Architecture Design
The SDK uses a layered architecture to stay small and extensible:
SDKFacade(src/index.ts): public API surface (init,on,off,close,destroy).FloatingAdPlayer(src/player.ts): orchestration layer for lifecycle, autoplay handling, timer, delayed close button, and cleanup.EventBus(src/events.ts): decoupled typed event system for ad telemetry hooks.UI Factory(src/ui.ts): Shadow DOM-based renderer to avoid CSS collision with host applications.types+constants: strict contracts and defaults.
This separation allows future extensions (ad queue, remote config, analytics plugins) without breaking the public interface.
2) Folder Structure
add-SDK/
src/
constants.ts
events.ts
index.ts
player.ts
types.ts
ui.ts
dist/ # generated after build
package.json
tsconfig.json
vite.config.ts3) Core Implementation Highlights
AdSDK.init({...})creates isolated floating player in Shadow DOM.- Auto-play strategy retries with muted mode if browser blocks first attempt.
- Close button appears only after
crossButtonDelay. - Timer overlay supports elapsed or remaining mode.
- Events:
impression,play,pause,ended,close,error,timeupdate. destroy()removes DOM + event listeners + timers to prevent leaks.
Public API
AdSDK.init({
videoUrl: "https://cdn.example.com/ad.mp4",
position: "bottom-right",
width: 320,
height: 180,
autoPlay: true,
loop: true,
mute: true,
crossButtonDelay: 5,
showTimer: true,
timerMode: "remaining",
containerZIndex: 2147483000,
onClose: () => console.log("Ad closed")
});
const unsubscribe = AdSDK.on("play", ({ currentTime }) => {
console.log("play", currentTime);
});
// Later:
unsubscribe();
AdSDK.destroy();4) Angular Integration Snippet
Use script import in index.html:
<script src="assets/ad-sdk.umd.js"></script>Then consume in Angular component:
import { Component, OnDestroy, OnInit } from "@angular/core";
declare global {
interface Window {
AdSDK: {
init: (options: {
videoUrl: string;
position: "bottom-right" | "bottom-left" | "top-right" | "top-left";
width?: number;
height?: number;
autoPlay?: boolean;
loop?: boolean;
mute?: boolean;
crossButtonDelay?: number;
showTimer?: boolean;
timerMode?: "elapsed" | "remaining";
containerZIndex?: number;
onClose?: () => void;
}) => void;
on: (event: string, cb: (payload: unknown) => void) => () => void;
destroy: () => void;
};
}
}
@Component({
selector: "app-ad-demo",
standalone: true,
template: `<p>Ad SDK initialized</p>`
})
export class AdDemoComponent implements OnInit, OnDestroy {
private offPlay?: () => void;
private offError?: () => void;
ngOnInit(): void {
window.AdSDK.init({
videoUrl: "https://cdn.example.com/ad.mp4",
position: "bottom-right",
autoPlay: true,
loop: true,
mute: true,
crossButtonDelay: 5,
showTimer: true
});
this.offPlay = window.AdSDK.on("play", (payload) => {
console.log("Ad playing", payload);
});
this.offError = window.AdSDK.on("error", (payload) => {
console.error("Ad error", payload);
});
}
ngOnDestroy(): void {
this.offPlay?.();
this.offError?.();
window.AdSDK.destroy();
}
}5) Performance Optimization Strategy
- Keep UI isolated in a single Shadow DOM root.
- Minimize reflow by creating and appending DOM once.
- Use native
videoevents (no polling loops). - Avoid framework runtime dependencies and keep bundle small.
- Deterministic cleanup on
destroy()to avoid detached nodes/listeners.
6) Edge Cases Handling
- Autoplay blocked: fallback to forced muted replay, then emit
errorif still blocked. - Video load/network failure: emit typed
errorevent with media error code. - Mobile playback restrictions: set
playsinlineandwebkit-playsinline. - Host CSS collisions: prevented through Shadow DOM encapsulation.
- Memory leaks: all timers/listeners tracked and disposed during close/destroy.
Build
npm install
npm run buildPublish to NPM
npm login
npm publish --access publicIf the package name is unavailable, change name in package.json (recommended: scoped name like @your-org/floating-ad-player-sdk) and publish again.
Angular Demo (Local)
An example Angular integration project exists in angular-sdk-demo/.
Run it:
cd angular-sdk-demo
npm install
npm start -- --host 127.0.0.1 --port 4201