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

@brainworker/tackback

v0.9.0

Published

Anchored comments for any web page — attach to a block, a text phrase, or a region over images/diagrams and other non-text content; export as JSON or hook into a backend. Headless, zero runtime dependencies, offline.

Readme

Tackback

Anchored comments for any web page. Attach a comment to a place — a block element, a selected text phrase, or a rectangle drawn over an image, diagram, or other non-text content — persist it locally, and export it as JSON or hook it into a backend (per comment or all at once). It works on any HTML, including Markdown rendered to HTML. No backend required, no network, no runtime dependencies — it runs from a single offline page.

Version 0.9.0 (staging). Pre-1.0: the API is functional and tested but may still change before the 1.0 stable release. The public API is the JavaScript API called in the browser (not an HTTP API).

Install

npm install @brainworker/tackback

Or drop in the pre-built UMD bundle (exposes a global Tackback, no build step):

<script src="https://unpkg.com/@brainworker/tackback/dist/tackback.umd.js"></script>

Quick taste

Headless core — state, anchors, events, import/export, no DOM:

import { Tackback } from '@brainworker/tackback';

const tb = Tackback.mount({ document: { id: 'my-doc', title: 'Design notes' } });
tb.on('change', ({ comments, changes, source }) => {/* one seam to sync elsewhere; source ∈ local|import|storage */});

const c = tb.addComment({ anchor: { type: 'block', elementId: 'para-3' }, body: 'unclear', reaction: 'question' });
tb.updateComment(c.id, { body: 'still unclear after the edit' });
const envelope = tb.exportEnvelope();            // → portable JSON (the seam)
tb.importEnvelope(envelope, { mode: 'merge' });  // also accepts older exports (auto-migrated)

With the default UI — right-click a block, or select text + right-click to pin a phrase:

import { Tackback } from '@brainworker/tackback';
import { attachPanel } from '@brainworker/tackback/panel';

const tb = Tackback.mount({ document: { id: 'my-doc', title: 'Design notes' } });
attachPanel(tb, {
  theme: 'auto', locale: 'en',        // theming / reactions / i18n are all customizable
  controls: { theme: true },          // pick which panel buttons show; the theme switch is hidden by default
});

PDF is optional and not a focus. A region surface can be any non-text content (image, <canvas>, SVG, diagram). A PDF page is just one such surface: an optional @brainworker/tackback/pdf adapter (bring your own pdf.js) is included as a small sample integration — see the post-v1 PDF preview block in demo/demo.html. The core and panel never depend on pdf.js.

Try it in a browser: demo/demo.html is a single page that exercises the whole tool — a single-<script> UMD drop-in that renders as a live, commentable page (block/range/region over text, an inline SVG, an image, and a marked surface). Build the bundle (npm run build), serve the package root over http, and open it. The bottom-left "Try it" bar flips locale, swaps the reaction set, and toggles the theme switch; the bottom-right panel lists comments and exports/imports JSON. The page also shows an optional post-v1 PDF region preview (pdf.js from a CDN; degrades to a note offline).

The three anchor types

  • block — a whole element (heading / paragraph / list item / cell). Right-click it.
  • range — a text phrase, stored as a W3C TextQuoteSelector (exact + prefix/suffix + offset). Re-resolves across edits/reflow; on drift it fails loud (anchor:orphaned) and never silently re-points. Painted via the CSS Custom Highlight API (no DOM mutation).
  • region — a rectangle over any non-text surface (an image/diagram in a <figure>, a marked [data-tb-surface] element, or a PDF page), stored as a normalized rect, so it is zoom-independent (overlay = normalized × current surface size). The surface set is configurable via attachPanel(core, { regionSurfaces }); the drawn rectangle stays visible while you type. To re-resolve after a reload, the surface needs a stable identity — a [data-tb-surface] mark, a PDF page, or its own id; an unmarked, id-less surface is annotatable in-session only.

Customization

Three independent axes, all on the default panel:

  • Theming--tb-* CSS variables; theme: 'auto' follows the OS light/dark preference live.
  • Reactions — a fully replaceable set of { id, icon, label } (per-locale labels).
  • LanguagesetLocale() at runtime; English and Japanese ship, bring your own bundle.
  • Panel controlscontrols: { author, export, theme, marks, clear } chooses which buttons render. The theme switch is hidden by default (auto already follows the OS).

Modules

| import | responsibility | |---|---| | @brainworker/tackback | Tackback.mount → instance: CRUD, typed events, import/export, media-adapter coordination, lifecycle, anchor:orphaned | | @brainworker/tackback/panel | attachPanel — control panel (configurable via controls), anchored marks, comment popup, gesture capture (right-click block, select+right-click range, right-drag region), theming/reactions/i18n | | @brainworker/tackback/pdf | createPdfAdapter — an optional PDF adapter (renders pages to surfaces; pdf.js is a peer the consumer provides). PDF/raster surfaces are a post-v1 sample, not a v1 focus. |

The two real entry points are the core and the panel; the pdf adapter is optional. Everything a typical integrator needs — the storage adapters (localStorageAdapter / memoryAdapter), the envelope helpers (buildEnvelope / parseEnvelope), and the model/migration helpers — is re-exported from the main @brainworker/tackback entry, so there are no separate /anchor, /model, or /storage subpaths to learn.

Type declarations (.d.ts, generated from JSDoc) ship with the package.

Tests

npm test     # node --test — 69 tests, zero external deps

node:test + node:assert are built into Node ≥ 18 — no install needed, matching the library's runtime zero-dependency ethos. DOM/PDF rendering is verified in the browser via the single bundled demo (demo/demo.html): run npm run build, serve the package root over http, and open it. (Append ?raf-shim when verifying in a headless/background tab so pdf.js can finish rendering.)

License

PolyForm Shield License 1.0.0 (see LICENSE).

Use it for any purpose, including commerciallyexcept to provide a product or service that competes with Tackback (or with a product Brainworker provides using Tackback). For a competing use, or anything the license doesn't allow, contact [email protected].

PDF support uses pdf.js (Apache-2.0) but does not bundle it — you inject your own pdf.js into createPdfAdapter, so nothing of pdf.js is redistributed here.

Caveats

  • One instance per document. A single Tackback instance + panel per document is the supported shape; multiple panels in one document share the tb-range CSS highlight registration and would interfere.
  • importEnvelope is not document-bound. It does not check the envelope's document.id/revision against the current document — callers are responsible for matching. A partially-invalid replace import is refused (throws IMPORT_INVALID) unless allowPartial: true, so a malformed file can't silently wipe existing comments.
  • ready resolves, never rejects. Initialization/adapter failures surface on the error event (fail-soft); don't treat await ready as an all-adapters-mounted signal.