A lightweight, zero-dependency SVG annotation library for computer vision and image labeling projects.
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
Live Demo - See MarkinJS in action with interactive examples
More Examples - Object detection, medical imaging, and advanced use cases
npm install markinjs<!-- 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>import MarkinJS from 'markinjs';const MarkinJS = require('markinjs');<script src="dist/markin.min.js"></script>// 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();- Bounding Boxes - Rectangular regions with resize handles
- Polygons - Precise outlines with draggable vertices
- Keypoints - Point markers for specific features
- Groups - Hierarchical element relationships
- 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
- Zero dependencies
- ~49KB minified
- TypeScript declarations included
- ESM, CJS, and IIFE builds
- Modern browser support
- Pixel-perfect precision
- Framework agnostic
Creates an SVG overlay on an existing image element.
const annotator = MarkinJS.createImageAnnotator('my-image', {
zoom: 1.0,
keyboardControls: true,
bindElements: true
});Uses an existing SVG element for annotations.
| 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 |
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"]
}
});| 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} |
// 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));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] }
]
});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>
`;
});| 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 |
- All modern browsers (Chrome, Firefox, Safari, Edge)
MarkinJS is currently in active development. We welcome feedback and bug reports!
See CONTRIBUTING.md for development setup and contribution guidelines.
- Website: markinjs.com
- Issues: GitHub Issues
- Contact: markinjs@datamarkin.com
MIT License - see LICENSE file for details.
Maintained by Datamarkin