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/rapier

v0.4.0

Published

Rapier physics for SceNoCo: <Physics> setting + RigidBody/Collider components on the EngineSystem seam

Readme

@scenoco-three/rapier

Optional 3D physics for SceNoCo on Rapier: a <Physics> scene setting plus <RigidBody> and per-shape *Collider components, built entirely on the public System seam in @scenoco-three/core. Import it to get physics; don't, and no physics (or Rapier WASM) ships. The 2D counterpart is @scenoco-three/box2d.

npm i @scenoco-three/rapier

Usage

Rapier is WASM — load it once before loading any scene that uses <Physics>:

import { initRapier } from '@scenoco-three/rapier'; // importing registers the tags
await initRapier();        // idempotent; builds the WASM
engine.loadScene(bundle);  // a scene that declares <Physics>/<RigidBody>/<Collider>

For the compiler/Vite plugin to validate the tags, register the package:

bundlePlugin({ registerPackages: ['@scenoco-three/rapier'] });
// or CLI: scenoco validate scene.xml --components src   (package imported by the scene)
<Scene>
  <Physics gravity="0 -9.81 0" />
  <Mesh position="0 5 0">
    <BoxGeometry /><MeshStandardMaterial />
    <Components>
      <RigidBody kind="dynamic" />
      <BoxCollider halfExtents="0.5 0.5 0.5" restitution="0.4" />
    </Components>
  </Mesh>
  <Mesh position="0 0 0">
    <BoxGeometry width="20" height="0.5" depth="20" /><MeshStandardMaterial />
    <Components><RigidBody kind="fixed" /><BoxCollider halfExtents="10 0.25 10" /></Components>
  </Mesh>
</Scene>

Tags

<Physics> — scene setting (on <Scene>)

| Attr | Type | Default | | | --- | --- | --- | --- | | gravity | vec3 | 0 -9.81 0 | World gravity vector. |

<RigidBody> — component

| Attr | Type | Default | | | --- | --- | --- | --- | | kind | dynamic \| fixed \| kinematic | dynamic | How the body moves. | | linearDamping | float | 0 | | | angularDamping | float | 0 | | | gravityScale | float | 1 | Multiplier on world gravity for this body. | | ccd | bool | false | Continuous collision detection — stops fast small bodies tunnelling thin colliders. |

Colliders — one tag per shape (each a component; attaches to the node's RigidBody)

Shared on every collider: restitution (float 0, bounciness 0..1), friction (float 0.5), density (float 1, kg/m³), isSensor (bool false — a trigger: reports overlaps with no collision response).

| Tag | Shape attrs | | --- | --- | | <BoxCollider> | halfExtents vec3 0.5 0.5 0.5 | | <SphereCollider> | radius float 0.5 | | <CapsuleCollider> | radius float 0.5, halfHeight float 0.5 (along Y) | | <CylinderCollider> | radius float 0.5, halfHeight float 0.5 (along Y) | | <PlaneCollider> | halfExtents vec2 5 5 (X and Z) |

<Joint> — component

Connects this node's <RigidBody> to another body's with a Rapier impulse joint.

| Attr | Type | Default | | | --- | --- | --- | --- | | kind | fixed \| revolute \| spherical \| prismatic \| spring | fixed | Joint type. | | connectedBody | node ref | — | The other node (must have a <RigidBody>). | | anchor | vec3 | 0 0 0 | Local anchor on this body. | | connectedAnchor | vec3 | 0 0 0 | Local anchor on the connected body. | | axis | vec3 | 0 1 0 | Hinge/slide axis (revolute, prismatic). | | stiffness / damping / restLength | float | 1 / 0.5 / 0 | Spring joint params. |

<Mesh id="hinge"><BoxGeometry /><Components><RigidBody kind="fixed" /><BoxCollider /></Components></Mesh>
<Mesh id="door" position="1 0 0">
  <BoxGeometry width="2" /><MeshStandardMaterial />
  <Components>
    <RigidBody /><BoxCollider halfExtents="1 0.5 0.1" />
    <Joint kind="revolute" connectedBody="#hinge" anchor="-1 0 0" axis="0 1 0" />
  </Components>
</Mesh>

Collision hooks (Unity-style)

Contacts are delivered to components via duck-typed hooks — implement any of (no 2D suffix, the 3D analogue of the box2d hooks):

onCollisionEnter(other: Object3D): void   // solid touch began
onCollisionExit(other: Object3D): void
onTriggerEnter(other: Object3D): void     // sensor (isSensor) overlap began
onTriggerExit(other: Object3D): void

Events are enabled on every collider automatically. They are collected from Rapier's event queue during the step and dispatched after it returns, so a hook may safely destroy a node (or any scene object) without corrupting the in-progress simulation.

@component({ name: 'Coin' })
export class Coin extends Component {
  onTriggerEnter(other: Object3D) {
    if (this.engine.getComponents(other).some((c) => c instanceof Player)) this.engine.destroy(this.node);
  }
}

How it works (the System seam)

A @system(RigidBody) (PhysicsSystem) reconciles a Rapier World from the live component set: it creates/destroys bodies and colliders as components appear/disappear, steps the world in fixedStep, and writes each body's transform back to its Object3D. Config comes from the <Physics> attachment, read via engine.findAttachment(Physics). @dimforge/rapier3d-compat is isolated here; core stays physics-free. This package is the reference example that the framework's add-on seams work.

Exports: initRapier, sceneTags, PhysicsSystem, RigidBody, Physics, Collider (abstract base), and each *Collider class.

Standalone & dependencies

Depends on @scenoco-three/core and @dimforge/rapier3d-compat (Rapier WASM); three is a peer. It plugs in entirely through core's public System seam — core has no idea it exists — so importing this package is the only thing that adds 3D physics (and its WASM) to a build. Drop the import and nothing physics-related ships.

See the repository and docs/physics-plan.md.

License

MIT