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

pulzie

v1.0.1

Published

A fine-grained reactive UI framework built from scratch

Readme

Pulzie

A reactive UI framework I built from scratch in vanilla JavaScript. No libraries, no compiler plugins, no magic — just the core ideas behind how frameworks like Solid and Vue actually work, implemented from first principles.

Signals drive reactivity. When a signal changes, only the effects that read it re-run. The DOM updates surgically, not from a full re-render.

Live demo →


Why I built this

I wanted to understand what's actually happening inside modern reactive frameworks — not just use them. So I built one.

The result is ~300 lines of source code that handles: reactive signals with automatic dependency tracking, batched async updates, virtual DOM diffing/patching, JSX, undo/redo history, and a devtools overlay.


What's inside

| Module | Responsibility | |---|---| | signal.js | Reactive values — callable functions that track who reads them | | effect.js | Runs when created, re-runs when any signal it read changes | | scheduler.js | Batches pending effects into one microtask flush | | element.js | h() — pure function that returns virtual DOM nodes | | renderer.js | Creates real DOM, diffs/patches on re-render | | history.js | Undo, redo, and replay with a linear change stack | | devtools.js | Live overlay panel showing signal state and recent transitions |


Getting started

git clone https://github.com/ahmadraza100/pulzie.git
cd pulzie
npm install
npm start        # demo at http://localhost:5173
npm test         # 56 tests, all passing
npm run build    # bundles to dist/

How it works

Signals

A signal is a function. Call it with no arguments to read, pass a value to write.

import { signal } from "pulzie";

const count = signal(0);

count();     // 0
count(5);
count();     // 5

Subscribing manually returns an unsubscribe function:

const stop = count.subscribe((val) => console.log(val));
count(10);   // logs 10
stop();
count(20);   // nothing

Effects

Effects re-run automatically whenever a signal they read changes. Dependencies are tracked per-run, so if a branch stops reading a signal, it stops reacting to it.

import { signal, effect } from "pulzie";

const user = signal("Ahmad");

effect(() => {
  document.title = user();   // runs now, and again every time user changes
});

user("Raza");   // effect re-runs

Components + JSX

Components are plain functions. The renderer re-runs them whenever their signals change and surgically patches only what's different in the DOM.

import { signal, mount, h } from "pulzie";

const count = signal(0);

function Counter() {
  return (
    <div>
      <p>{String(count())}</p>
      <button onclick={() => count(count() + 1)}>+1</button>
    </div>
  );
}

mount(<Counter />, document.getElementById("app"));

Undo / redo

Wrap any signal with track() to opt it into the change history. undo() and redo() step through it. Branching after an undo truncates the forward stack — same as any text editor.

import { signal, track, undo, redo } from "pulzie";

const count = signal(0);
track(count, "count");

count(1);
count(2);
undo();    // → 1
undo();    // → 0
count(5);  // branch — redo is gone

Interesting implementation details

Stale dependency cleanup — before each effect re-run, it removes itself from every subscriber set it was in, then re-subscribes fresh. This means if/else branches that stop reading a signal automatically unsubscribe from it.

Snapshot pattern in two places — signal writes iterate [...subscribers] (not the live Set) so a subscriber that unsubscribes mid-loop doesn't cause skips. The same pattern prevents replay() from infinitely appending to the log it's iterating.

resolve() before diffing — the reconciler flattens all function components into plain vnodes before comparing old and new trees. This means patch() never needs to handle function types — it only sees strings and element objects.

recording flag for undo/redo — when undo or redo writes back to a signal, the history module suppresses re-recording via a boolean flag, so stepping through history doesn't pollute the undo stack.


Project structure

src/          framework source
demo/         interactive demo app
tests/        56 unit tests (node:test, no extra dependencies)
examples/     benchmark script
dist/         built output — ESM + UMD