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

@dcl-regenesislabs/wearable-validator

v0.6.3

Published

The Decentraland wearable & emote rule book as code — every check runnable separately, in node and the browser.

Readme

@dcl-regenesislabs/wearable-validator

Decentraland's wearable and emote rule book as code. Hand it a Builder zip, a .glb or a published item and it returns every problem at once: what is wrong, where, the measured value against the limit, and how to fix it.

  • 35 code checks (files, model, emote, content) run anywhere: browser or Node.
  • 4 visual checks render the item and ask Claude to judge it. They run on a Node server only (a native Unity render server).
  • 1 code review (smart-wearable-code, group code) has Claude read a smart wearable's scene and bundle as text, never running it: it says what the code does, and malicious or spam code fails the item. It needs only the /ai reviewer.
npm i @dcl-regenesislabs/wearable-validator

In the browser: the code checks

Works with any bundler and needs no Node polyfills.

import { validate, fixes } from "@dcl-regenesislabs/wearable-validator";

const bytes = new Uint8Array(await file.arrayBuffer()); // a Builder .zip or a bare .glb
const result = await validate(bytes);

result.passed; // true, false, or null when not everything was checked (a bare .glb, a subset, a skipped check)
for (const finding of result.findings) {
  console.log(finding.severity, finding.message, finding.where, finding.measured, finding.limit);
  console.log("How to fix:", fixes[finding.check], finding.docs);
}

A published item works the same way:

import { validate, fetchCatalystItem, parseItemReference } from "@dcl-regenesislabs/wearable-validator";

// a marketplace or shop item URL, or a urn:decentraland:… reference
const item = await fetchCatalystItem(parseItemReference("https://decentraland.org/marketplace/contracts/0x…/items/0")!);
const result = await validate({ files: item.files, metadata: item.metadata, content: item.content });

On a Node server: code and visual (AI) checks

The visual checks need three things next to the package:

  1. The peer, pinned exactly: npm i @earendil-works/[email protected]
  2. The native render server (a Linux x86_64 Unity player that draws on the CPU through Mesa and Xvfb), a release asset checked by sha256:
    curl -fsSL https://github.com/dcl-regenesislabs/wearable-validator/releases/download/render-server-1/render-server.tar.gz -o render-server.tar.gz
    echo "99f4927a1f044ec3995f59b5610dc97ffaf8d1c4bbb68031fca25f2a4eb4ae76  render-server.tar.gz" | sha256sum -c -
    mkdir render-server && tar -xzf render-server.tar.gz -C render-server
    It needs libgl1 libglx-mesa0 libgl1-mesa-dri xvfb. The repository's root Dockerfile is a working image, and on a laptop packages/job/render-server-docker.sh runs it in Docker.
  3. A Claude setup token (claude setup-token, sk-ant-oat…, valid about a year). API keys are refused.
import { validate } from "@dcl-regenesislabs/wearable-validator";
import { createNativeRenderer } from "@dcl-regenesislabs/wearable-validator/native";
import { createPiReviewer, setupTokenCredentials } from "@dcl-regenesislabs/wearable-validator/ai";

// one long-running render server per process, reused across items
const renderer = await createNativeRenderer({ command: "./render-server/Builds/RenderServer/entrypoint.sh", build: "render-server-1" });
const reviewer = createPiReviewer({ credentials: setupTokenCredentials(process.env.ANTHROPIC_OAUTH_SETUP_TOKEN!) });

const result = await validate(zipBytes, {
  groups: ["files", "model", "emote", "content", "rendering"], // "rendering" adds the visual checks
  services: { renderer, reviewer }
});

await renderer.stop(); // on shutdown
  • Cost: everything renders on the CPU, with no GPU. Each item makes at most two model calls.
  • Re-runs: pass the earlier result.captures back as captures and only missing views are rendered again.
  • Safe failure: visual findings are warnings. A missing render, a refused or malformed answer, or no reviewer never passes; the row becomes skipped or errored with the reason. Each visual row carries review (model, prompt version, token usage).

Options

| Option | What it does | | --- | --- | | checks | Run only these checks by name ("triangle-count"; rule ids like "M-01" work too). The verdict becomes null. | | groups | files, model, emote, content (the default set), rendering and code. | | category, itemType | Hints for a bare .glb, which carries no metadata. | | onProgress | Called as each check starts and finishes, for a live UI. | | signal | An AbortSignal to cancel the run. | | captures, services | The visual checks, above. |

The result

  • passed: true or false; null when not everything was checked (a bare .glb, a subset of checks, or a row that was skipped or errored: its skipReason says why).
  • summary: { errors, warnings, checked, skipped }.
  • checks[]: one row per check, with status (passed, failed, warning, skipped or errored), measured and skipReason.
  • findings[]: check, severity, message (written for creators), where, measured, limit, rule, docs.

Lookups:

  • checks and registry describe every check: explanation, fix, details, docs.
  • fixes[name] holds each check's fix steps.
  • manifest holds every limit, and its version is the rules version.

CLI

npx @dcl-regenesislabs/wearable-validator validate item.zip [--checks triangle-count] [--groups model] [--json]

Hostile input

Every input path is bounded before it is decoded: the zip's entry count and inflated size, PNG and JPEG pixels, and what a GLB's accessors and images unpack to. A file past a bound gets an error finding, never a crash. To read a zip for display or previews, use unpackZip(bytes): it applies the same bounds and returns { files, emptyFiles }.

Versions

Every library change merged to main publishes a snapshot on the next tag (npm i @dcl-regenesislabs/wearable-validator@next). A GitHub release tagged with a semver version publishes it on latest; tag it with the rules version (manifest.version). More in the repository: how a visual review works and adding a check.

License

Apache-2.0