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

@demystify/play-learn

v0.2.0

Published

The Demystify Play learning engine — FSRS scheduling, item-Elo selection and Bayesian Knowledge Tracing mastery, all on-device.

Readme

@demystify/play-learn

The on-device learning engine for Demystify Play: item selection, mastery estimation and review scheduling, all running locally with no server.

npm install @demystify/play-learn

Three algorithms, three questions — deliberately not conflated

| Question | Algorithm | |---|---| | Which item next? | Elo | | Has this skill been mastered? | BKT | | When should this come back? | FSRS-6 |

Conflating any two is how spaced repetition earns a reputation for feeling arbitrary.

Elo — which item next

import { selectItem, updateAbility, newAbility, TARGET_SUCCESS } from "@demystify/play-learn";

const next = selectItem(pool, ability);          // targets ~80% success
const after = updateAbility(ability, item.d, correct);

The target is 80–85% success, not 50%. A 50% rate maximises information about the learner, which is what an exam wants and what a game must not do. K decays with evidence (1/(1+0.05n)), so a single unlucky slip on question 200 does not undo what 199 answers established.

Item difficulty ships pre-computed inside each pack, so the whole selection loop runs with no server. Selection is deterministic, including tie-breaks — a daily puzzle must be identical for everyone, and a replay has to reproduce the exact sequence of questions a player saw.

BKT — has it been mastered

import { observe, isMastered, guessRateFor } from "@demystify/play-learn";

const next = observe(skill, correct, { g: guessRateFor(item.options.length) });

BKT is unusually trustworthy here because its guess parameter is structurally known for a multiple-choice item: four options means a 1-in-4 floor, not a fudge. Mastery requires both a probability threshold and a minimum number of attempts — P(known) alone can cross 95% after two lucky answers through the transition term, and telling someone they have mastered a skill on that basis is a claim the product cannot support.

Mastery is deliberately sticky: the slip parameter says even someone who knows a skill fails 10% of the time, so two failures are a bad session rather than forgetting. A sustained run does revoke it.

FSRS — when should it come back

import { review, gradeFor, studyQueue } from "@demystify/play-learn";

const card = review(item.card, gradeFor(correct, elapsedMs), now);
const queue = studyQueue(items, now, 10);   // due before new, always

FSRS-6 via ts-fsrs (MIT). The scheduling formulas are short enough to reimplement; the fitted 21-parameter default weight vector is not, and inventing those numbers would be inventing a dataset.

Two configuration choices worth stating:

  • enable_fuzz: false. Fuzz jitters intervals to stop reviews clumping, which is right for a 10,000-card Anki deck and wrong here: it makes the schedule non-reproducible, so the same history on two devices would produce different due dates and a synced profile would look corrupted.
  • The grade is derived from the answer, not asked. gradeFor(correct, elapsedMs) uses time as a proxy for retrieval strength — recalling something in two seconds and dredging it up in fifteen are not the same memory — so the scheduler gets four levels of signal from an interaction the player was going to have anyway, with no survey interrupting play.

studyQueue puts due items before new ones, always. A learner shown new material while overdue items pile up ends up with a backlog they cannot clear, which is the most common way people abandon spaced repetition.

Licence

Apache-2.0 · Demystify Systems