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 🙏

© 2025 – Pkg Stats / Ryan Hefner

dupdupdraw

v1.0.0

Published

Forthish drawing bot

Readme

This is a simple HTML canvas experiment with a forth-like language.

As a quick primer:

How does Forth work?

Forth is a stack-machine based postfix language. Words in your program are executed in order, and the stack starts empty. A stack is like a list where the first thing you put in is the first thing you pull out.

stack: []
program: 2 3 + 4

In many programming languages you might think this adds 3 and 4 and gives an error about 2, but the language for dupdupdraw doesn't work that way. Words are executed from left to right, so...

  1. 2 is a number, so it goes on the stack: [2]
  2. 3 is the same: [2 3]
    • is an instruction, so it adds the top two numbers and puts the result on the stack: [5]
  3. 4 is just like 2 and 3, so our final stack is [5 4].

Trying to use an empty stack or using a word you haven't defined causes an error in a real Forth, but in dupdupdraw it's handled this way:

  • if the stack is empty you get enough zeros to perform the operation (so "2 +" -> [2]).
  • unknown words are assigned a random value which is constant for the whole picture. So "asdf asdf /" -> [1], and a whole program of "asdf asdf asdf" would make a picture that was some shade of gray. Note random values are not consistent between runs of the generator.

How does dupdupdraw work?

Your program (like a tweet) is executed once for every pixel of a 512 by 512 image. The three values at the top (right) end of the stack are the r, g, and b values for that pixel, on a scale of 0 to 255. So [0 0 0] is black, [128 128 128] is grey, and [255 0 0] is red. Values outside the range are simply treated as 255 or 0 appropriately. Leftover values on the stack are ignored.

Some built in keywords change what they do depending on your pixel's location; the most obvious are x and y, which evaluate to the value for that pixel's location.

What are the built in words?

A word in parens is an alias. ? and @ are not keywords, but are often used as random values.

  • +-/* - basic math
  • = - equality test - if the top two values are equal, then push 1 onto the stack, otherwise push 0
  • mod (%) - modulus "7 4 %" -> [3]. A
  • // - As division, but take the floor (round down).
  • sqrt (sr) - square root
  • sin - sin of the value multiplied by 255
  • r - random and re-evaluated for every pixel (adds noise)
  • dist (di) - the distance of the current pixel from the location denoted by the two values on the top of the stack ("10 20 di" gives distance from x: 10, y: 20).
  • < > - "10 7 <" -> [0], "7 10 <" -> [1]. There's no if in dupdupdraw, but this can be used in much the same way ("x dup 256 < *" is zero where x is not less than 256, for example.)
  • xl / xg / yl / yg - If the top of the stack is less than x (for xl), leave the next value alone, otherwise replace with zero. xg -> x greater, yg -> y greater etc. This is good for sectioning your canvas.
  • dup - duplicate the top of the stack ("23 dup" -> [23 23])
  • swap - swap the top of the stack with the next value "1 2 swap" -> [2 1]
  • ish - inverse sinh, 64 / sinh(input / 256). Good for curves. Thanks to @itszutak for introducing me to sinh. (sinh is also available but it's a very steep curve)
  • max - remove the two values from the top of the stack and put the higher one back.
  • rot - put the value two down the stack on top. "1 2 3 rot" -> [2 3 1]
  • over - make a copy of the second value on the stack and push it. "1 2 over" -> [1 2 1]

If you have any questions, feel free to ask me on Twitter. Thanks!

-POLM