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

@happyvertical/smrt-video

v0.36.0

Published

Video content management for AI-powered video production in the SMRT ecosystem

Readme

@happyvertical/smrt-video

Video production pipeline for AI-powered video generation in the SMRT ecosystem. Models characters, performers, scenes, shots, sequences, compositions, and ComfyUI workflow templates.

Installation

pnpm add @happyvertical/smrt-video

Usage

import {
  Character,
  Performer,
  Scene,
  VideoShot,
  VideoSequence,
  VideoComposition,
  VideoShotCharacter,
  VideoWorkflow,
} from '@happyvertical/smrt-video';
import { Asset } from '@happyvertical/smrt-assets';

// Character = role being played (outfit, voice, branding)
const anchor = new Character({
  name: 'Bentley News Anchor',
  voiceProfileId: 'voice-123',
});
await anchor.save();

const seedImage = new Asset({
  name: 'Anchor Seed',
  sourceUri: 'file:///tmp/anchor-seed.png',
  mimeType: 'image/png',
});
await seedImage.save();
await anchor.addAsset(seedImage, 'seed-image');

// Performer = physical likeness for IP-Adapter face consistency
const performer = new Performer({ name: 'Alex', ipAdapterWeight: 0.85 });

// Scene = virtual background (image, video, or 360 panorama)
const studio = new Scene({
  name: 'News Studio',
  sourceType: 'image',
  projection: 'flat',
});

// Hierarchy: Composition -> Sequence -> Shot -> ShotCharacter
const composition = new VideoComposition({
  title: 'Evening News - March 2, 2026',
  fps: 30,
  width: 1920,
  height: 1080,
});
await composition.save();

const shot = new VideoShot({
  scriptText: 'Welcome to the evening news broadcast.',
  targetDuration: 30,
});
await shot.save();
// Estimated speech duration: scriptWordCount / 2.7 words per second
shot.estimatedDuration; // ~2.2 seconds
await shot.addAsset(seedImage, 'thumbnail');

// ComfyUI workflow with dynamic parameter injection
const workflow = new VideoWorkflow({
  name: 'Wan 2.6 + EchoMimic',
  workflowType: 'broadcast',
  workflowJson: comfyuiApiJson,
  nodeMapping: { seedImage: '1', audioFile: '5', outputVideo: '12' },
  requiredModels: ['wan_2.6_t2v_14b_fp8', 'echomimic_v2'],
});
await workflow.save();

// Inject runtime parameters into a deep-cloned workflow
const injected = workflow.injectParameters({
  seedImage: '/path/to/anchor.png',
  audioFile: '/path/to/tts.wav',
});

API

Models

| Export | Description | |--------|------------| | Character | Virtual persona: seed image + voice profile + branding kit | | Performer | Physical likeness for IP-Adapter FaceID consistency | | Scene | Virtual background with viewpoints, lighting, and anchor points | | VideoShot | Atomic generation unit (extends Content) with script and frame duration | | VideoShotCharacter | Junction: shot-to-character with role (primary/secondary/background) | | VideoSequence | Thematic section (extends Content) with transition type and ordering | | VideoComposition | Top-level container (extends Content): fps, resolution, render status | | VideoWorkflow | ComfyUI template with node mapping for parameter injection | | CompositeJob | Tracks a multi-step video generation job |

Collections: CharacterCollection, VideoCompositionCollection, VideoSequenceCollection, VideoShotCollection, VideoShotCharacterCollection.

Canonical owned asset joins:

  • CharacterOwnedAsset -> character_assets
  • PerformerOwnedAsset -> performer_assets
  • SceneOwnedAsset -> scene_assets
  • VideoShot, VideoSequence, and VideoComposition inherit Content asset helpers backed by content_assets

Legacy STI asset subclasses CharacterAsset, PerformerAsset, SceneAsset, VideoCompositionAsset, VideoSequenceAsset, and VideoShotAsset remain readable during migration, but new writes should go through the model helpers. Provision the new join tables with smrt db:migrate before relying on canonical writes. Reads still fall back to legacy fields / STI rows when the new tables are not present yet.

Key Types

| Export | Description | |--------|------------| | CharacterStatus | pending, ready | | BrandingConfig | Logo, colors, fonts, lower-thirds, ticker settings | | WorkflowType | prebake, broadcast, lipsync, postprod, custom | | NodeMapping | Maps semantic names (seedImage, audioFile, etc.) to ComfyUI node IDs | | RenderStatus | draft, rendering, ready, failed | | VideoShotStatus | draft, queued, processing, ready, failed, published | | TransitionType | none, fade, slide, wipe | | VideoMetadata | Duration, resolution, codec, fps, word timings | | SceneSourceType | image, video, panorama_360, panorama_180 | | VideoShotCharacterRole | primary, secondary, background |

Design Principle

Store frames, compute seconds. All duration fields use durationInFrames; convert with frames / fps. Speech duration estimated at 2.7 words/second (+/- 15% tolerance).

Asset Ownership

Character, Performer, and Scene expose getAssets(), getAssetByRole(), addAsset(), and removeAsset() on canonical noun-join tables. They continue to read legacy scalar slots and legacy STI asset rows during migration.

VideoShot, VideoSequence, and VideoComposition inherit the same helpers from Content, so their canonical ownership table is content_assets rather than a video-specific join table.

Dependencies

  • @happyvertical/smrt-core -- ORM and code generation
  • @happyvertical/smrt-assets -- base asset management
  • @happyvertical/smrt-config -- configuration loading
  • @happyvertical/smrt-content -- content models (VideoShot/Sequence/Composition extend Content)
  • @happyvertical/smrt-profiles -- profile references for characters
  • @happyvertical/smrt-tenancy -- multi-tenant scoping
  • @happyvertical/smrt-voice -- voice profile references