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

nizora-media

v0.1.0

Published

Framework-independent browser media engine for the Nizora Photobooth ecosystem

Readme

@nizora/media

Modular, framework-independent, 100% headless browser media engine for the Nizora Photobooth Ecosystem.

@nizora/media is an enterprise-grade media SDK designed to run natively in modern browsers (Chrome, Safari, Firefox, Edge), Electron, and Progressive Web Apps (PWA). It is completely decoupled from any UI framework, giving you full freedom to build custom photobooth kiosks, mobile apps, or web editors with React, Vue, Svelte, Angular, Tailwind, or Vanilla JavaScript.


Architectural Principles

  1. 100% Headless and UI-Agnostic: Zero bundled UI components. Total styling freedom with any CSS framework or component library.
  2. Original Immutability: All original MediaAsset instances are frozen and immutable. Every crop, resize, or adjustment derives a new asset.
  3. Explicit Permissions: Camera access is never requested automatically upon module load; requires explicit user invocation.
  4. Progressive Enhancement: Adaptive rendering hierarchy: WebGPU -> WebGL2 -> OffscreenCanvas -> Canvas2D.
  5. Offline Resilience and Crash Protection: Complete operation without an internet connection once activated. Power-loss recovery via IndexedDB stores.

Installation

npm install @nizora/media

Tree-Shakeable Subpaths Overview

| Subpath | Key Classes and Functions | Description | | :--- | :--- | :--- | | @nizora/media/camera | CameraManager, CapabilityManager | Camera enumeration, WebRTC stream control, zoom, torch, resolutions | | @nizora/media/capture | PhotoCapture, BurstCapture | Zero-allocation snapshot capture prioritizing createImageBitmap | | @nizora/media/image | ImageEngine, ImageEditor, FX_PRESETS | Picsart and Lightroom tone adjustments, 50+ presets, pixel math | | @nizora/media/photoshoot | PhotoshootEngine | Finite state machine for multi-pose countdown sessions and retakes | | @nizora/media/frame | FrameDetector, FrameComposer, detectPhotoAreas | Auto-detect slots, white knockout foreground overlays, photostrips | | @nizora/media/print | PrintManager, PrintQueue, PrintSize, calculatePixels | Photo lab sizing (2R-12R, A4, 4R Strip), 300/600 DPI, print queue | | @nizora/media/gif | GifEngine, BurstGif | Pure TypeScript GIF89a encoder with LZW compression and palette quantizer | | @nizora/media/video | VideoRecorder | WebM / MP4 video recording with multi-codec fallback | | @nizora/media/storage | MediaStorage, SessionManager | IndexedDB binary persistence with session grouping and auto-retention | | @nizora/media/license | LicenseManager | RSA-2048 license validation, feature-gating and offline grace periods | | @nizora/media/adaptive | AdaptiveEngine, DeviceTier | Device tier detection (Low, Medium, High) and adaptive resolution scaling | | @nizora/media/renderer | CanvasRenderer, WebGL2Renderer | GPU WebGL2 hardware-accelerated and 2D canvas renderers |


Package API Reference


1. Camera Engine — @nizora/media/camera

CameraManager

Class responsible for managing WebRTC camera streams, device discovery, resolution negotiation, and hardware controls.

Methods:

  • initialize(config?: CameraConfig): Promise<MediaStream> Initializes the camera stream with user-specified constraints.
    const stream = await camera.initialize({
      deviceId: 'optional-device-id',
      facingMode: 'user', // 'user' | 'environment'
      width: { ideal: 1920 },
      height: { ideal: 1080 },
      frameRate: { ideal: 30, max: 60 },
    });
  • attach(videoElement: HTMLVideoElement): void Safely binds the active MediaStream to an HTMLVideoElement and calls play().
  • detach(): void Unbinds the stream from the attached video element without closing hardware tracks.
  • switchCamera(target: string | 'user' | 'environment'): Promise<MediaStream> Seamlessly switches active camera to a new device ID or facing mode.
  • setZoom(zoomLevel: number): Promise<void> Controls camera hardware digital/optical zoom if supported by device capabilities.
  • setTorch(enabled: boolean): Promise<void> Toggles the physical LED flashlight on supported mobile devices.
  • getAvailableDevices(): Promise<MediaDeviceInfo[]> Returns an array of available video input devices with labels and IDs.
  • getCapabilities(): MediaTrackCapabilities | null Retrieves device hardware capabilities (focus modes, exposure range, zoom range).
  • stop(): void Stops all active tracks, turns off camera indicators, and releases hardware resources.

2. High-Speed Capture — @nizora/media/capture

PhotoCapture

Captures zero-allocation snapshots directly from video streams, canvas, or bitmaps.

Methods:

  • capture(source: HTMLVideoElement | HTMLCanvasElement | ImageBitmap, options?: CaptureOptions): Promise<MediaAsset> Captures a high-resolution photo asset.

    CaptureOptions Table: | Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | format | 'image/jpeg' \| 'image/png' \| 'image/webp' | 'image/jpeg' | Export MIME type | | quality | number (0.0 to 1.0) | 0.95 | Compression quality for JPEG/WebP | | mirror | boolean | false | Horizontally flips the captured photo | | crop | { x: number, y: number, width: number, height: number } | undefined | Sub-region crop | | targetWidth | number | source.width | Output scaled width | | targetHeight| number | source.height| Output scaled height |

BurstCapture

  • captureBurst(source: HTMLVideoElement, options: BurstOptions): Promise<MediaAsset[]> Captures a sequence of photos at high speed (e.g. 5 photos at 200ms intervals).

3. Image Editor and Presets — @nizora/media/image

ImageEditor

Fluent, chainable photo editing wrapper designed for host applications.

Constructor:

  • new ImageEditor(config?: ImageEditorConfig | ImageEngine)
    const editor = new ImageEditor({
      allowedPresets: ['original', 'hd_pro', 'film_portra400', 'custom_filter'],
      customPresets: [
        {
          id: 'custom_filter',
          name: 'Brand Golden Hour',
          category: 'pop',
          description: 'Warm sunset curve',
          adjust: { temperature: 30, saturation: 20 },
        }
      ],
      defaultAdjust: { clarity: 10 },
    });

Methods:

  • load(asset: MediaAsset): this: Loads a photo asset and resets operation chain.
  • adjust(options: AdjustOptions): this: Applies parametric pixel tone and color adjustments.
  • applyPreset(presetIdOrConfig: string | AdjustOptions): this: Applies a preset by ID or raw config.
  • rotate(degrees: 0 | 90 | 180 | 270): this: Rotates the image clockwise.
  • flip(direction: 'horizontal' | 'vertical' | 'both'): this: Mirrors the image.
  • resize(options: ResizeOptions): this: Scales image with optional aspect ratio preservation (fit | fill | cover).
  • crop(options: CropOptions): this: Crops a specific bounding box.
  • export(options?: ExportOptions): Promise<MediaAsset>: Executes all queued operations and exports a new MediaAsset.
  • getAvailablePresets(): FilterPreset[]: Returns all presets allowed for the frontend UI.
  • registerPreset(preset: FilterPreset): this: Registers a new custom preset dynamically at runtime.
  • unregisterPreset(presetId: string): this: Removes a preset by ID.
  • setAllowedPresets(presetIds: string[] | null): this: Whitelists available presets on-the-fly.

AdjustOptions Parameters:

  • brightness (-100 to +100): Global exposure shift.
  • contrast (-100 to +100): Separation of lights and darks around mid-gray.
  • highlights (-100 to +100): Highlight compression and recovery.
  • shadows (-100 to +100): Shadow lifting and black point adjustment.
  • saturation (-100 to +100): Color intensity (-100 = full monochrome B&W).
  • temperature (-100 to +100): Cool Blue / Warm Amber white balance.
  • tint (-100 to +100): Green / Magenta color balance.
  • hue (-180° to +180°): 360-degree color spectrum shift.
  • clarity (-50 to +100): Midtone micro-contrast enhancement.
  • sharpen (0 to 100): 3x3 convolution unsharp edge mask.
  • vignette (0 to 100): Radial lens corner falloff darkening.
  • grain (0 to 100): Natural analog film noise generator.
  • fade (0 to 100): Matte black point lift.
  • blur (0 to 20px): Soft focus blur.

4. Automated Photoshoot Engine — @nizora/media/photoshoot

PhotoshootEngine

Finite state machine that automates photobooth multi-pose capture sessions.

Lifecycle States:

IDLE -> READY -> COUNTDOWN -> CAPTURING -> REVIEW -> NEXT -> COMPLETED (or ERROR / CANCELLED).

Methods:

  • start(captureFn: (poseIndex: number) => Promise<MediaAsset>): Promise<MediaAsset[]> Begins the automated photoshoot sequence.
  • retake(index: number, captureFn: () => Promise<MediaAsset>): Promise<MediaAsset> Allows the user to re-shoot a single specific photo pose in the session.
  • pause(): void: Pauses countdown timer.
  • resume(): void: Resumes paused countdown.
  • cancel(): void: Aborts active photoshoot and cleans up resources.

Typed Events (engine.on(event, handler)):

  • 'stateChange' ((state: PhotoshootState) => void): Emitted on state transitions.
  • 'countdown' ((secondsLeft: number) => void): Emitted every second during pose countdown.
  • 'capturing' ((poseIndex: number) => void): Emitted immediately prior to shutter capture.
  • 'shot' (({ index: number, asset: MediaAsset }) => void): Emitted when a pose photo is captured.
  • 'complete' ((photos: MediaAsset[]) => void): Emitted when all poses are captured.
  • 'error' ((err: Error) => void): Emitted on capture failure.

5. Frame Detection and Composition — @nizora/media/frame

FrameDetector

  • detect(fileOrBlob: Blob | File | string, options?: FrameDetectOptions): Promise<FrameDetectionResult> Automatically identifies photo slot cutout rectangles from template images using connected-component BFS analysis.

FrameComposer

  • compose(options: FrameComposeOptions): Promise<MediaAsset> Composes multiple photos into a photostrip template with background styling, photo slot clipping, white knockout foreground overlays, decorative SVG stickers, text captions, and QR codes.

6. Precision Print Queue and Sizing — @nizora/media/print

PrintSize

  • new PrintSize(preset: PrintSizePreset, customDims?: { widthMm: number, heightMm: number }) Supported presets: 2R, 3R, 4R, 5R, 6R, 8R, 10R, 12R, A4, A5, A6, LETTER, STRIP_2x6, CUSTOM.
  • toPixels(dpi: number = 300): { widthPx: number, heightPx: number } Computes pixel dimensions at 300, 600, or 1200 DPI.

PrintQueue

  • enqueue(asset: MediaAsset, options: PrintJobOptions): Promise<PrintJob> Enqueues print jobs in persistent IndexedDB with power-loss recovery.
  • processNext(): Promise<PrintJob | null> Executes the next job in the queue.
  • getQueue(): Promise<PrintJob[]> Retrieves all pending, printing, and completed print jobs.

7. Embedded GIF Engine — @nizora/media/gif

GifEngine

Pure TypeScript GIF89a encoder with LZW compression and median-cut color quantization. Zero external dependencies.

Methods:

  • encode(frames: ImageData[], options: GifEncodeOptions): Promise<Blob> Encodes raw frame pixel arrays into an animated GIF.
    • options.delay (ms per frame, default: 100)
    • options.repeat (0 for loop forever, -1 for no loop)
    • options.quality (1 = highest quality / slower, 10 = standard)

BurstGif

  • createFromAssets(assets: MediaAsset[], options?: GifOptions): Promise<MediaAsset> Turns a burst photo sequence into a looping GIF MediaAsset.

8. Video Recording — @nizora/media/video

VideoRecorder

  • start(stream: MediaStream, options?: VideoRecordOptions): void Begins recording live video with automatic codec negotiation (video/webm;codecs=vp9, vp8, h264, mp4).
  • pause(): void: Pauses active recording.
  • resume(): void: Resumes paused recording.
  • stop(): Promise<MediaAsset>: Stops recording and returns video MediaAsset.

9. Persistent Storage and Sessions — @nizora/media/storage

MediaStorage

IndexedDB binary media storage engine.

  • saveAsset(asset: MediaAsset): Promise<string>: Stores media blob.
  • getAsset(id: string): Promise<MediaAsset | null>: Retrieves media by ID.
  • deleteAsset(id: string): Promise<void>: Deletes media record.
  • clear(): Promise<void>: Clears storage partition.

SessionManager

Groups media assets into photobooth customer sessions.

  • createSession(metadata?: Record<string, any>): Promise<Session>
  • addAssetToSession(sessionId: string, asset: MediaAsset): Promise<void>
  • getSession(sessionId: string): Promise<Session | null>
  • cleanupOldSessions(maxAgeMs: number): Promise<number>

10. License and Feature Gating — @nizora/media/license

LicenseManager

  • activate(licenseKey: string, options?: LicenseOptions): Promise<LicenseStatus> Validates RSA-2048 signature, queries authorization servers, and configures offline grace periods.
  • requireFeature(feature: string): void Throws NizoraLicenseError if feature is not entitled under the active tier.
  • getStatus(): LicenseStatus Returns activation status, tier (basic | pro | enterprise), expiration, and offline grace deadline.

Development and Testing

# Run unit tests (102 tests across 18 test suites)
npm test

# Run tests with coverage
npm run test:coverage

# Build library bundle (ESM + CJS + .d.ts)
npm run build

# Run interactive documentation and playground
npm run docs

License

MIT (c) Nizora