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

@myrkh/memory-graph

v0.2.0

Published

Ambient reading-attention graph for React. Multi-page · multi-strategy · 2D column layout · annotations · intertab sync. Token-only styling. Zero network.

Readme

@myrkh/memory-graph

npm license React TypeScript

Visualize reading attention as a living node-link graph. Drop it into any React app, mark the elements you want tracked, and watch a graph materialize behind a slide-out panel — stations, passages, edges, annotations, the whole reading trail.

Multi-DOM. Multi-strategy. Smart defaults. Token-only styling. Zero network.

Install

npm i @myrkh/memory-graph
# or
pnpm add @myrkh/memory-graph

Peer deps: react >= 18, react-dom >= 18.

Quick start

Wrap your app once<MemoryGraph.Root> is a Provider, the canonical pattern for stateful libs (same idea as <QueryClientProvider>, <TooltipProvider>). Mark the elements you want tracked with data-mg-id, anywhere in the tree.

import '@myrkh/memory-graph/styles';
import '@myrkh/memory-graph/themes/stit-claude'; // optional theme
import { MemoryGraph } from '@myrkh/memory-graph';

export function App() {
  return (
    <MemoryGraph.Root storageKey="mg:my-app">
      <YourContent />

      {/* Panel + all chrome singletons — mount once */}
      <MemoryGraph.Handle />
      <MemoryGraph.Panel>{/* … head, stats, graph, footer */}</MemoryGraph.Panel>
      <MemoryGraph.Backdrop />
      <MemoryGraph.Tooltip />
      <MemoryGraph.SelectionToolbar />
      <MemoryGraph.KeyboardShortcuts />
    </MemoryGraph.Root>
  );
}

Then anywhere inside, on any DOM element:

<p data-mg-id="intro">…</p>                       {/* viewport dwell (default) */}
<h2 data-mg-id="s1">…</h2>                        {/* auto-inferred: heading kind */}
<button data-mg-id="tab1">…</button>              {/* auto: click strategy */}
<input data-mg-id="query" />                      {/* auto: focus strategy */}
<div data-mg-id="kpi1" data-mg-kind="kpi"         {/* explicit KPI square */}
     data-mg-strategy="hover" data-mg-dwell="1200">…</div>
<figure data-mg-id="fig1">…</figure>              {/* auto: figure diamond */}

Every [data-mg-id] gets uniform behavior: tracked, annotatable (partial selection → inline mark, full selection → block treatment), hover-linked, flash-reachable, persistable.

Multi-page tracking — the route dimension

Pass a route prop on <Root> to tell the graph which "bucket" the user is currently in. Whatever the consumer wants — URL pathname, tab id, doc id, feature flag. Agnostic of any routing library.

<MemoryGraph.Root
  storageKey="mg:my-app"
  route={currentPathname}        // "/home", "/docs", "/pricing", …
  onPersistError={(err) => toast(`Couldn't save: ${err.message}`)}
>
  {/* Stays rendered across route changes — track across the whole site. */}
</MemoryGraph.Root>

When two or more unique routes accumulate in state, the <Graph> automatically switches to a 2D column layout — one column per route, laid out chronologically in the order routes were first visited. Edges crossing a route boundary get a distinct coral-dashed treatment (data-mg-route-jump). Single-route graphs stay in the legacy single-column mode.

The graph auto-follows your current route with a smooth horizontal scroll, so navigating to a new page centers its column in the viewport.

Custom node shapes — renderNode

Give a specific tracked element its own SVG without polluting NodeKind with site-specific values :

<MemoryGraph.Graph
  renderNode={(item, ctx) =>
    item.id === 'ui-theme-toggle'
      ? <ThemeToggleNode r={ctx.r} />   /* your custom shape */
      : null                             /* fall back to default kind */
  }
/>

Pulse, pinned ring, highlight ring and order label stay library-managed — the escape hatch only replaces the shape geometry.

Zoom controls

<MemoryGraph.Graph> ships a floating zoom satellite (in / out / fit) anchored to the panel's right edge. Focal-point preservation keeps the viewport center anchored through the transition; a brief blur masks any perceptual jitter. Visibility is gated by the panel open state, so the controls never linger off-screen.

Intertab sync

Multiple tabs open on the same origin stay in sync automatically via the browser's native storage event. Any write from one tab is picked up by every other tab of the same origin and rehydrates into the reducer — no BroadcastChannel, no sync server, no dependency. Zero config.

Four capture strategies

| strategy | when it fires | inferred from | |---|---|---| | viewport (default) | element centered in attention band for DWELL_MS | <p>, <div>, everything else | | click | element is clicked | <button>, <a>, [role="button"\|"link"\|"tab"] | | focus | keyboard focus rests for data-mg-dwell ms | <input>, <textarea>, <select> | | hover | pointer rests for data-mg-dwell ms | explicit only — no tag maps to hover |

Override with data-mg-strategy="…" per element, or disable smart inference globally with strategyInference: 'explicit' on the tracker.

Five node kinds

| kind | shape | inferred from | |---|---|---| | paragraph (default) | circle | <p>, rest | | heading | concentric ring | <h1><h6>, [role="heading"] | | figure | diamond | <figure>, <img>, <picture>, <video> | | code | rounded square | <pre>, standalone <code> | | kpi | square | explicit only (data-mg-kind="kpi") |

Annotations, uniform

Select text inside any [data-mg-id] → toolbar opens → Note, Pin, or Link. Selections that cover the whole element become block-scope annotations (card-level treatment); partial selections become inline <mark> underlines. Same behavior in <p>, <aside>, <figure>, <blockquote> — zero primitive wrapping required.

Keyboard shortcuts

When <MemoryGraph.KeyboardShortcuts /> is mounted:

  • ⌘M / Ctrl+M — toggle the panel
  • P — toggle pin on the currently centered paragraph
  • Escape — close panel / cancel linking mode

Philosophy

Five non-negotiable laws, straight from the original vanilla component:

  1. Zero network. Everything lives in localStorage.
  2. Passive observation. Watch silently, respond only to explicit gestures.
  3. Temporal topology only. Y axis = firstAt. Never force-directed.
  4. Return-edges curve right. Cubic Bézier, non-negotiable signature.
  5. Three-second dwell. Below the threshold, it's a passage, not a station.

Docs

Full documentation, live demo, and source at github.com/Myrkh/memory-graph.

License

MIT — © Yoann Dumont