337 / 365 ≈ 92% —— 一年里九成的日子,就爱读
粘贴一段文字(或网页源码、文件、链接),自动切成可记忆的片段,用间隔重复把它们变成长期记忆。
不是打卡表,是记忆引擎:337 提供摄入节奏的默认配置,调度由算法决定而非日历。
本作品参与 WorkBuddy「1024 造物挑战」程序员节应用创作大赛。
家长带孩子晨读、语言学习者背原版书摘录,真正的痛点从来不是「读没读」,而是读过的都忘了。
市面上的打卡工具解决的是前一个问题——记录你今天有没有打开。它们用连击数制造动力,也用连击数制造压力:断一天清零,然后就是放弃。
92Reader 换了个思路。它把目标从「每天打卡」改成「把这些片段记住」,用间隔重复调度复习,用年度完成率替代连击。 断几天不惩罚,因为记忆本身就是有节奏的。
337 在原方法中是「3 体裁 × 3 篇 × 7 天周期」。本产品借用这三个数字做新的诠释:
一年 365 天,读 337 天,休 28 天,坚持率 92% 即达标。
这条理念直接决定打卡机制的设计——不做断卡清零的连击。清零是打卡类工具用户流失的主因, 本产品用年度完成率加容错额度替代:每年 28 天休读额度,未读的日子自动消耗额度,额度耗尽后的缺勤才计为未达标。
| 层 | 能力 |
|---|---|
| 输入层 | 书库选书 / 直接粘贴 / 粘贴网页源码 / 文件上传(txt·md·json·html)/ 链接抓取 |
| 分段层 | 自动切分记忆单元,粒度可调(短 / 中 / 长),导入前可预览重切 |
| 调度层 | SM-2 间隔重复队列,每日新学数与复习上限可配 |
| 记忆层 | 朗读(新学 + 逐级遮字背诵)→ 补全(复习)→ 漫游(自由重温) |
| 统计层 | 年度完成率、92% 目标线、容错余额、掌握度分布 |
| 传播层 | Canvas 渲染打卡分享图,导出 PNG |
关键算法(分段 / SM-2 调度 / 挖空补全 / 遗忘曲线加权漫游 / 完成率)见 REQUIREMENTS.md。
文库以书为单位组织:一本书就是一篇文档,书里已经按章 / 首分好记忆单元。 内置书库(全部公有领域):
| 书 | 单元数 |
|---|---|
| 《道德经》老子 | 81 章 |
| 《古诗词精选》 | 30 首 |
| 《小古文精选》 | 10 篇 |
| 《英文精选》 | 5 篇 |
每个记忆单元带段标题(静夜思 / 第一章)和副标题(唐 · 李白),朗读、补全、漫游、 今日卡片上都显示,读的时候始终知道在背哪一首、哪一章。标题留空会按书自动编号。
朗读弹窗里有遮挡背诵:原文 / 遮一些 / 遮大半 / 全遮四档,逐级加深——
床前明月光, 床前*月光, 床***光, * * * * *,
疑是地上霜。 → 疑是*上霜。 → 疑***霜。 → * * * * *。
遮的是汉字,标点保留(断句是记忆的骨架,遮了反而更难背);保留首尾字作为钩子, 中间均匀抽遮。切档只重绘文字区,朗读不会中断。
在「书库」里选要背的书加入文库,再点「在背这本」,今日新学就只从这本书里出; 这本学完了自动退回全部。想加别的书,按 DATA-FORMAT.md 的「按书整理」格式导入即可, 也可以在文库「编辑」里逐段改、增、删。
排版:古诗文按句读断行显示(体裁优先,其次看句长),散文整段横排——判据是句末标点切出的句子是否都短。 一两个字的碎行(如「鹅,鹅,鹅」)会并回同一行;挖空框宽度随答案字数自适应,诗歌模式下挖空长度也收敛到 3 字内。
node server.js # 默认 http://localhost:3000
PORT=9200 node server.js # 指定端口浏览器打开后即可使用。无需构建、无需安装依赖,要求 Node 22+。
端口只从 PORT 环境变量读取(云端托管平台会注入该变量,本地缺省 3000)。
也可以只用 app.html:单文件双击即开,或托管到任意静态空间。分段、调度、朗读、补全、
漫游、统计、分享图、导入导出全部在浏览器完成,不需要 Node 运行时——服务端只多做一件事,即网页抓取。
| 项 | 选择 |
|---|---|
| 后端 | server.js,Node 22 内置模块,单端口 HTTP,零第三方依赖 |
| 前端 | app.html 单文件,CSS / JS 全内联 |
| 存储 | 浏览器 localStorage,键 reader92.v1.state,无后端数据库、无登录 |
| 语音 | Web Speech API(浏览器 TTS,支持中英文) |
| 分享图 | Canvas 渲染后导出 PNG |
网页抓取分三级,任一级成功即止:
- 公共代理(纯前端主路径):走
r.jina.ai取回正文,地址在「设置」里可换或清空; - 自建服务端:整站部署时
GET /api/fetch?url=直出,自带正文提取,自动识别 UTF-8 / GBK; - 降级:都失败时明确提示改用「粘贴网页源码 / 导入 .html / 上传文件」,不静默失败。
前端的正文提取器与 server.js 同源逻辑:DOMParser 解析 → 去掉 script / nav / footer / 表单 →
article / main 优先,否则按「正文长度 + 段落数 − 链接文字」给容器打分 → 按行去噪。
压缩成一行的 HTML 会先补换行再切分;去噪过头时回退原文,宁可留噪音也不丢正文。
数据在浏览器 localStorage,键 reader92.v1.state。三个事实:
- localStorage 按「源」隔离。
localhost:3000、127.0.0.1:3000、localhost:8080、file://各自是独立仓库,换一个就看到另一份(往往是空的)数据。这不是丢数据,是看错了仓库。 - 首次打开自动补样例。 文库为空且从未填过时,启动即载入 45 篇公有领域样例,所以任何新源打开都不会是空白页。用户主动「清空全部数据」后会记住,不再自动灌。
- 存不住会明说。 私有模式、禁用 Cookie 等环境下写入失败时,页面顶部会出现提示条,不会假装存上了。跨环境搬运靠「设置 → 导出数据 / 导入数据」。
早期版本用过 jad92.v1 / readzy.v1 两个旧键,现在启动时自动迁移到 reader92.v1.state,旧键随即删除。
导入导出共用 reader92.v1,详见 DATA-FORMAT.md。
最小只需两个字段即可导入:
{ "title": "春晓", "content": "春眠不觉晓,处处闻啼鸟。夜来风雨声,花落知多少。" }外部流程(爬站、批量整理、其他工具导出)按此 schema 输出即可直接喂进应用。
.
├── README.md 本文件
├── REQUIREMENTS.md 需求定义 v1(定位 / 六层架构 / 算法 / 数据模型)
├── DATA-FORMAT.md reader92.v1 数据交换格式
├── server.js HTTP 服务 + 抓取接口(可选,纯静态部署时不需要)
├── app.html 单文件前端应用
├── SUBMISSION-1024.md 1024 造物挑战投稿文案
└── shots/ 应用界面截图
- 需求定义与算法设计
- 数据交换格式
-
server.js -
app.html - 样例库(30 古诗词 + 10 小古文 + 5 英文,共 45 篇,均为公有领域)
WorkBuddy「1024 造物挑战」程序员节应用创作大赛 https://www.workbuddy.link/p/8QYARuAmZ9RgQty3FSzNUs?source=2