npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@noma4i/nitro-play

v1.0.0

Published

Lightweight video player for React Native

Readme

NitroPlay

Native-first video player for React Native with shared HLS transport, stream cache, and first-frame preview utilities.

Installation

yarn add @noma4i/nitro-play react-native-nitro-modules
npm install @noma4i/nitro-play react-native-nitro-modules
pnpm add @noma4i/nitro-play react-native-nitro-modules

react-native-nitro-modules >= 0.35.0 is a required peer dependency. React and React Native come from your app.

iOS

cd ios && pod install

Android

No extra steps - standard React Native 0.77+ autolinking handles the module.

Installing a specific tag from GitHub

If you need a tag or branch before it is published to npm:

yarn add @noma4i/nitro-play@github:noma4i/nitro-player#v1.0.0

Quick Start

import React from 'react';
import { NitroPlayerView } from '@noma4i/nitro-play';

export function FeedCard() {
  return (
    <NitroPlayerView
      source={{
        uri: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
        startup: 'lazy',
        transport: { mode: 'auto' },
        retention: {
          preload: 'metadata',
          offscreen: 'metadata',
          feedPoolEligible: true
        },
        preview: { mode: 'listener', autoThumbnail: true }
      }}
      resizeMode="contain"
      keepScreenAwake
      style={{ width: '100%', aspectRatio: 16 / 9 }}
    />
  );
}

Core API

| Surface | Purpose | | ----------------------------------- | ------------------------------------------------------------------ | | NitroPlayerView | Declarative native view with fullscreen, attach, and event props | | NitroPlayer | Imperative player with properties, methods, and addEventListener | | createNitroSource(config) | URI normalization and hybrid source factory | | streamCache | Prefetch, header-aware stats, cache clear | | videoPreview | Generated and cache-only first-frame lookup | | usePlaybackState(player) | Subscribes to onPlaybackState and returns latest snapshot | | useEvent(player, event, listener) | Managed event subscription helper |

Deep-dive reference lives in docs/player-api.md.

Source DSL

Top-level NitroSourceConfig fields:

| Field | Type | Purpose | | ----------- | ---------------------------- | --------------------------------------------------------------------------------- | | uri | string \| number | Network URL, local file:// URI, absolute local file path, or React Native asset | | headers | Record<string, string> | Request headers (part of cache/preview identity) | | metadata | NitroSourceMetadata | Player-facing media metadata | | startup | 'eager' \| 'lazy' | Startup strategy (default eager) | | buffer | BufferConfig | Explicit buffering policy | | retention | NitroSourceRetentionConfig | Preload, offscreen retention, trim, feed eligibility | | transport | NitroSourceTransportConfig | Transport routing policy | | preview | NitroSourcePreviewConfig | First-frame generation policy |

NitroSourceMetadata

All fields optional.

| Field | Type | | ------------- | -------- | | title | string | | subtitle | string | | description | string | | artist | string | | imageUri | string |

NitroSourceRetentionConfig

| Field | Type | Purpose | | ------------------ | ------------------------------------ | ----------------------------------- | | preload | 'none' \| 'metadata' \| 'buffered' | Initial preload depth | | offscreen | 'cold' \| 'metadata' \| 'hot' | Offscreen retention level | | trimDelayMs | number | Delayed trim window | | feedPoolEligible | boolean | Participate in native feed hot pool |

NitroSourceTransportConfig

| Field | Type | Purpose | | ------ | ------------------------------- | ---------------------------------- | | mode | 'auto' \| 'direct' \| 'proxy' | Transport routing (default auto) |

auto prefers the shared HLS proxy and falls back to direct when the proxy cannot be readied for the active source generation. direct skips proxy routing. proxy forces proxy routing.

NitroSourcePreviewConfig

| Field | Type | Default | Purpose | | --------------- | ------------------------------------ | ---------- | ---------------------------------------------------- | | mode | 'listener' \| 'always' \| 'manual' | listener | Automatic first-frame behavior | | autoThumbnail | boolean | true | Native auto-thumbnail placeholder for attached views | | maxWidth | number | 480 | Output width hint | | maxHeight | number | 480 | Output height hint | | quality | number | 70 | JPEG quality hint |

See docs/source-config.md for source profiles and identity rules, and docs/buffer-config.md for BufferConfig (Android minBufferMs, maxBufferMs, iOS preferredForwardBufferDurationMs, preferredPeakBitRate, shared livePlayback).

NitroPlayerView

| Prop | Type | Notes | | --------------------- | ------------------------------- | ------------------------------------- | | source | NitroSourceConfig | Required | | playerDefaults | NitroPlayerDefaults | Declarative startup state | | controls | boolean | Native controls | | resizeMode | ResizeMode | contain \| cover \| stretch \| none | | keepScreenAwake | boolean | Screen wake lock | | surfaceType | 'surface' \| 'texture' | Android only | | style | ViewStyle | Inherited from ViewProps | | onAttached | (player: NitroPlayer) => void | View attached | | onDetached | () => void | View detached | | onFullscreenChange | (value: boolean) => void | Fullscreen state changed | | willEnterFullscreen | () => void | Pre-enter hook | | willExitFullscreen | () => void | Pre-exit hook |

NitroPlayerViewRef

| Member | Type | Notes | | ----------------------------------- | ---------------------- | ---------------------------------- | | player | NitroPlayer | Imperative player backing the view | | isAttached | boolean | Native attach state | | enterFullscreen() | void | Enter fullscreen | | exitFullscreen() | void | Exit fullscreen | | addEventListener(event, listener) | ListenerSubscription | View events only |

NitroPlayer

Properties

| Property | Type | Get | Set | | ------------------------ | ------------------------ | --- | --- | | source | NitroPlayerSource | yes | no | | status | NitroPlayerStatus | yes | no | | playbackState | PlaybackState | yes | no | | memorySnapshot | MemorySnapshot | yes | no | | duration | number | yes | no | | currentTime | number | yes | yes | | volume | number | yes | yes | | muted | boolean | yes | yes | | loop | boolean | yes | yes | | rate | number | yes | yes | | isPlaying | boolean | yes | no | | isBuffering | boolean | yes | no | | isVisualReady | boolean | yes | no | | bufferDuration | number | yes | no | | bufferedPosition | number | yes | no | | mixAudioMode | MixAudioMode | yes | yes | | ignoreSilentSwitchMode | IgnoreSilentSwitchMode | yes | yes | | playInBackground | boolean | yes | yes | | playWhenInactive | boolean | yes | yes |

Methods

| Method | Returns | Notes | | ----------------------------------- | ---------------------- | ------------------------------------- | | play() | void | Start playback; valid before onLoad | | pause() | void | Pause playback | | seekTo(seconds) | void | Absolute seek | | seekBy(seconds) | void | Relative seek | | initialize() | Promise<void> | Manual initialization | | preload() | Promise<void> | Warm source without starting playback | | replaceSourceAsync(source) | Promise<void> | Swap active source | | clearSourceAsync() | Promise<void> | Clear source and keep player reusable | | release() | void | Terminal teardown | | addEventListener(event, listener) | ListenerSubscription | Subscribe to a player event |

PlaybackState

| Field | Type | Notes | | ------------------- | ----------------------- | --------------------------------------------------------------------- | | status | NitroPlayerStatus | idle \| loading \| buffering \| playing \| paused \| ended \| error | | currentTime | number | Seconds | | duration | number | Seconds | | bufferDuration | number | Seconds buffered ahead | | bufferedPosition | number | Absolute buffered position | | rate | number | Effective playback rate | | isPlaying | boolean | Native playing state | | isBuffering | boolean | Native buffering state | | isVisualReady | boolean | First visual frame readiness | | error | PlaybackError \| null | Present when status === 'error' | | nativeTimestampMs | number | Native event timestamp |

Player Events

| Event | Payload | | ------------------- | -------------------- | | onPlaybackState | PlaybackState | | onLoadStart | onLoadStartData | | onLoad | onLoadData | | onError | PlaybackError | | onFirstFrame | onFirstFrameData | | onBandwidthUpdate | BandwidthData | | onVolumeChange | onVolumeChangeData |

Subscribe directly on the player instance:

const sub = player.addEventListener('onPlaybackState', state => {
  console.log(state.status, state.currentTime);
});
// later
sub.remove();

Stream Cache & Preview

| API | Returns | Purpose | | ------------------------------------- | --------------------------------- | -------------------------------------- | | streamCache.prefetch(source) | Promise<void> | Warm transport and first segment cache | | streamCache.getStats() | Promise<StreamCacheStats> | Total cache stats | | streamCache.getStats(source) | Promise<StreamSourceCacheStats> | Per-source stats, header-aware | | streamCache.clear() | Promise<boolean> | Clear stream disk cache | | videoPreview.getFirstFrame(source) | Promise<string \| null> | Cached or generated first-frame path | | videoPreview.peekFirstFrame(source) | Promise<string \| null> | Cached-only lookup (no generation) | | videoPreview.clear() | Promise<boolean> | Clear preview artifacts |

All source-taking methods accept either a URL string or { uri, headers }. Use the object form whenever headers are part of request identity. See docs/stream-runtime.md.

Hooks

| Hook | Signature | Purpose | | ------------------ | ------------------------------------------------------------------------- | ----------------------------------------------------------- | | usePlaybackState | (player: NitroPlayer \| null \| undefined) => PlaybackState \| null | Subscribes to onPlaybackState and returns latest snapshot | | useEvent | <T extends keyof AllNitroPlayerEvents>(player, event, callback) => void | Managed event subscription with automatic cleanup |

createNitroSource

import { createNitroSource } from '@noma4i/nitro-play';

const source = createNitroSource({ uri: require('./intro.mp4') });

Resolves React Native asset references via Image.resolveAssetSource, validates the URI, and returns a hybrid NitroPlayerSource. Usually you do not need to call this manually: NitroPlayerView and NitroPlayer accept a plain NitroSourceConfig and normalize it internally. Call createNitroSource explicitly when you want to reuse the same native source object across multiple replaceSourceAsync calls.

Common Types

| Type | Values / Shape | Purpose | | ------------------------ | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | | NitroPlayerStatus | idle \| loading \| buffering \| playing \| paused \| ended \| error | Player status | | ResizeMode | contain \| cover \| stretch \| none | View scaling | | MixAudioMode | mixWithOthers \| doNotMix \| duckOthers \| auto | Audio session mix behavior | | IgnoreSilentSwitchMode | auto \| ignore \| obey | iOS silent switch handling | | PreloadLevel | none \| metadata \| buffered | Initial preload depth | | OffscreenRetention | cold \| metadata \| hot | Offscreen retention level | | MemoryRetentionState | cold \| metadata \| hot | Retention snapshot value | | MemorySnapshot | { playerBytes, sourceBytes, totalBytes, preloadLevel, retentionState, isAttachedToView, isPlaying } | Current player memory footprint | | NitroPlayerDefaults | { loop?, muted?, volume?, rate?, mixAudioMode?, ignoreSilentSwitchMode?, playInBackground?, playWhenInactive? } | Declarative startup state for NitroPlayerView.playerDefaults | | NitroPlayerError | Discriminated on LibraryError \| PlayerError \| SourceError \| NitroPlayerViewError \| UnknownError | Typed error hierarchy used by onError and thrown runtime errors |

Runtime Contract

| Area | Behavior | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Early play | play() before onLoad is canonical | | Playback state | Built from native readiness, buffering, and actual playing state | | HLS startup | Native runtime uses lazy startup and bounded startup recovery | | Proxy fallback | transport.mode='auto' may fall back to direct URL if proxy is unavailable | | First frame | onFirstFrame is sticky per active source generation | | Preview policy | preview.mode='listener' auto-captures for attached views when autoThumbnail !== false; always warms preview automatically; manual disables background auto-warmup | | Mounted-view reveal | Attached NitroPlayerView owns native auto-thumbnail/first-frame placeholder by default; app code should not require JS poster swapping for active playback surfaces | | Manual preview | videoPreview.getFirstFrame(source) returns cached/generated frame path | | Cached preview reuse | videoPreview.peekFirstFrame(source) returns only an existing cached frame path and never starts generation | | Stream/preview identity | { uri, headers } is the canonical identity for cache stats and preview artifacts | | Stream cache | streamCache.prefetch(source) is safe to call repeatedly |

Absolute local file paths are accepted on both iOS and Android and are normalized internally to file:// URLs. App code should prefer canonical file:// URIs when it owns freshly recorded media paths.

Example App

The local example is a runtime lab, not just a smoke test.

It covers:

  • hero playback switching between transport.mode='auto', header-isolated HLS, and direct MP4
  • streamCache.prefetch/getStats/clear and videoPreview.getFirstFrame/peekFirstFrame/clear
  • a three-player feed stress block with the same HLS URL under different headers
  • live observation of onLoad, onError, onFirstFrame, bandwidth, attach state, and isVisualReady

Documentation

| File | Purpose | | ------------------------------------------------------ | ------------------------------------------------------- | | docs/player-api.md | Public player, view, events, hooks | | docs/source-config.md | Source DSL and normalized source model | | docs/buffer-config.md | buffer tuning | | docs/lifecycle-guide.md | retention model and startup intent | | docs/memory-management.md | Retention states, snapshots, feed pool | | docs/stream-runtime.md | Shared transport runtime, streamCache, videoPreview | | docs/migration-1.0.md | Migration to the current beta DSL |

Requirements

| Dependency | Version | | -------------------------- | ----------- | | React Native | >= 0.77.0 | | react-native-nitro-modules | >= 0.35.0 |

License

MIT