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

@grimoire-intel/mandala

v0.1.0

Published

Declarative, DOM-driven, AI-native SVG canvas Web Component

Readme

Mandala

Declarative, DOM-driven, AI-native SVG canvas Web Component.

<mnd-canvas width="400" height="300">
  <mnd-rect x="50" y="50" width="100" height="80" fill="blue" rx="8"></mnd-rect>
  <mnd-circle cx="250" cy="100" r="40" fill="red"></mnd-circle>
  <mnd-text x="150" y="200" font-size="24" fill="black">Hello, Mandala</mnd-text>
</mnd-canvas>

Installation

npm install @grimoire-intel/mandala

Usage

ES Modules

import '@grimoire-intel/mandala';

Script Tag

<script src="https://unpkg.com/@grimoire-intel/mandala/dist/index.iife.js"></script>

CommonJS

require('@grimoire-intel/mandala');

Elements

Canvas

<mnd-canvas width="600" height="400" background="#fafafa">
  <!-- children render as SVG -->
</mnd-canvas>

| Attribute | Description | |-----------|-------------| | width | Canvas width (px, %, or viewBox units) | | height | Canvas height | | viewbox | SVG viewBox (auto-computed if omitted) | | background | Background fill color | | interactive | Enable selection, drag, resize | | preserve-aspect-ratio | SVG preserveAspectRatio |

Primitives

| Element | SVG | Attributes | |---------|-----|------------| | <mnd-rect> | <rect> | x, y, width, height, rx, ry | | <mnd-circle> | <circle> | cx, cy, r | | <mnd-ellipse> | <ellipse> | cx, cy, rx, ry | | <mnd-line> | <line> | x1, y1, x2, y2 | | <mnd-polyline> | <polyline> | points | | <mnd-polygon> | <polygon> | points | | <mnd-path> | <path> | d | | <mnd-text> | <text> | x, y, font-size, font-family | | <mnd-image> | <image> | href, x, y, width, height | | <mnd-use> | <use> | href, x, y, width, height |

Structural

| Element | SVG | Purpose | |---------|-----|---------| | <mnd-group> | <g> | Group with shared transform | | <mnd-defs> | <defs> | Gradients, patterns, symbols |

Coordinate System

Three modes, distinguished by syntax:

<!-- ViewBox units (default, scales with canvas) -->
<mnd-rect x="50" y="50" width="100" height="80"></mnd-rect>

<!-- Pixels (fixed screen size) -->
<mnd-rect x="50px" y="50px" width="100px" height="80px"></mnd-rect>

<!-- Percentage (responsive) -->
<mnd-rect x="10%" y="10%" width="30%" height="20%"></mnd-rect>

Styling

All SVG presentation attributes pass through:

<mnd-rect
  fill="blue"
  stroke="black"
  stroke-width="2"
  opacity="0.8"
  transform="rotate(45)"
></mnd-rect>

CSS custom properties work:

<style>
  :root { --brand: #3b82f6; }
</style>
<mnd-rect fill="var(--brand)"></mnd-rect>

Interactive Mode

<mnd-canvas interactive>
  <mnd-rect x="50" y="50" width="100" height="80"></mnd-rect>
</mnd-canvas>
  • Click to select
  • Shift+Click for multi-select
  • Drag to move selected elements
  • Resize handles on single selection
  • Mouse wheel to zoom
  • Space+drag or middle mouse to pan

Events:

canvas.addEventListener('mnd-select', e => console.log(e.detail.target));
canvas.addEventListener('mnd-move', e => console.log(e.detail.x, e.detail.y));
canvas.addEventListener('mnd-resize', e => console.log(e.detail.width, e.detail.height));

Export

const canvas = document.querySelector('mnd-canvas');

// SVG string
const svg = canvas.toSVG();

// Data URL
const dataUrl = canvas.toDataURL();

// PNG Blob
const blob = await canvas.toPNG(2); // 2x resolution

Accessibility

ARIA attributes and title/desc pass through:

<mnd-rect
  role="img"
  aria-label="Blue square"
  title="Sales Q1"
  desc="Represents Q1 revenue"
></mnd-rect>

Grouping and Transforms

<mnd-group transform="translate(100, 100) rotate(45)">
  <mnd-rect x="0" y="0" width="50" height="50" fill="blue"></mnd-rect>
  <mnd-rect x="60" y="0" width="50" height="50" fill="red"></mnd-rect>
</mnd-group>

Gradients and Patterns

<mnd-canvas>
  <mnd-defs>
    <linearGradient id="sky" x1="0%" y1="0%" x2="0%" y2="100%">
      <stop offset="0%" stop-color="#87CEEB"/>
      <stop offset="100%" stop-color="#1E90FF"/>
    </linearGradient>
  </mnd-defs>

  <mnd-rect x="0" y="0" width="100%" height="100%" fill="url(#sky)"></mnd-rect>
</mnd-canvas>

API

const canvas = document.querySelector('mnd-canvas');

// Properties
canvas.svg              // The rendered SVG element
canvas.interactive      // Get/set interactive mode

// Methods
canvas.render()         // Force re-render
canvas.toSVG()          // Export as SVG string
canvas.toDataURL()      // Export as data URL
canvas.toPNG(scale)     // Export as PNG Blob

// Selection API (interactive mode)
canvas.getSelection()   // Get selected elements
canvas.select(element)  // Select programmatically
canvas.deselect(element)
canvas.clearSelection()

// Pan/Zoom API (interactive mode)
canvas.zoom(level)      // Set zoom (1 = 100%)
canvas.pan(x, y)        // Pan to position
canvas.resetView()      // Reset to initial view
canvas.getZoom()        // Get current zoom
canvas.getViewBox()     // Get current viewBox

Browser Support

Works in all modern browsers (Chrome, Firefox, Safari, Edge). Requires:

  • Custom Elements v1
  • Shadow DOM v1
  • ResizeObserver

License

MIT