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

@joycostudio/xyz

v1.0.0

Published

joyco.studio 3d toolkit

Readme

  Xyz

npm gzip

JOYCO's 3D toolkit. Keyed state ownership, typed definitions, CDN asset routing, ordered teardown, a declarative debug-pane layer over Tweakpane, and Three.js scene warmup that forces every shader compile and texture upload to happen before the player ever sees a hitch.

Mental model

Xyz is three independent pillars, each its own subpath so you only ship what you use:

  • Core (@joycostudio/xyz) — Derived and edge for state that multiple owners write to and one policy resolves; defineAssetSource for Chopper-aware CDN paths; Disposer for teardown that unwinds in reverse.
  • Debug (@joycostudio/xyz/debug) — DebugManager owns URL/keyboard activation and lazy pane creation; a declarative schema (slider, toggles, select, color, section, button, …) binds to a live Tweakpane folder without hand-wired glue.
  • Three (@joycostudio/xyz/three) — Warmup discovers a scene's full renderable graph, exposes it long enough to push every texture/shader through the driver once, then restores every mutation exactly as it found it.

Features

| Feature | Description | | ------------------------------- | --------------------------------------------------------------------------------------------------------------- | | Keyed ownership (Derived) | Independent writers claim a slot by key; value resolves all current intents through one explicit policy. | | Transition sync (edge) | Turns a selector into a callback that only fires when the selected value actually changes. | | Asset routing (defineAssetSource) | Keeps source names at call sites while selecting one output from a Chopper-compatible optimization plan. | | Ordered teardown (Disposer) | Registrations unwind in reverse order; disposal is idempotent and safe to register into after teardown. | | Declarative debug schema | slider, sliders, bool, toggles, select, color, colorString, section, button build a DebugSchema with no Tweakpane import required. | | URL + keyboard activation | DebugManager lazy-mounts the pane on ?debug or Option+D, and stays in sync with popstate. | | Survives enable/disable | Registrations remount from fresh definitions every cycle — no stale bindings after a toggle. | | Scene warmup | Warmup inventories geometries, materials, and textures (including TSL node graphs), pauses the driver, and forces one representative render before restoring visibility, culling, and draw ranges. | | Late-resource auditing | audit() warns once per resource introduced after warmup — a throttled dev-only diagnostic, never a runtime upload. | | No R3F dependency | The Three.js utilities are raw Three.js — bring your own renderer/canvas ownership split. |

Install

pnpm add @joycostudio/xyz

three and @tweakpane/core are optional peer dependencies — install them only if you use the /three or /debug subpaths.

defineAssetSource accepts Chopper's resolve function structurally, so Xyz does not require Chopper as a peer. Install @joycostudio/chopper in the consuming app when its config supplies the optimization plan.

Quick start

import { Derived, edge, maxOf } from '@joycostudio/xyz'

const blur = new Derived(0, maxOf)
blur.set('loader', 0.8)
blur.set('inspect', 0.35)
blur.value // 0.8

const syncPhase = edge(
  (state: { phase: string }) => state.phase,
  (next, previous) => console.log(previous, '→', next)
)

Asset routing

import chopper from './chopper.config'
import { defineAssetSource } from '@joycostudio/xyz'

export const asset = defineAssetSource({
  url: new URL('https://r2.joyco.studio/jam/'),
  planner: chopper.resolve,
  optimize: () =>
    typeof window === 'undefined' || new URLSearchParams(window.location.search).get('compressed') !== 'false',
  segments: {
    common: 'common',
    escapeFromHell: 'escape-from-hell',
  },
})

asset.common('textures/noise.png')
// https://r2.joyco.studio/jam/common/textures/compressed/noise.webp

The planner sees the stable source key without its query or hash. Exactly one planned output is selected; unmatched, failed, or multi-output plans fall back to the source path.

Quick start (debug)

import { DebugManager, property, slider, bool } from '@joycostudio/xyz/debug'
import { Pane } from 'tweakpane'

const state = { amount: 0.5, enabled: true }

const debug = new DebugManager({
  createPane: () => new Pane({ title: 'Scene' }),
})

debug.bind({
  title: 'scene',
  schema: () => ({
    amount: slider(property(state, 'amount'), { min: 0, max: 1 }),
    enabled: bool(property(state, 'enabled')),
  }),
})

Open with ?debug=true in the URL, or press Option+D.

Quick start (three)

import { Warmup } from '@joycostudio/xyz/three'

const warmup = new Warmup({
  pause: () => (clock.running = false),
  resume: () => (clock.running = true),
  initTexture: (texture) => renderer.initTexture(texture),
  compile: (scene, camera) => renderer.compileAsync(scene, camera),
  render: () => renderer.render(scene, camera),
  nextFrame: () => new Promise((resolve) => requestAnimationFrame(() => resolve())),
})

await warmup.start(scene, camera) // one representative frame, then the scene is restored
warmup.audit(scene) // dev-only: warns about resources introduced after warmup

Architecture

| Layer | Responsibility | | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | Core state (Derived, edge) | State resolution primitives with no DOM or rendering dependency. | | Definitions and assets | Literal-preserving configuration and pure source-to-CDN URL planning. | | Disposer | An owner-local teardown stack shared by the debug and three layers (and your own code). | | Debug schema (schema.ts) | Pure DebugField/DebugDefinition builders — no Tweakpane import, fully testable in isolation. | | Debug binding (bind.ts) | Binds a DebugDefinition into a live FolderApi: tracks live-refresh fields, nested sections, and computed sources for copy. | | DebugManager | Owns URL/keyboard activation and lazy pane creation; registrations survive disable/enable and remount fresh. | | Warmup orchestration | Warmup pauses the driver, runs registered Warmable.warmup() hooks, uploads textures, compiles, renders once, then restores everything in reverse — even on failure. |


Core API

State

| Export | Description | | ---------------------- | ------------------------------------------------------------------------------------------------- | | Derived<In, Out> | .set(key, value) / .clear(key) claim or release a slot; .value resolves through combine. | | maxOf | Resolve to the highest active value, never lower than the fallback. | | latestOf | Resolve to the most recently claimed slot. | | edge(select, onChange, equals?) | Returns a sync function: runs select every call, onChange only when the result changes. | | Disposer | .add(teardown), .listen(target, type, fn, options?), .dispose() — reverse-order, idempotent. | | defineAssetSource(definition) | Create a callable CDN resolver with typed builders for every declared segment. |

Debug

| Export | Description | | ------------------------------------------ | --------------------------------------------------------------------------------------- | | DebugManager | .register(source) / .bind(definition) to mount; .enable() / .disable() / .toggle() / .sync() control activation. | | bindDebugSchema(host, definition, opts?) | Binds a DebugDefinition into an existing Tweakpane folder; returns apply() / refresh() / values(). | | ref(read, write) / property(obj, key, changed?) | Adapt a getter/setter pair, or an object property, into a ValueRef. | | slider / sliders | One bounded numeric control, or several declared from an object's numeric keys at once. | | bool / toggles | One boolean control, or several declared from an object's boolean keys at once. | | select / enumField | A string/number option control (enumField is an alias). | | color / colorString / hexColor | Bind an RGB-compatible object, or a CSS color string (hexColor is an alias). | | folder / section | Nest a DebugDefinition as a field; section adds a collapsed, copyable group. | | button | Declare a sync or async debug action, with optional feedback text. | | schemaValues(schema) | Read every control's current value (recursing into folders, skipping buttons). |

Three

| Export | Description | | ----------------- | ------------------------------------------------------------------------------------------------------- | | Warmup | .add(entity) registers a Warmable; .start(scene, camera) runs once; .audit(scene); .dispose(). | | Warmable | Interface for entities whose render state isn't already in the scene — implement a synchronous or asynchronous warmup() hook. | | WarmupDriver | Renderer-owned hooks the caller supplies: pause, resume, initTexture, compile, render, nextFrame. |


Package exports

| Import path | Contents | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | @joycostudio/xyz | Disposer, Derived, maxOf, latestOf, edge, defineAssetSource, and their types. | | @joycostudio/xyz/debug | DebugManager, bindDebugSchema, ref, property, slider, sliders, bool, toggles, select, color, colorString, hexColor, enumField, folder, section, button, schemaValues, and their types. | | @joycostudio/xyz/three | Everything from /track, plus Warmup, ThreeDOM, ThreeProjector, projection/sizing helpers, and their types. | | @joycostudio/xyz/track | DynamicCanvas, TrackedElement, TrackingContext, createMetriCanvas, findStickyAncestor, and their types. |


DOM tracking

Three.js projects can import the DOM primitives and renderer adapters together from @joycostudio/xyz/three. Use @joycostudio/xyz/track for renderer-independent tracking. Both entry points expose the same classes and functions. This ports gl-sync's shared tracking, sticky positioning, WebGPU multi-canvas views, and shared WebGL2 fallback. Renderers, scenes, assets, and frame scheduling remain application-owned.

import { ThreeDOM } from '@joycostudio/xyz/three'

await renderer.init()
const dom = new ThreeDOM({ renderer, metri, container })
dom.addView(element, { scene, camera })
const world = dom.addScene({ scene: worldScene, camera: worldCamera })
world.track(objectElement, objectGroup)
renderer.setAnimationLoop((time) => {
  metri.update()
  dom.update(time)
  dom.render()
})
// On teardown: stop the loop, dom.destroy(), then dispose application resources.

To prepare independent view targets before starting the loop, call await dom.prepare(). Optional clip elements and per-view clipPadding restrict drawing without changing camera framing or target dimensions.

Views and shared scene objects can coexist on one renderer/device. ThreeDOM owns their placement and render passes. Pass an optional caller-owned TSL pipeline to addView() or addScene() to include post-processing in dom.render() and dom.prepare(), with per-registration sizing and final clipping. Use alpha: true for the native WebGPU overlay, a distinct camera for each registration, and a ClippingGroup for each clipped object binding. See the mixed rendering strategy for the architecture, Trazo diagram source, composition order, and ownership.

Requires @joycostudio/[email protected] and Three.js ^0.184.0 || ^0.185.1. See the tracking API guide for setup, ownership, and rendering constraints. gl-sync is the canonical ThreeDOM tracking adoption project. The guide includes a complete view example and server-rendered Trazo diagrams, with focused pages for TSL pipelines and tracking primitives. The browser suite exercises built package exports: pnpm test:track (install Chromium first with pnpm exec playwright install chromium).


Docs

The Fumadocs Core-backed site in apps/docs keeps its authored pages in apps/docs/content/docs as Markdown/MDX. The site shell uses the JOYCO UI kit, while the content embeds React examples from apps/docs/demos, including raw Three.js examples with no React Three Fiber dependency.

pnpm docs

Open the printed local URL and choose a concept from the catalog. Each page starts with a live demo and its actual source files in tabs directly underneath, followed by the API reference. Source is read from the same files that run the demo, including supporting files for multi-file examples. Register examples in apps/docs/lib/demos.ts and embed them with <DemoPreview name="…" />. The debug runtime page demonstrates DebugManager, URL semantics, and Option+D handling, while the declarative schemas page collects the live Tweakpane helpers. Use pnpm docs:build to verify the production integration.

Authored flow and seq code fences render as server-rendered SVG diagrams using Trazo. Add title="Description" after the fence language for an accessible title. Trazo validates syntax during the docs build; Markdown endpoints retain the original fences. Readers can expand and copy the source, and wide graphs scroll without shrinking their labels. Diagram colors follow the site theme through CSS, without a client-side diagram renderer.


Development

pnpm install
pnpm test          # Vitest suite (run); pnpm test:watch for watch mode
pnpm typecheck      # tsc --noEmit, plus the docs app
pnpm build          # tsup bundles, including tracking
pnpm lint           # eslint --fix

Releases go through Changesets:

pnpm changeset          # describe the change and bump type in a feature PR

After the feature PR merges, the Release workflow creates or updates Version Packages; merging that generated PR triggers publication. Beta releases use the same flow with Changesets prerelease mode. Follow the release guide; versioning and publishing commands are reserved for GitHub Actions.