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

alpha-mask-events

v1.0.1

Published

Enable click‑through on transparent regions of images (PNG, WebP, AVIF, GIF, SVG) using alpha masks.

Downloads

26

Readme

Alpha Mask Events

npm version License: MIT Build Status

Enable click-through on transparent parts of images (PNG, WebP, AVIF, etc.) and background-images, making irregularly shaped UI elements behave naturally.

Demo GIF

Why use Alpha Mask Events?

Ever been frustrated when:

  • You had to use CSS clip-paths or complex SVG masks to make irregularly shaped elements clickable only on their visible parts?
  • You wanted to stack elements and have clicks "fall through" the transparent regions?
  • You want greater control over pointer events and transparent images?

This lightweight library solves these problems with minimal setup and supports all modern image formats with transparency.

Supported Image Formats

✅ Full Transparency Support

  • PNG - Universal browser support, full alpha channel
  • WebP - Modern browsers (Chrome 23+, Firefox 65+, Safari 14+), full alpha channel
  • AVIF - Latest browsers (Chrome 85+, Firefox 93+, Safari 16.4+), full alpha channel
  • SVG - Modern browsers, transparency via CSS/opacity

⚠️ Limited Transparency Support

  • GIF - Universal support, binary transparency only
  • TIFF - Limited browser support, some transparency capability
  • ICO - Limited browser support, basic transparency

❌ No Transparency (processed with warnings)

  • JPEG/JPG - Universal support, no transparency
  • BMP - Limited support, no transparency

Table of Contents

Installation

npm install alpha-mask-events
# or
yarn add alpha-mask-events

Quick Start

Method 1: Auto-detect images (recommended)

Add .alpha-mask-events class to any image or element with background-image:

<img src="logo.png" class="alpha-mask-events" />
<img src="hero.webp" class="alpha-mask-events" />
<img src="avatar.avif" class="alpha-mask-events" />
<div class="alpha-mask-events" style="background-image: url('shape.png')"></div>
<div class="alpha-mask-events" style="background-image: url('icon.webp')"></div>

Initialize the library:

import AME from 'alpha-mask-events';

// Initialize and auto-detect all elements with .alpha-mask-events class
AME.init();

Method 2: Manual Registration

import AME from 'alpha-mask-events';

// Initialize without auto-detection
const manager = AME.init({ autoScan: false });

// Register specific elements
AME.register('#logo');
AME.register(document.querySelector('.irregular-button'));

CDN via JsDelivr

Grab the <script> code here: https://www.jsdelivr.com/package/npm/alpha-mask-events

JS:

AlphaMaskEvents.init(); // Scan and activate all .alpha-mask-events
AlphaMaskEvents.register(document.querySelector('#myImg'), { threshold: 0.95 });

HTML:

<img src="sprite.png" class="alpha-mask-events">

Use Cases

Interactive Maps with Irregularly Shaped Regions

<div class="map-container">
  <img src="map-background.jpg" style="width: 100%; height: auto;" />
  <img src="region1.png" class="alpha-mask-events region" data-region="north" />
  <img src="region2.png" class="alpha-mask-events region" data-region="south" />
</div>

<script>
  import AME from 'alpha-mask-events';
  
  // Initialize click-through behavior
  AME.init();
  
  // Add click handlers to regions
  document.querySelectorAll('.region').forEach(region => {
    region.addEventListener('click', () => {
      alert(`You clicked the ${region.dataset.region} region!`);
    });
  });
</script>

Dynamic UI with Overlapping Elements

// Create a layered UI where clicks pass through transparent areas
const layers = document.querySelectorAll('.ui-layer');
layers.forEach(layer => AME.register(layer));

// Dynamically adjust threshold based on user interaction
document.getElementById('sensitivity-slider').addEventListener('change', (e) => {
  AME.setThreshold(e.target.value / 100);
});

Shape-Conforming Buttons

Make clickable areas match the actual visible shape of buttons:

<button class="shaped-button alpha-mask-events">
  <img src="button-shape.png" alt="Custom Button" />
  <span class="button-text">Click Me</span>
</button>

<style>
  .shaped-button {
    position: relative;
    background: transparent;
    border: none;
    padding: 0;
  }
  .button-text {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: white;
    pointer-events: none; /* Let clicks go through to the image */
  }
</style>

API Reference

init(options)

Initialize click-through manager on the page.

  • options (object)
    • threshold (number, optional): Transparency cutoff (0–1). Pixels with alpha ≤ threshold are click-through. Default: 0.999
    • autoScan (boolean, optional): Auto-detect elements with .alpha-mask-events class. Default: true
    • log (boolean, optional): Enable console logs for debugging. Default: false

Returns the manager instance.

register(target, opts)

Register an element or selector for click-through.

  • target (HTMLElement|string): Element or CSS selector
  • opts (object, optional)
    • threshold (number, optional): Per-element transparency cutoff. Default: global threshold

unregister(target)

Stop hit-testing and restore normal pointer behavior on the element.

  • target (HTMLElement|string): Element or CSS selector

setThreshold(value)

Adjust global transparency threshold.

  • value (number): New threshold (0–1), where lower values make more pixels click-through

Custom Events

Alpha Mask Events dispatches custom events when the mouse cursor transitions between opaque and transparent regions of registered elements.

alpha-mask-over

Fired when the cursor moves from a transparent region to an opaque region (or enters an opaque region from outside the element).

alpha-mask-out

Fired when the cursor moves from an opaque region to a transparent region (or leaves an opaque region by exiting the element).

Event Object Properties

Both events include a detail object with the following properties:

  • element (HTMLElement): The element that triggered the event
  • alpha (number): The alpha value (0-1) at the cursor position
  • coordinates (object): Canvas coordinates { x: number, y: number } where the event occurred
  • threshold (number): The threshold value used for this element

Usage Example

import AME from 'alpha-mask-events';

// Initialize and register an element
AME.init();
const element = document.querySelector('.my-image');

// Listen for opacity transition events
element.addEventListener('alpha-mask-over', (event) => {
  console.log('Mouse entered opaque region');
  console.log('Alpha value:', event.detail.alpha);
  console.log('Coordinates:', event.detail.coordinates);
  console.log('Threshold:', event.detail.threshold);

  // Add visual feedback
  element.classList.add('hover-opaque');
});

element.addEventListener('alpha-mask-out', (event) => {
  console.log('Mouse left opaque region');
  
  // Remove visual feedback
  element.classList.remove('hover-opaque');
});

TypeScript Support

import AME, { AlphaMaskEvent } from 'alpha-mask-events';

const element = document.querySelector('.my-image') as HTMLElement;

element.addEventListener('alpha-mask-over', (event: AlphaMaskEvent) => {
  // TypeScript knows about event.detail properties
  const { alpha, coordinates, threshold, element } = event.detail;
  console.log(`Alpha: ${alpha}, Coords: ${coordinates.x},${coordinates.y}`);
});

CLI Usage

Generate compact masks for opaque regions in transparent images (useful for server-side optimizations).

npx ame-generate-masks <images...> --out <file> [options]

Supported formats: PNG, WebP, AVIF, GIF, BMP, TIFF

Examples:

# Process multiple PNG files
npx ame-generate-masks sprites/*.png --out masks.json

# Process mixed formats with custom threshold
npx ame-generate-masks logo.png hero.webp avatar.avif --out masks.json --threshold 0.2

# Process with blur for smoother edges
npx ame-generate-masks button.png --out button-mask.json --blur 2

Options:

  • <images...>: One or more image paths or glob patterns
  • --out (string, required): Path to output JSON file
  • --threshold (number, default: 0.1): Alpha threshold (0–1). Pixels with alpha > threshold are included in the opaque mask
  • --blur (number, default: 1): Box blur radius in pixels applied to alpha channel before thresholding

Output format:

{
  "logo.png": {
    "width": 256,
    "height": 256,
    "rects": [
      { "x": 10, "y": 10, "w": 50, "h": 1 },
      { "x": 8, "y": 11, "w": 54, "h": 1 }
    ]
  },
  "hero.webp": {
    "width": 800,
    "height": 600,
    "rects": [...]
  }
}

Advanced Examples

React Integration

import React, { useEffect, useRef } from 'react';
import AME from 'alpha-mask-events';

function TransparentButton({ imageUrl, onClick, threshold = 0.8 }) {
  const buttonRef = useRef(null);
  
  useEffect(() => {
    if (buttonRef.current) {
      // Register the element when component mounts
      AME.register(buttonRef.current, { threshold });
      
      // Clean up when component unmounts
      return () => {
        AME.unregister(buttonRef.current);
      };
    }
  }, [threshold]);
  
  return (
    <button 
      ref={buttonRef} 
      onClick={onClick}
      style={{ 
        backgroundImage: `url(${imageUrl})`,
        backgroundSize: 'contain',
        backgroundRepeat: 'no-repeat',
        border: 'none',
        padding: '20px'
      }}
    />
  );
}

// Usage
function App() {
  useEffect(() => {
    AME.init({ log: process.env.NODE_ENV === 'development' });
  }, []);
  
  return (
    <div>
      <TransparentButton 
        imageUrl="/irregular-button.png"
        onClick={() => console.log('Button clicked!')}
        threshold={0.5}
      />
    </div>
  );
}

Vue Integration

<template>
  <button 
    ref="transparentBtn"
    class="transparent-btn"
    @click="handleClick"
    :style="{ backgroundImage: `url(${imageUrl})` }"
  >
    <slot></slot>
  </button>
</template>

<script>
import AME from 'alpha-mask-events';

export default {
  props: {
    imageUrl: String,
    threshold: {
      type: Number,
      default: 0.8
    }
  },
  
  mounted() {
    // Initialize AME if this is the first component
    if (!this.$AME) {
      this.$AME = AME.init({ log: process.env.NODE_ENV === 'development' });
    }
    
    // Register this button
    AME.register(this.$refs.transparentBtn, { threshold: this.threshold });
  },
  
  beforeDestroy() {
    AME.unregister(this.$refs.transparentBtn);
  },
  
  methods: {
    handleClick() {
      this.$emit('click');
    }
  }
}
</script>

<style scoped>
.transparent-btn {
  background-size: contain;
  background-repeat: no-repeat;
  border: none;
  padding: 20px;
  cursor: pointer;
}
</style>

Dynamic Content and Intersection Observer

For dynamic content or long pages, combine with IntersectionObserver for better performance:

import AME from 'alpha-mask-events';

// Initialize
AME.init({ threshold: 0.8 });

// Setup IntersectionObserver to only process visible elements
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    const el = entry.target;
    
    if (entry.isIntersecting) {
      // Element is visible, register it
      AME.register(el);
    } else {
      // Element is off-screen, unregister to save resources
      AME.unregister(el);
    }
  });
}, { rootMargin: '100px' });

// Observe all transparency-enabled elements
document.querySelectorAll('.alpha-mask-events').forEach(el => {
  observer.observe(el);
});

Browser Compatibility

  • Chrome 50+
  • Firefox 50+
  • Safari 11+
  • Edge 18+
  • iOS Safari 11+
  • Android Browser 76+

Polyfill required for:

  • ResizeObserver (for older browsers)
  • PointerEvent (falls back to touch events on older mobile browsers)

Performance Tips

  1. Automatic Image Caching:

    • The library automatically caches loaded images to avoid redundant network requests
    • Multiple elements using the same image source share a single cached Image object
    • Cache persists for the entire page session, providing instant registration for repeated images
    • Memory efficient: images are cached by URL, not duplicated per element
  2. Use appropriate threshold values:

    • Higher values (closer to 1.0) make fewer pixels click-through
    • Lower values (closer to 0.0) make more pixels click-through
  3. Optimize image sizes:

    • Large images take longer to process
    • Consider resizing images to actual displayed dimensions
  4. Unregister elements when not needed:

    • Use AME.unregister() for elements being removed from DOM
  5. Use the CLI tool for static masks:

    • For static images, pre-generate mask data
    • Load JSON masks instead of analyzing images at runtime

How to Create a Mask Using the CLI

To generate a mask for an image using the CLI tool, use the npx ame-generate-masks command. This will analyze the transparency of your image and output a JSON mask file describing the opaque regions.

Example: Generate a Mask for a PNG Image

npx ame-generate-masks logo.png --out logo-mask.json

This command processes logo.png and writes the mask data to logo-mask.json.

Example: Custom Threshold and Blur

npx ame-generate-masks hero.webp --out hero-mask.json --threshold 0.2 --blur 2
  • --threshold 0.2: Pixels with alpha > 0.2 are considered opaque (included in mask).
  • --blur 2: Applies a box blur of radius 2 pixels to the alpha channel before thresholding.

Example: Multiple Images

npx ame-generate-masks sprites/*.png --out masks.json

Processes all PNG files in the sprites directory and outputs a combined mask file.

Output Format

The output JSON contains the dimensions and rectangles for each image's opaque regions:

{
  "logo.png": {
    "width": 256,
    "height": 256,
    "rects": [
      { "x": 10, "y": 10, "w": 50, "h": 1 },
      { "x": 8, "y": 11, "w": 54, "h": 1 }
    ]
  }
}

Tip: Use the generated mask file for server-side hit-testing or to optimize client-side performance by loading precomputed mask data.

Development

  • Build: npm run build (uses Rollup)
  • Test: npm test (Jest)
  • Lint: npm run lint

Testing

The library includes comprehensive tests to ensure reliability:

Browser Library Tests (manager.test.js)

  • Element Registration: Verifies elements can be added to and removed from the registry
  • Threshold Management: Tests that setThreshold updates all registered elements
  • Auto-scanning: Confirms that .alpha-mask-events elements are automatically detected
  • Event Handling: Validates pointer event handling infrastructure

CLI Tool Tests (generate-masks.test.js)

  • Mask Generation: Tests creation of JSON-based rectangle masks from PNG transparency
  • Output Validation: Ensures generated masks contain proper width, height and rectangle data
  • Error Handling: Verifies appropriate error when no images are provided
  • User Feedback: Confirms proper success messages are displayed

Run all tests with npm test.

Contributing

Contributions welcome! Please open an issue or pull request on GitHub.

License

MIT