ts-fsrs

repository·main·Indexed 18 days ago

https://github.com/open-spaced-repetition/ts-fsrs

A TypeScript toolkit for building spaced repetition systems using the Free Spaced Repetition Scheduler (FSRS) algorithm. It includes the @open-spaced-repetition/binding library for parameter optimization and review history processing, with support for WebAssembly, WASI, and multiple native architectures including Android ARM64, macOS x64, and Linux. The toolkit provides utilities for computing optimal learning/relearning steps and optimizing FSRS parameters from CSV review data.

Tokens
23.9K
Snippets
85
Records
113
Agent score
70%

What's inside ts-fsrs

  1. Overview of ts-fsrs packages

    main

    The ts-fsrs repository provides a TypeScript toolkit for building spaced repetition systems using the FSRS algorithm. It is divided into two primary packages:

    1. ts-fsrs: A scheduler used to build review flows. It implements the FSRS v6 algorithm.
    2. @open-spaced-repetition/binding: A high-performance optimizer used for parameter learning and CSV conversion.
  2. Preview vs Apply ratings with repeat() and next()

    main

    The scheduler provides two primary methods for processing reviews:

    1. repeat(card, date): Use this to preview all four possible outcomes (Again, Hard, Good, Easy) before a user makes a choice. It returns an object containing the resulting cards for each rating.
    2. next(card, date, rating, [afterHandler]): Use this when the rating is already known. It returns the new card state and a review log.

    You can provide an afterHandler to next() to transform the card and log objects into your own storage format (e.g., converting Dates to timestamps).

    // Previewing
    const preview = scheduler.repeat(card, new Date())
    
    // Applying with a custom handler for storage mapping
    const saved = scheduler.next(card, new Date(), Rating.Good, ({ card, log }) => ({
      card: {
        ...card,
        due: card.due.getTime(),
        last_review: card.last_review?.getTime() ?? null,
      },
      log: {
        ...log,
        due: log.due.getTime(),
        review: log.review.getTime(),
      },
    }))
  3. Compare repeat() and next()

    main

    Use repeat() to preview the potential outcomes of all four ratings before a user makes a choice. Use next() when the user has already provided a rating.

    Using an afterHandler with next(): You can pass an afterHandler to next() to map the resulting card and log directly into your own storage format (e.g., converting Dates to timestamps).

    const result = scheduler.next(card, new Date(), Rating.Good, ({ card, log }) => ({
      card: {
        ...card,
        due: card.due.getTime(),
        last_review: card.last_review?.getTime() ?? null,
      },
      log: {
        ...log,
        due: log.due.getTime(),
        review: log.review.getTime(),
      },
    }))
  4. Quickstart with ts-fsrs

    main

    To get started, import fsrs, createEmptyCard, and Rating. Initialize the scheduler with fsrs(), create a new card with createEmptyCard(), and use scheduler.next() to apply a rating or scheduler.repeat() to preview outcomes.

    import { createEmptyCard, fsrs, Rating } from 'ts-fsrs'
    
    const scheduler = fsrs()
    const card = createEmptyCard()
    
    // Preview all possible scheduling outcomes
    const preview = scheduler.repeat(card, new Date())
    console.log(preview[Rating.Again].card)
    
    // Apply a specific rating
    const result = scheduler.next(card, new Date(), Rating.Good)
    console.log(result.card)
    console.log(result.log)
  5. Configure pnpm for WebAssembly architecture support

    main

    If you are using pnpm as your package manager, you must explicitly configure supportedArchitectures in your package.json. This ensures that the @open-spaced-repetition/binding package correctly downloads the required WebAssembly (wasm32) binaries.

    Without this, pnpm may fail to fetch the correct dependencies for the FSRS bindings.

    {
      "pnpm": {
        "supportedArchitectures": {
          "cpu": [
            "current",
            "wasm32"
          ]
        }
      }
    }