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 🙏

© 2025 – Pkg Stats / Ryan Hefner

vivid--compose-layers-preview

v1.2.1

Published

Isolated React + TypeScript component for previewing composed image layers with status handling.

Downloads

46

Readme

ComposeLayersPreview

Universal React component for previewing composite image layers with support for different states (loading, success, error, empty).

Works in two ways:

  • As a normal NPM package in React apps
  • As a standalone CDN script on regular HTML pages (no React required)

Installation

NPM/Yarn

npm install vivid--compose-layers-preview
# or
yarn add vivid--compose-layers-preview

CDN (no installation required)

<!-- Standalone build: React included inside -->
<link rel="stylesheet" href="https://unpkg.com/vivid--compose-layers-preview/dist/standalone/style.css" />
<script src="https://unpkg.com/vivid--compose-layers-preview/dist/standalone/standalone.min.js"></script>

Usage

The component displays a stack of rendered image layers from a layers configuration. It handles different states (loading, success, error, empty) and allows users to preview how multiple layers combine into a final composite image. The layers are typically fetched from a render API endpoint and contain configuration data.

Important: The container element must have fixed dimensions (width and height) for the component to display correctly. The component will fill the entire container space and layer images will be positioned absolutely within it.

API Integration: This component is designed to work with configuration layer data returned by the render API endpoint https://renderapi-dev.vivid3d.tech/2d/renderConfigurationLayers. The component automatically processes the layer ordering and composites them into a visual preview based on the layerOrder property of each layer's options.

1) React applications (NPM)

import { useState, useEffect } from "react";
import { 
  ComposeLayersPreview, 
  type ComposeLayersArrT, 
  type ComposeLayerI,
  JOB_STATUSES 
} from "vivid--compose-layers-preview";

const exampleLayersData: ComposeLayersArrT = [
  {
    id: 5929,
    productId: 41,
    projectId: 2,
    type: "layer",
    status: "success",
    config: {
      stage: {
        id: 28,
        name: "M_TubyAnime",
        paramString: "",
        resourceUrl: "https://example.com/stage.pak",
      },
      camera: {
        id: 43,
        fov: 12,
        name: "Dimension",
        enabled: true,
        rotationType: "Disabled",
        nearClipPlane: 10,
        // ... other camera properties
      },
      products: [
        {
          id: 41,
          name: "Product 1",
          type: "layer",
          options: [
            {
              val: 19,
              name: "Switch",
              type: "geometry",
              layerOrder: 1,
              optionId: 8,
              // ... other option properties
            },
          ],
          projectId: 2,
          paramString: "",
          resourceUrl: "https://example.com/product.pak",
        },
      ],
      configurationHash: "11ffd93f00f849c7d2669c6d04a6a7a40f6fe163fb473e9e20c75a43eaf18cf8",
    },
    imageUrl: "https://example.com/render.png",
    thumbnailUrl: "https://example.com/thumbnail.webp",
    annotationUrl: null,
    configHash: "11ffd93f00f849c7d2669c6d04a6a7a40f6fe163fb473e9e20c75a43eaf18cf8",
    relationHash: null,
    massrenderJobId: 93,
    errorMessage: null,
    createdAt: "2025-10-03T09:30:12.762Z",
    updatedAt: "2025-10-03T09:31:45.972Z",
  },
  // Additional layers with different layerOrder values...
];

export default function MyComponent() {
  const [layers, setLayers] = useState<ComposeLayersArrT>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const fetchLayers = async () => {
    setLoading(true);
    try {
      const res = await fetch("https://renderapi-dev.vivid3d.tech/2d/renderConfigurationLayers");
      const data = await res.json();
      setLayers(data);
      setError(null);
    } catch (e) {
      setError("Failed to load layers");
    } finally {
      setLoading(false);
    }
  };

  const refreshLayers = async () => {
    fetchLayers();
  };

  useEffect(() => {
    fetchLayers();
  }, []);

  return (
    <div style={{ width: '800px', height: '600px' }}>
      <ComposeLayersPreview
        composeLayersArr={layers}
        refresh={refreshLayers}
        loading={loading}
        error={error}
        className="my-preview"
      />
    </div>
  );
}

TypeScript Types (NPM only)

When using the NPM package in TypeScript projects, you can import all the necessary types:

import { 
  ComposeLayersPreview,
  type ComposeLayersArrT,
  type ComposeLayerI,
  type ConfigI,
  type ProductI,
  type OptionI,
  type CameraI,
  type StageI,
  type TransformI,
  type PositionI,
  type RotationI,
  JOB_STATUSES
} from "vivid--compose-layers-preview";

2) Regular websites (CDN)

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>ComposeLayersPreview Demo</title>
    <link rel="stylesheet" href="https://unpkg.com/vivid--compose-layers-preview/dist/standalone/style.css" />
    <script src="https://unpkg.com/vivid--compose-layers-preview/dist/standalone/standalone.min.js"></script>
  </head>
  <body>
    <div id="preview" style="width:400px;height:300px"></div>
    <button onclick="fetchLayers()">Load Layers</button>
    <button onclick="refreshLayers()">Refresh</button>
    
    <script>
      let previewContainer = document.getElementById("preview");
      let currentLayers = [];
      let isLoading = false;
      let currentError = null;

      // Render component with current state
      function renderPreview() {
        ComposeLayersPreview.render(previewContainer, {
          composeLayersArr: currentLayers,
          refresh: refreshLayers,
          loading: isLoading,
          error: currentError,
          className: "my-preview",
        });
      }

      // Fetch layers from API
      async function fetchLayers() {
        isLoading = true;
        currentError = null;
        renderPreview();

        try {
          const response = await fetch("https://renderapi-dev.vivid3d.tech/2d/renderConfigurationLayers");
          
          if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
          }
          
          const data = await response.json();
          currentLayers = data;
          currentError = null;
        } catch (error) {
          console.error("Failed to fetch layers:", error);
          currentError = "Failed to load layers: " + error.message;
          currentLayers = [];
        } finally {
          isLoading = false;
          renderPreview();
        }
      }

      // Refresh function called by the component
      function refreshLayers() {
        fetchLayers();
      }

      // Initial render with empty state
      renderPreview();

      // Auto-load layers on page load
      fetchLayers();
    </script>
  </body>
</html>

Props

| Prop | Type | Required | Description | | ---------------- | ----------------- | -------- | --------------------------------- | | composeLayersArr | ComposeLayersArrT | Yes | Array of layer objects to display | | refresh | () => void | Yes | Trigger reloading/data fetch | | loading | boolean | No | Shows loading state | | error | string or null | No | Error text to display | | className | string | No | Extra CSS class on root |

Standalone (CDN) API

// Render component into a container element
ComposeLayersPreview.render(containerElement, props);

// Create React element (advanced)
ComposeLayersPreview.createElement(props);

// Direct access to React component
ComposeLayersPreview.ComposeLayersPreview;

Styling

This component uses CSS Modules. The safest way to customize appearance is via CSS variables on a parent element or globally:

Supported variables:

  • --content-main-color – main text color (default: #343a40)
  • --link-color – link color for the refresh action (default: #2a8efa)
  • --warning-color – error text color (default: #ff4b4b)

Example:

<div id="preview" style="--content-main-color:#222; --link-color:#0b74ff; --warning-color:#e11d48"></div>

Development

git clone https://github.com/Elementals-technical/compose-layers-preview.git
cd compose-layers-preview
npm install
npm run dev

Testing CDN Usage Locally

To test the CDN (standalone) version locally during development:

  1. Build the standalone version:

    npm run build:standalone
  2. Test with local files - Create an HTML file and use local paths:

    <!-- Use local build files -->
    <link rel="stylesheet" href="./dist/standalone/style.css" />
    <script src="./dist/standalone/standalone.min.js"></script>
  3. Test with CDN - Use the published CDN version:

    <!-- Use published CDN -->
    <link rel="stylesheet" href="https://unpkg.com/vivid--compose-layers-preview/dist/standalone/style.css" />
    <script src="https://unpkg.com/vivid--compose-layers-preview/dist/standalone/standalone.min.js"></script>
  4. Included test file - The repository includes standalone-test.html which demonstrates CDN usage with interactive examples.

    To run the test file locally:

    # Option 1: Using npx serve (recommended)
    npx serve .
    # Then open http://localhost:3000/standalone-test.html
       
    # Option 2: Using Python (if installed)
    python -m http.server 8000
    # Then open http://localhost:8000/standalone-test.html
       
    # Option 3: Using VS Code Live Server extension
    # Right-click on standalone-test.html → "Open with Live Server"

Note: When testing locally with file:// protocol, some browsers may block loading local files. Use a local server (like npx serve . or VS Code Live Server extension) for testing.