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

react-native-nitro-video-editor

v0.1.1

Published

Fast native photo and video editing for React Native powered by Nitro Modules

Downloads

253

Readme

react-native-nitro-video-editor

Fast native photo and video editing for React Native, powered by Nitro Modules.

The library is designed for social posting flows: pick from the native gallery, preview quickly, trim or style media, prepare the output only when needed, and stream uploads from native storage without copying large files through JavaScript.

Features

  • Native photo and video pickers
  • Cached native gallery flow for fast video selection
  • Timeline thumbnail generation for trim UIs
  • Video trim, playback speed, mute, external audio, filters, and upload preparation
  • Image crop, filters, drawing strokes, text/emoji overlays, and export
  • Native streaming upload with progress and cancellation
  • Source reuse for unchanged videos
  • Hardware-assisted native rendering for edits that require encoding
  • Typed Nitro HybridObject API

Why use this instead of a heavy editor SDK

This package focuses on the media pipeline rather than forcing a complete editor product into your app. Your React Native UI can match your app, while native code handles the expensive media work.

  • No large media buffers in the JS heap
  • No mandatory "export screen" before post
  • Apps can combine preparation and upload behind one Post button
  • Native sessions keep trim/filter/crop state close to the platform media APIs
  • The same low-level primitives can power custom Instagram-style, feed, story, or profile media flows

Platform support

| Platform | Status | | --- | --- | | iOS 15.1+ | PhotoKit gallery, AVFoundation editing, Core Image filters, native upload | | Android 6.0+ | Native picker, Media3 Transformer pipeline, native upload |

Installation

npm install react-native-nitro-video-editor react-native-nitro-modules
cd ios && pod install

This package requires react-native-nitro-modules because all native entry points are Nitro HybridObjects.

Pick a video

import { MediaEditor } from 'react-native-nitro-video-editor'

const asset = await MediaEditor.pickVideo({
  presentation: 'native-gallery',
  preferCurrentRepresentation: true,
})

if (asset === undefined) {
  return
}

console.log(asset.uri, asset.durationMs, asset.width, asset.height)

preferCurrentRepresentation asks the platform for the current Photos representation when possible. On iOS, this avoids an unnecessary picker-side transcode for compatible assets.

Build a timeline

const thumbnails = await asset.createThumbnails({
  startMs: 0,
  endMs: asset.durationMs,
  count: 12,
  maxDimensionPx: 180,
})

Thumbnails are generated natively and returned as temporary local file URIs.

Prepare a video for upload

const edit = asset.createEditSession()

edit.setTrimRange({ startMs: 1_500, endMs: 8_000 })
edit.setFilter('none')
edit.setAudio({
  muteSourceAudio: false,
  externalAudioVolume: 0.85,
  loopExternalAudio: true,
})

const task = edit.prepareForUpload({
  preset: 'original',
  fileType: 'mp4',
  optimizeForNetworkUse: true,
  playbackSpeed: 1,
})

const subscription = task.addOnProgressListener(progress => {
  console.log(Math.round(progress * 100))
})

try {
  const result = await task.start()
  console.log(result.uri, result.byteSize, result.outputStrategy)
} finally {
  subscription.remove()
}

playbackSpeed accepts values from 0.5 through 2. A value of 1 preserves the source speed. When the selected video is unchanged, the task can return the source file immediately. Trim-only or mute-only paths can avoid full video encoding when the platform can safely do so. Speed changes, filters, and resolution changes require rendering.

Edit an image

const image = await MediaEditor.pickImage()

if (image === undefined) {
  return
}

const edit = image.createEditSession()

edit.setCrop({ x: 0.1, y: 0, width: 0.8, height: 1 })
edit.setFilter('chrome')
edit.setOverlays([
  {
    id: 'caption-1',
    kind: 'text',
    content: 'TownCup',
    x: 0.5,
    y: 0.12,
    scale: 1,
    rotationDeg: 0,
    color: '#FFFFFF',
    fontSize: 32,
  },
])

const [full, thumbnail] = await Promise.all([
  edit.exportImage({ format: 'jpeg', quality: 0.9, maxDimensionPx: 2560 }),
  edit.exportImage({ format: 'jpeg', quality: 0.82, maxDimensionPx: 1200 }),
])

console.log(full.uri, thumbnail.uri)

Crop coordinates and overlay positions are normalized, so your UI can render at any screen size and export at native resolution.

Upload a prepared file

const upload = MediaEditor.createFileUpload(full.uri, {
  url: presignedUrl,
  method: 'put',
  headers: {
    'Content-Type': 'image/jpeg',
  },
})

const subscription = upload.addOnProgressListener(progress => {
  console.log(Math.round(progress * 100))
})

try {
  const result = await upload.start()
  console.log(result.statusCode, result.byteSize)
} finally {
  subscription.remove()
}

The upload task streams directly from native storage. This keeps memory stable for large videos and high-resolution images.

API architecture

  • MediaEditor is the autolinked root HybridObject.
  • ImageAsset and VideoAsset own native media references.
  • ImageEditSession owns crop, filter, drawing, and overlay state.
  • VideoEditSession owns trim, filter, mute, and external audio state.
  • VideoExportTask and FileUploadTask model progress, cancellation, and disposal.
  • Options and results are small typed structs.

Development

npm install
npm run specs
npm run typecheck
npm run example:typecheck

For the full implementation notes, see the repository docs:

  • docs/ARCHITECTURE.md
  • docs/UPLOAD_PIPELINE.md
  • docs/NITRO_IMPLEMENTATION_GUIDE.md
  • docs/ROADMAP.md

License

MIT