Getting started

Two ways to use Playerstack: drop the standalone bundle on a page (easy), or compose it from scoped packages (smaller bundle, more control).

One script tag, all 13 plugins included.

<!doctype html>
<html>
  <head>
    <script
      src="https://playerstack.techskills.academy/playerstack.min.js"
      defer
    ></script>
  </head>
  <body>
    <player-stack src="https://youtu.be/dQw4w9WgXcQ"></player-stack>
  </body>
</html>

The <player-stack> custom element registers itself, the sources plugin validates the URL, and the core element picks the right inner media element (native <video> for MP4/WebM, <youtube-video>, <vimeo-video>, or <hls-video>) and mounts a default <media-controller> UI. You can configure plugins via data-config JSON or shorthand attributes.

The bundle above is served free from this site’s Cloudflare Pages CDN.

Self-host the bundle

Prefer to serve it from your own domain (no third-party request)? Download playerstack.min.js, drop it next to your HTML, and point the script tag at your own path:

<script src="/js/playerstack.min.js" defer></script>

It is MIT-licensed, so you can host and redistribute it freely.

Option 2: scoped packages

Use this when you want a smaller bundle by including only the plugins you need.

The @playerstack/* packages are not published to npm yet. Until they are, use the standalone bundle above, or build from source (bun run --filter playerstack build).

npm install @playerstack/core @playerstack/plugin-sources @playerstack/plugin-cta-end
import { Playerstack } from "@playerstack/core";
import { sourcesPlugin } from "@playerstack/plugin-sources";
import { ctaEndPlugin } from "@playerstack/plugin-cta-end";

Playerstack.use(sourcesPlugin).use(ctaEndPlugin).define();

Now <player-stack> is registered with just two plugins instead of all 13.

Configuring a player

Two equivalent ways:

<!-- Shorthand attributes -->
<player-stack
  src="https://youtu.be/dQw4w9WgXcQ"
  poster="https://example.com/poster.webp"
  title="Demo"
>
</player-stack>

<!-- JSON config -->
<player-stack
  src="https://youtu.be/dQw4w9WgXcQ"
  data-config='{"poster":"https://example.com/poster.webp","title":"Demo"}'
>
</player-stack>

When both are present, data-config wins. Use shorthand for simple cases, JSON for plugin-specific options like controls, preview, brandedThumb, ctaEnd.

Next steps