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

@siali/sorolla

v2.4.2

Published

Annotation surface (bbox + polygon) for Siali, on React 19 + Konva

Readme

@siali/sorolla

Annotation surface for React 19: draw and correct bboxes and polygons over an image, with zoom, pan and keyboard shortcuts. The host owns the data, the toolbar and the chrome; the library owns the canvas.

pnpm add @siali/sorolla konva react-konva zustand

react, react-dom, konva and zustand are peer dependencies. React 18 users stay on the 1.x line:

pnpm add @siali/sorolla@react-18

Minimal example

'use client';

import { SorollaAnnotator, type Annotation } from '@siali/sorolla';
import { useState } from 'react';

export function Review({ image }: { image: string }) {
  const [annotations, setAnnotations] = useState<Annotation[]>([]);

  return (
    <div style={{ height: 600 }}>
      <SorollaAnnotator
        image={image}
        annotations={annotations}
        onAnnotationsChange={setAnnotations}
        createId={() => crypto.randomUUID()}
      />
    </div>
  );
}

The component fills its parent, so give the container a height. In Next.js, import it dynamically with ssr: false and mark canvas as a webpack external (Konva pulls the node bindings during SSR).

Model

Every coordinate is normalized to 0–1 against the image, never stage pixels.

type Annotation =
  | { id: string; type: 'bbox'; box: { x: number; y: number; w: number; h: number }; label?: string; meta?: Record<string, unknown> }
  | { id: string; type: 'polygon'; points: { x: number; y: number }[]; label?: string; meta?: Record<string, unknown> };

Invariants:

  • box.x / box.y is the top-left corner; box.w and box.h are >= 0.
  • A polygon has at least MIN_POLYGON_VERTICES (3) vertices, in contour order.
  • Ids are unique inside the array.
  • onAnnotationsChange always receives the full replacement array, never patches.
  • meta is opaque to the library: put domain data (detection ids, status, origin) there and map it in the host.

Style is render, not data: there are no color or stroke fields in the model. lookById[id].edges paints host strings on the four sides of a bbox (or the AABB of a polygon). Sorolla does not compute size or units.

Props

| Prop | Type | Notes | |---|---|---| | image | string | Image URL painted under the annotations | | annotations | Annotation[] | Source of truth, owned by the host | | onAnnotationsChange | (next: Annotation[]) => void | Full array on every create, edit and delete | | createId | () => string | Identity for new annotations | | tool / onToolChange | ToolId | select | bbox | polygon | pan | | selectedId / onSelectedIdChange | string \| null | Single selection, syncable with a host list | | hoveredId / onHoveredIdChange | string \| null | Single hover, syncable with a host list | | enableShortcuts | boolean (default true) | Registers the shortcut map on the annotator container | | enableHistory | boolean (default true) | Snapshot undo/redo, up to 50 steps | | bodyDraggable | boolean (default true) | When false, bodies do not drag; handles still resize | | lockedIds | readonly string[] | Geometry cannot be moved, resized or deleted | | lookById | Record<string, AnnotationLook> | Per-id stroke, idle caption, optional dash, optional edges labels | | onViewportChange | (viewport: Viewport) => void | Read-only viewport telemetry | | className / style | — | Applied to the container |

Ref handle: fit(), zoomIn(), zoomOut(), cancelDraft().

tool, selectedId and hoveredId are optional: pass them to control the surface from a host toolbar or sidebar, omit them and the surface keeps its own state.

Tools

  • select — click to select, drag to move, corner handles to resize a bbox, vertex handles to edit a polygon; the midpoint handle inserts a vertex.
  • bbox — press, drag, release. A drag smaller than MIN_BOX_SIZE creates nothing.
  • polygon — click to add vertices, close by clicking the first vertex, double-clicking, or pressing Enter with 3 or more vertices.
  • pan — drag the image. Also available while holding Space or dragging with the middle button.

Deleting is an action on the selection, not a tool. Selecting and editing (drag, resize, vertices) happen under select. Under bbox / polygon, existing shapes do not intercept the pointer so you can draw over them.

Touch

Pointer events are unified, so a stylus or a finger draws like a mouse. Two fingers pinch to zoom and drag to pan at the same time, and a two-finger gesture cancels any draft it interrupts. On touch-first devices the handles grow automatically.

Shortcuts

Registered on the annotator container, so the surface never steals keys from the rest of the page. Mod is Ctrl on Windows/Linux and Cmd on macOS.

| Key | Action | |---|---| | V / B / P / H | select / bbox / polygon / pan | | Space (hold) | temporary pan | | Escape | cancel the draft, or deselect | | Delete / Backspace | delete the selection | | = / - / 0 | zoom in / zoom out / fit | | Mod+Z / Mod+Shift+Z / Mod+Y | undo / redo |

Zoom and viewport

Wheel and trackpad zoom anchored at the cursor, fit-contain on load and on container resize, fit() through the ref. The viewport is internal state; onViewportChange only reports it.

Not in 2.0

Line and point tools, freehand, measuring, multi-select and marquee, copy/paste, a product toolbar, a bidirectional controlled viewport, custom keymaps.