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

honest-ai-loader

v0.2.0

Published

A configurable React TypeScript loading component with animated graphics and honest loading phrases

Readme

HonestAILoader

A silly proof-of-concept built to get hands-on with Claude Code and the Anthropic Console. The entire project — component, dictionaries, demo, and this README — was written through a conversation with Claude. The "honest" part refers to the loading phrases, which say what AI is actually doing to the world instead of the usual "Almost there…"


What it is

A configurable React loading component that combines an animated graphic (spinning circle or progress bar) with rotating, localized phrases sampled from thematic dictionaries. Built-in dictionaries cover seven categories — environment, work, society, power, data, cinema, and pop-culture quotes — all in English and Italian, all uncomfortably accurate.

You can mix dictionaries, weight them, add your own, and tune every visual aspect.


Installation

From npm

npm install honest-ai-loader

Then import the component and its stylesheet:

import { HonestAILoader } from 'honest-ai-loader';
import 'honest-ai-loader/style.css';

The CSS import is required. The component uses CSS Modules; the styles are shipped as a separate file in the package.

Run the demo locally

git clone https://github.com/sterte/honestailoader.git
cd honestailoader
npm install
npm run dev

Requires Node 18+ (developed on Node 22). Vite 5 will refuse older versions.


Quick example

import { HonestAILoader } from 'honest-ai-loader';
import 'honest-ai-loader/style.css';

// Minimal — spinning circle, English environment phrases
<HonestAILoader />

// Determinate linear bar, Italian, two dictionaries weighted unevenly
<HonestAILoader
  type="linear"
  loop={false}
  advancement={0.65}
  language="it"
  dictionaries={['work', 'society']}
  dictionaryProbabilities={[3, 1]}
/>

// Text overlaid on top of the graphic, custom colours
<HonestAILoader
  textPosition="over"
  styleOptions={{
    primaryColor: '#ef4444',
    secondaryColor: '#fecaca',
    textColor: '#1f2937',
    fontSize: '0.75rem',
    fontWeight: 600,
  }}
/>

// Custom dictionary only
const myDict = {
  language: 'en',
  categories: [{ category: 'startup', values: ['Disrupting disruption...', 'Pivoting the pivot...'] }],
};

<HonestAILoader
  dictionaries={[]}
  customDictionaries={myDict}
/>

API

<HonestAILoader />

All props are optional.

Graphic props

| Prop | Type | Default | Description | |------|------|---------|-------------| | showGraphic | boolean | true | Render the animated graphic | | type | 'circle' \| 'linear' | 'circle' | Shape of the graphic | | loop | boolean | true | true = indeterminate spinner; false = determinate progress | | advancement | number | 0 | Progress value 0..1, used when loop=false. Clamped silently | | speed | number | 1 | Animation speed multiplier when loop=true. 2 = twice as fast, 0.5 = half speed |

Text props

| Prop | Type | Default | Description | |------|------|---------|-------------| | showText | boolean | true | Render the cycling phrase | | language | string | 'en' | BCP 47 language tag. Only dictionaries matching this tag are used | | dictionaries | BuiltInDictionaryKey[] | ['environment'] | Built-in dictionary keys to sample from | | customDictionaries | Dictionary \| Dictionary[] | — | Extra dictionaries added to the pool | | dictionaryProbabilities | number[] | — | Unnormalized weights for each entry in dictionaries | | customDictionaryProbabilities | number[] | — | Unnormalized weights for each entry in customDictionaries | | textTime | number | 3000 | Milliseconds each phrase stays fully visible | | textTransition | 'fade' \| 'scroll-up' \| 'scroll-down' \| 'scroll-left' \| 'scroll-right' | 'fade' | Transition animation between phrases. Scroll variants name the entry direction; text exits from the opposite side | | transitionTime | number | 300 | Milliseconds for the in/out transition animation | | textPosition | TextPosition | 'bottom' | Where the text sits relative to the graphic (see below) | | styleOptions | StyleOptions | — | Visual overrides for colours, sizes, and font (see below) |

textPosition values

| Value | Effect | |-------|--------| | 'bottom' | Text below graphic (default) | | 'top' | Text above graphic | | 'left' | Text left of graphic | | 'right' | Text right of graphic | | 'over' | Text centered on top of graphic (higher z-index) | | 'under' | Text centered behind graphic (lower z-index) |


StyleOptions

All fields are optional.

Graphic

| Field | Type | Default | Description | |-------|------|---------|-------------| | primaryColor | string | #6366f1 | Animated arc / bar fill colour | | secondaryColor | string | #e5e7eb | Track / background colour | | size | number | 100 (circle) / 240 (linear) | Circle diameter or bar width in px | | strokeWidth | number | 6 | Circle stroke thickness in px (circle only) | | barHeight | number | 8 | Bar height in px (linear only) |

Text

| Field | Type | Default | Description | |-------|------|---------|-------------| | textColor | string | #6b7280 | Phrase text colour | | fontSize | string | '0.9rem' | CSS font-size value | | fontWeight | number \| string | 400 | CSS font-weight | | fontFamily | string | inherits | CSS font-family | | letterSpacing | string | normal | CSS letter-spacing | | lineHeight | number \| string | 1.5 | CSS line-height |


Dictionary shape

Use this to pass custom phrase sets via customDictionaries.

interface DictionaryCategory {
  category: string;   // label (unused by the sampler, for your reference)
  values: string[];   // the phrases
}

interface Dictionary {
  language: string;         // BCP 47 tag, e.g. "en", "it", "fr"
  categories: DictionaryCategory[];
}

If the active language does not match a dictionary's language field, that dictionary is silently excluded and its weight is redistributed.


Built-in dictionaries

| Key | Theme | |-----|-------| | 'environment' | Climate, pollution, resource depletion | | 'work' | Automation, precarious labour, gig economy | | 'society' | Surveillance, social fragmentation, misinformation | | 'power' | Big tech, monopolies, regulatory capture | | 'data' | Privacy, training data, consent | | 'quotes' | References to sci-fi AI classics (2001, Terminator, Matrix, Her, Foundation…) | | 'cinema' | What AI is doing to the film industry |

All dictionaries are available in 'en' and 'it'.


Phrase sampling

Phrases are sampled at each text cycle using weighted random selection:

  1. Active dictionaries (those matching language) are collected.
  2. Weights from dictionaryProbabilities / customDictionaryProbabilities are normalized to sum to 1. Missing weights default to 1.
  3. A dictionary is chosen by weight, then a category within it uniformly, then a phrase uniformly.
  4. A simple 5-attempt heuristic avoids repeating the immediately preceding phrase.

Publishing to npm

If you want to publish your own version:

# 1. Build the distributable bundle
npm run build:lib
# Produces dist/honest-ai-loader.js (ESM), dist/honest-ai-loader.cjs (CJS),
# dist/honest-ai-loader.d.ts (TypeScript declarations), dist/style.css

# 2. Create an account on https://www.npmjs.com if you don't have one

# 3. Log in from the terminal
npm login
# Prompts for username, password, and OTP if 2FA is enabled

# 4. (Optional) Change the package name in package.json if "honest-ai-loader" is taken,
#    or scope it: "@yourusername/honest-ai-loader"

# 5. Publish
npm publish --access public
# --access public is required for scoped packages (@yourusername/...)
# Unscoped packages are public by default

After publishing, users install it with:

npm install honest-ai-loader

Releasing a new version

npm uses semantic versioning. Bump the version before each publish:

npm version patch   # 0.1.0 → 0.1.1  (bug fixes)
npm version minor   # 0.1.0 → 0.2.0  (new features, backwards-compatible)
npm version major   # 0.1.0 → 1.0.0  (breaking changes)
npm publish --access public

npm version automatically updates package.json and creates a git tag.


Demo

Live demo: https://honest-ai-loader-demo.web.app

Or run it locally:

npm run dev   # http://localhost:5173
  • Left panel: preset selector and controls for all graphic, text, and style props.
  • Centre panel: live preview and generated code snippet.
  • Right panel: toggle and weight each built-in dictionary; build and export custom dictionaries as TypeScript.

Tech stack

  • React 18
  • TypeScript 5 (strict)
  • Vite 5
  • CSS Modules
  • No runtime dependencies beyond React

License

CC BY-NC-SA 4.0 — free to use, share, and adapt with attribution, for non-commercial purposes, under the same licence.