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

@vishxrad/openui-plotly

v0.3.1

Published

Standalone OpenUI + Plotly scaffold. Run `npx @vishxrad/openui-plotly my-app` for a working Next.js generative-UI chat with 47 typed Plotly chart components — or import <PlotlyChat /> into an existing app.

Readme

@vishxrad/openui-plotly

A single-command OpenUI chat shell with 47 typed Plotly chart components built in. An LLM speaking openui-lang gets bar, line, heatmap, violin, sankey, sunburst, candlestick, scatter3d, choropleth, parallel coordinates, and the rest of Plotly's catalog — plus a Figure escape hatch for raw Plotly Graph-Objects JSON. Replaces the multi-package openui-cli scaffolding flow.

Scaffold a new app

npx @vishxrad/openui-plotly my-app

That's it. The CLI generates a complete Next.js 16 + React 19 project with <PlotlyChat /> already wired up and an /api/chat OpenAI proxy. Then:

cd my-app
cp .env.local.example .env.local       # paste your OPENAI_API_KEY
npm run dev                              # http://localhost:3000

Open the URL, ask the agent "plot Q4 revenue by month for products A, B, C as grouped bars" — done.

Add to an existing app

If you already have a Next.js / Vite / Remix app and want to drop the chat into it:

npm install @vishxrad/openui-plotly
// src/app/page.tsx (or equivalent)
"use client";
import "@vishxrad/openui-plotly/styles.css";
import { PlotlyChat } from "@vishxrad/openui-plotly";

export default function Home() {
  return (
    <div className="h-screen w-screen overflow-hidden">
      <PlotlyChat />
    </div>
  );
}
// src/app/api/chat/route.ts — your LLM proxy
import { NextRequest } from "next/server";
import OpenAI from "openai";

const client = new OpenAI();

export async function POST(req: NextRequest) {
  const { messages, systemPrompt } = await req.json();
  const response = await client.chat.completions.create({
    model: "gpt-5.2",
    messages: [{ role: "system", content: systemPrompt }, ...messages],
    stream: true,
  });
  return new Response(response.toReadableStream(), {
    headers: {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache, no-transform",
      Connection: "keep-alive",
    },
  });
}

Set OPENAI_API_KEY, npm run dev, working chat.

Component catalog

| Family | Components | |---|---| | Layout | Stack, Card, CardHeader, Heading, Text, Callout, KPI | | Cartesian | Bar, Line, Scatter, Area, Histogram | | Distributions | Violin, Box | | Matrix & 2D-density | Heatmap, Histogram2D, Histogram2DContour, Contour | | Hierarchical | Sunburst, Treemap, Icicle | | Categorical | Pie, Donut, Funnel, FunnelArea, Waterfall | | Flow | Sankey | | Multivariate | ScatterMatrix, ParCoords, ParCats | | Financial | Candlestick, OHLC | | Polar | ScatterPolar, BarPolar | | Specialty coords | ScatterTernary, ScatterSmith | | Geo | Choropleth, ScatterGeo | | Data display | Indicator, Table | | Escape hatches | Figure, PlotlyJSON |

The LLM is taught these components via the auto-generated system prompt — you don't write Plotly schema by hand.

Customizing <PlotlyChat />

<PlotlyChat
  apiUrl="/api/llm"             // default: "/api/chat"
  agentName="Data analyst"      // default: "OpenUI × Plotly"
  systemPrompt={customPrompt}   // default: full Plotly catalog prompt
/>

Or supply your own message processor (overrides apiUrl):

<PlotlyChat
  processMessage={async ({ messages, abortController }) => {
    return fetch("https://my-backend.example.com/agent", {
      method: "POST",
      body: JSON.stringify({ messages }),
      signal: abortController.signal,
    });
  }}
/>

Custom chat shell

If <PlotlyChat /> is too restrictive, drop down to the lower-level pieces — they're all re-exported from this package:

"use client";
import "@vishxrad/openui-plotly/styles.css";
import {
  FullScreen,
  openAIMessageFormat,
  openAIReadableStreamAdapter,
  plotlyLibrary,
  plotlyPromptOptions,
  PlotlyAssistantMessage,
} from "@vishxrad/openui-plotly";

const systemPrompt = plotlyLibrary.prompt(plotlyPromptOptions);

export default function MyChat() {
  return (
    <FullScreen
      processMessage={async ({ messages, abortController }) =>
        fetch("/api/chat", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            systemPrompt,
            messages: openAIMessageFormat.toApi(messages),
          }),
          signal: abortController.signal,
        })
      }
      streamProtocol={openAIReadableStreamAdapter()}
      componentLibrary={plotlyLibrary}
      agentName="Custom"
      assistantMessage={({ message, isStreaming }) => (
        <PlotlyAssistantMessage
          message={message}
          isStreaming={isStreaming}
          library={plotlyLibrary}
        />
      )}
    />
  );
}

This is exactly what <PlotlyChat /> does internally — just inlined so you can swap any piece.

Two-tier component API

Following Plotly's own dual API:

Tier 1 — Typed Plotly-Express-style components. Small zod schemas, ergonomic for the LLM:

Bar(rows, "month", "revenue", "product")               # Express style
Bar(null, ["Jan", "Feb", "Mar"], [1.2, 1.5, 1.8])      # Graph-Objects style

Tier 2Figure accepts the full Plotly Graph-Objects schema. Use this for any chart Tier 1 doesn't cover — multi-trace overlays, dual axes, animation frames, custom polar/ternary/carpet, advanced 3D scenes:

Figure(
  [
    { type: "bar", x: months, y: vol, name: "Volume" },
    { type: "scatter", mode: "lines+markers", x: months, y: trend, yaxis: "y2", name: "Trend" }
  ],
  { yaxis2: { overlaying: "y", side: "right" } }
)

Tier 0PlotlyJSON({ figure }) renders a fully-formed Plotly figure JSON verbatim. Use this when a backend tool returns a precomputed figure (e.g. Python fig.to_json()).

What's bundled

  • @openuidev/react-ui — chat shell (FullScreen, BottomTray, Copilot, ThemeProvider)
  • @openuidev/react-headless — message formats, stream adapters
  • @openuidev/react-lang — generative-UI runtime (Renderer, parser, hooks)
  • plotly.js-dist-min — full pre-built Plotly bundle
  • react-plotly.js — React wrapper

You only need react, react-dom, and (transitively) zod from the consumer side.

Bundle & loading

  • The Plotly bundle (~3.5 MB minified) is loaded lazily via React.lazy on first chart render. The chat shell first paint is unaffected.
  • Chart instances mount only after the assistant message finishes streaming — avoids token-by-token flicker as the LLM populates trace shape.

Framework support

  • Next.js (App Router or Pages Router) — works out of the box. Wrap your chat shell page in "use client".
  • Vite SPA — works out of the box.
  • Remix / React Router — works.
  • CRA — works.

The package never imports next/* or any other framework-specific module. Everything routes through React.lazy + Suspense.

License

MIT