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

@sigx/three

v0.1.0

Published

three.js for SignalX apps — <Canvas>, useFrame/useThree, asset loading, input and instancing composables on top of @sigx/three-runtime

Readme

@sigx/three

npm

three.js for SignalX apps. Drop a <Canvas> into any sigx component, write the scene as TSX (<mesh>, <boxGeometry>, <meshStandardMaterial>), drive per-frame work with useFrame, bind signals straight to three.js properties, and keep the HUD in ordinary HTML next to it.

This is a companion library like @sigx/router or @sigx/store: you keep jsxImportSource: "sigx" and import component/signal from sigx. The three.js intrinsic elements merge into the same JSX table as the DOM ones.

🚧 Pre-release. Asset loading, input and instancing composables and the physics package land in the follow-up PRs tracked from signalxjs/three#1.

Install

pnpm add sigx @sigx/three three
pnpm add -D @types/three

sigx core (@sigx/reactivity, @sigx/runtime-core, @sigx/runtime-dom) and three are peer dependencies — your app owns the single copy.

Quick start

import { component, signal, defineApp } from 'sigx';
import { Canvas, useFrame, objectRef } from '@sigx/three';
import type { Mesh } from 'three';

const wire = signal(false);

const Cube = component(() => {
    const mesh = objectRef<Mesh>();
    useFrame((_, dt) => { mesh.current!.rotation.y += dt; });   // per-frame: direct mutation
    return () => (
        <mesh ref={mesh}>
            <boxGeometry args={[1, 1, 1]} />
            <meshStandardMaterial color="hotpink" wireframe={wire} />  {/* signal-bound prop */}
        </mesh>
    );
});

const App = component(() => () => (
    <>
        <button onClick={() => { wire.value = !wire.value; }}>Wireframe</button>
        <Canvas camera={{ position: [0, 0, 4] }}>
            <ambientLight intensity={0.5} />
            <directionalLight position={[3, 3, 3]} />
            <Cube />
        </Canvas>
    </>
));

defineApp(<App />).mount('#app');

Run it: pnpm dev:cube (after pnpm build) — examples/spinning-cube.

<Canvas>

A runtime-dom component that hosts a three root. It renders a wrapper div (your class/style/id go there; it fills its parent) with a canvas, creates the root on mount, and renders its children into the scene. Provide/inject, useAppContext() and error scopes flow from the DOM ancestors into the scene, so the HUD and the 3D tree can share signals, stores and services freely.

| Prop | | | --- | --- | | camera | A camera instance or { fov, near, far, position, lookAt, manual } (default perspective at z = 5 looking down −Z) | | gl | A renderer instance, WebGLRenderer params, or a factory (webgl() / webgpu() from @sigx/three-runtime/webgl & /webgpu) | | scene, shadows, dpr, fixedStep | Forwarded to createRoot | | frameloop | 'always' (default) · 'demand' (render on invalidate()) · 'never' (only advance()) | | events | false to disable pointer events, or { filter, onPointerMissed } | | onCreated(state, root) | After the root exists | | ref | CanvasApi: root, store, invalidate(), advance() |

Inside: useThree(), useFrame(), useFixedUpdate(), useSize(), objectRef() and every three element — see the @sigx/three-runtime README for elements, props, args, attach, signal-bound props, pointer events and the performance rules.

Server rendering: the wrapper and canvas render as markup; three never runs on the server. Hydration mounts the root.

Composables

All tree-shakable, one per file. They stop with the owning component (or reactive scope) and also return an explicit stop. On the server every one is an inert no-op. Inputs accept a value, a signal or a getter (toValue).

Assets

| | | | --- | --- | | useLoader(Loader, url \| url[], { extensions, onProgress }) | Any three loader. Returns { value, loading, error, state, reload } (getters — read them in render functions). Cached by url and shared by identity across roots and components; a cache hit resolves synchronously; a reactive url clears and reloads. | | preload(Loader, urls, extensions?) | Warm the cache ahead of time. | | clearLoaderCache(Loader?, url?) | Drop and dispose cached assets. | | useTexture(url \| url[] \| { map, normalMap, … }, { colorSpace, anisotropy }) | TextureLoader; sRGB by default. | | useGLTF(url, { draco }) + useGLTF.preload | GLTFLoader, optional DRACO. Mount with <primitive object={gltf.value.scene} />. | | useAudio(url, { positional, loop, volume }) | AudioLoader → an Audio/PositionalAudio on the camera's listener; play() before the buffer lands is queued. |

Why not useData: GPU assets are non-serializable, never load on the server, must be shared by identity, and need dispose(). The vocabulary is the same.

Input

Polled state for game loops — read it inside useFrame. Edges (justPressed / justReleased) are frame-accurate and cleared at the end of each frame. Nothing allocates per event or frame.

| | | | --- | --- | | useKeyboard({ target, preventDefault }) | isDown(code), justPressed, justReleased, pressed. Auto-repeat ignored; blur releases all. | | useGamepad(index, { deadzone, threshold }) | Standard mapping into buttons: Float32Array(17) / axes: Float32Array(4), isDown, justPressed, axis, reactive connected. GamepadButton / GamepadAxis name the indices. | | usePointer({ target }) | NDC x/y, per-frame dx/dy, buttons, isDown/justPressed/justReleased, over. For per-object hits use the onPointer* props. | | usePointerLock({ target }) | lock() from a gesture, reactive isLocked, per-frame movement.x/y. | | useActionMap({ jump: ['Space', 'GamepadA'] }, { axes: { turn: { neg: ['KeyA'], pos: ['KeyD'], stick: GamepadAxis.LeftX } } }) | Named actions and axes over keyboard + gamepad; bindings pre-resolved. |

Works in a DOM component above <Canvas> too (then it polls on requestAnimationFrame instead of the root's loop).

Instancing, helpers, animation

| | | | --- | --- | | useInstances(count, { color }) | Typed-array position / quaternion / scale (/ color); commit() composes every instance matrix with one scratch Matrix4. <instancedMesh ref={inst.ref} args={[geometry, material, inst.count]} />. | | useHelper(objectRef \| signal, Helper, ...args) | Adds a helper to the scene, updates it per frame, removes it when the target changes or the scope ends. | | useAnimations(clips, root) | AnimationMixer on the frame loop: play(name, { fade, loop, timeScale }), stop(), actions, names. |

examples/game-hud (pnpm dev:hud) puts it together: an HTML HUD sharing signals with the scene, useActionMap steering, 500 asteroids in one draw call, pointer lock.