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

@rybosome/tspice

v0.0.8

Published

`@rybosome/tspice` is the public facade for this repo.

Readme

@rybosome/tspice

Overview

@rybosome/tspice is the public facade for this repo.

The canonical way to construct SPICE clients is the spiceClients builder:

  • configure caching + kernel preload
  • pick an execution mode via a terminal method:
    • toSync() (in-process, sync-ish calls)
    • toAsync() (in-process, async calls)
    • toWebWorker() (async calls in a Web Worker)

CSPICE / NAIF disclosure

See docs/cspice-naif-disclosure.md for the canonical disclosure text, NAIF links, and pointers to notice files.

Depending on @rybosome/tspice will typically pull in backend packages that ship CSPICE-derived components; see each backend package NOTICE for details.

Installation

ESM-only (published package)

The published @rybosome/tspice package is ESM-only (type: "module"). It does not ship a CommonJS (require()) entrypoint.

If you're in a CommonJS project, use a dynamic import:

const { kernels, spiceClients } = await import("@rybosome/tspice");

Usage (Quickstart)

Browser / WASM (async)

Note: NAIF-hosted kernel URLs are blocked by browser CORS. For browsers, kernels.tspice() provides a small CORS-enabled community mirror for quickstart/testing. It is not recommended for production. It is self-funded and may be rate-limited, disabled, or trimmed if hosting costs become an issue. For production, self-host kernels (or proxy) and use kernels.naif({ ... }) / kernels.custom(...).

import { kernels, spiceClients } from "@rybosome/tspice";

const kernelPack = kernels.tspice().pick(
  "lsk/naif0012.tls",
  "pck/pck00011.tpc",
  "spk/planets/de432s.bsp",
);

const { spice, dispose } = await spiceClients
  // Optional: memoize responses at the transport/RPC layer.
  .caching({ maxEntries: 2_000 })
  // Optional: preload kernels over fetch().
  .withKernels(kernelPack)
  .toAsync({ backend: "wasm" });

try {
  const et = await spice.kit.utcToEt("2000 JAN 01 12:00:00");
  const state = await spice.kit.getState({ target: "EARTH", observer: "SUN", at: et });
  console.log(state.position, state.velocity);
} finally {
  await dispose();
}

Node / native addon (sync-ish)

import { spiceClients } from "@rybosome/tspice";

const { spice, dispose } = await spiceClients.toSync({ backend: "node" });
try {
  console.log(spice.raw.tkvrsn("TOOLKIT"));
} finally {
  await dispose();
}

Kernel loading

Note: KernelPack now carries an optional baseUrl; set pack.baseUrl (instead of passing a { baseUrl } options object to spiceClients.withKernels(...)).

Public kernel packs

Use kernels.tspice() for a small, typed, zero-config kernel catalog rooted at tspice's hosted mirror (https://tspice-viewer.ryboso.me/).

  • Intended for quickstart/testing.
  • Not recommended for production.
  • Returns fixed absolute URLs and does not accept configuration.

Use kernels.naif() to target the full NAIF generic_kernels inventory.

  • IDs are leaf paths like "lsk/naif0012.tls".
  • By default, origin is https://naif.jpl.nasa.gov/pub/naif/generic_kernels/.
  • By default, pathBase is empty (""), so kernel.path matches the picked leaf id.
  • Optional overrides are available via kernels.naif({ origin?, pathBase?, baseUrl? }).
  • baseUrl (when set) becomes pack.baseUrl and is used at load time to resolve relative kernel URLs.

Note: pick(...) preserves caller-provided ordering (no sorting / “safe load order” magic).

import { kernels, type NaifKernelId } from "@rybosome/tspice";

const NAIF_KERNEL_IDS: NaifKernelId[] = [
  "lsk/naif0012.tls",
  "pck/pck00011.tpc",
  "spk/planets/de432s.bsp",
];

const pack = kernels.naif().pick(NAIF_KERNEL_IDS);

// Self-hosting / subpath deployment example:
const selfHostedPack = kernels
  .naif({
    origin: "kernels/naif/",
    baseUrl: import.meta.env.BASE_URL,
    pathBase: "naif/",
  })
  .pick(NAIF_KERNEL_IDS);

Custom kernels

Use kernels.custom({ origin, pathBase, baseUrl? }) to build a KernelPack for arbitrary kernels.

  • Passing string ids maps to { url: origin + id, path: pathBase + id }.
  • You can also pass explicit { url, path? } entries as an escape hatch. If path is omitted, it defaults to a stable hashed path like /kernels/<hash>-<basename(url)>.
import { kernels, spiceClients } from "@rybosome/tspice";

const pack = kernels
  .custom({
    origin: "kernels/custom/",
    baseUrl: import.meta.env.BASE_URL,
    pathBase: "custom/",
  })
  .pick(
    "my-kernel.bsp",
    // Escape hatch:
    { url: "https://example.com/weird/location/attitude.ck" },
  );

const { spice } = await spiceClients
  .withKernels(pack)
  .toAsync({ backend: "wasm" });

Batching semantics

Kernel load order matches call order:

  • withKernels(pack) appends 1 batch
  • withKernels(packs) appends multiple batches

Backend notes

  • Node backend (backend: "node"): implemented by a native addon. Requires a compatible native binding to be present.
  • WASM backend (backend: "wasm"): implemented with a prebuilt .wasm. See tspice-backend-wasm.

Web Worker notes

spiceClients.toWebWorker() uses an inline blob worker by default (the worker source is generated at build time and embedded into the JS bundle). This means consumers do not need to separately bundle/host a worker entry JS file.

The worker still uses the WASM backend and must be able to fetch the .wasm binary. Most bundlers handle this automatically.

If your bundler or deployment setup relocates the .wasm asset, pass an explicit wasmUrl to toWebWorker():

import { spiceClients } from "@rybosome/tspice";

const { spice, dispose } = await spiceClients.toWebWorker({
  wasmUrl: "/assets/tspice_backend_wasm.wasm",
});

try {
  console.log(await spice.kit.toolkitVersion());
} finally {
  await dispose();
}

Development

pnpm --filter @rybosome/tspice run build
pnpm --filter @rybosome/tspice run typecheck
pnpm --filter @rybosome/tspice run test

Troubleshooting / FAQ

“Native addon tspice_backend_node.node not found” / “Failed to load tspice native backend ...”

If you selected the Node/native backend (backend: "node") and you’re running from the workspace and haven’t built the addon yet:

pnpm --filter tspice-backend-node run build:native

For more details (including TSPICE_BACKEND_NODE_BINDING_PATH), see tspice-backend-node.

Versioning

This package is under active development and the API shape is expected to churn.