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

hy-masonry

v1.0.0

Published

Animated Masonry Layout as Web Component - Living organisms that morph and breathe

Readme

HY Masonry 🏗️✨

Living Animated Masonry Layout - A JavaScript library that creates living, breathing masonry layouts where each box is an animated organism that can morph, grow, and respond to user interactions.

🌐 Live Demo & Documentation: https://masonry.ovh

🌟 Features

🧬 Living Organisms

  • Each masonry box is an animated entity with its own life cycle
  • Default breathing/pulsing animations that make items feel alive
  • Smooth transitions between states with organic movement patterns
  • Hardware-accelerated animations for 60fps performance

🔄 Dynamic Morphing

  • Boxes can temporarily change size (e.g., 1x2 → 1x4)
  • Morphing triggered by:
    • Hover: Items grow when you hover over them
    • Long Press: Items expand for preview mode
    • Programmatic Events: API-driven morphing
    • Automatic Cycles: Scheduled morphing animations

⚙️ Intuitive Configuration

  • Simple JSON-based configuration
  • Responsive design with breakpoint support
  • Customizable animation parameters
  • Easy integration with React, ShadCN, and any framework

🎨 Web Component Architecture

  • Native web component implementation
  • Framework-agnostic design
  • Customizable styling via CSS custom properties
  • Multiple themes: Default, Dark, Minimal

🚀 Quick Start

Installation

npm install hy-masonry

Basic Usage

<!DOCTYPE html>
<html>
<head>
    <script type="module">
        import 'hy-masonry';
    </script>
</head>
<body>
    <hy-masonry id="my-masonry" data-theme="default">
        <!-- Items will be added dynamically -->
    </hy-masonry>

    <script>
        const masonry = document.getElementById('my-masonry');
        
        // Add items
        masonry.addItem({
            id: 'item-1',
            size: '1x2',
            content: '<h3>Living Item</h3><p>I breathe and morph!</p>',
            animationType: 'breathing',
            backgroundColor: '#e3f2fd',
            morphSize: '2x4'
        });
    </script>
</body>
</html>

React Integration

import { useEffect, useRef } from 'react';
import 'hy-masonry';

function MasonryGallery() {
    const masonryRef = useRef(null);

    useEffect(() => {
        if (masonryRef.current) {
            masonryRef.current.addItem({
                id: 'react-item',
                size: '2x2',
                content: '<h3>React Item</h3><p>Works with React!</p>',
                animationType: 'pulse',
                morphOnHover: true,
                morphSize: '2x4'
            });
        }
    }, []);

    return (
        <hy-masonry 
            ref={masonryRef}
            data-theme="default"
            style={{ width: '100%', height: '400px' }}
        />
    );
}

📖 API Reference

Configuration

const config = {
    // Layout
    columns: 4,                    // Number of columns
    gap: 16,                       // Gap between items (px)
    padding: 20,                   // Container padding (px)
    
    // Animation
    animation: true,               // Enable animations
    breathingSpeed: 2000,          // Breathing cycle duration (ms)
    
    // Morphing
    morphing: true,                // Enable morphing
    morphDuration: 500,            // Morph animation duration (ms)
    hoverMorph: true,              // Morph on hover
    longPressMorph: true,          // Morph on long press
    
    // Responsive
    responsive: true,              // Enable responsive behavior
    breakpoints: {                 // Responsive breakpoints
        mobile: { columns: 2, gap: 12 },
        tablet: { columns: 3, gap: 14 },
        desktop: { columns: 4, gap: 16 }
    },
    
    // Styling
    theme: 'default',              // Theme: 'default', 'dark', 'minimal'
    borderRadius: 8,               // Border radius (px)
    shadow: true,                  // Enable shadows
};

Item Configuration

const item = {
    id: 'unique-id',               // Unique identifier
    size: '1x2',                   // Grid size: '1x1', '1x2', '2x1', '2x2', etc.
    content: '<h3>Title</h3><p>Content</p>', // HTML content
    image: 'path/to/image.jpg',    // Background image
    backgroundColor: '#ffffff',     // Background color
    textColor: '#000000',          // Text color
    
    // Animation
    animationType: 'breathing',    // 'breathing', 'pulse', 'float', 'none'
    animationDelay: 0,             // Animation delay (ms)
    
    // Morphing
    morphOnHover: true,            // Enable hover morphing
    morphOnLongPress: true,        // Enable long press morphing
    morphSize: '2x4',              // Size when morphed
    morphDuration: 500,            // Morph duration for this item
    
    // Interaction
    clickable: true,               // Make item clickable
    hoverable: true,               // Enable hover effects
    
    // Event handlers
    onClick: (event, item) => {},  // Click handler
    onHover: (event, item) => {}, // Hover handler
    onLongPress: (event, item) => {}, // Long press handler
};

Methods

// Add item
masonry.addItem(itemConfig);

// Remove item
masonry.removeItem(itemId);

// Update item
masonry.updateItem(itemId, newConfig);

// Morph item
masonry.morphItem(itemId, newSize, duration);

// Reset item to original size
masonry.resetItem(itemId);

// Refresh layout
masonry.refresh();

// Update configuration
masonry.updateConfig(newConfig);

// Get items
const items = masonry.getItems();
const item = masonry.getItem(itemId);
const layout = masonry.getLayoutInfo();

Events

// Listen to events
masonry.addEventListener('item:added', (event) => {
    console.log('Item added:', event.detail.item);
});

masonry.addEventListener('item:morphed', (event) => {
    console.log('Item morphed:', event.detail);
});

masonry.addEventListener('layout:updated', (event) => {
    console.log('Layout updated:', event.detail.layout);
});

masonry.addEventListener('animation:start', (event) => {
    console.log('Animation started:', event.detail);
});

🎨 Themes

Default Theme

--bg-color: #ffffff;
--text-color: #000000;
--border-color: #e0e0e0;
--shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
--hover-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);

Dark Theme

--bg-color: #1a1a1a;
--text-color: #ffffff;
--border-color: #333333;
--shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
--hover-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);

Minimal Theme

--bg-color: #fafafa;
--text-color: #333333;
--border-color: #e5e5e5;
--shadow: none;
--hover-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);

🔧 Customization

CSS Custom Properties

:root {
    --hy-masonry-gap: 16px;
    --hy-masonry-padding: 20px;
    --hy-masonry-border-radius: 8px;
    --hy-masonry-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    --hy-masonry-transition: 300ms ease;
    --hy-masonry-breathing-speed: 2000ms;
    --hy-masonry-morph-duration: 500ms;
    --hy-masonry-bg-color: #ffffff;
    --hy-masonry-text-color: #000000;
    --hy-masonry-border-color: #e0e0e0;
    --hy-masonry-hover-scale: 1.02;
    --hy-masonry-hover-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}

Custom Animations

// Register custom animation
HyMasonry.registerAnimation('custom', (element, deltaTime) => {
    // Your custom animation logic
    const rotation = (Date.now() / 1000) % 360;
    element.style.transform = `rotate(${rotation}deg)`;
});

📱 Responsive Design

The library automatically adapts to different screen sizes:

  • Mobile (< 768px): 2 columns, smaller gaps
  • Tablet (768px - 1024px): 3 columns, medium gaps
  • Desktop (> 1024px): 4 columns, full gaps

♿ Accessibility

  • Keyboard Navigation: Full keyboard support with focus indicators
  • Screen Readers: Proper ARIA labels and semantic structure
  • Reduced Motion: Respects prefers-reduced-motion user preference
  • High Contrast: Supports high contrast mode
  • Touch Support: Optimized for mobile devices with touch gestures

🚀 Performance

  • Hardware Acceleration: Uses CSS transforms for smooth animations
  • Intersection Observer: Only animates visible items
  • Throttled Updates: Efficient resize and scroll handling
  • Memory Management: Proper cleanup of event listeners and animations

🛠️ Development

Setup

git clone https://github.com/hy-masonry/hy-masonry.git
cd hy-masonry
npm install
npm run dev

Build

npm run build

Test

npm test

📄 License

MIT License - see LICENSE file for details.

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

📞 Support


HY Masonry - Creating living, breathing layouts since 2025 ✨