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

rgb-curve

v1.0.2

Published

A fast, lightweight RGB curve editor component for React - like Lightroom/Premiere Pro color grading

Readme

🎨 RGB Curve

A fast, lightweight RGB curve editor for React

Professional color grading curves like Adobe Lightroom, Premiere Pro, and Photoshop

npm version npm bundle size npm downloads license TypeScript

Demo

Demo

🚀 Live Demo📖 Full Docs🌐 Website


✨ Features

🎛️ Professional Grade

  • 4 channels: Master (RGB), Red, Green, Blue
  • Smooth cubic spline interpolation
  • Returns control points + 256-value LUT for pixel processing

🎨 Beautiful UI

  • Dark theme by default (Lightroom/Premiere Pro inspired)
  • Fully customizable via JSON style props
  • Smooth animations and interactions

⚡ Fast & Lightweight

  • Zero dependencies (only React as peer dep)
  • ~6KB gzipped
  • Optimized canvas rendering

🔧 Developer Friendly

  • Full TypeScript support
  • Comprehensive API
  • Extensive documentation

📦 Installation

Choose your preferred package manager:

# npm
npm install rgb-curve

# yarn
yarn add rgb-curve

# pnpm
pnpm add rgb-curve

# bun
bun add rgb-curve

� Table of Contents


�🚀 Quick Start

Get up and running in seconds:

import { RGBCurve } from 'rgb-curve';

function App() {
  return (
    <RGBCurve
      onChange={({ points, lut, activeChannel }) => {
        console.log('Control points:', points);
        console.log('LUT:', lut);
        console.log('Active channel:', activeChannel);
      }}
    />
  );
}

🎮 How to Use


📖 Documentation

Props API

onChange Data Structure

The onChange callback receives an object with:

interface CurveChangeData {
  // Control points for all channels
  points: {
    master: CurvePoint[];
    red: CurvePoint[];
    green: CurvePoint[];
    blue: CurvePoint[];
  };

  // Look-Up Table (256 values per channel) for pixel processing
  lut: {
    master: Uint8Array;
    red: Uint8Array;
    green: Uint8Array;
    blue: Uint8Array;
  };

  // Currently active channel
  activeChannel: 'master' | 'red' | 'green' | 'blue';
}

interface CurvePoint {
  x: number; // Input value: 0-255
  y: number; // Output value: 0-255
}

Ref Methods

Access component methods using React refs:

import { useRef } from 'react';
import { RGBCurve, RGBCurveRef } from 'rgb-curve';

function App() {
  const curveRef = useRef<RGBCurveRef>(null);

  return (
    <>
      <RGBCurve ref={curveRef} />

      <button onClick={() => curveRef.current?.reset()}>
        Reset All Channels
      </button>

      <button onClick={() => curveRef.current?.resetChannel('red')}>
        Reset Red Channel
      </button>

      <button onClick={() => {
        const lut = curveRef.current?.getLUT();
        console.log('Current LUT:', lut);
      }}>
        Get LUT Data
      </button>
    </>
  );
}

Available Methods


🎨 Styling

The component comes with a beautiful dark theme by default. You can customize every aspect using the styles prop.

Complete Styles Example

<RGBCurve
  styles={{
    // Container wrapper
    container: {
      background: '#1a1a1a',
      borderRadius: 12,
      padding: 16,
    },

    // Canvas wrapper
    canvasWrapper: {
      borderRadius: 8,
      overflow: 'hidden',
      background: '#0d0d0d',
    },

    // Grid lines
    grid: {
      color: '#2a2a2a',
      lineWidth: 1,
      subdivisions: 4,
      showDiagonal: true,
      diagonalColor: '#333333',
    },

    // Curve lines (per channel)
    curve: {
      master: {
        color: '#e0e0e0',
        width: 2,
        shadowColor: 'rgba(255, 255, 255, 0.3)',
        shadowBlur: 4,
      },
      red: {
        color: '#ff6b6b',
        width: 2,
        shadowColor: 'rgba(255, 107, 107, 0.4)',
        shadowBlur: 4,
      },
      green: {
        color: '#51cf66',
        width: 2,
        shadowColor: 'rgba(81, 207, 102, 0.4)',
        shadowBlur: 4,
      },
      blue: {
        color: '#339af0',
        width: 2,
        shadowColor: 'rgba(51, 154, 240, 0.4)',
        shadowBlur: 4,
      },
    },

    // Control points
    controlPoint: {
      radius: 6,
      fill: '#ffffff',
      stroke: '#000000',
      strokeWidth: 2,
      activeFill: '#ffd43b',
      activeStroke: '#000000',
      hoverScale: 1.2,
    },

    // Channel tabs
    tabs: {
      background: '#252525',
      borderRadius: 8,
      gap: 4,
      tab: {
        padding: '8px 16px',
        borderRadius: 6,
        fontSize: 13,
        fontWeight: 500,
        color: '#808080',
        background: 'transparent',
        hoverBackground: '#333333',
        activeColor: '#ffffff',
        activeBackground: '#404040',
      },
    },

    // Histogram (if enabled)
    histogram: {
      show: true,
      opacity: 0.3,
      fillColor: '#666666',
    },
  }}
/>

Style Reference

Container Style

container: CSSProperties

Standard React CSS properties for the outer container.

styles={{
  container: {
    background: 'linear-gradient(135deg, #1a1a2e, #16213e)',
    borderRadius: 16,
    padding: 20,
    boxShadow: '0 10px 40px rgba(0,0,0,0.5)',
  }
}}

Canvas Wrapper Style

canvasWrapper: CSSProperties

Standard React CSS properties for the canvas container.

styles={{
  canvasWrapper: {
    borderRadius: 12,
    border: '1px solid #333',
    overflow: 'hidden',
  }
}}

Grid Style

interface GridStyle {
  color?: string;        // Grid line color
  lineWidth?: number;    // Grid line width
  subdivisions?: number; // Number of grid divisions (default: 4)
  showDiagonal?: boolean; // Show diagonal baseline
  diagonalColor?: string; // Diagonal line color
}
styles={{
  grid: {
    color: '#333333',
    lineWidth: 1,
    subdivisions: 4,
    showDiagonal: true,
    diagonalColor: '#444444',
  }
}}

Curve Style

interface CurveLineStyle {
  color?: string;       // Curve line color
  width?: number;       // Curve line width
  shadowColor?: string; // Glow effect color
  shadowBlur?: number;  // Glow blur radius
}
styles={{
  curve: {
    master: { color: '#ffffff', width: 2 },
    red: { color: '#ff0000', width: 2, shadowColor: 'rgba(255,0,0,0.5)', shadowBlur: 8 },
    green: { color: '#00ff00', width: 2 },
    blue: { color: '#0088ff', width: 3 },
  }
}}

Control Point Style

interface ControlPointStyle {
  radius?: number;       // Point radius
  fill?: string;         // Point fill color
  stroke?: string;       // Point border color
  strokeWidth?: number;  // Point border width
  activeFill?: string;   // Fill when dragging
  activeStroke?: string; // Border when dragging
  hoverScale?: number;   // Scale on hover (1.2 = 120%)
}
styles={{
  controlPoint: {
    radius: 8,
    fill: '#ffffff',
    stroke: '#000000',
    strokeWidth: 2,
    activeFill: '#ffcc00',
    activeStroke: '#000000',
    hoverScale: 1.3,
  }
}}

Tabs Style

interface TabsStyle {
  background?: string;    // Tabs container background
  borderRadius?: number;  // Tabs container border radius
  gap?: number;           // Gap between tabs
  tab?: {
    padding?: string;
    borderRadius?: number;
    fontSize?: number;
    fontWeight?: number | string;
    color?: string;           // Inactive tab text color
    background?: string;      // Inactive tab background
    hoverBackground?: string; // Hover background
    activeColor?: string;     // Active tab text color
    activeBackground?: string; // Active tab background
  };
}
styles={{
  tabs: {
    background: '#1a1a1a',
    borderRadius: 10,
    gap: 8,
    tab: {
      padding: '10px 20px',
      borderRadius: 8,
      fontSize: 14,
      fontWeight: 600,
      color: '#666666',
      background: 'transparent',
      hoverBackground: '#2a2a2a',
      activeColor: '#ffffff',
      activeBackground: '#3a3a3a',
    },
  }
}}

Histogram Style

interface HistogramStyle {
  show?: boolean;     // Show/hide histogram
  opacity?: number;   // Histogram opacity (0-1)
  fillColor?: string; // Histogram bar color
}
<RGBCurve
  showHistogram={true}
  histogramData={myHistogramData} // Uint8Array of 256 values
  styles={{
    histogram: {
      opacity: 0.4,
      fillColor: '#888888',
    }
  }}
/>

🌈 Theme Examples

Light Theme

<RGBCurve
  styles={{
    container: {
      background: '#f5f5f5',
      borderRadius: 12,
      padding: 16,
    },
    canvasWrapper: {
      background: '#ffffff',
      borderRadius: 8,
      border: '1px solid #e0e0e0',
    },
    grid: {
      color: '#e0e0e0',
      diagonalColor: '#d0d0d0',
    },
    curve: {
      master: { color: '#333333', width: 2 },
      red: { color: '#e53935', width: 2 },
      green: { color: '#43a047', width: 2 },
      blue: { color: '#1e88e5', width: 2 },
    },
    controlPoint: {
      fill: '#ffffff',
      stroke: '#333333',
      activeFill: '#ffca28',
    },
    tabs: {
      background: '#e0e0e0',
      tab: {
        color: '#666666',
        activeColor: '#000000',
        activeBackground: '#ffffff',
        hoverBackground: '#eeeeee',
      },
    },
  }}
/>

Neon Theme

<RGBCurve
  styles={{
    container: {
      background: '#0a0a0a',
      borderRadius: 16,
      padding: 20,
      border: '1px solid #333',
    },
    canvasWrapper: {
      background: '#000000',
      borderRadius: 12,
    },
    grid: {
      color: '#1a1a1a',
      diagonalColor: '#2a2a2a',
    },
    curve: {
      master: {
        color: '#00ffff',
        width: 2,
        shadowColor: '#00ffff',
        shadowBlur: 10
      },
      red: {
        color: '#ff0066',
        width: 2,
        shadowColor: '#ff0066',
        shadowBlur: 10
      },
      green: {
        color: '#00ff66',
        width: 2,
        shadowColor: '#00ff66',
        shadowBlur: 10
      },
      blue: {
        color: '#0066ff',
        width: 2,
        shadowColor: '#0066ff',
        shadowBlur: 10
      },
    },
    controlPoint: {
      radius: 5,
      fill: '#ffffff',
      stroke: '#00ffff',
      strokeWidth: 2,
      activeFill: '#ff00ff',
      hoverScale: 1.4,
    },
    tabs: {
      background: '#111111',
      tab: {
        color: '#666666',
        activeColor: '#00ffff',
        activeBackground: '#1a1a1a',
        hoverBackground: '#1a1a1a',
      },
    },
  }}
/>

Minimal Theme

<RGBCurve
  styles={{
    container: {
      background: 'transparent',
      padding: 0,
    },
    canvasWrapper: {
      background: '#1a1a1a',
      borderRadius: 4,
    },
    grid: {
      color: '#252525',
      showDiagonal: false,
      subdivisions: 2,
    },
    curve: {
      master: { color: '#888', width: 1.5, shadowBlur: 0 },
      red: { color: '#f66', width: 1.5, shadowBlur: 0 },
      green: { color: '#6f6', width: 1.5, shadowBlur: 0 },
      blue: { color: '#66f', width: 1.5, shadowBlur: 0 },
    },
    controlPoint: {
      radius: 4,
      fill: '#fff',
      stroke: 'transparent',
      strokeWidth: 0,
      hoverScale: 1.5,
    },
    tabs: {
      background: 'transparent',
      gap: 8,
      tab: {
        padding: '6px 12px',
        background: 'transparent',
        hoverBackground: '#252525',
        activeBackground: '#333',
      },
    },
  }}
/>

🖼️ Applying LUT to Images

The LUT (Look-Up Table) returned by onChange enables fast, real-time pixel processing:

import { RGBCurve, applyLUT, LUTData } from 'rgb-curve';

function ImageEditor() {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const originalImageData = useRef<ImageData | null>(null);

  const handleCurveChange = ({ lut }: { lut: LUTData }) => {
    const canvas = canvasRef.current;
    if (!canvas || !originalImageData.current) return;

    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    // Clone original data
    const imageData = new ImageData(
      new Uint8ClampedArray(originalImageData.current.data),
      originalImageData.current.width,
      originalImageData.current.height
    );

    // Apply LUT to each pixel
    const data = imageData.data;
    for (let i = 0; i < data.length; i += 4) {
      const [r, g, b] = applyLUT(data[i], data[i + 1], data[i + 2], lut);
      data[i] = r;
      data[i + 1] = g;
      data[i + 2] = b;
    }

    ctx.putImageData(imageData, 0, 0);
  };

  return (
    <div>
      <RGBCurve onChange={handleCurveChange} />
      <canvas ref={canvasRef} />
    </div>
  );
}

🔧 Utility Exports

The package exports several utilities for advanced use cases:

import {
  // Components
  RGBCurve,
  CurveCanvas,
  ChannelTabs,

  // Hooks
  useCurvePoints,
  useCanvasInteraction,

  // Utilities
  generateLUT,
  generateChannelLUT,
  applyLUT,
  getDefaultPoints,
  getDefaultChannelPoints,
  monotoneCubicInterpolation,
  catmullRomInterpolation,
  sortPoints,
  clamp,

  // Constants
  CHANNELS,
  CHANNEL_INFO,
  CHANNEL_COLORS,
  DEFAULT_STYLES,
  DEFAULT_WIDTH,
  DEFAULT_HEIGHT,

  // Types
  type CurvePoint,
  type Channel,
  type ChannelPoints,
  type LUTData,
  type CurveChangeData,
  type RGBCurveProps,
  type RGBCurveRef,
  type RGBCurveStyles,
} from 'rgb-curve';

📘 TypeScript

Full TypeScript support is included. Import types as needed:

import type {
  CurvePoint,
  Channel,
  ChannelPoints,
  LUTData,
  CurveChangeData,
  RGBCurveProps,
  RGBCurveRef,
  RGBCurveStyles,
  CurveLineStyle,
  ControlPointStyle,
  GridStyle,
  TabsStyle,
  HistogramStyle,
} from 'rgb-curve';

🌐 Browser Support

| Browser | Version | |---------|---------| | Chrome | Latest ✅ | | Firefox | Latest ✅ | | Safari | Latest ✅ | | Edge | Latest ✅ |

Requirements: Browsers with Canvas 2D support.


🤝 Contributing

Contributions are welcome! Here's how you can help:

  1. 🐛 Report bugs - Open an issue with a reproduction
  2. 💡 Suggest features - Share your ideas for improvements
  3. 🔧 Submit PRs - Fix bugs or add features
  4. 📖 Improve docs - Help make the documentation better

Development Setup

# Clone the repository
git clone https://github.com/LittleBoy9/rgb-curve.git

# Install dependencies
npm install

# Start development server
npm run dev

# Build the library
npm run build:lib

📄 License

MIT © Sounak Das


Made with ❤️ by Sounak Das

If you find this project helpful, consider giving it a ⭐️ on GitHub!