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

@keniding/combobulating-orbs-native

v0.3.2

Published

Dotted thought-orb loading indicators for React Native (Skia) — port of combobulating-orbs

Readme

@keniding/combobulating-orbs-native

Dotted thought-orb loading indicators for React Native, rendered with Skia. Port of combobulating-orbs — fifteen animated states, two purpose-tuned sizes, automatic dark/light.

Status: not yet runtime-verified on a device or simulator. Geometry, types and the Skia draw sequence are verified as described below, but nobody has watched this render on a phone yet. Do not ship it to users until that happens.

Install

npm install @keniding/combobulating-orbs-native @shopify/react-native-skia react-native-reanimated

Usage

import { ThinkingOrb } from '@keniding/combobulating-orbs-native';

<ThinkingOrb state="searching" size={64} />;

Props mirror the web package: state, size (64 | 20), theme ('auto' | 'dark' | 'light'), speed, paused, accessibilityLabel, style, variant (retune a state: speed, density, dot size, per-mode knobs), progress (0–1, for state="progress"; exposed to VoiceOver/TalkBack as a progressbar with its value), onCycle (a cyclic state finished a loop) and onComplete (done / error came to rest) — see the web README.

How parity is achieved

The geometry is not re-implemented. This package depends on @keniding/combobulating-orbs/engine — the same compiled, React-free frame functions the web component runs — and only translates the resulting dot list into Skia draw calls. A frame arrives already z-sorted, radius-clamped and culled, so the renderer draws the array in order and derives nothing.

npm run verify:golden asserts the resolved engine reproduces spec/orbs-golden.json exactly (120 cases, 105,083 values, tolerance 1e-4). It is not checking arithmetic — it is checking that the dependency resolved to the engine those vectors came from, since a stale or duplicated copy of @keniding/combobulating-orbs in the tree would otherwise surface as an animation subtly out of step with the web.

How the Skia drawing is verified

scripts/render-canvaskit.mjs replays the exact draw sequence from ThinkingOrb.tsx through CanvasKit — the WASM build of the same Skia engine react-native-skia wraps — and scripts/diff-png.mjs pixel-diffs the result against the browser's canvas output for the same frozen instants (captured via demo/parity.html in the web repo).

node scripts/render-canvaskit.mjs
node scripts/diff-png.mjs canvaskit-out web-out

Last measured over the original 9 states at 64px, dark, two timestamps each: worst mean difference 1.4/255 (0.55%), centroids aligned to under half a device pixel. simmering and crystallizing render through CanvasKit but have not been diffed against the web yet (that needs the web captures from demo/parity.html). See below for what the residual is.

Threading

The frame is built and recorded into an SkPicture on the JS thread; Skia rasterises it on the UI thread. The heaviest mode (composing, 566 dots) costs 0.12 ms per frame on desktop V8 — under 1% of a 60 fps budget, and a few times that under Hermes on a mid-range phone.

That headroom is why the geometry is deliberately not workletized. Doing so would require 'worklet' directives throughout the shared engine (measured: without them Reanimated's Babel plugin produces zero worklets, so calling it from the UI thread would throw), coupling the web library to Reanimated's toolchain and risking a bundler silently stripping the directives. The part that actually must not jank — rasterisation — is on the UI thread either way.

Known difference from the web

Skia and Chrome's 2D canvas rasterise sub-pixel circles differently, and many of the far-depth dots in these animations are well under a pixel across. Measured on isolated circles (device px, ink = premultiplied luminance sum):

| radius | Skia | Chrome canvas | |---|---|---| | 20 | 320011 | 320456 | | 4 | 13300 | 13032 | | 1 | 764 | 872 | | 0.5 | 192 | 128 | | 0.35 | 64 | 0 |

At radius 20 the two agree to 0.14%, which rules out any colour-space, gamma, alpha or compositing discrepancy — the ink rule and premultiplication are correct. The divergence is purely a sub-pixel antialiasing curve, and at the bottom of the range Chrome drops the circle entirely while Skia still draws it.

Net effect: this port renders the faintest, smallest dots slightly more present than the web does. It is a rasteriser property rather than a port defect, and if anything the Skia result is the more faithful one — dots the engine asked for do not silently vanish. It is not worth compensating for: the bias is not even monotonic in radius (Skia is lighter at r=1 and heavier at r=0.5), so any correction would be a fitted transfer function chasing a sub-1%-mean difference.

License

MIT