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

@theclearsky/react-blender-nodes

v0.0.11

Published

A React component library inspired by Blender's node editor interface, providing a flexible and customizable node-based graph editor for web applications.

Readme

React Blender Nodes Banner

Quick Links

  • Storybook - Interactive examples and component playground
  • NPM - Install and use in your project
  • GitHub Issues - Report bugs and issues
  • GitHub Discussions - Request features and discuss ideas

Overview

React Blender Nodes recreates the iconic Blender node editor experience on the web. Built with modern React patterns and TypeScript, it offers a complete solution for creating interactive node-based interfaces with support for custom nodes, connections, and real-time manipulation. Features an intelligent type system with automatic inference, complex data validation, and comprehensive connection validation to ensure your node graphs are always type-safe and error-free.

Quick Start

Installation

npm install @theclearsky/react-blender-nodes

Basic Usage

import {
  FullGraph,
  useFullGraph,
  makeStateWithAutoInfer,
  makeTypeOfNodeWithAutoInfer,
  makeDataTypeWithAutoInfer,
} from 'react-blender-nodes';
import 'react-blender-nodes/style.css';

function MyNodeEditor() {
  // Define data types with auto-infer for type safety
  const dataTypes = {
    stringType: makeDataTypeWithAutoInfer({
      name: 'String',
      underlyingType: 'string',
      color: '#4A90E2',
    }),
    numberType: makeDataTypeWithAutoInfer({
      name: 'Number',
      underlyingType: 'number',
      color: '#7ED321',
    }),
  };

  // Define node types with auto-infer for type safety
  const typeOfNodes = {
    inputNode: makeTypeOfNodeWithAutoInfer({
      name: 'Input Node',
      headerColor: '#C44536',
      inputs: [
        { name: 'Text Input', dataType: 'stringType', allowInput: true },
        { name: 'Number Input', dataType: 'numberType', allowInput: true },
      ],
      outputs: [{ name: 'Output', dataType: 'stringType' }],
    }),
  };

  // Create state with auto-infer for complete type safety
  const initialState = makeStateWithAutoInfer({
    dataTypes,
    typeOfNodes,
    nodes: [],
    edges: [],
  });

  const { state, dispatch } = useFullGraph(initialState);

  return (
    <div style={{ height: '600px', width: '100%' }}>
      <FullGraph state={state} dispatch={dispatch} />
    </div>
  );
}

Type Safety with Auto-Infer Helpers

The auto-infer helper functions are essential for type safety in React Blender Nodes. They ensure TypeScript can properly validate type references throughout your graph system:

  • makeDataTypeWithAutoInfer: Validates data type definitions
  • makeTypeOfNodeWithAutoInfer: Validates node type definitions and dataType references
  • makeStateWithAutoInfer: Provides complete type inference for the entire state

Why use them?

  • Compile-time validation: Catch errors before runtime
  • IDE support: Better autocomplete and IntelliSense
  • Refactoring safety: TypeScript ensures consistency when renaming types
  • Runtime safety: Prevents invalid type references

Without auto-infer helpers:

// ❌ No type validation - errors only caught at runtime
const dataTypes = {
  stringType: { name: 'String', underlyingType: 'string', color: '#4A90E2' },
};

With auto-infer helpers:

// ✅ Full type validation - errors caught at compile time
const dataTypes = {
  stringType: makeDataTypeWithAutoInfer({
    name: 'String',
    underlyingType: 'string',
    color: '#4A90E2',
  }),
};

Features

🎨 Blender-Inspired Interface

Blender Interface

  • Authentic dark theme matching Blender's node editor
  • Familiar interactions and visual design
  • Smooth animations and transitions

🔧 Customizable Nodes

Customizable Nodes

  • Dynamic inputs and outputs with custom shapes
  • Collapsible input panels for complex configurations
  • Interactive input components (text, number sliders)
  • Custom handle shapes (circle, square, diamond, star, etc.)

🎮 Interactive Graph Editor

Interactive Graph

  • Pan, zoom, and select nodes with intuitive controls
  • Drag and drop node connections
  • Context menu for adding new nodes
  • Real-time node manipulation

🧠 Smart Type System & Validation + Advanced Features

https://github.com/user-attachments/assets/72d9384a-e9ca-4223-906a-dc422fb66f49

  • Intelligent Type Inference: Automatically infer node types from connections
    • Dynamic type resolution as you build your graph
    • Real-time type updates when connections change
    • Support for inferFromConnection data types
  • Advanced Type Validation: Comprehensive type checking system
    • Complex Type Checking: Zod schema validation for complex data structures
    • Type Conversion Control: Fine-grained control over allowed type conversions
    • Cycle Detection: Prevent infinite loops in your node graphs
  • Multiple Data Types: Support for diverse data structures
    • Basic types: string, number, boolean
    • Complex types: Custom objects with Zod schemas
    • Special types: inferFromConnection, noEquivalent
  • Runtime Safety: Catch type errors before they break your application
    • Connection validation with detailed error messages
    • Automatic type propagation across connected nodes
    • Schema compatibility checking for complex types
  • State Management: Integrated reducer for managing graph state
  • TypeScript Support: Full type safety with comprehensive definitions

🚀 Node Runner — Execute Your Graphs

Runner Panel with Timeline

Turn your node graphs into executable programs. The built-in runner compiles your graph into an execution plan and runs it — with full debugging support.

  • Two execution modes:
    • Instant: Runs the entire graph at once, then replay via the timeline
    • Step-by-step: Pause after each node, manually advance with step/resume
  • Execution timeline: Multi-track timeline visualization showing each node's execution as a block, grouped by concurrency level
    • Scrubber with drag-to-seek and snap-to-step
    • Zoom, pan, and auto-fit controls
    • Wall-clock and execution-time display modes (strips out pause/debug overhead)
    • Auto-scroll follows the current step during live execution
  • Step inspector: Click any timeline block to inspect a step's input values, output values, timing, errors, and loop/group context
  • Visual node states: Nodes on the canvas highlight in real time as idle, running, completed, skipped, or errored

Step-by-step Debugging

  • Loop support: Define iterative computation with loop-start/stop/end node triplets — the runner compiles loop bodies into LoopExecutionBlocks with per-iteration recording and configurable max-iteration limits
  • Node groups: Compose subgraphs into reusable group nodes — the compiler recursively resolves group subtrees into GroupExecutionScopes
  • Execution recording: Every run produces a full ExecutionRecord with per-step timing, input/output snapshots, and loop iteration details — export and import recordings as JSON for sharing and offline analysis

Loop Execution Timeline

Usage

import { FullGraph, useFullGraph } from 'react-blender-nodes';
import { makeFunctionImplementationsWithAutoInfer } from 'react-blender-nodes';

// Define what each node type does when executed
const functionImplementations = makeFunctionImplementationsWithAutoInfer({
  myNodeType: async ({ inputs }) => {
    // Process inputs and return outputs
    return { outputHandle: inputs.inputHandle * 2 };
  },
});

// Pass implementations to FullGraph to enable the runner
<FullGraph
  state={state}
  dispatch={dispatch}
  functionImplementations={functionImplementations}
/>;

useNodeRunner Hook

For advanced control over graph execution, use the useNodeRunner hook directly instead of relying on the built-in runner UI:

import { FullGraph, useFullGraph, useNodeRunner } from 'react-blender-nodes';

function MyExecutableGraph() {
  const { state, dispatch } = useFullGraph(initialState);

  const {
    // State
    runnerState, // 'idle' | 'compiling' | 'running' | 'paused' | 'completed' | 'errored'
    nodeVisualStates, // Map<nodeId, 'idle' | 'running' | 'completed' | 'errored' | 'skipped'>
    executionRecord, // Full execution recording with per-step timing and I/O snapshots
    currentStepIndex, // Index of the currently active/viewed step

    // Actions
    run, // Start execution (mode-aware: instant or step-by-step)
    pause, // Pause during step-by-step execution
    resume, // Resume paused step-by-step execution
    step, // Advance one step (starts a new run if idle)
    stop, // Abort the current execution
    reset, // Clear all execution state back to idle
    replayTo, // Seek to a specific step index in a completed recording
    loadRecord, // Load an imported ExecutionRecord (validates against current graph)

    // Settings
    mode, // Current execution mode: 'instant' | 'stepByStep'
    setMode, // Switch execution mode
    maxLoopIterations, // Max iterations before a loop is force-stopped
    setMaxLoopIterations,
  } = useNodeRunner({
    state,
    functionImplementations,
    options: { maxLoopIterations: 100 },
  });

  return (
    <div>
      <button onClick={run}>Run</button>
      <button onClick={step}>Step</button>
      <button onClick={pause}>Pause</button>
      <button onClick={resume}>Resume</button>
      <button onClick={stop}>Stop</button>
      <button onClick={reset}>Reset</button>
      <p>Status: {runnerState}</p>
      <FullGraph state={state} dispatch={dispatch} />
    </div>
  );
}

Import/Export & Automatic Repair

Graph state and execution recordings can be exported to JSON and re-imported later. On import, the library validates the structure and can automatically repair common issues via opt-in repair strategies.

State Import Repair Strategies

Pass a repair object to importGraphState to enable automatic fixes:

import { importGraphState } from 'react-blender-nodes';

const result = importGraphState(json, {
  dataTypes: myDataTypes,
  typeOfNodes: myTypeOfNodes,
  repair: {
    removeOrphanEdges: true, // Remove edges whose source or target node doesn't exist
    removeDuplicateNodeIds: true, // Deduplicate nodes with the same ID (keep first)
    removeDuplicateEdgeIds: true, // Deduplicate edges with the same ID (keep first)
    fillMissingDefaults: true, // Fill missing optional fields (viewport, etc.) with defaults
    rehydrateDataTypeObjects: true, // Rebuild handle dataType objects from provided dataTypes
  },
});

if (result.success) {
  // result.data is the repaired State
  // result.warnings contains info about what was repaired
} else {
  // result.errors contains fatal validation issues
}

Recording Import Repair Strategies

Pass a repair object to importExecutionRecord for recording-specific fixes:

import { importExecutionRecord } from 'react-blender-nodes';

const result = importExecutionRecord(json, {
  repair: {
    sanitizeNonSerializableValues: true, // Replace non-serializable values with "[non-serializable]"
    removeOrphanSteps: true, // Remove steps referencing nodes not present in the record
  },
});

All repair strategies default to false and must be explicitly enabled.

Usage Examples

Smart Type System with Validation

import { z } from 'zod';

// Define complex data types with Zod schemas
const userSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.string().email(),
});

const dataTypes = {
  stringType: makeDataTypeWithAutoInfer({
    name: 'String',
    underlyingType: 'string',
    color: '#4A90E2',
  }),
  userType: makeDataTypeWithAutoInfer({
    name: 'User',
    underlyingType: 'complex',
    complexSchema: userSchema,
    color: '#7ED321',
  }),
  inferredType: makeDataTypeWithAutoInfer({
    name: 'Inferred',
    underlyingType: 'inferFromConnection',
    color: '#FF6B6B',
  }),
};

// Enable advanced validation features
const initialState = makeStateWithAutoInfer({
  dataTypes,
  typeOfNodes: {
    userInput: makeTypeOfNodeWithAutoInfer({
      name: 'User Input',
      inputs: [{ name: 'User Data', dataType: 'userType' }],
      outputs: [{ name: 'Output', dataType: 'inferredType' }],
    }),
    stringProcessor: makeTypeOfNodeWithAutoInfer({
      name: 'String Processor',
      inputs: [{ name: 'Input', dataType: 'inferredType' }],
      outputs: [{ name: 'Result', dataType: 'stringType' }],
    }),
  },
  nodes: [],
  edges: [],
  // Enable smart validation features
  enableTypeInference: true,
  enableComplexTypeChecking: true,
  enableCycleChecking: true,
  allowedConversionsBetweenDataTypes: {
    userType: { stringType: true }, // Allow user to string conversion
  },
});

Custom Node with Panels

const customNode = {
  id: 'advanced-node',
  type: 'configurableNode',
  position: { x: 100, y: 100 },
  data: {
    name: 'Advanced Processor',
    headerColor: '#2D5A87',
    inputs: [
      {
        id: 'direct-input',
        name: 'Direct Input',
        type: 'string',
        handleColor: '#00BFFF',
        allowInput: true,
      },
      {
        id: 'settings-panel',
        name: 'Settings Panel',
        inputs: [
          {
            id: 'threshold',
            name: 'Threshold',
            type: 'number',
            handleColor: '#96CEB4',
            allowInput: true,
            handleShape: 'diamond',
          },
          {
            id: 'config',
            name: 'Configuration',
            type: 'string',
            handleColor: '#00FFFF',
            allowInput: true,
            handleShape: 'star',
          },
        ],
      },
    ],
    outputs: [
      {
        id: 'result',
        name: 'Result',
        type: 'string',
        handleColor: '#FECA57',
        handleShape: 'hexagon',
      },
    ],
  },
};

Handle Shapes Showcase

// Available handle shapes
const handleShapes = [
  'circle', // Default circular handle
  'square', // Square handle
  'rectangle', // Tall rectangle
  'diamond', // 45° rotated square
  'hexagon', // Regular hexagon
  'star', // 5-pointed star
  'cross', // Plus/cross shape
  'list', // Three horizontal bars
  'grid', // 2x2 grid of squares
  'trapezium', // Trapezoid shape
  'zigzag', // Zigzag pattern
  'sparkle', // Sparkle effect
  'parallelogram', // Parallelogram shape
];

Context Menu Integration

// Right-click anywhere on the graph to open context menu
// Automatically generates "Add Node" menu with all available node types
// Clicking a node type adds it at the cursor position

🎨 Styling

The library uses Tailwind CSS for styling and provides a dark theme that matches Blender's aesthetic:

/* Import the default styles */
@import 'react-blender-nodes/style.css';

/* Customize colors using CSS variables */
:root {
  --primary-black: #181818;
  --primary-dark-gray: #272727;
  --primary-gray: #3f3f3f;
  --primary-white: #ffffff;
}

📚 Documentation

Interactive Documentation

Explore all components with live examples:

npm run storybook

Visit http://localhost:6006 to see:

  • Component playgrounds
  • Interactive controls
  • Usage examples
  • Handle shape demonstrations

Architecture & Internal Documentation

For contributors and developers building on the library internals, a full documentation index is available at docs/index.md. It includes an ASCII architecture diagram, cross-feature dependency maps, and a "What to Read Based on What You're Building" guide:

| Task | Key Docs | | ---------------------------- | --------------------------------------------------------------------------- | | Adding a new data type | dataTypesDoc, handlesDoc, typeInferenceDoc, connectionValidationDoc | | Adding a new node type | nodesDoc, handlesDoc, configurableNodeDoc, stateManagementDoc | | Making nodes executable | runnerCompilerDoc, runnerExecutorDoc, runnerHookDoc | | Building node groups / loops | nodeGroupsDoc, loopsDoc, connectionValidationDoc | | Modifying graph editor UI | fullGraphDoc, configurableNodeDoc, contextMenuDoc | | Working with state/reducer | stateManagementDoc, immerDoc, edgesDoc |

See the full index for all 32 feature docs with relative links organized by tier.

Component API

FullGraph

The main graph editor component with full ReactFlow integration.

interface FullGraphProps {
  /** The current state of the graph including nodes, edges, and type definitions */
  state: State;
  /** Dispatch function for updating the graph state */
  dispatch: Dispatch;
  /** Function implementations for each node type, enables the runner when provided */
  functionImplementations?: FunctionImplementations;
  /** Called when state is successfully imported. Receives the raw parsed state. */
  onStateImported?: (importedState: State) => void;
  /** Called when a recording is successfully imported. Receives the parsed ExecutionRecord. */
  onRecordingImported?: (record: ExecutionRecord) => void;
  /** Called when import validation fails. Receives the error messages. */
  onImportError?: (errors: string[]) => void;
  /** Controlled execution record. When provided, FullGraph uses this instead of internal state. */
  executionRecord?: ExecutionRecord | null;
  /** Called whenever the execution record changes (run completes, reset, load, etc.). */
  onExecutionRecordChange?: (record: ExecutionRecord | null) => void;
}

ConfigurableNode

Customizable node component with dynamic inputs and outputs.

interface ConfigurableNodeProps {
  /** Unique identifier for the node (shown when enableDebugMode is true) */
  id?: string;
  /** Display name of the node */
  name?: string;
  /** Background color of the node header */
  headerColor?: string;
  /** Array of inputs and input panels */
  inputs?: (ConfigurableNodeInput | ConfigurableNodeInputPanel)[];
  /** Array of output sockets */
  outputs?: ConfigurableNodeOutput[];
  /** Whether the node is currently inside a ReactFlow context */
  isCurrentlyInsideReactFlow?: boolean;
  /** Props for the node resizer component */
  nodeResizerProps?: NodeResizerWithMoreControlsProps;
  /** Node type unique id */
  nodeTypeUniqueId?: string;
  /** Whether to show the node open button (used by node groups) */
  showNodeOpenButton?: boolean;
  /** Runner visual state for this node (undefined = no runner overlay) */
  runnerVisualState?: NodeVisualState;
  /** Errors from the runner for this node */
  runnerErrors?: ReadonlyArray<GraphError>;
  /** Warnings from the runner for this node */
  runnerWarnings?: ReadonlyArray<string>;
}

🔗 Links

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details on:

  • Setting up the development environment
  • Code style and conventions
  • Submitting pull requests
  • Reporting issues

📄 License

MIT License - see LICENSE for details.

🙏 Acknowledgments

  • Blender Foundation: For creating the amazing Blender software that inspired this project
  • ReactFlow: For providing the foundation for the graph editor functionality
  • Shadcn/ui: For the component design system and utilities

Note: This project is not affiliated with Blender Foundation. If you find Blender useful, consider donating to support their work.


Made with ❤️ for the Blender and React communities