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

@modeldesk/respec

v0.1.1

Published

Reading features for ReSpec documents built from ModelDesk content bundles

Readme

ModelDesk ReSpec runtime

Reading features for ReSpec documents whose content comes from a ModelDesk content bundle. The runtime works off the data-md-* markers the bundle emits and nothing else, so it knows no metamodel. It is one classic script with its stylesheet inside and no dependencies.

Use

Load the script without class="remove", so that a published copy keeps it, and pin it with its integrity hash (the release prints the sha384 hash of each published version):

<script class="remove">
  var respecConfig = { specStatus: 'unofficial' };
</script>
<script
  src="https://cdn.jsdelivr.net/npm/@modeldesk/[email protected]/dist/modeldesk-respec.js"
  integrity="sha384-ytqM8F2hafxjLjoYd+eWA+WUrGOvq5v93wQvBwr/WEsUnR8CIMsCmuMmm2rFLlNV"
  crossorigin="anonymous"
></script>
<script src="https://www.w3.org/Tools/respec/respec-w3c" class="remove" defer></script>
  • Load it as a plain script, without async or defer: it has to be in place before ReSpec starts processing.
  • While ReSpec processes the document, the runtime runs as the last entry of respecConfig.postProcess, after data-include has put the diagram SVGs in the page and before an export saves it. Your own entries stay where they are. ReSpec ignores a postProcess that is a single function rather than an array; the runtime wraps it in an array, so it runs as well.
  • respecConfig may be declared before or after the script.
  • A saved copy carries the markup the runtime added. ReSpec's export marks the copy with a <meta name="generator">; there the runtime runs itself when the DOM is ready, even if a respecConfig was kept. It reuses that markup and only attaches its event handlers.
  • The stylesheet is injected as a <style> element. A page whose Content Security Policy restricts style-src has to allow it (with 'unsafe-inline' or the stylesheet's hash), or the diagrams show without the runtime's styles.

The interface text is Dutch when the document's lang starts with nl, English otherwise.

Diagrams

A bundle emits each diagram as a figure[data-md-diagram] that includes the SVG and holds the PNG as a fallback.

  • Strip. A slim strip above each diagram holds its full-view button on the right, so the button covers nothing the diagram draws and comes before the diagram's links in the Tab order. The button is 26 by 26 pixels; its edge, its icon and its focus ring stand at 3:1 or more against the page. A published copy keeps its strip; one saved by an older runtime, with the button over the drawing, has the button moved into one.

  • Inline. The SVG is shown at its own width through its viewBox, shrunk to the column when wider and never enlarged. Node and line links work as page links; hover and keyboard focus outline a node. A line that draws a model element (a relatiesoort, a generalisatie) answers within a few pixels of its route, and hover and focus light up the whole line, route and labels, in the focus colour; keyboard focus also draws the focus ring around the line's link. An element drawn as lines is one Tab stop and one link to a screen reader: the first line's route, named by the line's title without the isolates that keep its parts apart on screen (aria-label) and described by its end labels (its <desc>, isolates removed). Its labels' links, and the routes of any further lines of the same element, are for the pointer only (tabindex="-1", aria-hidden="true"). Host link styles (underline, colour, background, border) are reset inside the diagram. The page never listens to the wheel over a diagram, so scrolling past one scrolls the page.

  • Element list. Off unless the document asks for it:

    var respecConfig = {
      // …
      modeldesk: { features: { diagrams: { elementList: true } } },
    };

    Then, between each diagram and its caption, a <details data-md-detail> lists every linked node, then every linked line under the heading "Relaties" ("Relations" in a document that is not Dutch), each labelled from its <title> and sorted by label, as a way to each element's section from the keyboard. A line is listed once, although the SVG stamps it twice: around its route and around its labels. The heading's id comes from the figure's data-md-diagram, made unique in the page, and labels the list of lines (aria-labelledby). A configuration that is not an object literal at every step is ignored. A published copy runs without a configuration: it keeps the lists it was saved with and builds none. The list is not the diagram's text alternative; the document is, since every element the diagram links to has a section of its own, and the SVG carries its names as text.

  • Full view. The strip's button, or a click on the drawing outside a link, opens a dialog over the whole window. Drag to pan; zoom with the wheel, a pinch or the buttons; on the keyboard, + and - zoom, 0 fits, the arrow keys pan and Escape closes. Pan and zoom rewrite the SVG's viewBox and never transform it, so the drawing is sharp at every zoom level.

    • A click on a node or a line closes the view and goes to its section. A click that asks for another tab (Ctrl, Cmd, Shift, middle button) is left to the browser. Tab reaches nodes and lines, and pans one that is off the stage into view.
    • Links that do not point into the document do nothing in the full view.
    • The view shows a copy of the diagram without scripts, embedded documents, animations or event handlers.
    • A ReSpec save while the view is open leaves it out.
  • PNG. A figure whose SVG did not load, and an image in a section of a document from an older bundle, open the same full view on the PNG, at its own size at most. The figure gets the same strip, and so does an image that stands alone in its block; an image in running text, a heading, a caption, a table cell, a list item or a control opens on a click alone, since a strip there would break the text or nest a button. On such a figure the runtime removes ReSpec's error tooltip from the include, keeping ReSpec's id.

  • Landing. A jump from a diagram highlights the heading it lands on for a moment. A table row, row group or table that is a link target (an enumeration value, a constraint, a generalisatie, a relatiesoort in a relatierol table) lands a third of the way down the window, so its table header and the heading above it stay in view.

  • Print. The diagram prints at page width, in one piece, without the strip or the element list, and with no gap where the strip was; the full view never prints.

Animations and transitions are off for readers who ask for reduced motion. Text from the model (titles, captions, labels) is only ever written as text, never parsed as HTML.

The runtime is held to WCAG 2.1 AA, which Dutch government publications meet through the Webrichtlijnen: npm run test:browser runs axe-core over an inline figure, the open full view, the element list and a PNG figure, walks a figure and its full view with the keyboard, and reads Chromium's accessibility tree for a line's name and description. A screen-reader pass and Firefox and Safari remain manual.

Node and line links are realized when the bundle is written. An SVG that carries element stamps but no links is shown unlinked and gets no element list. The runtime tells a line from a node by the invisible band the serializer draws along a line's route to take the pointer; every group with that line's stamp is the line's.

Development

npm test               # vitest under jsdom
npm run test:browser   # what jsdom cannot show (layout, painted styles, pointer capture), in Chromium
npm run build          # dist/modeldesk-respec.js
npm run test:bundle    # the built script itself in Chromium (run the build first); the release runs it on the packed file
npm run dev            # serves the package and rebuilds dev/dist/ on change; open the printed /dev/ URL
npm run typecheck
npm run lint

dev/index.html is a ReSpec document for the manual walk:

  • an SVG figure as a bundle emits it;
  • a second one with edges, markers and clipped outlines;
  • a figure whose SVG include fails, so its PNG stays;
  • an image the way older bundles show diagrams;
  • enough text to judge landing and print.

To try a real bundle, pull one into the git-ignored dev/bundle/ by running modeldesk bundle pull --model <modelId> --stack respec --template <template> from that folder, and include its fragments from a page there. Include a fragment that carries figures without data-include-replace: ReSpec does not process the includes inside replaced content, so every figure would keep its PNG. The element list is off there unless the page's respecConfig adds modeldesk: { features: { diagrams: { elementList: true } } }, as dev/index.html does.

The build refuses any input from outside src/: the package is published under the MIT licence without a third-party notice, so neither a dependency nor a private workspace package may end up in the script. It also refuses a bundle that names a way to parse HTML or evaluate a string, which the lint refuses in the sources.

Layout

src/
  index.ts             entry: registers init with ReSpec or runs it on a published copy
  register.ts          the respecConfig.postProcess hook
  config.ts            the runtime's own options, under respecConfig.modeldesk
  init.ts              puts the stylesheet in the page and mounts every feature
  styles.ts            composes the feature styles; motion behind prefers-reduced-motion
  copy.ts              interface text, Dutch and English
  dom.ts               DOM construction and HTML-only lookups
  markers.ts           the documentation contract's markers the runtime reads
  navigation.ts        going to a fragment, and the event that announces it
  features/
    feature.ts         the Feature interface
    index.ts           the features the runtime mounts, with their styles
    diagrams/          figures, element list, full view and its copy of the SVG, viewBox arithmetic, PNG figures
    landing/           the landing highlight

A feature is a module under src/features/<id>/ with a mount(document, config) that finds its markers and reuses what a published copy already carries, and its share of the stylesheet. Features do not import each other; one that reacts to another listens for an event on the document. Realizing links in an SVG that has element stamps only, from an element-to-anchor map, belongs in features/diagrams/ before the element list is built, since the list reads the links.

License

MIT