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

hullabaloo

v1.0.0

Published

A Luxury Programming Framework

Readme

Hullabaloo

A Programming Framework for Young Coders

Hullabaloo is a way to build web apps and command-line programs by describing what you want, instead of writing hundreds of lines of instructions.

You tell Hullabaloo what your program has — signals, buttons, regions on the page, data pipelines — and it takes care of wiring everything together. You focus on the ideas. Hullabaloo handles the rest.

this.declare({
  signals: { name: 'Ada' },
  regions: { greeting: '#greetingBox' },
  content:  { name: 'greeting' },
});

That is all it takes. The #greetingBox element on your page now shows "Ada", and updates automatically whenever this.name changes — no extra code required.


The big idea

Most programming frameworks make you write a lot of plumbing code — event listeners, state management, manual DOM updates, cleanup functions. Hullabaloo hides all of that.

You write a plugin — a class that describes itself with this.declare({...}). Inside that object you list the features you want. Each feature is one key in the object. Hullabaloo reads the list and sets everything up for you.

import { Hullabaloo } from 'hullabaloo';

export default class MyPlugin extends Hullabaloo {
  constructor(options = {}, app) {
    super({ app });

    this.declare({
      objects:  { app, options },                        // attach things to this
      signals:  { loaded: false, started: false },       // values that can change
      capture:  { started: true, loaded: true },         // listen for events → save to signals
      combine:  { ready: { loaded: true, started: true } }, // combine signals → new signal
      regions:  { hello: '#helloRegion' },               // connect to HTML elements
      buttons:  { 'button#hello': 'say:hello' },         // wire clicks to events
      emitter:  { say: { hello: () => this.hello() } },  // define what events do
      binding:  { '#emailInput': 'email' },              // two-way input ↔ signal sync
      content:  { email: 'hello' },                      // signal value → region text
      filters:  [ ['email:changed', 'validate', 'email:valid'] ], // data pipelines
      persist:  { localStorage: { email: { load: true, tabs: true } } }, // remember values
    });
  }

  hello() {
    this.region.hello.textContent = 'Hello!';
  }

  async validate(packet) {
    return packet.includes('@') ? packet : null; // null drops the packet
  }

  async start() {
    if (this.started) return this;
    this.emit('loaded', true);
    this.emit('started', true);
    return this;
  }

  async stop() {
    if (!this.started && !this.loaded) return this;
    this.emit('started', false);
    this.emit('loaded', false);
    return this;
  }
}

Features

Every key in this.declare({...}) is a feature. Here is what each one does:

| Feature | What it gives you | Read more | |---|---|---| | objects | Attach things to your plugin so you can reach them with this. | | | signals | Values that your plugin watches and reacts to automatically | | | capture | Listen for events and save what arrived into a signal | | | combine | Create a signal that is only truthy when several others all match | | | regions | Connect your plugin to HTML elements on the page | | | buttons | Wire button clicks to events in your plugin | | | emitter | Define what your plugin does when events are fired | | | binding | Two-way sync between an input field and a signal | | | content | Automatically put a signal's value into a region on the page | | | filters | Describe data pipelines: where data comes from, how it transforms, where it goes | | | persist | Remember signal values in the browser so they survive a page reload | |


The Application

Plugins live inside an Application. The Application starts them in order, stops them in reverse order, and cleans everything up automatically.

import { Application } from 'hullabaloo';
import Logger   from './plug-ins/system/logger/Logger.js';
import MyPlugin from './plug-ins/examples/my-plugin/MyPlugin.js';

const app = new Application();

app.use(Logger, { outputs: [ConsoleOutput({ level: 'info' })] });
app.use(MyPlugin, { greeting: 'Hello!' });

await app.start();
// ... your program runs ...
await app.stop();

The Application itself is also a Hullabaloo — it has the same signals, declare, when, and unless methods.


Signals up close

A Signal is a value that tells everyone watching it when it changes.

import { Signal } from 'hullabaloo';

const count = new Signal(0);
count.subscribe(v => console.log('count is now', v)); // fires immediately: "count is now 0"
count.value = 1; // fires again: "count is now 1"
count.value = 1; // nothing — same value, no notification

Inside a plugin, signals declared with signals: get a convenient shorthand:

// After  signals: { loaded: false }  ...
this.loaded           // reads the current value (false)
this.loaded = true    // changes the value and notifies everyone
this.signals.loaded   // the Signal itself, for subscribing

autoSignal — signals on demand

Pass autoSignal: true to super() to make this.signals smart. Any signal name you access that does not exist yet will be created automatically as Signal(null).

super({ app, autoSignal: true });

This solves a timing problem: normally this.signals.myName inside a declare({}) argument is evaluated before any features run, so it would be undefined. With autoSignal: true it is always a live Signal, ready to use as a source or destination in filters:.


filters — data pipelines

The filters feature lets you describe how data flows through your plugin step by step. Each pipeline is one array inside the filters: list.

filters: [
  // [ source,  ...transforms,  destination ]

  ['user:typed', 'sanitize', 'display:text'],
  //  ↑ event     ↑ method     ↑ event to fire

  [this.signals.email, p => p.toUpperCase(), this.signals.upperEmail],
  //  ↑ Signal source   ↑ arrow function      ↑ Signal destination

  ['data:in', 'fetchFromServer', 'log:result'],
  //  transforms can be async — await is handled for you
]

To use Filters.fromEvent(emitter, 'event') for external emitters, import it:

import { filters } from 'hullabaloo';

filters: [
  [ filters.fromEvent(someOtherThing, 'click'), 'handleClick', 'ui:updated' ],
]

Exports

import {
  Application,  // orchestrates plugins
  Hullabaloo,   // base class for plugins
  Signal,       // observable value
  Disposable,   // lifecycle / cleanup helper
  Events,       // event emitter base class
  Filters,      // filter pipeline helper (also exported as 'filters')
  filters,      // same as Filters — lowercase for readability
} from 'hullabaloo';

Example plugins

| File | What it shows | |---|---| | plug-ins/examples/my-plugin/MyPlugin.js | Basic plugin with signals, capture, combine | | plug-ins/examples/my-region/MyRegion.js | Full example: regions, buttons, binding, content, filters, persist | | HelloCommandLine.js | Running an app from the terminal | | HelloWebApp.js | Running an app in the browser |


Philosophy

Programming should feel like building with blocks — snap things together, see what happens, break it, try again, learn by doing.

Hullabaloo is designed to get beginners to interesting programs as fast as possible. The hard parts (memory cleanup, event wiring, state synchronisation, cross-tab communication) are handled automatically. What is left for you is the fun part: describing what your program is and what it does.

Every error message in this framework is written to teach, not to scold. If something goes wrong, Hullabaloo will show you exactly what to fix and how.

"We are the HyperCard to the youngest generation of young programmers. We need to help them program and understand — and set them free to innovate."