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

@pragdave/picjs

v0.3.0

Published

A language for creating animated, constraint-based SVG diagrams

Readme

picjs

A language for drawing — and animating — diagrams. You describe what you want; picjs works out where everything goes.

A simple flow chart with three boxes, connected by arrows

Palette.current = "shuksan"
box "Input" -> box "Process" fill ~b2 -> box "Output"

Have a play in the playground, or read the documentation.

Diagrams in your markdown

Write a diagram where it belongs — in the document that talks about it:

Here is how the parts fit together:


<!-- picjs:9b843399:plain
box "Input" -> box "Process" -> box "Output"
-->
<svg viewBox="-0.7 -0.575 5.4 1.15" class="_myopic-1" xmlns="http://www.w3.org/2000/svg"><style>.pj-fill-sunset-b1{fill:#41476b}
.pj-fill-sunset-f1{fill:#fbdfa2}
.pj-stroke-sunset-b1{stroke:#41476b}
[data-theme="light"] .pj-fill-sunset-b1{fill:#8b90b8}
[data-theme="light"] .pj-fill-sunset-f1{fill:#1a1a2e}
[data-theme="light"] .pj-stroke-sunset-b1{stroke:#8b90b8}</style><g data-jp-id="SBox-1"><rect width="1" height="0.75" stroke="none" stroke-width="0.015" rx="0.06" ry="0.06" x="-0.5" y="-0.375" class="pj-fill-sunset-b1" data-jp-id="SBox-1"></rect><text font-family="Roboto, sans-serif" font-size="0.14" font-style="normal" font-variant="normal" font-weight="normal" font-stretch="normal" x="-0.16100000000000003" y="-0.084" class="pj-fill-sunset-f1" dominant-baseline="text-before-edge" data-jp-id="SLabel-2">Input</text></g><g data-jp-id="SLine-3"><path stroke-width="0.04" x="1" y="0" d="M 0.5 0 L 1.284 0" fill="none" class="pj-stroke-sunset-b1"></path><path d="M 1.284 -0.06 L 1.44 0 L 1.284 0.06 Z" stroke="none" class="pj-fill-sunset-b1"></path></g><g data-jp-id="SBox-4"><rect width="1" height="0.75" stroke="none" stroke-width="0.015" rx="0.06" ry="0.06" x="1.5" y="-0.375" class="pj-fill-sunset-b1" data-jp-id="SBox-4"></rect><text font-family="Roboto, sans-serif" font-size="0.14" font-style="normal" font-variant="normal" font-weight="normal" font-stretch="normal" x="1.7746" y="-0.084" class="pj-fill-sunset-f1" dominant-baseline="text-before-edge" data-jp-id="SLabel-5">Process</text></g><g data-jp-id="SLine-6"><path stroke-width="0.04" x="3" y="0" d="M 2.5 0 L 3.284 0" fill="none" class="pj-stroke-sunset-b1"></path><path d="M 3.284 -0.06 L 3.44 0 L 3.284 0.06 Z" stroke="none" class="pj-fill-sunset-b1"></path></g><g data-jp-id="SBox-7"><rect width="1" height="0.75" stroke="none" stroke-width="0.015" rx="0.06" ry="0.06" x="3.5" y="-0.375" class="pj-fill-sunset-b1" data-jp-id="SBox-7"></rect><text font-family="Roboto, sans-serif" font-size="0.14" font-style="normal" font-variant="normal" font-weight="normal" font-stretch="normal" x="3.8068" y="-0.084" class="pj-fill-sunset-f1" dominant-baseline="text-before-edge" data-jp-id="SLabel-8">Output</text></g></svg>
<!-- /picjs -->

Then run picjs over the file:

$ npx picjs process README.md

Each block is replaced by the rendered SVG, with the source kept beside it in a comment. Edit the source and run it again and the picture is redrawn; leave it alone and nothing changes. The result is static SVG, so it works anywhere — including here, on GitHub.

If you control your site's markdown pipeline, the Lume and Eleventy plugins do the same thing at build time.

It is a real language

petals = 17
start_color = oklch(70%, .3, 0)

petal = (color) => {
  4.times(=> {
    Arc stroke color
    Arc ccw stroke color.spin(10)
    Arc stroke color.spin(20)
  })
}

petals.times(n => {
  Face 360/petals*n
  petal(start_color.spin(n*30))
})

Image drawn using arcs and 17-fold rotational symmetry

Shapes follow on from one another, so petal needs no coordinates at all. The outer loop turns the drawing direction a little each time and shifts the hue to match.

And it animates

Screenshot of the Towers of Hanoi animation

Towers of Hanoi, solved recursively, with every move animated — in under sixty lines. There is a walk-through of how it works.

Installing

$ npm install @pragdave/picjs

In a page:

<script type="module">
  import { renderAll } from '@pragdave/picjs'
  renderAll('.picjs')          // renders every element with class "picjs"
</script>
<div class="picjs">box "Hello"</div>

On a server:

import { renderToStringAsync } from '@pragdave/picjs'
const { svg, width, height } = await renderToStringAsync('box "Hello"')

Documentation

The skills/ directory has two skills files, should you want an AI to write picjs with you.

What you get

  • Shapes that flow one after another, or sit where you pin them
  • Constraints that hold: move a shape and whatever is attached follows
  • Groups that nest, and behave as shapes themselves
  • Colour palettes with light and dark variants, checked for contrast
  • A timeline: shapes appear, move, and change over it
  • Numbers, strings, lists, ranges, colours, positions and functions, with closures — and attributes on every value, which is enough to build mixins

License

See LICENSE.md.