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

fidelity-ui

v0.1.1

Published

Wireframe, sketch and skeleton views generated from your real markup. A reveal that melts the wireframe into the final design, self-shaped loading skeletons, and a compare slider.

Readme

fidelity-ui

npm CI license

Wireframe, sketch and skeleton views generated from your real markup. There is nothing to draw by hand: the package copies the content, keeps its layout, and repaints it at a lower fidelity. Text becomes bars, images become crossed boxes, buttons become outlines, and headings and controls get small tags.

  • <fidelity-reveal> melts the wireframe into the real content on its own, when the element scrolls into view or when its data has loaded.
  • <fidelity-skeleton> covers content with a skeleton of itself while it loads, so the placeholder always matches what will appear.
  • <fidelity-compare> puts a draggable split between the wireframe and the real content, for case studies.

Framework-free custom elements, no dependencies, ~6.5 kB minified and gzipped. They work anywhere HTML does: plain pages, Astro, React 19, Vue, Svelte.

Live demo

Install

npm install fidelity-ui
import { define } from 'fidelity-ui';
define(); // registers the three elements; safe to call twice, a no-op on the server

Or straight from a CDN:

<script type="module">
  import { define } from 'https://cdn.jsdelivr.net/npm/[email protected]/dist/index.js';
  define();
</script>

Your markup is rendered as usual, and the low-fidelity copy is added on the client. If JavaScript doesn't load, people just see the real content.

<fidelity-reveal>

<fidelity-reveal mode="wireframe">
  <section>…any markup: a hero, a card, a whole page section…</section>
</fidelity-reveal>

Stagger a list with delay:

<fidelity-reveal mode="sketch" delay="0">…</fidelity-reveal>
<fidelity-reveal mode="sketch" delay="180">…</fidelity-reveal>
<fidelity-reveal mode="sketch" delay="360">…</fidelity-reveal>

With trigger="load", the copy stays while you fetch. Render the component with placeholder data, then remove loading when the real data is in. The copy repaints as the data arrives, so the final layout is what melts in.

<fidelity-reveal trigger="load" loading mode="skeleton">
  <profile-card>…</profile-card>
</fidelity-reveal>
const el = document.querySelector('fidelity-reveal');
await loadProfile();
el.loading = false; // sweeps the skeleton away

| Attribute | Default | | |---|---|---| | mode | wireframe | wireframe, sketch (hand-drawn wobble) or skeleton. | | trigger | view | view: when 30% of it is visible. load: covered while loading is set, revealed when it's removed. manual: call reveal(). | | direction | ltr | ltr, rtl, ttb or btt. | | duration / delay | 1100 / 0 | In milliseconds. | | replay | off | Covers again when it leaves the viewport and reveals again on return. | | line | off | Shows a thin line in the middle of the soft edge. | | no-tags | off | Hides the H1 / Button / Link tags inside the copy. |

  • Methods: reveal() and conceal() sweep the copy away and back (both return a promise); cover() puts it back instantly.
  • Event: fidelity-revealed.

<fidelity-skeleton>

<fidelity-skeleton loading>
  <article>…the component rendered with placeholder or previous data…</article>
</fidelity-skeleton>

While loading is set, the content is covered by a pulsing skeleton built from its own layout and the element has aria-busy="true". Remove the attribute (or set el.loading = false) and the skeleton fades out. Any mode works.

<fidelity-compare>

<fidelity-compare mode="wireframe" value="50" intro>
  <section>…</section>
</fidelity-compare>

| Attribute | Default | | |---|---|---| | mode | wireframe | wireframe or sketch. | | value | 50 | Split in percent; 0 shows only the real content. | | intro | off | Glides from 85 to value when it scrolls into view. | | start-label / end-label | mode name / Final | The corner tags. hide-labels hides them. | | label | "Compare wireframe and final design" | Accessible name of the slider. |

Properties and methods: value, glideTo(n) and refresh(). It fires a fidelity-change event.

Theming

Set these custom properties on .fl-root (the copy): --fl-paper, --fl-ink, --fl-line and --fl-fill. Set --fl-handle and --fl-focus on <fidelity-compare>.

Accessibility

  • Screen readers: the copy is aria-hidden and inert, so assistive tech only reads the real content.
  • Forms: controls in the copy are disabled and lose their name, so the copy never submits, validates or joins your radio groups.
  • Loading state: <fidelity-skeleton> and <fidelity-reveal trigger="load"> set aria-busy while loading.
  • Compare slider: it is a native range input with aria-valuetext ("Wireframe 40%, final 60%"). When keyboard focus lands on a link under the copy, the split glides away so the focused element is visible.
  • Reduced motion: content appears without the sweep, and skeletons stop pulsing.
  • Forced colors: in forced-colors mode the handle and lines use system colors.

Without custom elements

import { paintLofi, LofiController } from 'fidelity-ui';

paintLofi(layer, [sourceElement], { mode: 'sketch' });            // one-off copy into `layer`
const lofi = new LofiController(host, () => ({ mode: 'wireframe' })); // keeps a layer in `host` repainted
lofi.start();

Position the layer over the sources yourself.

Limits

  • Measurement: the copy is measured when it's painted. It repaints on resize, on content changes and once web fonts load.
  • Selectors: the copy sits one level deeper than your elements. Child-combinator selectors that start outside the element (.parent > .child) won't match it; class, tag and attribute selectors do.
  • IDs: the copy keeps them, so ID-based CSS still applies. The originals come first in the document, so getElementById and #anchor links keep pointing at the real elements.
  • Nested custom elements: they are cloned too, so their constructors run again.
  • Placeholder colors: image placeholders are data URIs and keep the default colors when you theme the copy.

Develop

npm install
npm test        # vitest + happy-dom
npm run demo    # http://127.0.0.1:5173/demo/
npm run media   # re-records the README animations (headless Chrome + ffmpeg, animated WebP)

License

MIT © Görkem Yıldız