Software Mansion's react-native-moq — Media over QUIC (MoQ) live streaming for React Native: sub-second-latency video/audio playback, camera/mic/screen publishing, and realtime data tracks over a MoQ relay. MUST USE before writing, reviewing, or debugging ANY code that uses react-native-moq or react-native-moq-ui. Trigger on: 'react-native-moq', 'MoQ', 'Media over QUIC', 'moq relay', 'moq-kit', 'useSession', 'useBroadcasts', 'useVideoPlayer', 'useAudioPlayer', 'usePublisher', 'useCamera', 'useM…
Software Mansion's react-native-moq — Media over QUIC (MoQ) live streaming for React Native: sub-second-latency video/audio playback, camera/mic/screen publishing, and realtime data tracks over a MoQ relay.
MUST USE before writing, reviewing, or debugging ANY code that uses react-native-moq or react-native-moq-ui.
Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.
Claude CodeNot declared
CursorNot declared
CodexNot declared
GitHub CopilotNot declared
WindsurfNot declared
Gemini CLINot declared
ClineNot declared
OpenCodeNot declared
Repository health
Stars282
LicenseMIT
Default branchmain
Open issues3
Status
Active
Skill metadata
Parsed from SKILL.md frontmatter.
LicenseMIT
Package contents
Files included with this skill beyond the listing page.
skill mdSKILL.md6,449 B
docsSUMMARY.md796 B
History
First seen on skills.sh
First recorded snapshot · 240 installs
SKILL.md
react-native-moq
React Native bindings for Media over QUIC (MoQ): live video, audio, and data tracks with sub-second latency, published to and consumed from a MoQ relay. Built on Software Mansion's moq-kit native library.
Requirements: React Native New Architecture (Fabric + TurboModules), iOS 16+, Android API 30+.
npm install react-native-moq
cd ios && pod install
Optional player chrome (fullscreen modal, controls, volume slider):
iOS also needs MaterialIcons.ttf under UIAppFonts in Info.plist, then pod install again. Skip this package if composing your own player UI on <VideoView>.
Mental model
A Session is one connection to a MoQ relay (useSession(url)). It does not auto-connect — call session.connect() yourself. One session serves both subscribing and publishing.
Subscribing:useBroadcasts(session, prefix) lists live broadcasts under a path prefix → pick a BroadcastInfo → useVideoPlayer / useAudioPlayer → render with <VideoView player={player}>. Raw-media alternatives: useAudioChunks (encoded or PCM to JS) and useDataMessages (string payloads).
Publishing: capture hooks produce tracks (useCamera, useMicrophone, useMultiCamera) or you generate them (useDataTrack, useAudioSource, useVideoSource) → usePublisher(session).publish({ path, tracks }). Screen sharing (useScreenBroadcast) is separate and out-of-process.
Every hook has a hook-free counterpart — create (returns the object plus destroy()) for the stateful ones, subscribe (returns start()/stop()) for the subscription hooks — see [references/imperative.md](references/imperative.md).
Objects expose reactive state (session.state, publisher.state, player.isPlaying, …); hooks re-render on changes. Subscribe manually with addListener or the useEvent/useEventListener helpers.
Errors are strings, not exceptions. States are unions like 'connected' | 'error:...'; check state.startsWith('error:'). Nothing throws on media failure. Sessions carry the message only in the state string (state.slice(6)); capture tracks and the publisher additionally expose a lastError field. Players have no error surface at all — watch session and publisher state instead.
publish() requires session.state === 'connected', otherwise the publisher goes straight to error:session is not connected. Gate the go-live button on session state.
Gate codecs with getSupportedVideoCodecs() / getSupportedAudioCodecs(). On Android an unsupported encoder (often h265) makes publishing start then silently stop with no error. Default to h264/opus.
Permissions are the host app's job — request CAMERA/RECORD_AUDIO on Android, add NSCameraUsageDescription/NSMicrophoneUsageDescription on iOS. A black preview usually means a missing permission.
<VideoView> takes no children (the Android native view is not a ViewGroup). Render overlays as absolutely-positioned siblings.
Capture hooks are refcounted device singletons — all consumers share the physical camera/mic; flip() affects everyone. Use enabled: false to keep hardware off while mounted instead of calling hooks conditionally.
Broadcast paths are relative to the subscription prefix (broadcast live/test appears as path: 'test' under prefix 'live'). Subscribe with '' to see full paths. A listed broadcast that won't play (relay error code=13 NotFound) means a path/prefix mismatch.
Data tracks are not in the catalog — publisher and subscriber must agree on the track name out of band (default 'data').
An idle iOS microphone capture holds the audio session in playAndRecord and can block other audio libraries (insufficientPriority). Disable the mic (enabled: false) when not publishing.