@uln/hls 0.3.1 / examples / clip-card

clip-card HLS MP4

How previews work, on one card: the clip plays on hover, gets the film ready from its moment, and a tap opens the film there

examples/clip-card/App.tsx

import { playFullscreen, preload, useVideo, Video } from "@uln/hls/react";
import { useState } from "react";
import { film } from "../films";

/**
 * How a preview works, on one card. A preview is not a separate feature: it
 * is a `<Video>` given the film's short silent clip instead of the film.
 *
 * 1. Hovering or focusing the card plays the clip (`playing`). The clip
 *    downloads whole into memory, so it starts on its first frame and never stalls.
 * 2. Once it plays, the film gets ready to open from the clip's moment
 *    (`preload` with `start`): its opening at that moment lands in the HTTP cache.
 * 3. A tap opens the film in the phone's own player at the same moment
 *    (`playFullscreen` with `start`). On desktop, `fallback` opens your own player.
 */
export function App() {
  const clip = useVideo();
  const [active, setActive] = useState(false);
  if (!film.clip) return <img src={film.poster} alt={film.title} />;
  const clipStart = film.clip.start;
  // Where the film is at this moment of the clip.
  const filmTime = () => clipStart + clip.currentTime;

  return (
    <button
      type="button"
      className="card"
      onPointerEnter={() => setActive(true)}
      onPointerLeave={() => setActive(false)}
      onFocus={() => setActive(true)}
      onBlur={() => setActive(false)}
      onClick={() => playFullscreen(film.hls, { start: filmTime(), poster: film.poster })}
    >
      <Video
        src={film.clip.url}
        poster={film.poster}
        player={clip}
        playing={active}
        muted
        loop
        onPlay={() => preload(film.hls, { start: filmTime() })}
      />
      <span>{film.title}</span>
    </button>
  );
}