Skip to content

Creating your own player UI

This guide will walk you through the process of creating your own custom player UI for Streamplace. We’ll use the existing MobileUi component as a reference to understand how to leverage the available hooks and components.

The mobile UI is built using React Native and relies on a set of custom hooks to manage state and interactions related to the livestream. By composing these hooks and the UI components from @streamplace/components, you can build a unique viewing and streaming experience.

  • React Hooks: State management and logic are encapsulated in hooks (e.g., useLivestreamInfo, usePlayerDimensions). This keeps the UI component clean and focused on rendering.
  • Component Library: A shared component and UI library (@streamplace/components) provides ready-to-use UI elements like PlayerUI, Toast, and View.
  • Styling: A theme-based styling system (atoms) is used for consistency.

Let’s break down the default MobileUi component to understand its structure.

streamplace/js/app/components/mobile/ui.tsx
import { useNavigation } from "@react-navigation/native";
import {
atoms,
PlayerUI,
Text,
Toast,
useAvatars,
useCameraToggle,
useKeyboardSlide,
useLivestreamInfo,
usePlayerDimensions,
useSegmentTiming as useSegmentMetrics,
View,
} from "@streamplace/components";
import { ChevronLeft, SwitchCamera } from "lucide-react-native";
import { useEffect } from "react";
import { Image, Pressable } from "react-native";
// Ready-to-use chat component is not available yet
import { ChatPanel } from "./chat";
const { borders, colors, gap, h, layout, position, w } = atoms;
export function MobileUi() {
// 1. Hooks for State and Logic
const navigation = useNavigation();
const {
ingest,
profile,
title,
setTitle,
showCountdown,
setShowCountdown,
recordSubmitted,
setRecordSubmitted,
ingestStarting,
setIngestStarting,
connectionQuality,
toggleGoLive,
} = useLivestreamInfo();
const { width, height, isPlayerRatioGreater } = usePlayerDimensions();
const { slideKeyboard } = useKeyboardSlide();
const { segmentDeltas, mean, range } = useSegmentMetrics();
const { doSetIngestCamera } = useCameraToggle();
const avatars = useAvatars(profile?.did ? [profile?.did] : []);
// 2. Effects and Derived State
useEffect(() => {
return () => {
if (ingestStarting) {
setIngestStarting(false);
}
};
}, [ingestStarting, setIngestStarting]);
const isSelfAndNotLive = ingest === "new";
const isLive = ingest !== null && ingest !== "new";
// 3. JSX for Rendering
return (
<>
{/* Top Bar: Navigation, Profile, and Camera Switch */}
<View style={[layout.position.absolute, h.percent[100], w.percent[100]]}>
{/* ... */}
</View>
{/* Metrics Panel */}
{isLive && (
<View>
<PlayerUI.MetricsPanel
connectionQuality={connectionQuality}
showMetrics={isLive || isSelfAndNotLive}
segmentDeltas={segmentDeltas}
mean={mean || 999}
range={range || 999}
/>
</View>
)}
{/* Input Panel (for streamer) or Chat Panel (for viewer, or streamer when live) */}
{isSelfAndNotLive ? (
<PlayerUI.InputPanel
title={title}
setTitle={setTitle}
ingestStarting={ingestStarting}
toggleGoLive={toggleGoLive}
slideKeyboard={slideKeyboard}
/>
) : (
<ChatPanel
isPlayerRatioGreater={isPlayerRatioGreater}
slideKeyboard={slideKeyboard}
/>
)}
{/* Overlays and Toasts */}
<PlayerUI.CountdownOverlay
visible={showCountdown}
width={width}
height={height}
startFrom={3}
onDone={() => setShowCountdown(false)}
/>
<Toast
open={recordSubmitted}
onOpenChange={setRecordSubmitted}
title="You're live!"
description="We're notifying your followers that you just went live."
duration={5}
/>
</>
);
}

Create a new file for your custom UI component, for example, MyCustomUi.tsx, inside streamplace/js/app/components/mobile/.

Start by importing the tools you’ll need. The more important ones are:

  • useLivestreamInfo: Provides all core data and actions for the stream (e.g., ingest status, profile info, toggleGoLive function).
  • usePlayerDimensions: Gives you the width and height of the video player area.
  • @streamplace/components: Our source for pre-built hooks, UI elements (PlayerUI, View, Text, etc.) and styling atoms.
  • react-native: For basic components like Pressable and Image.