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

wabijs

v0.1.0

Published

A lightweight JavaScript library for adding organic geometric imperfection to HTML elements

Readme

wabi.js

A lightweight JavaScript library for adding subtle geometric imperfection to HTML elements.

See the demo and configuration

How It Works

wabi.js uses CSS clip-path: polygon() to redefine the visible boundaries of HTML elements. Instead of perfect rectangular corners, it creates subtle random offsets that give elements an organic, hand-crafted feel.

Installation

For WordPress & Web Developers (Simple Setup)

Download wabi.min.js from the dist folder and add it to your site:

<!-- Add this before </body> -->
<script src="/path/to/wabi.min.js"></script>

Or use the CDN:

<script src="https://unpkg.com/wabi"></script>

For NPM Users

npm install wabi

Usage

Simple Usage (WordPress, handcoded sites)

Add the script and call wabi() when the page loads:

<!-- 1. Add the script before </body> -->
<script src="https://unpkg.com/wabi"></script>

<!-- 2. Call wabi() on your elements -->
<script>
  window.addEventListener('load', function() { 
    wabi('.my-cards', { corners: { x: 5, y: 4 } }); 
    //You can apply different settings to different elements by calling wabi() multiple times:
wabi('.buttons', { corners: { x: 2, y: 2 }, animate: true });
</script> 
  });
</script>

That's it! The effect is applied when the page loads.

ES Modules (Bundlers, Modern JS)

import wabi from 'wabi'; 
 
const result = wabi('#myDiv', { corners: { x: 5, y: 4 } }); 
result.restore(); // Restore original shape

Shorthand Syntax

// Inside your load event handler: 
wabi('#myDiv', 5, 4);  // Corner displacement only 
wabi('#myDiv', 5, 4, 2);  // Corner displacement + edge points

With Edge Points

wabi('.cards', { 
  corners: { x: 3, y: 3 }, 
  edges: { 
    points: 2,      // 2 points per edge 
    deviation: 2    // max offset from edge line 
  } 
});

With Shadow

Since clip-path clips box-shadow, wabi.js provides a built-in shadow option using filter: drop-shadow():

wabi('#card', { 
  corners: { x: 5, y: 4 }, 
  shadow: { 
    x: 0,                      // horizontal offset (default: 0) 
    y: 4,                      // vertical offset (default: 4) 
    blur: 8,                   // blur radius (default: 8) 
    color: 'rgba(0,0,0,0.15)'  // shadow color 
  } 
});

Warning: Enabling shadows wraps the target element in a DOM container to apply the shadow without clipping it. While wabi.js automatically copies layout styles (flex, grid, position, etc.) to this wrapper, this might still affect complex layouts or CSS selectors that depend on parent-child relationships. Test thoroughly when using shadows.

Animation

Continuously randomize the shape at a given interval for a dynamic effect:

<script>
  window.addEventListener('load', function() { 
    var result = wabi('.cards', { corners: { x: 5, y: 4 } }); 
 
    // Start animation (default: 100ms interval) 
    result.animate(); 
 
    // Or with custom interval 
    result.animate({ interval: 200 }); 
 
    // Stop animation 
    result.stop(); 
 
    // Check if animating 
    console.log(result.isAnimating); // true or false 
  });
</script>

You can also auto-start animation via options:

// Auto-start with default 100ms interval 
wabi('.cards', { corners: { x: 5, y: 4 }, animate: true }); 
 
// Auto-start with custom interval 
wabi('.cards', { corners: { x: 5, y: 4 }, animate: { interval: 200 } });

API

wabi(selector, options)

| Parameter | Type | Description | |-----------|------|-------------| | selector | string \| Element \| NodeList | CSS selector, DOM element, or collection | | options | object | Configuration object |

Options

{ 
  corners: { 
    x: 5,              // Max horizontal offset (default: 5) 
    y: 4,              // Max vertical offset (default: 4) 
    independent: true  // Each corner moves independently 
  }, 
  edges: { 
    points: 0,         // Points per edge (default: 0, disabled) 
    deviation: 3,      // Max perpendicular offset 
    distribution: 'random'  // 'random' | 'even' | 'weighted-center' 
  }, 
  shadow: {            // Shadow options (null or false = disabled) 
    x: 0,              // Horizontal offset in px (default: 0) 
    y: 4,              // Vertical offset in px (default: 4) 
    blur: 8,           // Blur radius in px (default: 8) 
    color: 'rgba(0,0,0,0.15)'  // Shadow color 
  }, 
  cutCorners: 0,       // Number of corners (0-4) to cut off (default: 0) 
  cornerChamfer: 1,    // How far to cut corners, 0-1 (default: 1, full cut) 
  seed: null,          // Random seed for reproducibility 
  units: '%',          // 'px' or '%' 
  preserveOnResize: true, 
  wrapperClass: '',    // Custom class to add to shadow wrapper 
  animate: false       // true or { interval: 100 } to auto-start animation 
}

Return Value

{ 
  elements: [...],      // Array of affected DOM elements 
  restore: Function,    // Remove effect, restore original 
  update: Function,     // Regenerate with new random values 
  setOptions: Function, // Update options and re-render 
  animate: Function,    // Start animation: animate({ interval: 100 }) 
  stop: Function,       // Stop animation 
  isAnimating: boolean  // Whether animation is running 
}

Browser Support

Works in all modern browsers that support clip-path: polygon():

  • Chrome 55+
  • Firefox 54+
  • Safari 9.1+
  • Edge 79+

Limitations

  • clip-path clips visually but doesn't affect layout
  • Borders are clipped (use the built-in shadow option for shadows)
  • Overrides border-radius
  • Shadows: Change DOM structure by wrapping element (see warning above), will not work on elements with absolute or fixed positioning, might break margin:auto alignment.

License

MIT