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 thets-fsrsGeneratorParametersinterface- Grade threshold fields (
fsrsEasyLimit,fsrsGoodLimit,fsrsHardLimit) — Map wrong-answer counts to FSRSRatingvalues
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_fuzzandenable_short_term - Array editors for
learning_stepsandrelearning_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:
- Reads
store.fsrsParametersto construct a newFSRSinstance - Uses the threshold fields to convert raw wrong-attempt counts into
Ratingvalues - 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.tsholds 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 instore.fsrsParameters - Grade logic:
fsrsEasyLimit,fsrsGoodLimit,fsrsHardLimitcontrol the mapping from wrong attempts to FSRS ratings - Integration point:
app/core/hooks/fsrs.tsinstantiatesFSRSwith 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →