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

react-rich-painter

v0.1.0

Published

React + Painter Library

Readme

🎨 React Rich Painter

React Rich Painterは、 Reactで統合可能なPainterライブラリです。

Demo on Storybook

ショーケース

ペイントアプリ 手書き日記 共有ホワイトボード

特徴🌴

  • ノート利用とペイントツール利用が可能
  • マウス入力 / タッチ入力 / ペン入力🚀
    • スマート入力切り替え: ペン入力を最優先し、使用パターンに応じて自動的に入力タイプを切り替え✨
  • Webでの本格的でなめらかな線👥
  • レイヤー機能: 最大30レイヤーのサポート、名前編集、可視化・不透明度調整、順序変更、ドラッグ可能なパネル📱
  • ブラシ機能 / スポイト機能 などの豊富な機能拡張🎨
  • 最適化された軽量なライブラリ💥
  • NextJS / Vite などReactに統合可能なTSの柔軟なライブラリ🤖
  • UI位置の自動保存(localStorage統合)💾

Usage💡

npm install react-rich-painter
# or
yarn add react-rich-painter
# or
pnpm install react-rich-painter
import { ReactRichPainter } from "react-rich-painter";

function App() {
  return (
    <div style={{ width: "100vw", height: "100vh" }}>
      {/* autoSize=true(デフォルト)の場合、親要素のサイズの0.8倍が自動的に設定されます */}
      <ReactRichPainter />
    </div>
  );
}

// または固定サイズを指定する場合
function AppWithFixedSize() {
  return <ReactRichPainter autoSize={false} width={800} height={600} />;
}

// Notebookプリセット:シンプルなメモ・スケッチ向け
function NotebookApp() {
  return (
    <div style={{ width: "100vw", height: "100vh" }}>
      {/* 親要素いっぱいにキャンバスを配置し、必要最小限の機能のみ表示 */}
      <ReactRichPainter preset="notebook" />
    </div>
  );
}

プロパティ

  • autoSize?: boolean - 親要素のサイズから自動的にキャンバスサイズを決定するかどうか(デフォルト: true
    • true (paintingモード): 親要素のサイズの0.8倍が自動的にキャンバスサイズとして設定されます
    • true (notebookモード): 親要素のサイズの1倍(親要素いっぱい)にキャンバスが配置されます
    • false: widthheightプロパティで固定サイズを指定する必要があります
  • preset?: 'painting' | 'notebook' - プリセット設定(デフォルト: 'painting'
    • 'painting': フル機能モード(ToolBar、BrushBar、レイヤーパネル)
    • 'notebook': シンプルモード(ペン・消しゴム・サイズ・色のみのNotebookBar)
  • width?: number - キャンバスの幅(ピクセル)※autoSize=falseの場合に使用
  • height?: number - キャンバスの高さ(ピクセル)※autoSize=falseの場合に使用
  • toolbar?: boolean - ツールバーを表示するかどうか(デフォルト: true)※notebookプリセットでは無視されます
  • brushbar?: boolean - ブラシバーを表示するかどうか(デフォルト: true)※notebookプリセットでは無視されます
  • defaultCustomBrush?: boolean - デフォルトのカスタムブラシを使用するかどうか(デフォルト: true
  • backgroundSize?: number - 背景グリッドのサイズ(ピクセル)(デフォルト: 20
  • onUpdate?: (state: PainterState) => void - Painter状態更新時のコールバック(100msでthrottleされます)
  • initialState?: PainterState - 初期状態(Import機能)
  • showFileMenu?: boolean - FileMenuを表示するかどうか(デフォルト: false

共有機能(Share)

リアルタイム共有ホワイトボードを構築するためのプロパティです。share=trueの場合のみ有効になります。

  • share?: boolean - 共有モードを有効にするか(デフォルト: false
  • userId?: string - 共有モード時のユーザー識別子
  • userName?: string - 共有モード時のユーザー表示名
  • onStrokeStart?: (data: StrokeStartData) => void - ストローク開始時のコールバック
  • onStrokeMove?: (data: StrokeMoveData) => void - ストローク移動時のコールバック
  • onStrokeEnd?: (data: StrokeEndData) => void - ストローク終了時のコールバック

共有モードでは、refを使用して外部からリモートユーザーの描画を適用できます:

import { ReactRichPainter, PainterHandle } from "react-rich-painter";
import { useRef } from "react";

function SharedWhiteboard() {
  const painterRef = useRef<PainterHandle>(null);

  // リモートからのストロークを適用
  const handleRemoteStroke = (data) => {
    painterRef.current?.applyRemoteStrokeStart(data);
    // applyRemoteStrokeMove, applyRemoteStrokeEnd も同様
  };

  return (
    <ReactRichPainter
      ref={painterRef}
      share={true}
      userId="user-123"
      userName="田中"
      onStrokeStart={(data) => sendToServer(data)}
      onStrokeMove={(data) => sendToServer(data)}
      onStrokeEnd={(data) => sendToServer(data)}
    />
  );
}

スマート入力切り替え機能

React Rich Painterは、ユーザーの使用パターンに基づいて入力タイプ(ペン/マウス/タッチ)を自動的に切り替える機能を搭載しています。

動作ルール

  1. ペン入力の最優先: ペン入力が検知されると即座にペンモードに切り替わります
  2. 使用パターンの追跡: ペンモード中に他の入力(マウス/タッチ)を連続して使用すると、自動的にその入力タイプに切り替わります
  3. 手動切り替えも可能: ツールバーの入力タイプボタンで手動切り替えもできます

この機能により、ペンタブレットとマウス、タッチデバイスを併用する環境でも快適に描画できます。

Import/Export機能

React Rich Painterは、描画状態を完全に保存・復元できるImport/Export機能を提供しています。

UIからのImport/Export(showFileMenu prop)

import { ReactRichPainter } from "react-rich-painter";

function App() {
  return (
    <div style={{ width: "100vw", height: "100vh" }}>
      {/* showFileMenu=trueでToolBar/NotebookBarにFileメニューが表示されます */}
      <ReactRichPainter showFileMenu={true} />
    </div>
  );
}

FileMenuから以下の操作が可能です:

  • ファイルを開く: JSONファイルから描画状態を復元
  • エクスポート: 現在の描画状態をJSONファイルとして保存
  • 画像を保存: 統合されたキャンバス画像をPNG形式で保存

プログラムからのImport/Export

import {
  ReactRichPainter,
  PainterState,
  exportPainterState,
  serializePainterState,
} from "react-rich-painter";
import { useState } from "react";

function App() {
  const [savedState, setSavedState] = useState<PainterState | undefined>();

  const handleUpdate = (state: PainterState) => {
    // 状態が更新されるたびに呼ばれます(100msでthrottle)
    console.log("Painter state updated:", state);
    setSavedState(state);
  };

  return (
    <div style={{ width: "100vw", height: "100vh" }}>
      {/* onUpdateで状態変更を監視 */}
      <ReactRichPainter
        onUpdate={handleUpdate}
        initialState={savedState} // 保存した状態から復元
      />

      {savedState && (
        <button
          onClick={() => {
            // JSONとしてエクスポート
            const json = serializePainterState(savedState);
            const blob = new Blob([json], { type: "application/json" });
            const url = URL.createObjectURL(blob);
            const link = document.createElement("a");
            link.href = url;
            link.download = "painting.json";
            link.click();
          }}
        >
          エクスポート
        </button>
      )}
    </div>
  );
}

PainterStateの構造

type PainterState = {
  version: string; // フォーマットバージョン
  canvas: {
    width: number;
    height: number;
  };
  layers: Array<{
    id: string;
    name: string;
    visible: boolean;
    opacity: number;
    imageData: string; // Base64エンコードされた画像データ
  }>;
  selectedLayerId: string;
  brush: {
    color: string;
    size: number;
    spacing: number;
    flow: number;
    merge: number;
    minimumSize: number;
    opacity: number;
  };
  stabilizer: {
    level: number;
    weight: number;
  };
  currentTool: "pen" | "eraser" | "dripper" | "lasso" | "move";
  inputType: "pen" | "mouse" | "touch";
};

開発者 / Contributor

fork後にPRを出してください。

セットアップ

# 依存関係のインストール
pnpm install

# 開発サーバーの起動
pnpm dev

# ビルド
pnpm run build

Storybookで確認

Storybookを使用して、様々なパラメータでReact Rich Painterをインタラクティブにテストできます。

# Storybookの起動
pnpm run storybook

ブラウザで http://localhost:6006 を開く

Storybookのビルド

# Storybookの静的ファイルを生成
pnpm run build-storybook