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

@scenoco-three/compiler

v0.4.0

Published

SceNoCo build-time compiler, CLI and watcher

Readme

@scenoco-three/compiler

The build-time toolchain for SceNoCo: the XML parser, the validator, the scene compiler, the optimized bundle encoder, the XSD/docs exporters, component discovery, a file watcher, and the scenoco CLI. None of this ships to the browser — the runtime (@scenoco-three/core) loads only the compiled bundle.

npm i -D @scenoco-three/compiler

CLI

scenoco init [dir]                        Scaffold a runnable project
scenoco new component <Name>              Generate assets/components/<Name>.ts
scenoco new scene <name>                  Generate assets/scenes/<name>.scene.xml
scenoco check                             Pre-flight: scans components, flags physics setup
scenoco validate <file...>                "tsc for scenes": file:line:col diagnostics
scenoco bundle <file> [-o out]            Build the runtime bundle (.bundle.json)
scenoco decompile <bundle.json> [-o out]  Inverse of bundle: back to canonical XML
scenoco watch <file...> [--out dir]       Rebuild bundles on XML/resource changes
scenoco export [--out dir]                Write scene/prefab/material .xsd + scene-api.json (default ./schema)

  --components <dirs>   Comma-separated dirs scanned for @component classes (default "assets")
  --packages <pkgs>     Comma-separated tag packages to register (default: every
                        @scenoco-three/* dependency in the project's package.json)

Configuration is zero-config by convention — components/scenes under assets/, tag packages read from package.json. The exit code is non-zero when validation fails — wire it straight into an edit→check→fix loop.

scenoco init my-app
scenoco validate assets/scenes/hello.scene.xml     # all problems, with fix-its
scenoco bundle   assets/scenes/hello.scene.xml -o hello.bundle.json
scenoco export   --out schema                      # XSDs for IDE autocomplete + scene-api.json

Library API

import {
  compileSceneXml, compilePrefabXml,  // XML → validated CompiledScene
  bundleScene, bundlePrefab,          // CompiledScene → optimized Bundle
  serializeScene,                     // CompiledScene → canonical XML (round-trip)
  patchSceneXml,                      // surgical, position-preserving edits to XML text
  validateScene, parseScene,          // lower-level passes
  generateXsd, generateApi, generateApiJson, // exporters (from the registry)
  scanComponents, loadComponents,     // discover + register project @component files
  watchSceneFiles,                    // rebuild on source/resource change
  parseUniforms, glslMatches,         // shader uniform parsing/validation helpers
  formatDiagnostic,
} from '@scenoco-three/compiler';

Compile a scene

const result = compileSceneXml(xml, { path, resolve });
if (result.ok) {
  const bundle = bundleScene(result.scene);
  writeFileSync('scene.bundle.json', JSON.stringify(bundle));
} else {
  for (const d of result.diagnostics) console.error(formatDiagnostic(d, path));
}

CompileOptions: path? (referrer for relative src= paths) and resolve? (ResourceResolver = (request, referrer) => { path, contents } | null) — required only for scenes that pull in resource files via src=. CompileResult is { ok: true; scene } | { ok: false; diagnostics }.

Discover project components

const scan = await loadComponents(['assets'], undefined, { packages: ['@scenoco-three/box2d'] });
// scan.byName: component name → file · scan.byTag: tag → module · scan.files: watched files

loadComponents compiles project .ts (via esbuild) and registers the decorated classes in this Node process, so the validator sees the full vocabulary. scanComponents is the static (non-executing) scan.

Watch

const handle = watchSceneFiles({ files: ['scenes/level.scene.xml'], componentRoots: ['assets'] });
handle.on?.((event) => { /* 'diagnostics' | 'success' | 'error' */ });

Exporters

writeFileSync('schema/scene.xsd', generateXsd());        // IDE autocomplete + inline validation
writeFileSync('schema/scene-api.json', generateApiJson()); // machine-readable API surface
const api = generateApi(); // { nodes, attachments, components, systems, … } — derived from the registry

The compile pipeline

XML ──parse(saxes)──► expand prefabs ──► VALIDATE ──► compile (resolve refs/resources) ──► bundle
  • parsesaxes, element-only (no text content); positions tracked for diagnostics.
  • validate — never fail-fasts: one pass returns every problem. Unknown tag/attr, bad value, dangling #ref, cardinality, etc. — each with file:line:col and a fix-it.
  • compile — resolves references and src= resources, inlines shader GLSL, validates <Uniform>s against the shader; produces a flat CompiledScene.
  • bundle — interns a string pool, elides default attrs via bitmasks, integer-encodes references and transforms (~73% smaller than naive JSON). Decode is in core.

The validator, compiler, and exporters are all generated views of the same registry as the runtime, so the schema cannot drift.

Prefabs

A prefab file has a <Prefab> root wrapping one node; a scene places an instance of it with <PrefabInstance src="…prefab.xml" id="…">. Expansion happens before validation — the <PrefabInstance> is replaced by the prefab's node subtree, so the validator/compiler/bundle see ordinary nodes. During expansion:

  • the prefab file is parsed, expanded, and validated standalone (a prefab is self-contained, which is what makes it dynamically spawnable);
  • internal ids are namespaced into the instance scope (osct1/osc; nested composes to t1/inner/osc) and internal #refs are rewritten to match — so the scene can address an instance internal by its scoped id (<Follow source="#t1/osc"/>);
  • instance transform attrs (position/rotation/scale) override the prefab root's.

Per-instance customization uses two children:

<PrefabInstance src="turbine.prefab.xml" id="t2" position="5 0 0">
  <Override target="#osc" amplitude="1.5" />   <!-- patch an internal by prefab-local id -->
  <Components><Highlight color="#f00" /></Components> <!-- extra components on the instance root -->
</PrefabInstance>

<Override> values are validated against the target's schema, so mistakes point at the <Override> you wrote, not into the prefab file.

Wiring a prefab internal to a scene reference (the cross-boundary case)

Because a prefab is validated standalone, it can't name a scene object. Leave the reference unset in the prefab and wire it from the instance — the override value is applied after id-scoping, so a scene id passes through unchanged and resolves in the normal scene reference pass:

<Mesh id="hud"><Components><GameManager id="gm" /></Components></Mesh>
<PrefabInstance src="player.prefab.xml" id="p1">
  <Override target="#controller" gameManager="#gm" />   <!-- #gm is a SCENE id -->
</PrefabInstance>

This connects the spawned player's controller.gameManager to the scene's <GameManager>. For a prefab spawned at runtime (engine.instantiate / PrefabRef.spawn, no scene context at author time), wire it in code instead — see the @scenoco-three/core README (spawn → getComponent → set field, or the prefab's script resolving the scene object via getComponentsOfType / findComponent).

Diagnostics

type SceDiagnostic = { code: string; message: string; line: number; column: number; … };
formatDiagnostic(d, filePath); // "level.scene.xml:12:7  unknown attribute 'colour' on <Mesh> — did you mean 'color'?"

Standalone & dependencies

Depends on @scenoco-three/core (it imports the registry to know every tag/attr) plus saxes (XML parse), esbuild (load project component .ts for discovery), and chokidar (watch). It needs only core — no vite or editor. Use it as a library or as the scenoco CLI; the Vite plugin and the editor are thin consumers of this package. Nothing here is meant for the browser bundle.

See the repository and ARCHITECTURE.md.

License

MIT