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

@loothero/dm-engine

v0.10.0

Published

Death Mountain game rules and commit-reveal protocol, ported from the Cairo contracts. Shared by the client, the indexer and the API.

Readme

@provable-games/dm-engine

The Death Mountain game rules and commit-reveal protocol in TypeScript — a mirror of the Cairo in contracts/src.

Consumed by three places that must agree exactly:

| | | | --- | --- | | death-mountain-client | the board the player acts on | | indexer | off-chain replay of committed transcripts into the event tables | | api | token-id decoding |

Why it has to be shared

Under commit-reveal the chain executes nothing. The client's simulation is not a guess that on-chain events correct a second later — it is the board, and nothing corrects it. If it diverges from the Cairo replay by one point of health, the next committed action is state-invalid, settlement rejects the transcript, and the run is permanently unplayable.

Two copies of the rules would drift. There is one.

Keeping it honest

The rules are hand-maintained, so nothing in Cairo forces them to stay in step. Three things do:

  • test/vectors.scheme.json — root, fold, action_entropy and every opcode encoding, printed by the real Cairo. Regenerate with snforge test commit_reveal::test_vectors in contracts/, then paste into the fixture.
  • test/replay.entropy.test.ts — asserts each action is a pure function of (state, action, entropy) and draws zero Math.random(). A missed roll is the bug class that bricks runs.
  • GameSettled cross-check — in production the indexer diffs its replayed adventurer against the contract's packed result and writes a replay_divergences row on mismatch. That is the only genuinely independent check, since the client and the indexer share this code.

Configurable markets

Every item has a configurable probability from 0% to 100% in 3.125% steps. The sum of these probabilities is the target average number of distinct items; it is not a hard size limit. Default settings put every item at 25%, averaging 25.25 items per market.

GameSettingsData.market_config is required and comes directly from get_settings. Its three felts may be decimal/hex strings or the bigints starknet.js returns; a felt coerced to JS number, or a string that is not a decimal or hex literal ("" included), is rejected with a TypeError rather than silently producing the wrong market. packMarketConfig builds it from 101 densities (0..32), and unpackMarketConfig recovers them. uniformMarketConfig(density) builds a single-density profile and DEFAULT_MARKET_CONFIG is the registered default; reach for packMarketConfig only for a genuinely per-item profile. getAvailableItemsBitmap takes the raw level_salt; marketBitmapToIds converts the bitmap for display. An all-zero profile is an empty market.

These rules target a new contract deployment and a new frontend. Use the new address and ABI; both the settings storage layout and the market algorithm differ from the existing deployment. SettingsAdded announces an ID and name; fetch its profile with get_settings, or from the minigame standard's settings_details view, whose Market Cutoff Plane 0..4 and Market Enabled Plane rows carry the profile's six 101-bit planes as decimal ascii (a plane is at most 31 digits, exactly what a felt252 short string holds) -- marketConfigFromSettingRows finds them by name, takes the values felt-encoded or already ascii-decoded, and returns a PackedMarketConfig. See the market guide for the complete API/event mapping, per-item examples, target-size tradeoffs and encoding. The purchase/drop differential fixtures and market vectors are checked against Cairo.

V0 action packets

Version 0.10 uses the packet protocol in COMMIT-REVEAL.md. Each felt contains 1–15 aligned 16-bit instructions; bits 240–243 hold count minus one, and version/reserved bits are zero. This is a protocol cutover, incompatible with legacy aggregate transcripts. Initialization is separate: call initializeAdventurer with the mint-block hash before replaying packet zero. There is no START instruction.

encodeActionPacket and decodeActionPacket preserve player instruction order. Families may repeat; random actions need not be last; equipment and combat can share a packet. Consecutive stat upgrades, equipment operations, and drops aggregate within their existing uniqueness and size limits. Consecutive item purchases absorb one following potion instruction. A potion before items and repeated potion instructions execute in separate calls. encodeBuy and gameActionInstructions emit items before potions to preserve the market handler's ordering.

applyActionPacket validates the entire reached packet before dispatch and brackets each group with stat boosts. Every dispatch derives its seeds from its current state and the packet's shared entropy. It stops immediately at death or surrender, returning only executed groups and their events, plus terminalReason. Replay callers must skip all later packets without decoding them; commitment folding still includes their raw felts. Counts and transcript cursors measure packets. The compatibility primary/packetPrimary helpers expose only the first scalar gameplay instruction; use groups or instructions for all actions and execution results for terminality.

encodeActionPacketBundle packs ordered subsystem groups while preserving dispatch boundaries. It separates adjacent groups only when concatenation would merge their dispatches or exceed capacity. decodeGameAction supports a single group; use decodeGameActions or applyActionPacket for a complete packet. ATTACK replaces the beast-health threshold with BeastDeathPolicy: allow kills, stop before a guaranteed kill, or stop before a possible kill. The latter two inspect reachable normal/critical damage before every exchange without inspecting its entropy.

Publishing

indexer_v2 consumes this package through workspace:*. Rebuild the engine before validating that consumer. The player-facing client lives in a separate repository and needs a published release containing the matching wire protocol.

From the repository root:

pnpm --dir packages/engine test
pnpm --dir packages/engine typecheck
pnpm --dir packages/engine build

Publish from packages/engine only as part of the coordinated release. The manifest already names version 0.10.0; do not increment it again while publishing that release. Update the external client's package range and deployment configuration together with the compatible contracts and v2 indexer. Legacy aggregate transcripts require the previous protocol.

Layout

src/
  protocol.ts    domains, action codec, root / fold / actionEntropy
  transcript.ts  ActionCommitted decoding, re-folding, chain ordering
  actions.ts     GameAction <-> encoded felt
  replay.ts      applyAction(state, action, entropy)
  packing.ts     unpackAdventurer / unpackBag
  rules/         combat, exploration, loot, market, beast, token ids

applyAction is the client's useGameCore body verbatim; only the wrapper differs. It never themes a beast — the indexer stores raw ids and every reader restyles on read.