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

@typeonce/ritmo-math

v0.17.0

Published

The 2D helpers most Ritmo games would otherwise rewrite (vectors, angles, swept collision, flow field), plain data in and out, built on Ops so they replay the same on every engine

Readme

@typeonce/ritmo-math

ritmo-math holds the 2D helpers most games would otherwise rewrite, as plain data in and plain data out, built on Ops so they replay the same on every engine; it never ports a third-party algorithm, and determinism alone is never a reason to add one.

  • Vec2: vector arithmetic on { x, y }, lengths, perpendicular, fromAngle and angle, moveToward, clampLength, and decayToward, an ease that is the same at any step rate.
  • Angle: wrap into [-π, π) and turnToward the short way at a capped rate, for headings stored as one number.
  • Scalar: moveToward, lerp, decayToward, and spring, a value with momentum that overshoots and wobbles back (squash, a pop), on plain numbers; both eases are the same at any step rate.
  • Box2 edge boxes and Segment2 walls at any angle, with circle overlap tests and Box2.closestPoint.
  • Collide2: swept circle collision against boxes and segments that slides along walls and never tunnels through them, circle against circle, and pushOut.
  • FlowField: one search toward a goal that leads every body around the walls.
import { Collide2, FlowField, Vec2 } from "@typeonce/ritmo-math"

// Once: a flow field with 30-unit cells (a typed failure for a bad size).
const made = FlowField.make(30)
if (!made.ok) throw new Error(`bad cell size ${made.error.value}`)
const paths = made.value

// Each step: chase the player around the walls, sliding along them.
paths.setWalls(walls, radius)
paths.setGoal(player)
const way = paths.way(enemy) ?? Vec2.normalizeOr(Vec2.subtract(player, enemy), Vec2.zero)
const moved = Collide2.moveCircle(enemy, Vec2.scale(way, speed * dt), radius, { boxes: walls })
pnpm add @typeonce/ritmo-math @typeonce/ritmo

Values come in already validated: a position is a component the game's own schema checked when it entered the world (z.object({ x: z.number(), y: z.number() }) and the like), and every helper reads and returns that plain shape. There are no math value types to construct and no codecs here.

Determinism

Every helper that needs a non-exact function (cos, sin, atan2, exp, hypot) calls Ops from @typeonce/ritmo, so a session recorded in one browser replays on any other engine. Angle, Box2, Segment2, perpendicular, and the rest use only operations every engine rounds exactly. Game code that needs other math calls Ops directly; the ritmo/use-ops-for-math rule of @typeonce/oxlint-plugin-ritmo reports a Math call left in simulation code, and oxlint --fix rewrites it.

A broad phase (a spatial grid) is not here: the skill has one to copy into the game, sized to its own data.

Released together with @typeonce/ritmo, always with the same version.

Source: https://github.com/typeonce-dev/ritmo