> ## Documentation Index
> Fetch the complete documentation index at: https://docs.livepeer.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Core Web (hls.js)

> Framework-agnostic video playback with hls.js. Use Livepeer HLS playback URLs with Vue, Svelte, Angular, or vanilla JavaScript.

export const CenteredContainer = ({children, maxWidth = "800px", padding = "0", preset = "default", width = "", minWidth = "", marginRight = "", marginBottom = "", textAlign = "", style = {}, className = "", ...rest}) => {
  const presets = {
    default: {},
    fitContent: {
      width: "fit-content",
      minWidth: "fit-content"
    },
    readable70: {
      width: "70%",
      minWidth: "fit-content"
    },
    readable80: {
      width: "80%",
      minWidth: "fit-content"
    },
    readable90: {
      width: "90%"
    },
    wide900: {
      maxWidth: "900px"
    }
  };
  const presetStyle = presets[preset] || presets.default;
  return <div className={className} style={{
    maxWidth: presetStyle.maxWidth || maxWidth,
    margin: "0 auto",
    padding: padding,
    ...presetStyle.width ? {
      width: presetStyle.width
    } : {},
    ...presetStyle.minWidth ? {
      minWidth: presetStyle.minWidth
    } : {},
    ...width ? {
      width
    } : {},
    ...minWidth ? {
      minWidth
    } : {},
    ...marginRight ? {
      marginRight
    } : {},
    ...marginBottom ? {
      marginBottom
    } : {},
    ...textAlign ? {
      textAlign
    } : {},
    ...style
  }} {...rest}>
      {children}
    </div>;
};

export const CustomDivider = ({color = "var(--lp-color-border-default)", middleText = "", spacing = "default", style = {}, className = "", ...rest}) => {
  const spacingPresets = {
    default: {
      margin: "24px 0"
    },
    overlap: {
      margin: "-1rem 0 -1rem 0"
    },
    tight: {
      margin: "0 0 -1rem 0"
    },
    section: {
      margin: "0 0 -2rem 0"
    },
    sectionOverlap: {
      margin: "-1rem 0 -2rem 0"
    },
    deepOverlap: {
      margin: "-1rem 0 -1.5rem 0"
    }
  };
  const spacingStyle = spacingPresets[spacing] || spacingPresets.default;
  return <div role="separator" aria-orientation="horizontal" className={className} style={{
    display: "flex",
    alignItems: "center",
    ...spacingStyle,
    fontSize: style?.fontSize || "16px",
    height: "fit-content",
    ...style
  }} {...rest}>
      <span style={{
    marginRight: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
      </span>
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      {middleText && <>
          <Icon icon="circle" size={2} />
          <span style={{
    margin: "0 8px",
    fontWeight: "bold",
    color: color,
    opacity: 0.7
  }}>
            {middleText}
          </span>
          <Icon icon="circle" size={2} />
        </>}
      <div style={{
    flex: 1,
    height: "1px",
    background: "var(--lp-color-border-default)",
    opacity: 0.4
  }}></div>
      <span style={{
    marginLeft: "var(--lp-spacing-px-8)",
    opacity: 0.2
  }}>
        <span style={{
    display: "inline-block",
    transform: "scaleX(-1)"
  }}>
          <Icon icon="/snippets/assets/logos/Livepeer-Logo-Symbol-Theme.svg" />
        </span>
      </span>
    </div>;
};

<CenteredContainer preset="readable90">
  <Tip>Livepeer playback URLs are standard HLS manifests. Any HLS player works. HLS.js is the most common choice for non-React applications.</Tip>
</CenteredContainer>

<CustomDivider />

Every Livepeer stream and asset produces a standard HLS manifest URL at `https://livepeercdn.studio/hls/{playbackId}/index.m3u8`. This URL works with any HLS-compatible player. For non-React applications (Vue, Svelte, Angular, vanilla JavaScript), HLS.js is the standard library.

<CustomDivider />

## HLS.js integration

```bash icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
npm install hls.js
```

```html icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
<video id="player" controls></video>

<script type="module">
  import Hls from 'hls.js';

  const playbackId = 'your-playback-id';
  const src = \`https://livepeercdn.studio/hls/\${playbackId}/index.m3u8\`;
  const video = document.getElementById('player');

  if (Hls.isSupported()) {
    const hls = new Hls();
    hls.loadSource(src);
    hls.attachMedia(video);
    hls.on(Hls.Events.ERROR, (event, data) => {
      if (data.fatal) {
        switch (data.type) {
          case Hls.ErrorTypes.NETWORK_ERROR:
            hls.startLoad(); // retry on network error
            break;
          case Hls.ErrorTypes.MEDIA_ERROR:
            hls.recoverMediaError();
            break;
          default:
            hls.destroy();
            break;
        }
      }
    });
  } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
    // Safari has native HLS support
    video.src = src;
  }
</script>
```

Safari supports HLS natively; the `else if` branch handles that case without HLS.js.

<CustomDivider />

## Vue example

```vue icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
<template>
  <video ref="videoEl" controls />
</template>

<script setup lang="ts">
import Hls from 'hls.js';
import { ref, onMounted, onBeforeUnmount } from 'vue';

const props = defineProps<{ playbackId: string }>();
const videoEl = ref<HTMLVideoElement>();
let hls: Hls | null = null;

onMounted(() => {
  const src = \`https://livepeercdn.studio/hls/\${props.playbackId}/index.m3u8\`;
  if (Hls.isSupported() && videoEl.value) {
    hls = new Hls();
    hls.loadSource(src);
    hls.attachMedia(videoEl.value);
  } else if (videoEl.value?.canPlayType('application/vnd.apple.mpegurl')) {
    videoEl.value.src = src;
  }
});

onBeforeUnmount(() => hls?.destroy());
</script>
```

<CustomDivider />

## Native video element

For Safari-only applications or when HLS support is guaranteed:

```html icon="terminal" theme={"theme":{"light":"github-light","dark":"dark-plus"}}
<video
  src="https://livepeercdn.studio/hls/{playbackId}/index.m3u8"
  controls
  playsinline
/>
```

No JavaScript library required. This works in Safari and any browser with native HLS support (iOS Safari, macOS Safari).

<CustomDivider />

The [React Player](/v2/developers/build/applications/frontend-react-player) provides a richer component model for React applications. The [video overview](/v2/developers/build/video/overview) covers stream and asset creation.
