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

@effing/effie-preview

v0.18.0

Published

Preview components for Effie video compositions

Readme

@effing/effie-preview

Preview components for Effie video compositions.

Part of the Effing family — programmatic video creation with TypeScript.

Preview covers, backgrounds, layers, and segments before rendering. Uses @effing/annie-player for animation playback.

Installation

npm install @effing/effie-preview @effing/effie @effing/annie-player

Quick Start

React

React components are available in @effing/effie-preview/react.

Simple API (built-in styles)

import { createEffieSourceResolver } from "@effing/effie-preview";
import {
  EffieCoverPreview,
  EffieBackgroundPreview,
  EffieSegmentPreview,
} from "@effing/effie-preview/react";

function EffiePreview({ effieJson, renderedVideoUrl }) {
  const resolveSource = createEffieSourceResolver(effieJson.sources);

  return (
    <div>
      <h2>Cover</h2>
      <EffieCoverPreview cover={effieJson.cover} video={renderedVideoUrl} />

      <h2>Background</h2>
      <EffieBackgroundPreview
        background={effieJson.background}
        resolveSource={resolveSource}
      />

      <h2>Segments</h2>
      {effieJson.segments.map((segment, i) => (
        <EffieSegmentPreview
          key={i}
          segment={segment}
          index={i}
          resolveSource={resolveSource}
        />
      ))}
    </div>
  );
}

Compound API (full control)

For custom layouts, use the compound sub-components:

import {
  EffieBackgroundPreview,
  EffieSegmentPreview,
  EffieLayerPreview,
} from "@effing/effie-preview/react";

function CustomLayout({ effieJson }) {
  const resolveSource = createEffieSourceResolver(effieJson.sources);

  return (
    <div>
      {/* Background with custom layout */}
      <EffieBackgroundPreview.Root style={{ display: "grid", gap: "2rem" }}>
        <EffieBackgroundPreview.Media
          background={effieJson.background}
          resolveSource={resolveSource}
          style={{ height: 300, objectFit: "cover" }}
        />
        <EffieBackgroundPreview.Info
          background={effieJson.background}
          style={{ fontSize: "0.9rem" }}
        />
      </EffieBackgroundPreview.Root>

      {/* Segments with custom layer layout */}
      {effieJson.segments.map((segment, i) => (
        <EffieSegmentPreview.Root key={i} style={{ padding: "2rem" }}>
          <EffieSegmentPreview.Header style={{ fontWeight: 700 }}>
            Segment {i + 1} — {segment.duration}s
          </EffieSegmentPreview.Header>
          <EffieSegmentPreview.Layers
            style={{ display: "grid", gridTemplateColumns: "repeat(2, 1fr)" }}
          >
            {segment.layers.map((layer, j) => (
              <EffieLayerPreview.Root key={j}>
                <EffieLayerPreview.Media
                  layer={layer}
                  index={j}
                  resolveSource={resolveSource}
                  resolution={{ width: 356, height: 200 }}
                />
                <EffieLayerPreview.Info layer={layer} index={j} />
              </EffieLayerPreview.Root>
            ))}
          </EffieSegmentPreview.Layers>
        </EffieSegmentPreview.Root>
      ))}
    </div>
  );
}

Concepts

Source Resolution

Effie compositions can reference sources by name (#mySource) instead of full URLs. The preview components use a source resolver to look up these references:

import { createEffieSourceResolver } from "@effing/effie-preview";

const resolve = createEffieSourceResolver(effieJson.sources);
resolve("#background"); // Returns the actual URL
resolve("https://..."); // Returns as-is

API Overview

Core

createEffieSourceResolver(sources?)

Create a function that resolves source references:

function createEffieSourceResolver(sources?: EffieSources): EffieSourceResolver;

type EffieSourceResolver = (src: string) => string;

React Components

All preview components support both simple and compound usage patterns.

EffieVideoPreview

Standalone video player that streams a video via MSE (with blob fallback) so the entire file is buffered in memory. This avoids follow-up network requests on seek, which is critical for one-time-consumption URLs like FFS render endpoints.

<EffieVideoPreview
  url={string}                // Video URL to stream
  poster={string}             // Optional poster image URL
  onPlay={() => void}         // Callback when video starts playing
  onFullyBuffered={() => void} // Callback when video is fully buffered
  className={string}          // Class name for the video element
  style={CSSProperties}       // Style for the video element
/>

EffieCoverPreview

Display the cover image, or a video player if a rendered video is available. Uses EffieVideoPreview internally when a video URL is provided.

<EffieCoverPreview
  cover={EffieWebUrl}         // Cover image URL
  resolution={{ width, height }} // Preview resolution
  video={string | null}       // Optional rendered video URL
  onPlay={() => void}         // Callback when video starts playing
  onFullyBuffered={() => void} // Callback when video is fully buffered
  className={string}          // Class name for img/video element
  style={CSSProperties}       // Style for img/video element
/>

EffieBackgroundPreview

Preview the composition background (color, image, or video).

Simple:

<EffieBackgroundPreview
  background={EffieBackground}
  resolveSource={EffieSourceResolver}
  resolution={{ width, height }}
  className={string}
  style={CSSProperties}
/>

Compound:

<EffieBackgroundPreview.Root className={string} style={CSSProperties}>
  <EffieBackgroundPreview.Media
    background={EffieBackground}
    resolveSource={EffieSourceResolver}
    className={string}
    style={CSSProperties}
  />
  <EffieBackgroundPreview.Info
    background={EffieBackground}
    className={string}
    style={CSSProperties}
  />
</EffieBackgroundPreview.Root>

EffieSegmentPreview

Preview a segment with all its layers. The stacking prop controls how layers are arranged:

  • "vertical" (default): layers stack vertically, info beside each layer
  • "horizontal": layers flow horizontally, info below each layer

Simple:

<EffieSegmentPreview
  segment={EffieSegment}
  index={number}
  resolveSource={EffieSourceResolver}
  resolution={{ width, height }}
  stacking={"vertical" | "horizontal"} // Default: "vertical"
  className={string}
  style={CSSProperties}
/>

Compound:

<EffieSegmentPreview.Root className={string} style={CSSProperties}>
  <EffieSegmentPreview.Header className={string} style={CSSProperties}>
    {children}
  </EffieSegmentPreview.Header>
  <EffieSegmentPreview.Layers className={string} style={CSSProperties}>
    {children}
  </EffieSegmentPreview.Layers>
</EffieSegmentPreview.Root>

EffieLayerPreview

Preview a single layer (image or animation). The stacking prop controls layout:

  • "horizontal" (default): info beside media (flex row)
  • "vertical": info below media (flex column)

Simple:

<EffieLayerPreview
  layer={EffieLayer}
  index={number}
  resolveSource={EffieSourceResolver}
  resolution={{ width, height }}
  stacking={"vertical" | "horizontal"} // Default: "horizontal"
  className={string}
  style={CSSProperties}
/>

Compound:

<EffieLayerPreview.Root className={string} style={CSSProperties}>
  <EffieLayerPreview.Media
    layer={EffieLayer}
    index={number}
    resolveSource={EffieSourceResolver}
    resolution={{ width, height }}
    className={string}
    style={CSSProperties}
  />
  <EffieLayerPreview.Info
    layer={EffieLayer}
    index={number}
    className={string}
    style={CSSProperties}
  />
</EffieLayerPreview.Root>

For animation layers, EffieLayerPreview.Media renders an AnniePlayer with load/play controls.

Validation Errors

parseEffieValidationIssues(issues)

Parse validation issues from an error response:

import { parseEffieValidationIssues } from "@effing/effie-preview";

const response = await fetch("ffs.example.com/render", {
  method: "POST",
  body,
});
if (!response.ok) {
  const errorBody = await response.json();
  const issues = parseEffieValidationIssues(errorBody.issues);
  // issues: EffieValidationIssue[] | undefined
}

EffieValidationErrors

Display validation errors with detailed issue breakdown:

import { EffieValidationErrors } from "@effing/effie-preview/react";

<EffieValidationErrors
  error={string}                    // Error message (e.g., "Invalid effie data")
  issues={EffieValidationIssue[]}   // Optional list of validation issues
  className={string}
  style={CSSProperties}
/>

Each EffieValidationIssue contains:

  • path — Path to the field that failed validation (e.g., "segments.0.transition.sweep")
  • message — Human-readable error message

Related Packages