Learning Goose
This is an application designed specifically for family learning. I hope to spend more time properly using education on children. The project originated from a simple wish: to make family education more effective and efficient.
Core features include:
- Learning timer system based on the Pomodoro Technique (45 minutes of study, 15 minutes of rest)
- Chinese dictation practice tool
- English dictation practice tool
- Chinese word dictionary

There were several factors that motivated me to develop this app:
- I wanted to explore SwiftUI development and see a different market. With AI emerging, cross-domain rapid development has become possible.
- I don’t have much time to help kids with their studies regularly. When I do have time at home, I often lack patience. 😄 So I decided to do what I’m good at and create something for the children.
Project Reflections:
- Time management is useful but not as effective as expected. The Pomodoro Technique works, but not as dramatically as hoped. Applying it to children requires more patience. The product needs more thought, but I may not have enough time to refine it slowly.
- Concerns about children’s extended phone usage
- Time management + homework assistance - the concepts are mixed together. If AI tutoring is the goal, why not make it a separate app?
This journey ends here for now, 👋
Perhaps it will return in another form someday?
Development Notes 📝
Positioning: After-school learning management
Pending homework -> Time management -> Completion -> Homework correction -> Statistical review
|
---> Bottlenecks, Tools & AI assistance
Early design draft

听写
- Synchronize textbook resources, which can be found on the National Educational Resources Public Service Platform.
- PDF text extraction, using the Adobe Extract PDF API tool to extract text from PDFs.
- AI organization and output of JSON data Google Gemini
- Generate the SQLite database required for the application.
Prompt example
I extracted some data from pdf, it is chinese textbook, contians char and pinyin
I will paste it to you
liAng 两 nA 哪 kuQn 宽 dJng顶 yAn眼
require you return json to me, format is like
{
words: [
{ char: "两", pinyin: "liang" },
{ char: "哪", pinyin: "na" },
{ char: "宽", pinyin: "kuan" },
{ char: "顶", pinyin: "ding" },
{ char: "眼", pinyin: "yan" },
]
}
Please infer the pinyin field, all lower case。
Later, I found that using the pinyin-pro library made it easier to generate pinyin with tone marks. Of course, AI helped a lot in transforming the format. 👍
Apple’s AVFoundation framework makes it easy to play audio, but the effect of reading characters is not particularly good, so the format and accuracy of pinyin and tone in the data preparation stage are especially important.
Prepare the data source, organized through the file directory structure
vocabulary/
├── join in 三年级起点
│ ├── 三年级
│ │ └── 上册.json
│ ├── 五年级
│ │ ├── 上册.json
│ │ └── 下册.json
│ ├── 六年级
│ │ ├── 上册.json
│ │ └── 下册.json
│ └── 四年级
│ ├── 上册.json
│ └── 下册.json
└── 语文(统编版)
├── 一年级
│ ├── 上册
│ │ └── 写字表.json
│ └── 下册
│ └── 写字表.json
├── 三年级
│ ├── 上册
│ │ ├── 写字表.json
│ │ └── 词语表.json
│ └── 下册
│ ├── 写字表.json
│ └── 词语表.json
# ....
Database structure
CREATE TABLE IF NOT EXISTS units (
id INTEGER PRIMARY KEY AUTOINCREMENT,
lang TEXT NOT NULL, -- Language (e.g., 'zh', 'en')
book TEXT NOT NULL, -- Book name (e.g., '语文(统编版)', 'join-in')
grade TEXT NOT NULL, -- School grade level (e.g., '一年级', '二年级')
term TEXT NOT NULL, -- Academic term (e.g., '上册', '下册')
type TEXT, -- Type of content (e.g., '词语表', '生字表')
unit TEXT NOT NULL, -- Unit identifier (e.g., '课文 1', '课文 2')
UNIQUE(lang, book, grade, term, type, unit) -- Ensure no duplicate units
);
CREATE TABLE IF NOT EXISTS words (
id INTEGER PRIMARY KEY AUTOINCREMENT,
unit_id INTEGER NOT NULL, -- References units.id
text TEXT NOT NULL, -- characters (e.g., '看见', '孩子', 'cinema')
pinyin TEXT, -- Pinyin pronunciation (e.g., 'kàn jiàn', 'hái zǐ')
pinyin_num TEXT, -- Numeric tone notation (e.g., 'kan3 jian4', 'hai2 zi3')
explanation TEXT, -- Chinese explanation (e.g., '看见', '孩子', '电影院')
level TEXT, -- Level of difficulty (e.g., 'core', 'regular', 'over')
FOREIGN KEY (unit_id) REFERENCES units(id)
);
Write a script to generate the SQLite database
node vocabulary/index.mjs
✔ 选择要处理的文件 (Ctrl+C 退出):
[zh] 语文(统编版)/一年级/上册/写字表
[zh] 语文(统编版)/一年级/下册/写字表
# ...
[en] join in 三年级起点/五年级/下册
[en] join in 三年级起点/六年级/上册
[en] join in 三年级起点/六年级/下册
# ⏎
✅ [zh] 语文(统编版)/一年级/上册/写字表 Inserted data
✅ [zh] 语文(统编版)/一年级/下册/写字表 Inserted data
✅ [zh] 语文(统编版)/二年级/上册/写字表 Inserted data
# ...
Pomodoro Timer
Design
- Task List and Execution:
- Tasks are arranged in sequence, executed one after another
- The entire task list has unified start, pause, and resume functions
- Current task automatically tracks time
- Task Management:
- Users can add new tasks, including task name and
estimated time - Users can edit existing task names and
estimated times - Tasks can be completed early
or extended - Completed tasks are removed from the list
- Users can add new tasks, including task name and
- Time Management:
- Each task has an estimated completion time (default 30 minutes)
- Actual time can differ from estimated time
- Pomodoro timer (45 minutes work, 15 minutes rest)
- Interface Design:
- Main interface displays ordered task list
- Current task is highlighted
- Shows Pomodoro timer
- Supports dark mode
- Data Recording and Display:
- Shows records after task completion (may include actual time spent, on-time completion status, etc.)
- Displays number of Pomodoros completed today
User Flow
- User opens app, sees task list and Pomodoro timer
- User can add new tasks, set task names and estimated times
- User can adjust task order (if needed)
- User clicks “Start” button, first task begins timing
- During task execution, user can:
- Pause entire task list
- Complete current task early
- Extend current task time
- After current task completion, automatically starts next task
- After all tasks complete, displays summary information
Overview diagram
graph TD
A[User opens the app] --> B[View the task list and Pomodoro timer]
B --> C{User operations}
C -->|Add new tasks| D[Set task name and estimated time]
C -->|Adjust task order| E[Reorder tasks]
C -->|Start task| F[Click Start button]
F --> G{Timing phase}
G -->|Give up| B[Return to task list]
G -->|Complete| H[Task completed]
Timing phase
graph TD
F[Click Start button] --> G[First task starts timing]
G --> H{Task in progress}
H -->|Pause| I[Pause the entire task list]
H -->|Complete early| J[End current task]
H -->|Complete| L{Is there another task?}
L -->|Yes| M[Start next task]
M --> H
L -->|No| N[Display summary information]
I --> H
J --> L
Completion Progress
P0: Core functionality (must be implemented, constituting the MVP - Minimum Viable Product)
- Task list creation and display
- Add new tasks (including setting estimated time)
- Start/pause the entire task list
- Tasks execute in sequence automatically
- Current task timing function
- Basic Pomodoro timer (45 minutes work, 15 minutes rest)
P1: Important functionality (significantly improves user experience, but not required for MVP)
- Edit existing tasks (name and estimated time)
- Complete or extend current task early
- Display simple records after task completion (e.g., actual time spent)
- Interface improvements MidJourney
- Different stages of animation effects Rive
P2: Additional functionality (optimization and improvement, can be added in later versions)
- Adjust task order
- Dark mode support
- Data visualization report, persistence
Dictionary
Optional open source data sources
- Chinese Xinhua, crawler https://github.com/pwxcoo/chinese-xinhua
- 爬虫的,数据结构更全 https://github.com/mapull/chinese-dictionary
Finally, I used the mapull version, but still need to clean up the data
- Only the 《General Standard Chinese Characters List》 is needed for primary school students
- Some pinyin special symbols look the same but have different codes
- Some annotations are incorrect
Like dictation, for tone marks, they need to be output as pinyin with tone numbers, such as sheng1 diao4. This requires using the pinyin-pro library.
Combine AI and manual preparation of some metadata
const pinyinCombinations = {
a: ["a", "ai", "an", "ang", "ao"],
b: ["ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao", "bie", "bin", "bing", "bo", "bu"],
c: ["ca", "cai", "can", "cang", "cao", "ce", "cen", "ceng", "cha", "chai", "chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun", "chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo"],
d: ["da", "dai", "dan", "dang", "dao", "de", "dei", "den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo"],
e: ["e", "ei", "en", "er"],
f: ["fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu"],
g: ["ga", "gai", "gan", "gang", "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo"],
h: ["ha", "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hong", "hou", "hu", "hua", "huai", "huan", "huang", "hui", "hun", "huo"],
j: ["ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", "jue", "jun"],
k: ["ka", "kai", "kan", "kang", "kao", "ke", "ken", "keng", "kong", "kou", "ku", "kua", "kuai", "kuan", "kuang", "kui", "kun", "kuo"],
l: ["la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian", "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lüe", "lun", "luo", "lü"],
m: ["ma", "mai", "man", "mang", "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu"],
n: ["na", "nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", "niu", "nong", "nou", "nu", "nuan", "nüe", "nuo", "nü"],
o: ["o", "ou"],
p: ["pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", "pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu"],
q: ["qi", "qia", "qian", "qiang", "qiao", "qie", "qin", "qing", "qiong", "qiu", "qu", "quan", "que", "qun"],
r: ["ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou", "ru", "ruan", "rui", "run", "ruo"],
s: ["sa", "sai", "san", "sang", "sao", "se", "sen", "seng", "sha", "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo"],
t: ["ta", "tai", "tan", "tang", "tao", "te", "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo"],
w: ["wa", "wai", "wan", "wang", "wei", "wen", "weng", "wo", "wu"],
x: ["xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", "xu", "xuan", "xue", "xun"],
y: ["ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yo", "yong", "you", "yu", "yuan", "yue", "yun"],
z: ["za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao", "zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi", "zong", "zou", "zu", "zuan", "zui", "zun", "zuo"]
}
// 部首列表参考来源 Wiki
// 顺序和变体组织,主要参考 《新华字典》
const radicalsByStroke = {
1: ["一", "丨", "丶", "丿", "乛"],
2: [
"二", "十", "厂", "匚", "刂", "卜", "冂", "亻", "八", "人",
"入", "⺈", "⺆", "勹", "𠘨", "儿", "匕", "几", "亠", "冫",
"丷", "冖", "讠", "凵", "卩", "阝", "刀", "力", "又", "厶",
"廴"
],
3: [
"干", "工", "土", "士", "扌", "艹", "寸", "廾", "大", "兀",
"尢", "弋", "小", "⺌", "口", "囗", "山", "巾", "彳", "彡",
"犭", "夕", "夂", "饣", "丬", "广", "门", "氵", "忄", "宀",
"辶", "彐", "尸", "己", "弓", "子", "屮", "女", "飞", "马",
"纟", "幺", "巛", "川", "彑"
],
4: [
"王", "无", "韦", "耂", "木", "攴", "支", "犬", "歹", "车",
"牙", "戈", "旡", "比", "瓦", "止", "⺗", "日", "⺝", "贝",
"水", "见", "牛", "手", "龵", "气", "毛", "攵", "长", "片",
"斤", "爪", "父", "爫", "月", "氏", "欠", "风", "殳", "文",
"方", "火", "斗", "灬", "户", "礻", "心", "肀", "爿", "毋",
"卝", "厄", "爻"
],
5: [
"玉", "示", "甘", "石", "龙", "业", "氺", "目", "田", "罒",
"皿", "钅", "生", "矢", "禾", "白", "瓜", "鸟", "疒", "立",
"穴", "衤", "疋", "皮", "癶", "矛", "母", "用",
],
6: ["先", "竹", "米", "糸", "糹", "缶", "羊", "羽", "而", "耒", "耳", "聿", "肉", "臣", "自", "至", "臼", "舌", "舟", "艮", "色", "虍", "虫", "血", "行", "衣", "覀", "页", "齐"],
7: ["克", "卤", "角", "言", "谷", "豆", "豕", "豸", "貝", "赤", "走", "足", "身", "辛", "辰", "邑", "酉", "采", "里", "麦"],
8: ["金", "長", "阜", "隶", "隹", "雨", "靑", "青", "非", "靣", "鱼", "齿"],
// nine and above
9: ["面", "革", "韭", "音", "首", "香", "骨", "鬼", "高", "髟", "鬥", "鬯", "鬲", "魚", "鹿", "麻", "黄", "黍", "黑", "黹", "鼎", "鼓", "鼠", "鼻", "龠"]
}
/** the radical display name: "$mainForm ($variants)" */
const radicalVariants = {
"乛": ["亅", "乚", "乙"],
"阝": ["左耳", "右耳"],
"己": ["已", "巳"],
"卩": ["㔾"],
"王": ["𤣩"],
"日": ["曰", "⺜"],
"牛": ["牜"],
"疋": ["𤴔"],
"覀": ["西"],
"竹": ["𥫗"],
"羊": ["⺶", "𦍌"],
"聿": ["⺻"],
"足": ["𧾷"],
"雨": ["⻗"],
"黾": ["黽"],
"食": ["飠"]
}
Data structure and script, no further discussion.
Break time
A short break (about 15 minutes) provides interesting and beneficial activities to help them relax and prepare for the next learning cycle.
Activity categories
- Learning efficiency improvement
- Time management skills
- Concentration exercises
- Memory improvement methods
- Physical and mental health
- Simple stretching exercises
- Meditation and breathing exercises
- Positive thinking cultivation
- Life skills
- Organization and storage methods
- Basic household skills
- Personal hygiene habits
Break bell
Play a little 🤏 classical music to relax.
./Resources/classic/
├── Air on the G String.mp3
├── Claire de Lune.mp3
├── June Barcarolle.mp3
└── Serenade in G Major.mp3