npm package: @hyperstream/player
Description: Hyperstream Player React Component
Latest version: 0.3.6

# @hyperstream/player

`@hyperstream/player` is a production-ready media player for React, Next.js, and standard HTML pages.

It provides two integration paths:

1. A React package that exports `HyperstreamVideoPlayer` and `HyperstreamAudioPlayer`.
2. A standalone `player.js` script that registers the `<hyperstream-player>` custom element for framework-free embeds.

The player supports Hyperstream and FAHS URLs, direct HLS or media-file playback, captions, chapters, playlists, brand styling, portrait layouts, and imperative playback APIs.

If you load `player.js`, `<hyperstream-player>` is the primary custom element. The legacy aliases `<hyperstream-video-player>` and `<hp-video-player>` remain supported for backward compatibility.

## Choose an Integration

### React or Next.js

Install the npm package when you want typed React components, props, and ref-based control APIs.

```bash
npm install @hyperstream/player
```

### Plain HTML, CMS, or No-Build Environments

Load the standalone script when you want to embed the player on any web page without React.

```html
<script src="https://videoplayer.flowautomate.com/player.js"></script>
```

## Supported Input Sources

You can provide media through any of these inputs:

1. A Hyperstream or FAHS video URL.
2. A direct HLS stream ending in `.m3u8`.
3. A direct media file such as `.mp4` or `.mp3`.
4. A short slug passed through `q` in HTML embeds.

If you want the fastest path to a working embed, start with the plain HTML example below.

## Quick Start: Plain HTML

Copy and paste this into your page:

```html
<script src="https://videoplayer.flowautomate.com/player.js"></script>

<hyperstream-player
  src="https://fahs.io/your-video"
  title="My Video"
  brand-color="#00704A"
  show-controls="true"
  show-title="true"
></hyperstream-player>
```

Then replace these values:

1. Replace `https://fahs.io/your-video` with your own video URL.
2. Replace `My Video` with the title you want people to see.
3. Replace `#00704A` with your own brand color, if you want one.

That is enough for a working player.

### Using a Video Slug

You can use the short slug with `q` instead of a full URL:

```html
<script src="https://videoplayer.flowautomate.com/player.js"></script>

<hyperstream-player
  q="your-video-slug"
  title="My Video"
  brand-color="#00704A"
></hyperstream-player>
```

### Playing a Direct MP4 or HLS File

Use `direct-src` when you want to bypass Hyperstream or FAHS resolution and load the file directly:

```html
<script src="https://videoplayer.flowautomate.com/player.js"></script>

<hyperstream-player
  direct-src="https://example.com/video.mp4"
  title="Product Demo"
  poster="https://example.com/poster.jpg"
></hyperstream-player>
```

## Quick Start: React

Install the package and import the bundled stylesheet:

```bash
npm install @hyperstream/player
```

```tsx
import { HyperstreamVideoPlayer } from "@hyperstream/player";
import "@hyperstream/player/dist/styles.css";
```

Then render the player:

```tsx
import { HyperstreamVideoPlayer } from "@hyperstream/player";
import "@hyperstream/player/dist/styles.css";

export default function App() {
  return (
    <HyperstreamVideoPlayer
      hyperstreamUrl="https://fahs.io/your-video"
      title="My Video"
      brandColor="#00704A"
      showControls
      showTitle
    />
  );
}
```

If you already have a direct media file, use `directSrc` instead:

```tsx
<HyperstreamVideoPlayer
  directSrc="https://example.com/video.mp4"
  title="Product Demo"
  thumbnail="https://example.com/poster.jpg"
/>
```

## Common Examples

### Portrait Video

```tsx
<HyperstreamVideoPlayer
  hyperstreamUrl="https://fahs.io/your-video"
  title="Mobile Story"
  aspectRatio="9:16"
  maxStageHeight="70vh"
  brandColor="#0F766E"
/>
```

### Start Muted for Autoplay

```tsx
<HyperstreamVideoPlayer
  hyperstreamUrl="https://fahs.io/your-video"
  title="Homepage Banner"
  autoplay
  muteOnStart
/>
```

### Audio Player

```tsx
import { HyperstreamAudioPlayer } from "@hyperstream/player";
import "@hyperstream/player/dist/styles.css";

<HyperstreamAudioPlayer
  directSrc="https://example.com/audio.mp3"
  title="Episode 12"
  artist="Flow Automate"
  thumbnail="https://example.com/cover.jpg"
  skin="glass"
/>
```

`HyperstreamAudioPlayer` shares the common media, branding, playlist, and playback props and supports these audio-first skins: `minimal`, `card`, `horizontal`, `bar`, `modern`, `classic`, `neon`, and `glass`. The video-only `controls`, `showControls`, and `showTitle` props are intentionally not part of the audio player API.

### HTML Embed with Additional Options

```html
<script src="https://videoplayer.flowautomate.com/player.js"></script>

<hyperstream-player
  src="https://fahs.io/your-video"
  title="Training Video"
  artist="Flow Automate"
  poster="https://example.com/poster.jpg"
  brand-color="#0F766E"
  aspect-ratio="16:9"
  max-stage-height="75vh"
  autoplay="false"
  mute-on-start="false"
  show-controls="true"
  initial-volume="80"
  playback-speed="1"
></hyperstream-player>
```

## React Props

The package exports both `HyperstreamVideoPlayer` and `HyperstreamAudioPlayer`.
The tables below describe the current public prop surface based on the published TypeScript types.

`skin` appears in the component-specific sections because audio and video accept different skin values.

### Global Props

These props are shared by both `HyperstreamVideoPlayer` and `HyperstreamAudioPlayer`.

| Prop | Type | What it does |
| --- | --- | --- |
| `hyperstreamUrl` | `string` | Main Hyperstream or FAHS media URL. |
| `url` | `string` | Alias for `hyperstreamUrl`. Use either one, not both. |
| `directSrc` | `string` | Direct media file URL such as MP4, MP3, or HLS. |
| `poster` | `string` | Poster image shown before playback. |
| `watermark` | `string` | Watermark image shown on the player. |
| `thumbnail` | `string` | Thumbnail or artwork image shown in the UI. |
| `title` | `string` | Main title shown in the player. |
| `artist` | `string` | Secondary text shown under or alongside the title. |
| `brandColor` | `string` | Main accent color. |
| `primaryColor` | `string` | Alias for `brandColor`. |
| `playlist` | `HyperstreamVideoPlayerProps["playlist"]` | Loads multiple items into a playlist. |
| `autoplay` | `boolean` | Starts playback as soon as the browser allows it. |
| `muted` | `boolean` | Starts muted. |
| `muteOnStart` | `boolean` | Forces the first play to start muted. |
| `initialVolume` | `number` | Starting volume. `0–100` is preferred; `0–1` legacy values are also accepted. |
| `playbackSpeed` | `number` | Starting speed from `0.25` to `4`. |
| `loop` | `boolean` | Restarts automatically when playback ends. |
| `objectFit` | `"contain" \| "cover" \| "fill" \| "none" \| "scale-down"` | Controls how the media fits inside the player area. |
| `aspectRatio` | `number \| string` | Forces the player shape, for example `"16:9"`, `"9:16"`, or `1.777`. |
| `maxStageHeight` | `string` | Limits the maximum stage height, for example `"70vh"`. |
| `overlayColor` | `"dark" \| "light"` | Changes the overlay style used on text and playback UI. |
| `apiKey` | `string` | Sends an API key for protected streams. |
| `containerWidth` | `number` | Advanced layout override for the container width. |
| `isMobile` | `boolean` | Advanced layout override for mobile rendering. |
| `onMediaTypeDetected` | `function` | Called with `"AUDIO"` or `"VIDEO"` once the loaded media type is known. |
| `onPlaybackStateChange` | `function` | Called whenever the core playback state changes. |
| `onActivePlaylistItemChange` | `function` | Called whenever the active playlist item changes. |
| `onPlaylistItemsChange` | `function` | Called whenever playlist items become available or update. |
| `onAssetAuthChange` | `function` | Called when the player resolves `signature` and `ivhex` for protected assets. |
| `onTranscriptStateChange` | `function` | Called whenever transcript lines, languages, or the active language changes. |
| `onDockStateChange` | `function` | Called whenever the companion dock opens, closes, or its visible data changes. |

### Audio Player Props

These props are specific to `HyperstreamAudioPlayer`.

| Prop | Type | What it does |
| --- | --- | --- |
| `skin` | `"minimal" \| "card" \| "horizontal" \| "bar" \| "modern" \| "classic" \| "neon" \| "glass" \| "expanded"` | Selects the audio player skin. |
| `externalPlayerRef` | `React ref object` | Lets the audio UI control an external hidden player instance. |
| `playbackStore` | `store object` | Supplies external playback snapshots when the audio UI is driven by another player instance. |
| `activePlaylistItem` | `object \| null` | Controlled active playlist item for synced audio shells. |
| `playlistItems` | `array` | Controlled playlist items for synced audio shells. |
| `externalTranscriptState` | `object \| null` | Controlled transcript state for synced audio shells. |
| `bottomFixed` | `boolean` | Docks the audio player to the bottom of the viewport. |
| `bottomWidth` | `boolean` | When docked, stretches the audio player surface to `100vw`. |

`HyperstreamAudioPlayer` does not accept `controls`, `showControls`, or `showTitle`; it renders its own transport UI.

### Video Player Props

These props are specific to `HyperstreamVideoPlayer`.

| Prop | Type | What it does |
| --- | --- | --- |
| `skin` | `"default" \| "minimalist" \| "minimal" \| "card" \| "horizontal" \| "bar" \| "modern" \| "classic" \| "neon" \| "glass" \| "expanded"` | Selects the video player skin. Only `default` and `minimalist` currently render as distinct video skins; other accepted values currently fall back to `default`. |
| `controls` | `boolean` | Enables the video player controls. |
| `showControls` | `boolean` | Shows or hides the custom video control bar. |
| `showTitle` | `boolean` | Shows or hides the video title area. |

All of these props are reactive. If you change them later, the player updates without needing to remount.

TypeScript note: `PlaylistConfig` is not currently re-exported from the package. If you want the exact inferred playlist type, derive it from the component props:

```tsx
import type { HyperstreamVideoPlayerProps } from "@hyperstream/player";

type PlayerPlaylist = NonNullable<HyperstreamVideoPlayerProps["playlist"]>;
```

## Web Component Attributes

Use these attributes on `<hyperstream-player>` when you are embedding the standalone `player.js` build.

| Attribute | What it does |
| --- | --- |
| `src` | Main video URL. |
| `q` | Short video slug. |
| `direct-src` | Direct media file URL. |
| `title` | Main title shown on the player. |
| `artist` | Secondary text shown under the title. |
| `thumbnail` | Poster or thumbnail image URL. |
| `poster` | Poster image URL. |
| `brand-color` | Main accent color. |
| `primary-color` | Alias for the accent color. |
| `secondary-color` | Secondary brand color. |
| `text-color` | Text color override. |
| `autoplay` | `true` or `false`. |
| `muted` | `true` or `false`. |
| `mute-on-start` | `true` or `false`. |
| `controls` | `true` or `false`. Video mode only. |
| `show-controls` | `true` or `false`. Video mode only. |
| `show-title` | `true` or `false`. Video mode only. |
| `loop` | `true` or `false`. |
| `initial-volume` | Number from `0` to `100`. |
| `playback-speed` | Number from `0.25` to `4`. |
| `object-fit` | `contain`, `cover`, `fill`, `none`, or `scale-down`. |
| `aspect-ratio` | For example `16:9`, `9:16`, `1:1`, or `1.777`. |
| `max-stage-height` | For example `70vh` or `100%`. |
| `overlay-color` | `dark` or `light` overlay treatment for titles and controls. |
| `skin` | UI skin name. |
| `mode` | Reserved mode string forwarded to the embedded `/watch` route. It currently has no built-in effect in the default player. |
| `api-key` | API key for protected streams. |

## React Ref API

Use a ref when you want to control the React player instance from UI outside the component.

```tsx
import { useRef } from "react";
import {
  HyperstreamVideoPlayer,
  type HyperstreamVideoPlayerRef,
} from "@hyperstream/player";
import "@hyperstream/player/dist/styles.css";

export default function Example() {
  const playerRef = useRef<HyperstreamVideoPlayerRef>(null);

  return (
    <>
      <HyperstreamVideoPlayer
        ref={playerRef}
        hyperstreamUrl="https://fahs.io/your-video"
        title="Demo"
      />

      <button onClick={() => void playerRef.current?.play()}>Play</button>
      <button onClick={() => playerRef.current?.pause()}>Pause</button>
      <button onClick={() => playerRef.current?.seek(30)}>Go to 0:30</button>
    </>
  );
}
```

### Available Ref Methods

| Method | What it does |
| --- | --- |
| `play()` | Starts playback. |
| `pause()` | Pauses playback. |
| `seek(time)` | Jumps to a time in seconds. |
| `setVolume(volume)` | Sets volume from `0` to `1`. |
| `setPlaybackRate(rate)` | Changes speed from `0.25` to `4`. |
| `setMuted(muted)` | Mutes or unmutes the player. |
| `getCurrentTime()` | Returns the current playback time in seconds. |
| `getDuration()` | Returns the full duration in seconds. |
| `getHlsInstance()` | Returns the underlying HLS instance for advanced use. |
| `nextTrack()` | Plays the next playlist item. |
| `prevTrack()` | Plays the previous playlist item. |
| `selectPlaylistItem(item)` | Loads a specific playlist item object. |
| `playItemById(id)` | Loads a playlist item by its id. |
| `closeDock()` | Closes the dock panel. |
| `setDockTab(tab)` | Switches the dock tab to `A`, `B`, or `C`. |
| `setActiveCaption(language)` | Changes the active caption or transcript language. |

## Web Component JavaScript API

Once the custom element is mounted, you can control it with plain browser JavaScript.

Command methods are fire-and-forget. Getter methods return promises because the custom element forwards commands to the player running inside its iframe bridge.

```html
<script>
  const player = document.querySelector("hyperstream-player");

  player.play();
  player.pause();
  player.seek(30);
  player.setVolume(0.8);
  player.setPlaybackRate(1.25);
  player.setMuted(true);
  player.mute();
  player.unmute();
</script>
```

### Available Web Component Methods

| Method | Returns | What it does |
| --- | --- | --- |
| `play()` | `void` | Starts playback. |
| `pause()` | `void` | Pauses playback. |
| `seek(time)` | `void` | Seeks to a time in seconds. |
| `seekTo(time)` | `void` | Alias for `seek()` using the player bridge's seek-to message. |
| `setVolume(volume)` | `void` | Sets volume from `0` to `1`. |
| `setPlaybackRate(rate)` | `void` | Sets playback speed. |
| `setMuted(muted)` | `void` | Mutes or unmutes playback. |
| `mute()` | `void` | Shortcut for `setMuted(true)`. |
| `unmute()` | `void` | Shortcut for `setMuted(false)`. |
| `playItem(id)` | `void` | Plays a playlist item by id. |
| `setLanguage(language)` | `void` | Switches the active caption or transcript language. |
| `closeDock()` | `void` | Closes the companion dock. |
| `getDuration()` | `Promise<number>` | Returns the total duration in seconds. |
| `getCurrentTime()` | `Promise<number>` | Returns the current playback time in seconds. |
| `getVolume()` | `Promise<number>` | Returns the current volume from `0` to `1`. |
| `getMuted()` | `Promise<boolean>` | Returns whether the player is muted. |
| `getPaused()` | `Promise<boolean>` | Returns whether playback is paused. |
| `getPlaybackRate()` | `Promise<number>` | Returns the current playback rate. |

## Web Component Events

The custom element emits standard browser events that you can subscribe to from any page.

```html
<script>
  const player = document.querySelector("hyperstream-player");

  player.addEventListener("ready", () => {
    console.log("Player ready");
  });

  player.addEventListener("play", () => {
    console.log("Playing");
  });

  player.addEventListener("pause", () => {
    console.log("Paused");
  });

  player.addEventListener("timeupdate", (event) => {
    console.log(event.detail.currentTime, event.detail.duration);
  });
  
  player.addEventListener("error", (event) => {
    console.error(event.detail);
  });
</script>
```

| Event | What it means |
| --- | --- |
| `ready` | The player has loaded and is ready. |
| `play` | Playback has started. |
| `pause` | Playback has paused. |
| `ended` | Playback reached the end. |
| `timeupdate` | Current time changed. `event.detail` contains `currentTime` and `duration`. |
| `volumechange` | Volume or mute state changed. `event.detail` contains `volume` and `muted`. |
| `ratechange` | Playback speed changed. `event.detail` contains `rate`. |
| `mediatypedetected` | Media type was detected. `event.detail` contains `{ mediaType: "AUDIO" | "VIDEO" }`. |
| `error` | An error happened. `event.detail` contains the error data. |

## Troubleshooting

### The player appears, but the media does not load

Start by validating the source you are passing into the player.

1. Make sure the URL is correct.
2. If you are using `directSrc` or `direct-src`, make sure the file is publicly reachable.
3. If the stream is protected, pass the correct `apiKey`.

### Autoplay does not work

Most browsers block autoplay when audio starts unmuted.

Use one of these approaches:

1. Set `muteOnStart` in React.
2. Set `mute-on-start="true"` in HTML.

### The player looks unstyled in React

Confirm that you imported the package stylesheet:

```tsx
import "@hyperstream/player/dist/styles.css";
```

### Chapters, transcript, or playlist do not appear

Those panels render only when the loaded source includes that data.

### I am not technical. What should I try first?

Start with the plain HTML example in this README. Replace only these three values first:

1. `src`
2. `title`
3. `brand-color`

Once that works, add the other settings one by one.

## License

MIT