npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@norskvideo/norsk-player

v1.2.1

Published

A browser-native, frame-accurate video player custom element (<norsk-video>) for content served from a TAMS (Time-addressable Media Store).

Downloads

418

Readme

@norskvideo/norsk-player

A browser-native, frame-accurate video player for content served from a TAMS store.

norsk-player ships as a custom element<norsk-video> — that you drop into any web page. It decodes media in the browser with WebCodecs, lets you scrub and step through footage a single frame at a time, and reads media directly from a TAMS API rather than from a single monolithic file. It works with any framework, or none. A React wrapper is also available.

The player is designed for, and tested against, Norsk's TAMS implementation, but it targets the open TAMS API and works against any conforming store.


What is TAMS?

TAMSTime-addressable Media Store — is an open API, originally developed by the BBC, for storing and retrieving media as a timeline of segments rather than as fixed files. A client asks for a source, over a time range and the store returns the media objects that cover it. This makes it a natural fit for growing/live recordings, instant replay, and frame-accurate navigation of long-form content.

You do not need to understand the TAMS API to use this player — you point it at a URL and it does the rest. The TAMS client is also exported if you want to query the store yourself.


Installation

npm install @norskvideo/norsk-player

The package is an ES module. It bundles everything it needs, including Media Chrome for the player controls — no separate install required. You will typically consume it through a bundler such as Vite, Webpack, or Parcel.


New to web components?

A web component (custom element) is a reusable HTML tag backed by JavaScript, built into every modern browser — no framework needed. Importing this package registers the <norsk-video> tag (and the Media Chrome control elements) with the browser. After the import runs once, you can use those tags in your HTML just like <video> or <div>:

import '@norskvideo/norsk-player';
// <norsk-video> is now a valid element anywhere on the page.

<norsk-video> renders the video surface but no controls of its own — you pair it with a <media-controller> (from the bundled Media Chrome) to get a play button, scrubber, volume, fullscreen, and so on. The example below shows the whole thing wired up.


Get started

The quickest path is a Vite project.

1. Create a project and add the player

npm create vite@latest my-player -- --template vanilla
cd my-player
npm install @norskvideo/norsk-player

2. Replace main.js with:

import '@norskvideo/norsk-player';

3. Put the player in index.html, inside a Media Chrome controller:

<media-controller style="width: 100%; aspect-ratio: 16 / 9;">
  <norsk-video
    slot="media"
    src="http://localhost:8080/x-tams/"
    style="width: 100%; height: 100%;"
  ></norsk-video>

  <media-control-bar>
    <media-play-button></media-play-button>
    <media-time-range></media-time-range>
    <media-time-display show-duration></media-time-display>
    <media-mute-button></media-mute-button>
    <media-volume-range></media-volume-range>
    <media-fullscreen-button></media-fullscreen-button>
  </media-control-bar>
</media-controller>

4. Run it

npm run dev

Point src at your own TAMS store (see Configuration). With the default src above, the player plays the latest audio and video source the store knows about.

Frame stepping: press . / n to step forward one frame and , / p to step back (the React wrapper wires these keys up for you; in plain HTML, dispatch frame-next / frame-previous events at the element — see Programmatic control).


Configuration

The src URL

src points at a TAMS store, or at a plain MP4/fMP4 file. The player accepts several forms:

| src value | Plays | | --- | --- | | https://host/x-tams/ | The latest audio and video source in the store | | https://host/x-tams/sources/{sourceId} | The latest audio and video of a particular source/stream | | https://host/x-tams/sources/{audioId},https://host/x-tams/sources/{videoId} | The two specific sources given (comma-separated), one audio and one video | | https://host/path/clip.mp4 (or .fmp4) | A single progressive/fragmented MP4 file, no TAMS involved |

There is also a WebSocket endpoint at …/x-tams/ws that emits events as sources and flows change — useful for building your own source picker.

Attributes

Set these as HTML attributes on <norsk-video>:

| Attribute | Type | Default | Purpose | | --- | --- | --- | --- | | src | string | — | Media source (see above). Required. | | fillContainer | boolean | false | Fill the container (crop) instead of letterboxing to fit. | | prefetchAudioMs | number | 2000 | How far ahead, in ms, to prefetch audio. | | thumbnailWidth | number | 144 | Width of generated scrubber thumbnails. | | thumbnailHeight | number | 81 | Height of generated scrubber thumbnails. | | class / style | string | — | Forwarded to the inner <video> element. |

src is read once when the element is connected. To load a different source, replace the element (e.g. change its key in React) rather than mutating the attribute in place.

Authentication

If your TAMS store requires authorization, set the authHeader property (not an attribute) to a function returning the header value. It is called on every request, so you can rotate or refresh tokens without re-creating the player:

const player = document.querySelector('norsk-video');

// Bearer token
player.authHeader = () => `Bearer ${myAccessToken}`;

// or HTTP Basic
player.authHeader = () => `Basic ${btoa(`${user}:${pass}`)}`;

Programmatic control

<norsk-video> implements a subset of the standard HTMLMediaElement interface, so it drives Media Chrome and behaves much like a <video> element:

const player = document.querySelector('norsk-video');

player.play();
player.pause();

player.currentTime = 12.5;   // seconds, relative to the start of playback
player.volume = 0.5;         // 0..1
player.muted = true;

player.currentTime;          // read position
player.duration;             // total length (seconds)
player.paused;               // boolean
player.readyState;           // HAVE_NOTHING … HAVE_ENOUGH_DATA
player.videoWidth;           // intrinsic width

// Absolute media timestamp of playback zero — add it to `currentTime` to get an
// absolute TAMS timestamp, or subtract to seek to one.
player.mediaTimeOrigin;

// Frame-accurate stepping:
player.dispatchEvent(new Event('frame-next'));
player.dispatchEvent(new Event('frame-previous'));

It emits the usual media events, which is what lets Media Chrome (or your own UI) stay in sync: loadstart, loadedmetadata, loadeddata, canplay, play, playing, pause, ended, waiting, seeking, seeked, timeupdate, durationchange, progress, volumechange, and error.


Talking to TAMS directly

The package also exports a small typed TAMS client (and the generated API types under API) if you want to enumerate sources yourself — for example to build a source picker before choosing a src:

import { TAMS } from '@norskvideo/norsk-player';

const tams = new TAMS('https://host/x-tams/', () => `Bearer ${token}`);
const sources = await tams.getSources();

React

If you use React, prefer the wrapper package, which provides a <Player> component with the Media Chrome control bar already assembled:

npm install @norskvideo/norsk-player-react
import { Player } from '@norskvideo/norsk-player-react';

<Player
  className="w-full h-full"
  src="https://host/x-tams/"
  authHeader={() => `Bearer ${token}`}
/>;

Browser support

The player decodes media in the browser with the WebCodecs and Web Audio APIs, and must be served from a secure context (HTTPS, or localhost). This means a recent Chromium-based browser (Chrome, Edge) or another browser with WebCodecs support. Check current availability at caniuse: WebCodecs.


Source

https://github.com/id3as/norsk-player