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

powerflow

v0.1.4

Published

Animated, framework-agnostic SVG energy-flow diagram — solar, grid, home, battery and wallbox with power-proportional flow animation. Ships as a <power-flow> Web Component and a vanilla API; works with React, Angular, Vue or plain HTML.

Readme

⚡ powerflow

Animated, framework-agnostic SVG energy-flow diagram.

Live power flow between solar, grid, home, battery and two wallboxes — with dots whose speed is proportional to the actual power.

npm bundle size zero deps license

▶ Try the live playground


It ships as a <power-flow> Web Component, so it works natively in React, Angular, Vue, Svelte or plain HTML — plus a tiny vanilla API. No canvas, just crisp scalable vectors; no runtime framework dependency.

  • Optional nodes — solar, battery and both wallboxes appear automatically when you pass their values; empty rows are trimmed so there's no dead space.
  • Power-proportional animation — dot speed scales with watts and stays smooth (no jumping) as values update live.
  • Consistent flow math — each source is split across its sinks with no double-counting, modelled after Home Assistant's power-flow-card-plus.
  • Coverage rings — home ring shows load sources (solar / battery / grid); grid ring shows export sources; battery ring shows state of charge.
  • Themeable — every node colour (including separate charge/discharge colours for battery and grid), every label, and every node icon is overridable.
  • Adjustable animation — dot speed multiplier lets you slow down or speed up the flow independently of the power values.
  • Tiny & isolated — ~7 kB min+gzip, zero runtime deps, shadow DOM so its styles never leak into your app.

Install

npm install powerflow

…or straight from a CDN, no build step:

<script type="module" src="https://unpkg.com/powerflow"></script>

Quick start (any framework / plain HTML)

<script type="module">
  import 'powerflow'; // registers the <power-flow> element
</script>

<power-flow id="pf"></power-flow>

<script type="module">
  const pf = document.getElementById('pf');
  pf.data = {
    solar: 3000, // PV production (W); omit/null hides the node
    grid: -600, // grid power: positive = import, negative = export
    load: 2400, // total house consumption (W)
    battery: -500, // negative = charging, positive = discharging; omit/null hides
    batterySoc: 72, // state of charge in % (optional, shows SoC ring)
    wallbox: 3600, // EV charger below the house (optional)
    wallbox2: 3600, // second EV charger above the house (optional)
  };
</script>

data, colors, labels, icons and speedScale are set as JS properties. In plain HTML you can also pass data, colors and labels as JSON attributes: <power-flow data='{"solar":2400,"grid":-600,"load":1800}'></power-flow>.

Framework usage

import 'powerflow';
import { useRef, useEffect } from 'react';

export function Energy({ data }) {
  const ref = useRef(null);
  useEffect(() => {
    ref.current.data = data;
  }, [data]);
  return <power-flow ref={ref} />;
}

React ≥ 19 also lets you pass data={data} directly.

Add CUSTOM_ELEMENTS_SCHEMA to your module/component, import "powerflow"; once, then:

<power-flow [data]="data" [colors]="colors"></power-flow>

import "powerflow"; once, tell Vue the tag is a custom element (compilerOptions.isCustomElement), then:

<power-flow :data="data" :labels="labels" />
import { createPowerFlow } from 'powerflow';

const pf = createPowerFlow(document.getElementById('box'), { data });
pf.update({ data: nextData }); // cheap, call as often as you like
pf.destroy();

The diagram renders into a shadow root on the host element, so its styles never leak into your app.

API

| Property / option | Type | Description | | ----------------- | --------------------- | --------------------------------------------------------- | | data | FlowData | Live power readings (watts). | | colors | Partial<FlowColors> | Override any accent colour. | | labels | Partial<FlowLabels> | Override node labels (i18n). | | icons | Partial<FlowIcons> | Override node icons (any SVG <path d=""> string). | | speedScale | number | Dot speed multiplier. 1 = default, 2 = twice as fast. |

FlowData

| Field | Type | Description | | ------------ | ---------------- | -------------------------------------------------------- | | solar | number \| null | Solar / PV production (≥ 0). Optional. | | grid | number | Grid power. Positive = import, negative = export. | | load | number | Total house consumption (≥ 0). | | battery | number \| null | Positive = discharging, negative = charging. Optional. | | batterySoc | number \| null | Battery state of charge in percent. Optional. | | wallbox | number \| null | EV charger consumption, drawn below the house. Optional. | | wallbox2 | number \| null | Second EV charger, drawn above the house. Optional. |

Only grid and load are required. Omitting (or passing null for) solar / battery / wallbox / wallbox2 hides that node, and the diagram trims the now-empty row so there's no dead space. Both wallboxes are sub-consumers of load, not extra load on top of it.

colors

{
  solar:      "#fcd34d", // amber-yellow
  home:       "#818cf8", // periwinkle
  gridIn:     "#60a5fa", // sky blue  — importing from grid
  gridOut:    "#f472b6", // pink      — exporting to grid
  batteryIn:  "#4ade80", // lime green — charging
  batteryOut: "#fb923c", // orange    — discharging
  wallbox:    "#22d3ee", // cyan
  wallbox2:   "#2dd4bf", // teal
}

labels (i18n)

Defaults are English. Override per language, e.g. { grid: "Netz", home: "Haus", battery: "Akku" }.

icons

Each value is a valid SVG <path d="…"> string. The defaults use Material Design Icons, but any SVG path drawn in a 24×24 viewBox works:

import { mdiSolarPanel, mdiFlash } from '@mdi/js';

pf.icons = {
  solar: mdiSolarPanel, // swap the default solar-power-variant icon
  grid: mdiFlash, // swap the transmission tower
  // home / battery / wallbox / wallbox2 — all optional
};

speedScale

Multiplies the base dot speed for all animated legs. The base speed is already proportional to power, so speedScale lets you tune the visual intensity without changing the underlying data:

pf.speedScale = 0.5; // half speed — calmer animation
pf.speedScale = 2; // twice as fast — more energetic feel

How the flows are computed

Meters only tell you the net at each node, so powerflow decomposes them into the individual legs by priority — every source is split across the sinks it feeds, with nothing double-counted:

  1. a charging battery is fed from solar first (the rest from the grid),
  2. remaining solar serves the house, then exports,
  3. a discharging battery covers the house's remaining demand, then exports,
  4. the grid covers whatever the house still needs.

This matches the convention of power-flow-card-plus, so e.g. solar 1000 W, load 1000 W, battery charging 100 W, grid +100 W correctly shows solar→battery 100, solar→home 900 and grid→home 100 — not a single solar→home line.

Development

npm install
npm run dev           # playground at localhost:5173 — sliders, test cases, simulate day

npm run build         # build:lib + build:site
npm run build:lib     # → dist/      publishable library (JS bundles + .d.ts)
npm run build:site    # → dist-site/ static playground (GitHub Pages)

npm run capture:gif   # re-generate docs/preview.gif (requires ffmpeg + chromium)

Credits

Inspired by power-flow-card-plus by @flixlix — the excellent Home Assistant card. powerflow reuses its flow-allocation conventions but is a standalone, framework-agnostic Web Component with no Home Assistant dependency.

License

MIT © Thomas Mihailovits