Skip to main content

Player

Dependencies​

npm install @mui/material @emotion/react @emotion/styled @mui/icons-material lodash

Usage​

import {
AudioHolder,
MiniPlayer,
PlayerContextProvider,
usePlayer,
VideoPlayer,
} from "@arclockproject/common/components/Player";

A video and audio player made of parts that share one state:

  • PlayerContextProvider holds the state. Put it high in the tree so playback survives page changes.
  • VideoPlayer shows the video and controls.
  • AudioHolder plays the audio. Keep it mounted so audio keeps playing when VideoPlayer is removed.
  • MiniPlayer is a small player bar fixed to the bottom-right of the screen.
  • usePlayer gives your own components access to the state.

The examples below are live. Edit the code to try your own values.

Single video​

Pass videoData to load an entry as soon as the player mounts.

▶ Show code (click to view and edit)
Live Editor
<PlayerContextProvider>
  <div
    style={{
      width: "80%",
      maxWidth: "600px",
    }}
  >
    <VideoPlayer
      videoData={{
        files: {
          video: `${REMOTE.base}/PXQZNGjZIFo.mp4`,
          audio: `${REMOTE.base}/PXQZNGjZIFo.m4a`,
          subtitles: null,
          thumbnail: `${REMOTE.base}/PXQZNGjZIFo.webp`,
        },
        id: "original-2-eis3",
        title: "Original Piece #2 by Eis3",
        meta: null,
      }}
      isPlaylist={false}
      chapters={[]}
      heatmap={[]}
      showInlineTitle
    />
    <AudioHolder />
  </div>
</PlayerContextProvider>
Result
Loading...

Mini player and playlist​

Load a video, then press VideoPlayer Unload. As long as <AudioHolder /> stays mounted, the audio keeps playing in the mini player. When the player is loaded again, it syncs back.

▶ Show code (click to view and edit)
Live Editor
function main() {
  function PageWithPlayer() {
    let exampleVideos = [
      {
        files: {
          video: `${REMOTE.base}/PXQZNGjZIFo.mp4`,
          audio: `${REMOTE.base}/PXQZNGjZIFo.m4a`,
          subtitles: null,
          thumbnail: `${REMOTE.base}/PXQZNGjZIFo.webp`,
        },
        id: "original-2-eis3",
        title: "Original Piece #2 by Eis3",
        meta: null,
      },
      {
        files: {
          video: `${REMOTE.base}/jkZ53T1Pu7k.mp4`,
          audio: `${REMOTE.base}/jkZ53T1Pu7k.m4a`,
          subtitles: null,
          thumbnail: `${REMOTE.base}/jkZ53T1Pu7k.webp`,
        },
        id: "original-3-eis3",
        title: "Original Piece #3 by Eis3",
        meta: null,
      },
    ];
    const player = usePlayer();
    return (
      <div>
        <div
          style={{
            width: "80%",
            maxWidth: "600px",
          }}
        >
          <VideoPlayer
            isPlaylist={false}
            chapters={[]}
            heatmap={[]}
            showInlineTitle
          />
          {player.internal.playerData.value !== null && (
            <button
              onClick={() => player.internal.playlistContent.set(exampleVideos)}
            >
              Load All (playlist)
            </button>
          )}
          {exampleVideos.map((entry) => (
            <button
              onClick={() => player.internal.playerData.set(entry)}
              key={entry.id}
            >
              {entry.title}
            </button>
          ))}
        </div>
      </div>
    );
  }

  function App() {
    const [page, setPage] = useState(0);
    return (
      <>
        <div>
          <button onClick={() => setPage(0)}>VideoPlayer Unload</button>
          <button onClick={() => setPage(1)}>VideoPlayer Load</button>
        </div>
        <div style={{ width: "80%", maxWidth: "600px" }}>
          {page === 0 ? <p>VideoPlayer not rendering</p> : <PageWithPlayer />}
        </div>
      </>
    );
  }

  return (
    <PlayerContextProvider>
      <div style={{ height: "400px" }}>
        <App />
      </div>
      <MiniPlayer />
      <AudioHolder />
    </PlayerContextProvider>
  );
}
Result
Loading...

Sticky mobile player​

With sticky: true, the video stays at the top on mobile while the page scrolls below it.

▶ Show code (click to view and edit)
Live Editor
<PlayerContextProvider
  settings={{
    autoAudioOnly: false,
    autoPlay: false,
    videoBackgroundBloom: true,
    allowMiniPlayer: true,
    sticky: true, // changed
    stickySpacing: 0, // Gap above the sticky player in px (e.g. for a navbar). Hidden while scrolling down.
    stickyTriggerDistance: 0, // Pixels to scroll before the gap hides or comes back. 0 is immidiate
  }}
>
  <div style={{ height: "500px", overflowY: "scroll" }}>
    <VideoPlayer
      videoData={{
        files: {
          video: `${REMOTE.base}/PXQZNGjZIFo.mp4`,
          audio: `${REMOTE.base}/PXQZNGjZIFo.m4a`,
          subtitles: null,
          thumbnail: `${REMOTE.base}/PXQZNGjZIFo.webp`,
        },
        id: "original-2-eis3",
        title: "Original Piece #2 by Eis3",
        meta: null,
      }}
      isPlaylist={false}
      chapters={[]}
      heatmap={[]}
      showInlineTitle
    />
    <div style={{ height: "500px" }}>
      I am 500px tall. If you view me on mobile, you will see that the video
      stays there and this text will go below the video as you scroll. Try to
      scroll and see me disappear!
      <br />
      <br />
      <br />
      <br />
      <br />
      <br />
      <br />
      <br />
      Still here!
    </div>
  </div>
  <AudioHolder />
</PlayerContextProvider>
Result
Loading...

API​

See the Player API reference for every prop, method and type.