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

@aarpaardev/stix-visualizer

v1.3.2

Published

STIX Visualizer is a React-based, enhanced version of the OASIS CTI STIX Visualization project. It offers interactive canvas-based rendering of STIX 2.0 bundles with support for custom nodes, links, labels, and complete styling and behavior control.

Readme

📦 STIX Visualizer

STIX Visualizer is a React-based, enhanced version of the OASIS CTI STIX Visualization project. It offers interactive canvas-based rendering of STIX 2.0 bundles with support for custom nodes, links, labels, and complete styling and behavior control.


🚀 Features

  • Visualizes STIX 2.x bundles
  • Canvas-based performance with directional links and animations
  • Fully customizable via props
  • Optional legends with configurable positions
  • Zoom/hover/click event hooks
  • Storybook integration for isolated component previews

🚧 Try it out / Live Demo

You can interact with the live Storybook demo and explore props such as node interaction and neighbor customization on hover:

Live preview:
Open the demo on Storybook


📦 Installation

npm install @aarpaardev/stix-visualizer
# or
yarn add @aarpaardev/stix-visualizer

🔰 Usage

🧩 React (via npm/yarn)

import React, { useEffect, useState } from 'react';
import { Stix2Visualizer } from '@aarpaardev/stix-visualizer';

export default function App() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('https://raw.githubusercontent.com/aarpaardev/stix2-visualizer/main/src/examples/MandiantAPT1Report.json')
      .then(res => res.json())
      .then(setData);
  }, []);

  if (!data) return <div>Loading...</div>;

  return <Stix2Visualizer data={data} />;
}

🌐 HTML (via CDN/UMD)

<!DOCTYPE html>
<html>

<head>
  <title>STIX Visualizer Test</title>
  <!-- React & ReactDOM -->
  <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>

    <!-- UMD Bundle of Stix Visualizer -->
  <script src="https://unpkg.com/@aarpaardev/stix-visualizer@latest/dist/index.min.js"></script>
</head>

<body>
  <div id="root"></div>

  <script>

    // Load a STIX2 JSON file
    fetch('https://raw.githubusercontent.com/aarpaardev/stix2-visualizer/main/src/examples/MandiantAPT1Report.json')
      .then(res => res.json())
      .then(json => {
        props = { data: json };

        const Visualizer = window.AaarPaarDevStixVisualizer.Stix2Visualizer;
        ReactDOM.render(React.createElement(Visualizer, props), document.getElementById('root'));
      });
  </script>
</body>

</html>

🧩 Props

Stix2VisualizerProps

| Prop | Type | Required | Description | |--------------------|------------------------|----------|-------------| | data | StixBundle \| object | ✅ | A valid STIX 2.x Bundle JSON object that defines the entities and relationships to be visualized. Refer to this sample STIX bundle for reference. | | height | number | ❌ | Height of canvas (default is undefined)| | width | number | ❌ | With of canvas (default is undefined)| | nodeOptions | INodeOptions | ❌ | Configuration for visual node appearance (e.g., color, radius, interactivity). See table below. | | nodeOptions | INodeOptions | ❌ | Configuration for visual node appearance (e.g., color, radius, interactivity). See table below. | | linkOptions | ILinkOptions | ❌ | Configuration for link appearance and behavior. See table below. | | noiseOptions | INoiseOptions | ❌ | Configuration for noise options (e.g., "object_refs" relations with "Report" object). See table below. | | legendOptions | ILegendOptions | ❌ | Options for showing and positioning the legend. See table below. | | directionOptions | ILinkDirectionOptions| ❌ | Defines directional indicators on links like arrows and particles. See table below. | | linkLabelOptions | ILabelOptions | ❌ | Options for displaying text labels on links. See table below. | | nodeLabelOptions | ILabelOptions | ❌ | Options for displaying text labels on nodes. See table below. |

nodeOptions Props

| Property | Type | Default | Description | | -------------------- | -------------------------------- | ------------- | ---------------------------------------------------------------------------- | | size | number | 12 | Node size in pixels. | | disableZoomOnClick | boolean | false | Disables zoom behavior on node click. | | onHover | (node, ctx, neighbors) => void | (See below) | Callback for when a node is hovered. Highlights neighboring nodes. | | onClick | (node, ref?) => void | undefined | Callback for when a node is clicked. You can access the graph ref if needed. |

Default onHover
/**
 * @param {NodeObject} node Node Object
 * @param {CanvasRenderingContext2D} ctx node canvas context
 * @param {Set<NodeObject>} neighbors node canvas context
 */
(node: NodeObject, ctx: CanvasRenderingContext2D, neighbors: Set<NodeObject>) => {
  Array.from(neighbors.values()).forEach((neighbor: NodeObject) => {
    /**
     *
     * @param {CanvasRenderingContext2D} neighCtx node canvas context
     * @param {number} x starting x-axis position of node
     * @param {number} y starting y-axis position of node
     */
    neighbor.drawHighlight = (
      neighCtx: CanvasRenderingContext2D,
      x: number,
      y: number
    ): void => {
      neighCtx.beginPath();
      neighCtx.arc(x, y, 10, 0, Math.PI * 2); // full circle
      neighCtx.fillStyle = 'rgba(182, 181, 181, 0.5)';
      neighCtx.fill();
      neighCtx.stroke();
    };
  });
  node.links?.forEach((link: LinkObject) => {
    link.particleWidth = 4;
  });
  if (node.img && node.x && node.y) {
    ctx.drawImage(node.img, node.x - 20 / 2, node.y - 20 / 2, 20, 20);
  }
}

linkOptions Props

| Prop | Type | Default | Description | | -------------------- | ----------------------------------------------------------- | --------------------------------- | ----------------------------------------------------------------- | | width | number | (link: LinkObject) => number | 1 | Width of the link line or a function to calculate it dynamically. | | curvature | number | 0.25 | Controls how curved the link lines are. | | distance | number | 60 | Distance between connected nodes. | | color | string | 'rgba(126,126,126, 0.6)' | Stroke color of the link. | | disableZoomOnClick | boolean | false | Prevents zoom on link click if set to true. | | onHover | (link: LinkObject, ctx: CanvasRenderingContext2D) => void | (See below) | Callback invoked when hovering over a link. | | onClick | (link: LinkObject, ref?: ReactForceRef) => void | undefined | Callback invoked when clicking a link. |

Default onHover
/**
 * @param {LinkObject} link link Object
 * @param {CanvasRenderingContext2D} ctx node canvas context
 */
(link: LinkObject, ctx: CanvasRenderingContext2D) => {
  ctx.strokeStyle = 'rgba(36, 35, 35, 0.6)';
  ctx.stroke();

  /**
   *
   * @param {CanvasRenderingContext2D} neighCtx node canvas context
   * @param {number} x starting x-axis position of node
   * @param {number} y starting y-axis position of node
   */
  const drawHighlightFunc = (
    neighCtx: CanvasRenderingContext2D,
    x: number,
    y: number
  ): void => {
    neighCtx.beginPath();
    neighCtx.arc(x, y, 10, 0, Math.PI * 2); // full circle
    neighCtx.fillStyle = 'rgba(182, 181, 181, 0.5)';
    neighCtx.fill();
    neighCtx.stroke();
  };
  if (link.source) {
    (link.source as NodeObject).drawHighlight = drawHighlightFunc;
  }
  if (link.target) {
    (link.target as NodeObject).drawHighlight = drawHighlightFunc;
  }
}

noiseOptions Props

| Prop | Type | Default | Description | |-----------------|----------------------------|---------------|---------------------------------------------------------------------------------------------| | ignoreReportObjectRefs | boolean | true | Whether to show the "object_refs" relations to "Report" object or not. |

legendOptions Props

| Prop | Type | Default | Description | |-----------------|----------------------------|---------------|---------------------------------------------------------------------------------------------| | display | boolean | true | Whether to show the legend. | | position | 'top-right' \| 'top-left' \| 'bottom-right' \| 'bottom-left' | 'top-right' | Position of the legend in the container. | | containerStyle| React.CSSProperties | undefined | Optional custom style object for the legend container.
| displayignoreReportObjectRefsCheckBox| boolean | true | Optional Checkbox to reduce noise by ignoring certain relations (see noiseOption prop). |

nodeLabelOptions Props

| Prop | Type | Default | Description | |--------------------|-----------------|--------------------------------|-------------------------------------------------------------------| | font | string | undefined | Font family to use for labels (e.g., 'Arial', 'Roboto'). | | fontSize | number | 4 | Size of the label font. | | backgroundColor | string | undefined | Optional background color behind the label. | | color | string | 'rgba(39, 37, 37, 0.9)' | Color of the label text. | | display | boolean | true | Whether to display the label. | | onZoomOutDisplay | boolean | false | Whether to continue showing the label when zoomed out. |

linkLabelOptions Props

| Prop | Type | Default | Description | |--------------------|-----------------|--------------------------------|-------------------------------------------------------------------| | font | string | undefined | Font family to use for labels (e.g., 'Arial', 'Roboto'). | | fontSize | number | 4 | Size of the label font. | | backgroundColor | string | undefined | Optional background color behind the label. | | color | string | 'rgba(39, 37, 37, 0.9)' | Color of the label text. | | display | boolean | true | Whether to display the label. | | onZoomOutDisplay | boolean | false | Whether to continue showing the label when zoomed out. |

directionOptions Props

| Prop | Type | Default | Description | |--------------------------------------------|----------------------------------------------|--------------------------------|-----------------------------------------------------------------------------| | directionSize | number | (link: LinkObject) => number | 4 | Size of the arrow indicating direction. | | arrowRelativePositions | number | (link: LinkObject) => number | 0.98 | Position of the arrow relative to the link length. | | directionalParticles | number | (link: LinkObject) => number | 10 | Number of directional particles to display on a link. | | directionalParticleSize | number | (link: LinkObject) => number | 1 | Size of directional particles. | | directionalParticleSpeed | number | (link: LinkObject) => number | 0.005 | Speed of directional particles. | | directionalParticlesAndArrowColor | string | (link: LinkObject) => string | 'rgba(0, 0, 0, 0, 0)' | Color of both arrows and directional particles. | | onHoverParticlesSize | number | 4 | Size of directional particles on hover. | | onHoverArrowSize | number | undefined | Optional custom arrow size on hover. | | displayDirections | boolean | true | Whether to display link directions using arrows. | | displayParticles | boolean | true | Whether to display directional particles along the links (Greater than 0 will cause the canvas to be continuously redrawn to simulate particle motion). |

📚 Storybook

The project includes a Storybook setup for developing, testing, and showcasing components in isolation.

🔧 Run Storybook locally

To start the Storybook server:

npm run storybook

This will launch Storybook at:

http://localhost:6006

You can visually explore all customizable props, states, and interactions of the Stix2Visualizer component from there.

🧱 Interfaces & Types

ILabelOptions

interface ILabelOptions {
  font?: string;
  fontSize?: number;
  backgroundColor?: string;
  color?: string;
  display?: boolean;
  onZoomOutDisplay?: boolean;
}

Used to style and control label rendering for nodes and links.

INodeOptions

interface INodeOptions {
  size?: number;
  disableZoomOnClick?: boolean;
  onHover?: (
    node: NodeObject,
    ctx: CanvasRenderingContext2D,
    highlightedNeighbors: Set<NodeObject>
  ) => void;
  onClick?: (node: NodeObject, ref?: ReactForceRef) => void;
}

Controls how nodes behave, appear, and respond to interaction.

ILinkOptions

interface ILinkOptions {
  width?: ((link: LinkObject) => number) | number;
  curvature?: number;
  distance?: number;
  color?: string;
  disableZoomOnClick?: boolean;
  onHover?: (link: LinkObject, ctx: CanvasRenderingContext2D) => void;
  onClick?: (link: LinkObject, ref?: ReactForceRef) => void;
}

Defines link styling, interaction behavior, and rendering logic.

ILinkDirectionOptions

interface ILinkDirectionOptions {
  directionSize?: ((link: LinkObject) => number) | number;
  arrowRelativePositions?: ((link: LinkObject) => number) | number;
  directionalParticles?: ((link: LinkObject) => number) | number;
  directionalParticleSpeed?: ((link: LinkObject) => number) | number;
  directionalParticleSize?: ((link: LinkObject) => number) | number;
  directionalParticlesAndArrowColor?: ((link: LinkObject) => string) | string;
  onHoverParticlesSize?: number;
  onHoverArrowSize?: number;
  displayDirections?: boolean;
  displayParticles?: boolean;
}

Configures directional arrows and animated particles on links.

⚠️ Performance Note
If directionalParticles is greater than 0, the canvas will be continuously redrawn to simulate particle motion.
This may impact performance on large graphs. Use this option with caution.

ILegendOptions

type LegendPosition =
  | 'top-left'
  | 'top-right'
  | 'bottom-left'
  | 'bottom-right'
  | 'top-center'
  | 'bottom-center';

interface ILegendOptions {
  display?: boolean;
  position?: LegendPosition;
  containerStyle?: React.CSSProperties;
}

NodeObject

type NodeObject<NodeType = object> = NodeType & {
  id: string | number;
  img?: HTMLImageElement;
  size?: number;
  name?: string;
  val?: number;
  x?: number;
  y?: number;
  z?: number;
  vx?: number;
  vy?: number;
  vz?: number;
  fx?: number;
  fy?: number;
  fz?: number;
  draw?: (ctx: CanvasRenderingContext2D, x: number, y: number) => void;
  drawHighlight?: (ctx: CanvasRenderingContext2D, x: number, y: number) => void;
  neighbors?: Array<NodeObject>;
  links?: Array<LinkObject>;
  [others: string]: unknown;
};  

Represents a node in the visualizer. This is a generic structure and can be extended with additional fields as needed.

LinkObject

type LinkObject<NodeType = object, LinkType = object> = LinkType & {
  source?: string | number | NodeObject<NodeType>;
  target?: string | number | NodeObject<NodeType>;
  drawHighlight?: (ctx: CanvasRenderingContext2D) => void;
  particleWidth?: number;
  color?: string;
  [others: string]: unknown;
};

Defines a connection between two nodes. Can be enriched with custom properties.

🛠 Development

Follow these steps to set up the project locally for development:

🔧 Prerequisites

  • Node.js (version 20.10.0 or above recommended)
  • npm or yarn

📥 Clone the repository and run

git clone https://github.com/your-org/stix-visualizer.git
cd stix-visualizer
npm run storybook

🤝 Contributing

Contributions are welcome!

  • Fork the repository

  • Create your feature branch:

    git checkout -b feature/amazing-feature
  • Commit your changes:

    git commit -m 'Add amazing feature'
  • Push to the branch:

    git push origin feature/amazing-feature
  • Open Pull Request