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

openalgo-heatmap

v0.2.0

Published

Finviz-style market heatmap for React: squarified treemap sized by value, colored by percent change. Includes an NSE Nifty 500 demo; pure layout engine ships separately at /core.

Readme

openalgo-heatmap

OpenAlgo npm license: MIT

OpenAlgo NSE Nifty 500 heatmap

A Finviz-style market heatmap for React, from OpenAlgo. Tiles are sized by market cap with a squarified treemap and colored by percent change on a diverging red-to-green scale. Sectors and industries nest as labeled groups.

The layout and color math ships separately at openalgo-heatmap/core with zero dependencies (no React, no DOM, no network), so you can reuse it in a Canvas or WebGL renderer, run it in Node for server-side image generation, or use it as a reference when porting to Go or Rust.

What is this?

Three things in one repo:

  • A React componentMarketHeatmap, the <MarketHeatmap data={...} /> you drop into your own React app. This is the product.
  • A zero-dependency engine — the layout + colour math at openalgo-heatmap/core (no React, no DOM, no network). Reuse it in a Canvas/WebGL renderer, in Node for server-side images, or as a port reference.
  • A runnable demo app — a full-screen NSE Nifty 500 heatmap in demo/ (the "OpenAlgo heatmap"). See Run the app.

So it is a library (a publishable npm package: component + engine), and the repo also ships a demo app that showcases it with real NSE data. The demo is a harness — you embed the component in your own app rather than shipping demo/.

Features

  • Squarified treemap layout (near-square tiles, like Finviz)
  • Nested sector and industry groups to any depth
  • Diverging color scale with a configurable saturation cap
  • Realtime updates that repaint colors without recomputing the layout
  • Responsive SVG that scales to its container
  • Pure, dependency-free engine on a separate import path
  • TypeScript types included

Install

npm i openalgo-heatmap

React 18 or newer is a peer dependency, so it is never bundled.

Quick start

import { MarketHeatmap, type HeatmapNode } from "openalgo-heatmap";

const data: HeatmapNode[] = [
  {
    name: "SEMICONDUCTORS",
    children: [
      { symbol: "NVDA", value: 3000, change: -4.99 },
      { symbol: "AMD", value: 250, change: -9.11 },
    ],
  },
  {
    name: "SOFTWARE",
    children: [{ symbol: "MSFT", value: 3100, change: -1.82 }],
  },
];

export default function App() {
  return <MarketHeatmap data={data} title="TECHNOLOGY" cap={3} />;
}

value drives tile size, change drives color. Nest children to any depth.

Realtime data

The component does no fetching. It is transport-agnostic, so any source works: REST polling, WebSocket, or SSE. For streaming, pass a quotes map (symbol to latest percent change). Updating quotes repaints tile colors only and skips the treemap recompute, so it stays smooth at high tick rates.

One rule: keep data referentially stable across renders and push ticks through quotes. If you build a new data array on every tick, the layout recomputes every tick. Define data once (or memoize it), then stream into quotes.

WebSocket example:

import { useEffect, useState } from "react";
import { MarketHeatmap } from "openalgo-heatmap";

function useLiveQuotes(symbols: string[]) {
  const [quotes, setQuotes] = useState<Record<string, number>>({});
  useEffect(() => {
    const ws = new WebSocket("wss://your-feed.example/quotes");
    ws.onopen = () => ws.send(JSON.stringify({ subscribe: symbols }));
    ws.onmessage = (e) => {
      const tick = JSON.parse(e.data); // { symbol, changePct }
      setQuotes((q) => ({ ...q, [tick.symbol]: tick.changePct }));
    };
    return () => ws.close();
  }, [symbols]);
  return quotes;
}

// <MarketHeatmap data={structure} quotes={useLiveQuotes(symbols)} cap={1.5} />

REST polling is the same idea with an interval:

useEffect(() => {
  const id = setInterval(async () => {
    const res = await fetch("/api/quotes");
    setQuotes(await res.json()); // { NVDA: -4.2, AMD: 1.1, ... }
  }, 1000);
  return () => clearInterval(id);
}, []);

In production, coalesce bursts of ticks (for example to one update per animation frame or every 250 ms) so the UI does not re-render faster than the eye can read.

Sizing and layout

The output is an SVG (not a <canvas>). It scales to fill its container width while preserving aspect ratio, so you control the on-screen size from the parent:

<div style={{ maxWidth: 1000, margin: "0 auto" }}>
  <MarketHeatmap data={data} />
</div>

width and height set the internal coordinate space, which fixes the aspect ratio and the label density, not the pixel size. Use a landscape ratio for a dashboard panel (for example width={1280} height={720}) or the portrait default for a tall column. You can also pass className and style, which are merged onto the root element, to size or theme it with your own CSS.

For a very large universe (several thousand tiles), SVG gets heavy. The engine is renderer-agnostic, so at that scale draw the same layoutTree output to a <canvas> instead and keep everything else.

Props

| Prop | Default | Notes | | ------------- | ----------- | ------------------------------------------------------------------ | | data | required | Array of groups; leaves are { symbol, value, change }. Keep it stable. | | quotes | none | Record<symbol, number> of live percent changes. Overrides color only. | | cap | 3 | Percent move that saturates the scale. Use 1.5 to 2 for calmer markets. | | colorScale | built-in | (change, cap) => cssColor to override the red/green ramp. | | title | "" | Top-left label; omit to drop the title bar. | | width | 920 | viewBox width (coordinate space and aspect ratio). | | height | 1180 | viewBox height. | | pad | 2 | Gap between groups. | | headerHeight| 17 | Group label strip height. | | background | "#0d0d0f" | Backdrop and tile gridline color. | | fontFamily | Inter stack | Font for labels. | | showLegend | true | Show the gradient legend below the map. | | className | none | Passed to the root element. | | style | none | Merged onto the root element (set width, height, maxWidth here). |

Engine only

No React required. Useful for a Canvas/WebGL renderer or server-side rendering.

import { layoutTree, changeColor, escapeXml, type LayoutItem } from "openalgo-heatmap/core";

const items: LayoutItem[] = [];
layoutTree(data, { x: 0, y: 0, w: 800, h: 600 }, 0, { headerHeight: 16, pad: 2 }, items);

// items is a flat list of positioned rects:
//   { type: "group", rect, name, headerHeight, depth }
//   { type: "leaf",  rect, node, depth }
// Color leaves with changeColor(node.change, cap). If you emit SVG as a raw
// string, wrap any label with escapeXml() first.

Security

This is a pure rendering component, which keeps the surface small:

  • It renders every label as a React text node and sets colors as plain attributes. It never uses dangerouslySetInnerHTML, innerHTML, or eval, so ticker and sector names cannot inject script. It is XSS-safe by default.
  • It makes no network requests of its own, so there is no request forgery or data exfiltration path inside the library. You own the data fetch.
  • Numeric inputs are handled defensively: non-finite or non-positive sizes are dropped, and a non-finite live change falls back to the baked-in value, so a malformed feed degrades gracefully instead of corrupting the layout.
  • Secure the feed, not the renderer. Serve quotes over https/wss, authenticate the socket with a short-lived token, and keep broker API keys on your server by proxying the feed. This is a browser component; never ship secrets in the client bundle.
  • For non-React rendering (server-side PNG, or a Go/Rust port) escape text and attribute values. The core exports escapeXml for that.
  • Content Security Policy: the component uses inline styles. Under a strict style-src allow inline styles, or pass your own className and move styling to a stylesheet.

Development

npm i
npm run build       # tsup -> dist (ESM + CJS + .d.ts) for both entries
npm run typecheck

Run the app

The demo/ folder is a full-screen, Finviz-style NSE Nifty 500 heatmap. Tiles are sized by traded value (₹ Cr) and coloured by percent change, grouped by sector. Hover a stock to spotlight its whole sector and open a card with that sector's mini-treemap and a ranked peer list; scroll to zoom, drag to pan, double-click to reset.

npm install
npm run demo        # Vite dev server at http://localhost:5173

That is the whole app. npm run build / npm run typecheck are for the library, not the demo.

Custom data

Into the component (your own app)

MarketHeatmap takes a data prop: an array of groups whose leaves are { symbol, value, change }. value sizes each tile, change colours it. Nest children to any depth to add sector → industry levels.

import { MarketHeatmap, type HeatmapNode } from "openalgo-heatmap";

const data: HeatmapNode[] = [
  { name: "BANKS", children: [
    { symbol: "HDFCBANK", value: 1200, change: -0.8 },
    { symbol: "ICICIBANK", value: 900, change: 1.4 },
  ]},
  { name: "IT", children: [{ symbol: "TCS", value: 1400, change: 0.3 }]},
];

<MarketHeatmap data={data} title="MY UNIVERSE" cap={3} />;

Keep data referentially stable and stream live ticks through quotes ({ HDFCBANK: -0.8, ICICIBANK: 1.4, ... }), which repaints colours without recomputing the layout — see Realtime data.

Into the demo (swap the NSE export)

The demo parses demo/nifty500.csv at runtime. Replace it with a fresh NSE Nifty 500 export and reload — no rebuild needed. The parser tolerates the BOM and the multi-line quoted headers in NSE's file and reads these columns (the rest are ignored):

| Column | Drives | | ------------------ | ------------------------------- | | SYMBOL | join key (matches the reference) | | LTP | last price in the hover card | | %CHNG | tile colour | | VALUE (₹ Crores) | tile size |

Company names & sectors

These are not in the quote CSV, so they are joined in from demo/nse-reference.ts (symbol -> { name, sector }). Sectors come from NSE's official macro classification. To refresh them from an official constituents file (Company Name, Industry, Symbol, ...):

node demo/build-reference.cjs   # demo/nse500_official.csv -> demo/nse-reference.ts

Hand-edit demo/nse-reference.ts to override a name or sector. A symbol with no reference entry falls back to sector OTHER with the symbol as its name.

To drive the demo from a non-NSE universe entirely, edit demo/nifty.ts: it only has to produce Row[] (symbol, name, sector, ltp, change, value); the component and hover card take it from there.

Publish

Published to npm as openalgo-heatmap. Only dist/ ships (see files); the demo/ app is not part of the package.

npm login            # one-time, with the account that owns the package
npm run build        # or rely on the prepublishOnly hook
npm publish          # runs prepublishOnly (build) first
# next releases:
npm version patch && npm publish

License

MIT © Marketcalls — see LICENSE.