How to Customize FSRS Algorithm Parameters in TypeWords

TypeWords uses the open-source ts-fsrs spaced-repetition engine, with all FSRS algorithm parameters stored in a reactive Pinia store at app/core/stores/setting.ts and editable through a built-in UI or programmatically.

TypeWords leverages the ts-fsrs library to power its adaptive flashcard scheduling. Whether you want to tune retention targets, adjust grade thresholds, or modify the weight vector, every configurable aspect of the algorithm is exposed through a centralized Pinia store. This guide explains where these parameters live, how the UI connects to them, and how to override them in code.

Where FSRS Parameters Are Stored

All FSRS configuration resides in the Pinia setting store (app/core/stores/setting.ts). The store maintains two related structures:

  • store.fsrsParameters — Core algorithm parameters passed directly to the ts-fsrs GeneratorParameters interface
  • Grade threshold fields (fsrsEasyLimit, fsrsGoodLimit, fsrsHardLimit) — Map wrong-answer counts to FSRS Rating values

Core FSRS Parameters in store.fsrsParameters

Parameter Type Description
request_retention number Target retention probability (0–1, default ~0.9)
maximum_interval number Hard cap on interval length in days
w number[] 17-element weight vector controlling the model
enable_fuzz boolean Adds small random noise to intervals
enable_short_term boolean Enables short-term scheduling
learning_steps number[] Minutes between learning-stage reviews
relearning_steps number[] Minutes between relearning-stage reviews

Grade Threshold Mapping

The fsrsEasyLimit, fsrsGoodLimit, and fsrsHardLimit values determine how many wrong attempts translate to each FSRS Rating:

  • Again: Wrong times > fsrsHardLimit
  • Hard: fsrsGoodLimit < wrong times ≤ fsrsHardLimit
  • Good: fsrsEasyLimit < wrong times ≤ fsrsGoodLimit
  • Easy: wrong times ≤ fsrsEasyLimit

This conversion happens in app/core/hooks/fsrs.ts, where the store values are used to instantiate a fresh FSRS object and to compute ratings.

Method 1: Programmatically Update the Store

For dynamic customization, import useSettingStore() and mutate the reactive properties directly. Changes propagate immediately to the FSRS helper.

Update Core Algorithm Parameters

import { useSettingStore } from '@/core/stores/setting.ts'

const setting = useSettingStore()

// Raise retention target to 95%
setting.fsrsParameters.request_retention = 0.95

// Enable fuzz to reduce card clustering
setting.fsrsParameters.enable_fuzz = true

// Modify the weight vector for faster decay
setting.fsrsParameters.w = setting.fsrsParameters.w.map(w => w * 0.8)

Adjust Grade Thresholds

import { useSettingStore } from '@/core/stores/setting.ts'

const setting = useSettingStore()

// Stricter grading: Easy only with 0–1 mistakes, Good with 2–3, Hard with 4–6
setting.fsrsEasyLimit = 1
setting.fsrsGoodLimit = 3
setting.fsrsHardLimit = 6

Because the store is reactive, the next call to useNextCard() or any FSRS operation automatically uses the updated configuration. No manual persistence is required.

Method 2: Use the Built-in FSRS Settings UI

TypeWords ships with a dedicated settings component at app/components/setting/FsrsSetting.vue. This component binds form inputs directly to the Pinia store fields, providing:

  • Numeric inputs for request_retention, maximum_interval, and weight vector elements
  • Toggles for enable_fuzz and enable_short_term
  • Array editors for learning_steps and relearning_steps
  • Threshold inputs for fsrsEasyLimit, fsrsGoodLimit, fsrsHardLimit

To embed the settings UI elsewhere in your application:

<template>
  <FsrsSetting />
</template>

<script setup lang="ts">
import FsrsSetting from '@/components/setting/FsrsSetting.vue'
</script>

How the FSRS Hook Consumes Parameters

The app/core/hooks/fsrs.ts file bridges the store to the ts-fsrs engine. It:

  1. Reads store.fsrsParameters to construct a new FSRS instance
  2. Uses the threshold fields to convert raw wrong-attempt counts into Rating values
  3. Exposes useNextCard() and related composables that automatically pick up store changes

This architecture ensures that customizing FSRS algorithm parameters in TypeWords is always consistent—whether through UI interaction or direct store manipulation.

Summary

  • Primary storage: app/core/stores/setting.ts holds all FSRS configuration in a reactive Pinia store
  • Two customization paths: Built-in UI component (FsrsSetting.vue) or programmatic store access
  • Core parameters: request_retention, w, enable_fuzz, maximum_interval, and step arrays in store.fsrsParameters
  • Grade logic: fsrsEasyLimit, fsrsGoodLimit, fsrsHardLimit control the mapping from wrong attempts to FSRS ratings
  • Integration point: app/core/hooks/fsrs.ts instantiates FSRS with current store values and handles rating conversion

Frequently Asked Questions

What is the default request_retention value in TypeWords?

The default retention target is approximately 0.9 (90%), but you should verify the exact initialization in app/core/stores/setting.ts. This value represents the probability that you will recall a card when it next appears, with higher values producing more frequent reviews.

Can I modify the 17-element weight vector w without breaking the algorithm?

Yes, but cautiously. The weight vector is exposed for advanced tuning, yet arbitrary changes may destabilize scheduling. Start with small perturbations (±10–20%) and monitor retention metrics. For production stability, prefer adjusting request_retention or enabling enable_fuzz before tampering with w directly.

Why does useNextCard() reflect changes immediately without reloading?

The FSRS helper in app/core/hooks/fsrs.ts constructs a fresh FSRS instance on each relevant call using the reactive store.fsrsParameters. Since Pinia stores are reactive, any mutation triggers dependent consumers to re-evaluate with the latest configuration.

How do grade thresholds interact with the ts-fsrs Ratings?

TypeWords extends raw FSRS by converting typing-performance metrics (wrong attempt counts) into the four standard FSRS Rating values. The thresholds in store.fsrsEasyLimit, store.fsrsGoodLimit, and store.fsrsHardLimit define the boundaries for this conversion, effectively customizing how strictly your typing accuracy maps to scheduler difficulty.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →