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

playverse-makers-spec

v0.1.2

Published

Engine-agnostic schema, migrations, and validation for Makers MapDocument. Use this when building adapters or play platforms that consume Makers maps without Babylon.

Readme

playverse-makers-spec

Engine-agnostic schema, migrations, and validation for the Playverse Makers authoring tool's MapDocument format.

Pure TypeScript. No Babylon. No DOM. No browser APIs. Use this when you need to read, validate, transform, or migrate maps without running the full Babylon runtime.

import { migrate, validateMap, collectAssetUrls } from 'playverse-makers-spec';

const doc = migrate(rawJson); // any version → current
const issues = await validateMap(doc, { requireLicenseOnModels: true });
const urls = collectAssetUrls(doc); // all model / texture URLs

🤖 AI-targeted guide: AGENTS.md ships in the published package — point your LLM coding assistant at node_modules/playverse-makers-spec/AGENTS.md for a tight decision tree (when to call which function, how to generate valid maps, common mistakes).


Table of contents


spec vs playverse-makers

| | playverse-makers-spec (this) | playverse-makers | | ---------------- | ------------------------------------------ | ------------------------------------------ | | Layer | Data — types, validation, migration | Runtime — Babylon scene + physics + player | | Dependencies | None | Babylon.js (peer) | | Bundle size | ~20 KB gzip | ~33 KB gzip + Babylon | | Browser required | No | Yes | | Use it when | Building an adapter / validator / SSR tool | Drawing the map on screen |

If you're shipping a Babylon game, use playverse-makers — it re-exports everything from spec so you don't need both. Reach for spec directly when you want to avoid Babylon entirely.


Install

pnpm add playverse-makers-spec

Zero runtime dependencies. ESM only. Requires TypeScript 5+ / ES2022.


Use cases

| You're building... | Why spec is the right answer | | -------------------------------------------- | --------------------------------------------------------------------------------------- | | Three.js / Unity / Godot adapter | Read MapDocument and instantiate scene in your engine of choice — no Babylon dragged in | | Server-side validator (CI, publish hook) | Validate map shape, license, asset URLs without booting a browser | | AI tooling (auto-generate, audit) | Inspect node graph, collect assets, extract capabilities manifest | | Map list / detail UI | Load metadata server-side (SSR), render summary cards without scene | | Migration utility (CLI, batch job) | Bring legacy v1 / v2 saves up to current schema | | Static analysis / lint | Walk the document, enforce custom rules per organization |


Quickstart

Validate a map before publishing

import { validateMap, type ValidationIssue } from 'playverse-makers-spec';

const issues: ValidationIssue[] = await validateMap(doc, {
  requireLicenseOnModels: true,
  checkAssetReachability: true, // HEAD-fetches each model URL
});

if (issues.length > 0) {
  console.error('Map failed validation:', issues);
  process.exit(1);
}

Migrate a legacy save

import { migrate, MAP_SCHEMA_VERSION } from 'playverse-makers-spec';

const oldDoc = JSON.parse(legacyJson); // schemaVersion: 1
const current = migrate(oldDoc); // schemaVersion: MAP_SCHEMA_VERSION

migrate() is idempotent — passing a current-version document is a no-op.

Inline external asset URLs (mirroring / offline bundles)

import { transformAssetUrls } from 'playverse-makers-spec';

const offlineDoc = transformAssetUrls(doc, async (url, kind) => {
  // download to local CDN, return new URL
  const local = await mirror(url);
  return local;
});

Build a Three.js renderer (no Babylon)

import * as THREE from 'three';
import type { MapDocument, MeshNode } from 'playverse-makers-spec';
import { migrate } from 'playverse-makers-spec';

function buildThree(scene: THREE.Scene, raw: unknown) {
  const doc = migrate(raw);
  for (const node of doc.nodes) {
    if (node.kind === 'mesh') buildMesh(scene, node as MeshNode);
    // ... light, model, spawn, trigger
  }
}

The Babylon runtime in playverse-makers is one such consumer — your Three.js / Unity / Godot adapter mirrors it for a different engine.


What's exported

Schema types (re-exported under specific names too)

MapDocument, MapNode, MeshNode, ModelNode, LightNode, SpawnNode, TriggerNode, SoundNode, ParticleNode, DecalNode, TerrainNode, AnimationTimelineNode, ExtensionNode, MaterialSpec, PhysicsSpec, EnvironmentSpec, LightmapBake, LooseMapDocument.

Plus the MAP_SCHEMA_VERSION constant (current major) and 2D variants (SpriteAtlasGrid, SpriteAnimationClip, TileMetadata, View2DSpec, BackgroundLayerSpec).

Migrations

| Symbol | Purpose | | --------------------------------- | ------------------------------------------------------ | | migrate(doc) | Bring any older document up to current schema | | registerMigration(from, to, fn) | Register a migration step for a custom field/extension | | listRegisteredMigrations() | Enumerate registered migrations (debugging) | | UnsupportedSchemaError | Thrown when no path exists to current version |

Validation

| Symbol | Purpose | | ------------------------ | ------------------------------------------------- | | validateMap(doc, opts) | Full async validation (license, URL reachability) | | validateMapShape(doc) | Sync — type/shape only, no network | | collectAssetUrls(doc) | Every model / texture / audio URL referenced | | collectCredits(doc) | License + author entries (attribution UIs) |

Asset URL transform

| Symbol | Purpose | | ----------------------------- | --------------------------------------------------- | | transformAssetUrls(doc, fn) | Rewrite asset URLs (mirroring, signing, bundling) | | isExternalUrl(url) | True for http(s):// URLs (vs. blob/data/relative) |

Capabilities

| Symbol | Purpose | | ----------------------- | ---------------------------------------------------- | | extractManifest(doc) | Inventory of node kinds + trigger verbs the doc uses | | applyManifest(doc, m) | Re-attach a manifest extracted earlier |

Custom node registration

| Symbol | Purpose | | ---------------------------------------- | ---------------------------------------------------------- | | registerCustomNodeSchema(kind, schema) | Register your own node kind for validateMap to recognize | | getCustomNodeSchema(kind) | Retrieve a registered schema |

Document kind helpers

| Symbol | Purpose | | ----------------------------------------- | -------------------- | | documentKind(doc) | '2d' or '3d' | | is2DDocument(doc) / is3DDocument(doc) | Type guards | | newMapDocument2D(opts) | Empty 2D map starter | | defaultView2D() | Default 2D viewport |


Recipes

Generate a manifest of a map's capabilities

import { extractManifest } from 'playverse-makers-spec';

const manifest = extractManifest(doc);
console.log(manifest.nodeKinds); // ['mesh', 'model', 'spawn', 'trigger']
console.log(manifest.triggerVerbs); // ['log', 'event', 'show', 'teleport']

A play platform reads these to ensure it supports every feature the map uses before accepting it.

Strip out unsupported features from a map

const safeDoc: MapDocument = {
  ...doc,
  nodes: doc.nodes.filter((n) => n.kind !== 'particle'), // drop particles
};

Useful when targeting a renderer that doesn't implement a feature yet.

CLI — validate every map in a directory

#!/usr/bin/env node
import { readdir, readFile } from 'node:fs/promises';
import { migrate, validateMap } from 'playverse-makers-spec';

const dir = process.argv[2];
let failed = 0;
for (const file of (await readdir(dir)).filter((f) => f.endsWith('.json'))) {
  const raw = JSON.parse(await readFile(`${dir}/${file}`, 'utf8'));
  const doc = migrate(raw);
  const issues = await validateMap(doc, { requireLicenseOnModels: true });
  if (issues.length > 0) {
    console.error(`✗ ${file}:`, issues);
    failed += 1;
  } else {
    console.log(`✓ ${file}`);
  }
}
process.exit(failed > 0 ? 1 : 0);

Schema versioning policy

MapDocument follows a strict additive evolution policy:

  • Additive minor (e.g. v3 adds SoundNode) — never breaks existing saves. migrate() no-ops for older fields you don't touch.
  • Breaking major (e.g. v4 renames a field) — always ships with a migration registered in this package, plus a MIGRATION.md entry. Older saves load forward without consumer code changes.

The current schema version is exported as MAP_SCHEMA_VERSION. Migrations register at module load via a side-effect import — you don't need to register them manually.


Capabilities manifest

Play platforms publish a manifest declaring which node kinds and trigger verbs they implement. Authoring tools can warn map creators when they use a feature not all platforms support. See capabilities-manifest spec.


License

MIT