# Spotlight's frontend package is private at 0.1.0 while the releases ship as v1.8.2

> Renumics Spotlight is a local tool that opens a browser viewer over an existing dataframe, handling images, audio, text, video, time-series and geometric data, with Python 3.10 or newer as the floor. The interface is small and the install paths are clear, but the version number lives in two places that disagree, the Node package points its runtime exports at uncompiled TypeScript, and the test scripts skip a directory the repository actually carries.

**Renumics/spotlight** — Interactively explore unstructured datasets from your dataframe.

- Repository: https://github.com/Renumics/spotlight
- Website: https://renumics.com
- Stars: 1,281 · Forks: 94
- Language: TypeScript
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/renumics-spotlight

## The Node package is private at 0.1.0, and the version comes from the git tag instead

`package.json` at the root of this repository reads `"name": "@renumics/spotlight"`, `"private": true`, `"version": "0.1.0"`. A private package is never published, so that 0.1.0 is a placeholder that nothing consumes.

The Python side is where the version actually lives. `pyproject.toml` names the distribution `renumics-spotlight`, sets `dynamic = ["version"]`, and defers to a tool at build time:

```make
export VERSION := $(shell uv run uv-dynamic-versioning)
```

The Makefile shells out to `uv run uv-dynamic-versioning` and exports the result as `VERSION`, which means the number is derived from the git tag rather than from a file. The releases are v1.8.2 from 2026-08-03, v1.8.1 from 2026-07-22 and v1.8.0 from 2026-04-28.

So the two version numbers never had to agree, and the 1.x line lives entirely in tags. The oddity is the classifier sitting next to it: `Development Status :: 5 - Production/Stable`, asserted by a package whose sibling manifest says 0.1.0 and private.

## `exports` points the runtime condition at `./src/lib.ts`, not at a build

The export map has three subpaths, and the interesting one is the root. Its `types` condition resolves to `./build/frontend/lib.d.ts` while its `import` condition resolves to `./src/lib.ts`, which is TypeScript source in the repository. A consumer importing the package would receive source files rather than compiled JavaScript, and would need a bundler that handles TypeScript to get anywhere.

That works here because nothing outside the build imports it. `"files": ["build/frontend"]` is the whole publishable surface, and `private: true` means even that never ships to a registry. The frontend is a build artifact that the Python package embeds after Vite compiles it.

The `./datatypes` subpath is shaped differently again: it declares only `types`, with no `import` entry at all. So one subpath hands you source at runtime, another hands you declarations only, and the third, `./icons`, follows the first pattern with `./src/icons/index.ts`.

## `prepare` compiles types, so a Node install is not a pure download step

Three scripts chain together:

```json
"prepare": "pnpm run build:types",
"build:types": "tsc -p tsconfig.types.json",
"build": "vite build && pnpm run build:types"
```

`prepare` is the hook npm and pnpm run after an install, so the moment you install dependencies the TypeScript compiler runs against `tsconfig.types.json` and fails the install if the declarations do not build. There are three tsconfig files, `tsconfig.json`, `tsconfig.node.json` and `tsconfig.types.json`, splitting the app, the build tooling and the emitted declarations.

The seam this creates is worth being explicit about. The thing people install is `renumics-spotlight` on PyPI, a Python distribution. What ends up inside it is a React application built by Vite from `src/`, with `@react-three/fiber` and `@react-three/drei` for 3D, d3 and `chroma-js` for the 2D views, and `comlink` for the worker boundary. Producing that package requires a Node toolchain even though the entry point is `import pandas as pd`.

## `pnpm lint` and `make lint` read different files, and both test scripts skip `tests/`

The Node-side lint is `eslint --max-warnings 0 src`, scoped to `src` with zero warnings tolerated. The Makefile target named `lint` runs something else entirely:

```make
uv run pre-commit run ruff-check --all-files
uv run pre-commit run eslint --all-files
```

Same tool, different scope. `make lint` covers every file a pre-commit hook is configured for; `pnpm lint` covers one directory. Typechecking has the same split, with `uv run pre-commit run mypy --all-files` in the Makefile against `pnpm exec tsc --noEmit` in the package scripts.

The test paths are the sharper version of the problem. `"test": "jest src"` and `"api-test": "jest api-tests"` are the only two runners, yet the repository carries a top-level `tests/` directory and a `setupTests.js` at the root. Neither script points at either, so whatever is in `tests/` is not being executed by either command.

Formatting goes the same way, with ruff-format and prettier both invoked through pre-commit rather than through a script.

## Torch is an extra, and audio on Hugging Face datasets 4 also needs system FFmpeg

The base install is one line:

```bash
pip install renumics-spotlight
```

Optional capabilities are extras. `analyzers` pulls the optional analyzers, and `torch` pulls the embeddings support. The torch extra has three documented shapes:

```bash
pip install --extra-index-url https://download.pytorch.org/whl/cpu renumics-spotlight[torch]
pip install --extra-index-url https://download.pytorch.org/whl/cu128 renumics-spotlight[torch]
```

The CUDA index is pinned to a single wheel channel, cu128, with a plain default install as the third option.

The audio caveat is the part that bites. With Hugging Face `datasets` at version 4, which is the current default, audio data needs the `torch` extra and FFmpeg installed on the system. Neither is required for images or text, so a text-first user never hits it and an audio user discovers it after the dataset is already loaded.

The floor is `requires-python = ">=3.10"`, and `uvloop` is declared only for `sys_platform == 'Linux' or sys_platform == 'Darwin'` while the classifiers list Linux, Windows and MacOS alike.

## The dependency list is the real feature list, and it stops mid-entry

`pyproject.toml` enumerates what Spotlight actually is. `fastapi`, `uvicorn`, `httptools` and `orjson` are the local server that backs the browser viewer. `h5py` and `databases[sqlite]` are the local storage, with `diskcache` for the derived artifacts.

Then the data modalities appear one by one as libraries. `imageio` and `trimesh` with `pygltflib` for geometric data. `umap-learn` for the embedding projection. `networkx` for graph-shaped work. `requests` for anything remote, `loguru` and `tqdm` for the progress and log output, and `pydantic` pinned to the 2.x line with an upper bound below 3.0.0.

Two details are worth reading twice. The SQLite requirement is written `databases[sqlite] (>=0.1.3)`, with the version bound parenthesised inside the requirement string rather than attached to it. And the list ends partway through an entry, at `scikit`, so the final dependency is not fully stated in what is visible.

On the browser side the mirror image appears: `bleu-score` for text similarity, `@uiw/react-json-view` pinned to the exact version `2.0.0-alpha.7` with no caret, and `@types/dompurify` sitting in runtime dependencies rather than in development ones.

## Five dependency locks and three environment files share the repository root

There are five ways this project pins its toolchain: `uv.lock` for Python, `pnpm-lock.yaml` for Node, `flake.lock` with `flake.nix` for a Nix environment, `.tool-versions` for a version manager, and `.pre-commit-config.yaml` for hooks. The Makefile treats Python and Node as separate setup steps, with `init` running `uv sync --all-extras --no-group playbook` and then `pnpm install`, while `init-playbook` runs `uv sync --all-extras --all-groups` to add the playbook group back.

At the same level sit `.env`, `.env.development` and `.envrc`. `.envrc` is the direnv entry point, so a checked-in direnv file decides which of the other two get loaded and when. Their contents are not part of what can be read here, and `.gitignore` may well exclude them, but three dotenv or direnv files at the top of a public repository is the first thing to look at before opening an issue about configuration.

The development entry point ties it together. `make dev` runs `uv run spotlight --analyze-all` with `SPOTLIGHT_TABLE_FILE` pointed at a small HDF5 table and `SPOTLIGHT_DEV` defaulted to true, so the dev server and the analysis pass are the same command.

## Two readme files exist because the GitHub one is mostly emoji in a table

`pyproject.toml` sets `readme = "README-PyPI.md"`, and the tree carries both `README.md` and `README-PyPI.md`. The reason is visible in the GitHub version itself. The use-case section is an HTML table whose link cells contain nothing but three emoji: one for a code snippet, one for an interactive demo, one for a blog article. Nine rows across image, audio, text and mixed modalities, each row pointing at Hugging Face Spaces and Medium posts.

None of that survives a plain-text renderer, which is exactly what a package index is. So the marketing surface lives on GitHub and a separate file serves the index, and the two have to be kept in step by hand.

Documentation is split the same way. `docs/` with a `mkdocs.yml` is one system, `playbook/` is a second tree linked as the data-centric AI playbook, and `openapitools.json` at the root points at a third, generated from the `Framework :: FastAPI` service. Two asset directories sit alongside them, `public/` for the Vite build and `static/` for the docs site.

## Conclusion

Spotlight is a good fit if you already hold the data in a dataframe and want a browser surface over it without exporting anything, particularly for image and embedding work. Four things to check first. Do not read a version off the Node manifest: it is marked private and pinned at 0.1.0, so the real number comes from the git tag at Python build time. Install the `torch` extra before you try audio on Hugging Face `datasets` version 4, and have FFmpeg on the system, or that path fails quietly. Expect the install to run a TypeScript build, because `prepare` compiles types before anything else. And if you rely on the test suite, note that `jest src` and `jest api-tests` between them skip the `tests/` directory at the repository root.

## FAQ

### What is Renumics Spotlight and which data types does it handle?

It is a local tool that opens an interactive visualization in your browser from an existing dataframe, so nothing has to be exported first. The supported unstructured types are images, audio, text, videos, time-series and geometric data, and you can attach data enrichments such as embeddings, predictions and uncertainties to find problem clusters in the set.

### How do I install Spotlight and what are the extras for?

`pip install renumics-spotlight` gets the base install, and Python 3.10 or newer is required. `pip install renumics-spotlight[analyzers]` adds the optional analyzers, and the `torch` extra adds optional embeddings support, with variants that point pip at the CPU wheel index or at the cu128 CUDA index. Installing into a separate virtual environment is the recommended route.

### What does `spotlight.show` do with a pandas DataFrame?

It opens Spotlight in your browser with the dataframe ready to explore. The `dtype` argument sets custom column types for the viewer, so `spotlight.show(df, dtype={"image": spotlight.Image, "embedding": spotlight.Embedding})` tells the browser which columns hold images and which hold embeddings rather than leaving it to guess from the values.

### Does Spotlight support audio from Hugging Face datasets?

Yes, with two extra requirements. With Hugging Face `datasets` at version 4, which is the current default, audio data needs the `torch` extra installed and FFmpeg present on your system. The quickstart also shows loading a Hugging Face audio dataset with embeddings and a pre-defined layout, which the excerpt does not carry through to the end.

### How is the Spotlight version determined?

Dynamically, from the git tag. `pyproject.toml` sets `dynamic = ["version"]` and the Makefile exports a VERSION value produced by `uv run uv-dynamic-versioning`, so the recent releases are v1.8.2, v1.8.1 and v1.8.0. The Node package `@renumics/spotlight` in `package.json` is marked private and stuck at 0.1.0, so it is not a usable version source.

## Sources

- [License: MIT](https://github.com/Renumics/spotlight/blob/main/LICENSE)
- [Project website](https://renumics.com)
- [README](https://github.com/Renumics/spotlight/blob/main/README.md)
- [Releases](https://github.com/Renumics/spotlight/releases)
- [Renumics/spotlight on GitHub](https://github.com/Renumics/spotlight)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/renumics-spotlight
