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

markinjs

v0.1.0

Published

A lightweight, zero-dependency SVG annotation library for computer vision and image labeling projects

Readme

MarkinJS

A lightweight, zero-dependency SVG annotation library for computer vision and image labeling projects.

npm version npm downloads GitHub stars License Bundle Size No Dependencies


Overview

MarkinJS enables developers to create precise, pixel-perfect annotations on images for computer vision applications. Built for simplicity and performance, it provides a complete toolkit for bounding boxes, polygons, and keypoint annotations with advanced features like element binding, containment rules, and hierarchical relationships.

Perfect for:

  • Computer vision datasets
  • Image labeling workflows
  • Data annotation platforms
  • ML training data preparation
  • Research and prototyping

Demo

Live Demo - See MarkinJS in action with interactive examples

More Examples - Object detection, medical imaging, and advanced use cases

Installation

npm

npm install markinjs

CDN

<!-- Latest version -->
<script src="https://unpkg.com/markinjs/dist/markin.min.js"></script>

<!-- Or via jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/markinjs/dist/markin.min.js"></script>

ES Module

import MarkinJS from 'markinjs';

CommonJS

const MarkinJS = require('markinjs');

Script Tag

<script src="dist/markin.min.js"></script>

Quick Start

// Create annotator on an existing image
const annotator = MarkinJS.createImageAnnotator('your-image-id', {
    zoom: 1.0,
    keyboardControls: true
});

// Add a bounding box
annotator.createAnnotation({
    class: "person",
    bbox: [100, 100, 300, 250]
});

// Listen for events
annotator.on('select', (data) => {
    console.log('Selected:', data.element);
});

// Clean up when done
annotator.destroy();

Core Features

Annotation Types

  • Bounding Boxes - Rectangular regions with resize handles
  • Polygons - Precise outlines with draggable vertices
  • Keypoints - Point markers for specific features
  • Groups - Hierarchical element relationships

Advanced Capabilities

  • Element Binding - Child elements move with parents
  • Containment Rules - Keep elements within boundaries
  • Custom Deletion Rules - Configure cascade deletion behavior
  • Keyboard Controls - Precise movement (1px, 10px, 0.2px)
  • Event System - Rich interaction events for custom UI
  • Zoom Support - Works at any zoom level
  • Undo/Redo - Built-in history management

Technical Highlights

  • Zero dependencies
  • ~49KB minified
  • TypeScript declarations included
  • ESM, CJS, and IIFE builds
  • Modern browser support
  • Pixel-perfect precision
  • Framework agnostic

API Reference

Initialization

MarkinJS.createImageAnnotator(imageId, options)

Creates an SVG overlay on an existing image element.

const annotator = MarkinJS.createImageAnnotator('my-image', {
    zoom: 1.0,
    keyboardControls: true,
    bindElements: true
});

MarkinJS.createAnnotator(svgId, options)

Uses an existing SVG element for annotations.

Core Methods

| Method | Description | |--------|-------------| | createAnnotation(options) | Create new annotation | | getSelectedElement() | Get currently selected element | | deleteSelectedElement() | Delete selected element | | enable() / disable() | Toggle annotator state | | destroy() | Fully destroy the annotator and clean up all resources | | setZoom(level) | Set zoom level | | on(event, callback) | Add event listener | | off(event, callback) | Remove event listener | | saveState() | Save current state for undo | | undo() / redo() | Undo/redo operations |

Annotation Options

annotator.createAnnotation({
    uuid: "unique-id",           // Optional: auto-generated if not provided
    class: "person",             // Classification label
    bbox: [x1, y1, x2, y2],     // Bounding box coordinates
    segmentation: [x1,y1,x2,y2...], // Polygon points (flat array)
    keypoints: [                 // Named keypoints
        { name: "head", point: [x, y] },
        { name: "center", point: [x, y] }
    ],
    bindElements: true,          // Bind child elements to parent
    containRules: ["keypoint"],  // Elements to keep inside bbox
    deletionRules: {             // Custom deletion behavior
        "bbox": ["keypoint", "polygon"],
        "polygon": ["bbox"]
    }
});

Events

| Event | Description | Data | |-------|-------------|------| | select | Element selected | {element, type, data} | | deselect | Element deselected | {element, type} | | annotationcreated | New annotation created | {uuid, class, group, elements} | | delete | Element deleted | {role, groupId} | | elementmoved | Element moved | {element, type, deltaX, deltaY} | | dragstart, drag, dragend | Drag operations | {element, position} |

Examples

Computer Vision Dataset

// Initialize on dataset image
const annotator = MarkinJS.createImageAnnotator('dataset-image');

// Add person detection
annotator.createAnnotation({
    class: "person",
    bbox: [150, 100, 300, 400],
    keypoints: [
        { name: "head", point: [225, 120] },
        { name: "torso", point: [225, 250] }
    ],
    bindElements: true,
    containRules: ["keypoint"]
});

// Export annotations
const annotations = annotator.exportAllAnnotations();
console.log(JSON.stringify(annotations));

Medical Imaging

const annotator = MarkinJS.createImageAnnotator('medical-scan', {
    keyboardControls: true,
    deletionRules: {
        "bbox": ["keypoint"],  // Remove markers with regions
        "keypoint": []         // Keep regions when removing markers
    }
});

// Add anatomical region
annotator.createAnnotation({
    class: "lesion",
    bbox: [200, 150, 280, 220],
    keypoints: [
        { name: "center", point: [240, 185] },
        { name: "edge", point: [270, 200] }
    ]
});

Interactive Labeling Tool

const annotator = MarkinJS.createImageAnnotator('labeling-canvas');

// Real-time coordinate display
annotator.on('elementmoved', (data) => {
    document.getElementById('coordinates').textContent =
        `Position: (${Math.round(data.position.x)}, ${Math.round(data.position.y)})`;
});

// Selection info panel
annotator.on('select', (data) => {
    document.getElementById('selection-info').innerHTML = `
        <h3>Selected: ${data.type}</h3>
        <p>Class: ${data.data.class || 'None'}</p>
        <p>UUID: ${data.data.uuid || 'None'}</p>
    `;
});

Configuration

| Option | Type | Default | Description | |--------|------|---------|-------------| | zoom | Number | 1.0 | Current zoom level | | keyboardControls | Boolean | true | Enable arrow key movement | | bindElements | Boolean | true | Bind child to parent elements | | requireBbox | Boolean | false | Require bbox for all annotations | | bboxContainPolygon | Boolean | true | Keep polygons inside bbox | | bboxContainKeypoints | Boolean | true | Keep keypoints inside bbox | | historyEnabled | Boolean | true | Enable undo/redo history | | historyMaxStates | Number | 50 | Maximum number of undo states | | requireSelectionToDrag | Boolean | true | Require selection before dragging | | deletionRules | Object | See docs | Default deletion behavior |

Browser Support

  • All modern browsers (Chrome, Firefox, Safari, Edge)

Contributing

MarkinJS is currently in active development. We welcome feedback and bug reports!

See CONTRIBUTING.md for development setup and contribution guidelines.

Support

License

MIT License - see LICENSE file for details.


Maintained by Datamarkin