探字星球 项目设计文档
版本: 3.0 | 日期: 2026-07-19 基于 web/ TypeScript 项目重构,含 Mock API 层
一、项目概述
探字星球是专为 3-8 岁儿童设计的汉字学习应用,通过趣味互动和游戏化学习认识 500 个精选汉字。当前为纯前端实现 + Mock API 模拟后端。
1.1 核心设计理念
- 游戏化驱动学习:段位升级、徽章收集、星球探索三条成长线并行
- 数据闭环:每种学习行为都产生 record,驱动艾宾浩斯复习调度
- 少选择、多引导:用户不面对"选哪种模式"的决策,系统直接告诉"该复习这些字"
- 渐进式解锁:星球、关卡、徽章均按完成度逐步解锁,保持持续激励
1.2 用户画像
| 角色 | 需求 | 使用场景 |
|---|---|---|
| 3-8岁儿童 | 识字、认读、书写 | 每日15-30分钟学习 |
| 家长 | 管理学习内容、控制奖励 | 设置密码、配置奖励 |
二、总体架构
2.1 技术栈
| 类别 | 技术 | 版本 |
|---|---|---|
| 框架 | Vue 3 | Composition API + <script setup> + TypeScript |
| 路由 | vue-router | 22条命名路由 + 3条重定向 |
| 状态管理 | Pinia | 5个Store(TypeScript) |
| UI组件库 | tdesign-mobile-vue | 移动端UI |
| HTTP | axios | api-service 统一封装 |
| Mock API | mockjs | 39个RESTful接口 |
| 汉字书写 | hanzi-writer | 笔顺动画 + 描红练习 |
| 3D渲染 | three.js | WebGL + GLSL着色器 |
| 构建 | Vite | 开发服务器 + 生产构建 |
| 测试 | vitest | 140个测试用例 |
| 类型检查 | vue-tsc | TypeScript 严格模式 |
2.2 四层架构
Pages/Components → Stores → api-service.ts (axios) → Mock API (mockjs) → localStorage
↑ ↑ ↑ ↑
UI交互层 状态管理层 HTTP请求层 数据模拟层- Pages/Components:UI渲染和用户交互,引用Store和Composable
- Stores:数据持久化入口,通过 api-service 统一访问 Mock API
- api-service.ts:axios 封装,统一请求/响应拦截
- Mock API:mockjs 拦截 axios 请求,模拟后端接口(39个RESTful接口)
- Services:跨模块奖励发放(reward-service)、CDN资源管理(resource-service)
- Composables:可复用的逻辑组合(复习调度、汉字筛选、游戏计时、拖拽交互)
2.3 模块依赖图
App.vue (TabBar: 首页/汉字星际/星球地图/我的)
├── 首页 (index) → 复习计划 / 游戏中心 / 积分商店
├── 汉字星际 (char-select) → 汉字详情 (character) → 书写练习 (write) → 书写结果 (write-result)
├── 星球地图 (planet-map) → 星球详情 (planet-detail) → 汉字分类 (planet-series) → 书写
└── 我的 (profile) → 成就系统 / 设置 / 复习统计 / 关于
├── 成就系统 (achievement-home) → 徽章墙 (badge-wall)
└── 设置 (settings) → 家长管理 (shop-manage)三、路由设计
3.1 完整路由表
| 路径 | 名称 | 组件 | Tab | 说明 |
|---|---|---|---|---|
/onboarding | onboarding | onboarding.vue | - | 首次引导页 |
/index | index | index.vue | ✓ | 首页 |
/char-select | char-select | char-select.vue | ✓ | 汉字星际 |
/character | character | character.vue | - | 汉字详情 |
/write | write | write.vue | - | 书写练习 |
/write-result | write-result | write-result.vue | - | 书写结果 |
/profile | profile | profile.vue | ✓ | 我的 |
/settings | settings | settings.vue | - | 设置 |
/review-today | review-today | review-today.vue | - | 今日复习 |
/planet-map | planet-map | planet-map.vue | ✓ | 星球地图 |
/planet-detail | planet-detail | planet-detail.vue | - | 星球详情 |
/planet-series | planet-series | planet-series.vue | - | 汉字分类 |
/achievement-home | achievement-home | achievement-home.vue | - | 成就系统 |
/badge-wall | badge-wall | badge-wall.vue | - | 徽章墙 |
/game-menu | game-menu | game-menu.vue | - | 汉字游戏 |
/pictograph-match | pictograph-match | pictograph-match.vue | - | 象形配对 |
/stroke-puzzle | stroke-puzzle | stroke-puzzle.vue | - | 拼图闯关 |
/char-match3 | char-match3 | char-match3.vue | - | 汉字消消乐 |
/review-stats | review-stats | review-stats.vue | - | 复习统计 |
/shop | shop | shop.vue | - | 积分商店 |
/shop-manage | shop-manage | shop-manage.vue | - | 家长管理 |
/about | about | about.vue | - | 关于 |
重定向规则:
/→/onboarding/review-mode→/review-today(旧路由兼容)/:pathMatch(.*)*→/onboarding
3.2 路由守卫
router.beforeEach((to, from, next) => {
const hasOnboarded = localStorage.getItem("tzxq_onboarded")
if (!hasOnboarded && to.path !== "/onboarding") {
next("/onboarding") // 首次进入 → 引导页
} else if (hasOnboarded && to.path === "/onboarding") {
next("/index") // 已引导 → 跳过引导页
} else {
next()
}
})3.3 TabBar 配置
4个底部Tab:首页(/index)、汉字星际(/char-select)、星球地图(/planet-map)、我的(/profile)
四、数据模型
4.1 核心数据结构
userStore (userData) — 用户数据
interface UserData {
userName: "汉字探索者", // 用户名
avatar: "", // 头像
learned: [], // 已学会汉字列表(score≥60)
records: [], // 学习记录 [{ char, type, score, date }]
reviewStages: {}, // 复习阶段 { [char]: { stage, nextReviewDate, history[] } }
lastDailyReview: null, // 上次完成每日复习日期
settings: { dailyGoal, strokeHint, autoAudio, fontSize, darkMode, showFooterCredit },
streak: 0, // 连续学习天数
maxStreak: 0, // 最长连续天数
lastStudyDate: null, // 最后学习日期
badges: [], // 已解锁徽章 [{ badgeId, unlockedAt }]
totalEXP: 0, // 总经验值
shopPoints: 0, // 积分余额
pointLog: [], // 积分日志 [{ id, type, amount, balance, source, desc, time }]
etymologyViewed: [], // 已查看字源的汉字列表
shopRewards: [], // 自定义奖励 [{ id, name, cost, icon, enabled, createdAt }]
shopHistory: [], // 兑换历史(保留最新50条)
shopPassword: "", // 密码哈希(SHA-256)
shopLockUntil: 0, // 密码锁定截止时间戳
shopAttempts: 0, // 密码错误尝试次数
planetUnlocks: ["nature_planet"], // 已解锁星球列表
}character.json — 汉字数据
interface Character {
version: "2.3.0",
total: 500,
categories: { /* 6大分类 × 24子分类 */ },
characters: {
"一": {
pinyin: "yī1", // 拼音+声调(1-4声,5=轻声)
radical: "一", // 部首
strokes: 1, // 笔画数
structure: "独体", // 结构
meaning: "数字一", // 释义
words: ["一定", "一起"], // 词组
sentences: ["我是一年级学生。"],
etymology: { // 字源
stages: {
oracle: { description: "..." },
bronze: { description: "..." },
seal: { description: "..." },
clerical: { description: "..." },
regular: { description: "..." }
}
},
category: "number", // 分类
sub_category: "number_basic",
difficulty: 1, // 难度 1-5
frequency: 1, // 频率 1-5
is_common: true,
is_multi_pinyin: false, // 是否多音字
pinyins: [] // 多音字列表(含词组和造句)
}
}
}categories.json — 分类体系
6大分类(自然、人物、动物、器物、植物、天文)× 24子分类,每个含 color、icon、description。
planets.json — 星球配置
6颗星球,每颗含 sub_series(子系列)、rhyme(童谣)、unlock_condition。默认解锁 nature_planet。
games.json — 游戏关卡
3款游戏 × 10关 = 30关,每关含 difficulty(1-5)、rewards.exp、rewards.coins、stars阈值。
4.2 数据持久化
| Key | 说明 | 管理方式 |
|---|---|---|
tzxq_mock_db | 用户数据(Mock API 管理) | Mock API 自动保存 |
tzxq_onboarded | 引导完成标记 | 直接 localStorage |
tzxq_resource_cache | LRU资源缓存 | resource-cache.ts |
五、奖励系统
5.1 奖励常量定义
所有奖励统一由 reward-service.ts 管理,定义在 REWARD 常量对象:
| 常量 | EXP | 积分 | source | 触发场景 |
|---|---|---|---|---|
WRITE_COMPLETE | +10 | +1 | write_complete | 每次书写完成 |
WRITE_PERFECT | +10 | +1 | write_perfect | 书写满分(100分) |
FIRST_LEARN | +5 | +1 | first_learn | 首次学会(score≥60首次进入learned) |
RECOGNITION_PASS | +5 | 0 | recognition_pass | 认读选择题答对 |
RECOGNITION_FAIL | +1 | 0 | recognition_fail | 认读选择题答错 |
REVIEW_CHAR | +5 | +1 | review_char | 完成单字复习全流程 |
DAILY_REVIEW_FULL | +50 | +5 | daily_review | 每日复习100%完成 |
DAILY_REVIEW_80 | +30 | +3 | daily_review | 每日复习≥80%完成 |
BADGE_UNLOCK | +50 | +5 | badge_unlock | 每解锁一枚徽章 |
5.2 奖励发放流程
行为触发 → awardXxxReward() → achievementStore.addEXP/addPoints()
↓
userStore.addEXP/addPoints()
↓
api-service.ts → Mock API → localStorage 持久化
↓
徽章检测 (watch → checkBadges)5.3 去重机制
- 复习单字去重:
reviewedCharsSet,同一会话中同一汉字只奖励一次 - 每日复习去重:
lastDailyReview日期检查,每天只奖励一次
5.4 游戏奖励
游戏奖励通过 awardGameReward(gameType, level, stars, levelConfig) 发放,公式:
exp = baseExp × starMultiplier × difficultyMultiplier
coins = baseCoins × starMultiplier × difficultyMultiplier
starMultiplier: 1★=1.0x, 2★=1.5x, 3★=2.0x
difficultyMultiplier: [1.0, 1.0, 1.2, 1.5, 1.8, 2.0][difficulty]失败(stars≤0)不发放奖励。
六、段位系统
6.1 段位定义
5大级别 × 10小段 = 50段,每段经验值递增:
| 级别 | 名称 | 颜色 | EXP区间 | 每段EXP |
|---|---|---|---|---|
| 青铜 | bronze | #cd7f32 | 0-999 | 100 |
| 白银 | silver | #c0c0c0 | 1000-2499 | 150 |
| 黄金 | gold | #ffd700 | 2500-4499 | 200 |
| 铂金 | platinum | #42a5f5 | 4500-6999 | 250 |
| 王者 | king | #ab47bc | 7000-9999 | 300 |
段位计算:segment = startSegment + floor((totalEXP - tierMin) / segmentExp),最高50段。
6.2 升级所需总EXP
| 级别 | 到达所需EXP |
|---|---|
| 青铜 | 0 |
| 白银 | 1000 |
| 黄金 | 2500 |
| 铂金 | 4500 |
| 王者 | 7000 |
| 满级 | 10000 |
七、徽章系统
7.1 徽章总览(30枚)
| 类别 | 数量 | 徽章 | 解锁条件 |
|---|---|---|---|
| 书写 (write) | 6 | first_write, write_10/50/100, perfect_10/30 | 累计书写次数/满分次数 |
| 探索 (explore) | 6 | learn_10/50/100/200/300/500 | 累计学会汉字数 |
| 恒心 (streak) | 6 | streak_3/7/14/30/60/100 | 连续学习天数 |
| 字源 (etymology) | 6 | etymology_10/30/50/100/200/300 | 累计查看字源字数 |
| 游戏 (game) | 6 | game_1/5/10/26, game_perfect_3/10 | 累计完成关卡/3星通关数 |
7.2 徽章解锁机制
- 书写/探索/恒心/字源:通过
watch监听对应数据变化自动检测 - 游戏:通过
watch监听gameStore.getGameProgress()变化自动检测 - 初始化检查:
achievementStore创建时执行checkWriteBadges()等,确保从localStorage恢复后正确检测
7.3 徽章奖励
每解锁一枚徽章:+50 EXP, +5 积分。
八、书写系统
8.1 书写流程
汉字详情页 (character) → 书写练习页 (write) → 书写结果页 (write-result)8.2 三种入口
| 入口 | from参数 | 汉字列表 | 掌握判定 | 全部掌握后跳转 |
|---|---|---|---|---|
| 汉字星际 | char-select | 全部汉字 | maxScore ≥ 60 | /char-select |
| 星球地图 | planet-series | 按subCategory过滤 | maxScore ≥ 60 | /planet-series |
| 薄弱字 | review-stats | Top 10薄弱字(动态重算) | 准确率 ≥ 100% | /review-stats |
8.3 书写评分公式
score = accuracyScore(0-70) + completionScore(0-25) + speedBonus(0-5)
accuracyScore = max(0, 1 - totalMistakes / attempted) × 70
completionScore = quizComplete ? 25 : (currentStroke / totalStrokes) × 25
speedBonus = quizComplete ? round(5 × min(1, expectedTime / totalTime)) : 08.4 评分等级
| 分数 | 星级 | 文案 |
|---|---|---|
| ≥95 | 5星 | 太棒了!书写完美! |
| ≥80 | 4星 | 写得不错,继续加油! |
| ≥60 | 3星 | 还可以,多练习会更好 |
| ≥40 | 2星 | 需要多多练习哦 |
| <40 | 1星 | 加油,坚持就是胜利! |
8.5 HanziWriter 配置
- 描红模式:笔画颜色
#1f2937(黑色) - 笔顺演示模式:笔画颜色
#3b82f6(蓝色) - 模式切换时保留writer实例,通过
setCharacter()重置状态 - 笔画数据通过
resource-service.ts统一获取,含请求去重
九、复习系统
9.1 设计概述
基于艾宾浩斯遗忘曲线的间隔复习,已从旧版"只看首次学习日期"升级为阶段追踪制。
9.2 复习间隔
REVIEW_INTERVALS = [1, 3, 7, 15, 30] 天useReviewScheduler.ts 为唯一定义点,userStore和review-today均引用此常量。
9.3 阶段推进规则
| 条件 | 行为 |
|---|---|
| 复习得分 ≥ 80 | stage + 1(不超过4),nextReviewDate按REVIEW_INTERVALS[stage]推算 |
| 复习得分 60-79 | stage 不变,nextReviewDate = 明天(重试) |
| 复习得分 < 60 | stage 重置为 0,nextReviewDate = 明天(重新学) |
| 错过复习日(超过nextReviewDate + 3天) | 标记为"过期复习" |
9.4 复习流程(三步)
步骤1: 认读测试 — 展示汉字 → 4选1拼音选择题
正确 → +5 EXP, record score=100
错误 → +1 EXP, record score=0
步骤2: 书写练习 — 跳转HanziWriter描红 → 评分(0-100)
步骤3: 字源回顾 — 字源演变缩略图 + 记忆提示 → 自动进入下个字关键设计改进:
- 认读从主观自评改为客观选择题(4选1拼音),产生record
- 每步都产生record,驱动艾宾浩斯调度
- 单字完成奖励 +5 EXP, +1 积分(带去重)
9.5 每日复习奖励
| 条件 | EXP | 积分 |
|---|---|---|
| 完成率 = 100% | +50 | +5 |
| 完成率 ≥ 80% | +30 | +3 |
| 完成率 < 80% | 0 | 0 |
每天仅触发一次,通过 lastDailyReview 日期去重。
9.6 页面结构
首页 → /review-today(主入口)
├── 列表视图:今日复习概览 + 待复习汉字列表 + 快捷入口
├── 复习流程视图(ReviewFlow):三步复习流程
└── 完成庆祝视图(ReviewComplete):奖励汇总/review-mode 已删除,替换为重定向 /review-mode → /review-today。
9.7 复习统计(review-stats)
- 显示复习阶段分布(各阶段字数、百分比、过期字数)
- 正确率基于全部records计算
- 阶段分布基于
reviewStages数据实时计算
十、游戏系统
10.1 游戏总览
| 游戏 | 类型 | 核心机制 | 道具 | 关卡数 |
|---|---|---|---|---|
| 象形配对 | 配对 | 60s限时,古文字→现代汉字配对 | 1次提示 | 10关 |
| 拼图闯关 | 拖放 | 笔画拼块拖放,进度记忆 | 提示(-5分) | 10关 |
| 汉字消消乐 | Match-3 | 7×7棋盘,步数限制 | 锤子(3)、洗牌(2)、提示(3) | 10关 |
10.2 游戏奖励配置
象形配对 (pictograph_match)
| 关卡 | 难度 | 基础EXP | 基础积分 | 1★分数 | 2★分数 | 3★分数 |
|---|---|---|---|---|---|---|
| 1 | 1 | 15 | 8 | 30 | 50 | 70 |
| 2 | 1 | 20 | 10 | 30 | 50 | 70 |
| 3 | 2 | 25 | 12 | 50 | 80 | 110 |
| 4 | 2 | 30 | 15 | 50 | 80 | 110 |
| 5 | 3 | 40 | 18 | 70 | 110 | 150 |
| 6 | 3 | 50 | 22 | 70 | 110 | 150 |
| 7 | 4 | 60 | 26 | 90 | 140 | 190 |
| 8 | 4 | 70 | 30 | 110 | 170 | 230 |
| 9 | 5 | 80 | 35 | 100 | 150 | 200 |
| 10 | 5 | 100 | 40 | 130 | 190 | 250 |
拼图闯关 (stroke_puzzle)
| 关卡 | 难度 | 基础EXP | 基础积分 |
|---|---|---|---|
| 1 | 1 | 15 | 8 |
| 2 | 1 | 20 | 10 |
| 3 | 2 | 25 | 12 |
| 4 | 2 | 30 | 15 |
| 5 | 3 | 40 | 18 |
| 6 | 3 | 50 | 22 |
| 7 | 4 | 60 | 26 |
| 8 | 4 | 70 | 30 |
| 9 | 5 | 80 | 35 |
| 10 | 5 | 100 | 40 |
汉字消消乐 (char_match3)
同上,3款游戏使用相同的奖励配置。
10.3 关卡解锁
前一关通关(目标完成)即标记 completed,与星级无关,下一关自动解锁。
10.4 失败处理
- 象形配对:错误次数达到上限(配对数×50%)→ 弹出失败弹窗
- 拼图闯关:错误次数达到上限(3-5次,随难度递增)→ 失败
- 汉字消消乐:步数耗尽 → 1秒后弹出失败弹窗,
endGame(false),earnedExp=0, earnedCoins=0
十一、星球系统
11.1 星球列表
| 星球 | ID | 主题色 | 分类 | 解锁条件 |
|---|---|---|---|---|
| 自然星球 | nature_planet | #4CAF50 | nature | 默认解锁 |
| 人物星球 | human_planet | 红色系 | human | 完成自然星球 |
| 动物星球 | animal_planet | 暖色系 | animal | 完成人物星球 |
| 器物星球 | object_planet | 蓝色系 | object | 完成动物星球 |
| 植物星球 | plant_planet | 绿色系 | plant | 完成器物星球 |
| 天文星球 | astronomy_planet | 紫色系 | astronomy | 完成植物星球 |
11.2 解锁机制
- 默认解锁第一颗星球(nature_planet)
- 完成星球全部内容后自动解锁下一颗
- 设置页面可手动解锁/锁定(第一颗不可锁定)
- 解锁状态通过
userStore.planetUnlocks[]管理
11.3 星球地图 3D渲染
- 使用 Three.js + 6个GLSL着色器
- 三态切换:orbit(轨道漫游)→ focus(聚焦单星)→ single(进入星球)
- 光线投射检测点击
- 相机飞行动画
- 星空粒子背景 + 星云效果
- 星球椭圆轨道运动
11.4 星球详情
- 星球封面3D模型(CoverGalaxy)
- 学习进度条:
position: sticky; top: 48px,通过IntersectionObserver检测悬浮状态 - 汉字分类展示(SeriesCharIcon使用HanziWriter绘制笔画动画)
- 星球介绍 + 童谣
十二、积分商店
12.1 兑换流程
查找奖励 → 验证状态(enabled + 余额充足) → 扣除积分 → 生成积分日志 → 记录兑换历史12.2 自定义奖励
数据结构:{ id, name, cost, icon, enabled, createdAt }
管理接口:addReward(), updateReward(), toggleReward(), deleteReward()
10种预设图标:tv(看电视)、toy(玩具)、park(去公园)、book(书籍)、gamepad(打游戏)、candy(零食)、bike(骑自行车)、phone(玩手机)、star(自定义)、gift(礼物)
12.3 密码保护
- SHA-256哈希存储(Web Crypto API)
- 3次错误尝试 → 锁定60秒
- 锁定状态持久化(防刷新绕过)
- 密码修改需输入原密码验证
12.4 积分日志
- 每条日志包含:id、type(earn/spend)、amount、balance、source、sourceId、desc、time
- 所有积分变动均记录
- 兑换历史保留最新50条
十三、资源服务
13.1 资源加载策略
| 资源类型 | 加载方式 | 回退 |
|---|---|---|
| hanziWriter笔顺 | 本地 JSON(import.meta.glob) | - |
| 字源SVG | 本地 public/data/ → CNB CDN | jsDelivr CDN |
| 汉字音频 | 本地 public/data/ → bcebos CDN → CNB CDN | jsDelivr CDN → TTS |
13.2 关键机制
- 统一入口:所有CDN资源通过
resource-service.ts访问,禁止裸fetch - 请求去重:
getHanziWriterData使用_hwPendingMap,同汉字并发请求复用同一Promise - LRU缓存:
resource-cache.ts,最大50条,持久化到localStorage - 字源预检:
preCheckStages()先加载index.json,只对available的阶段加载SVG,缺失阶段生成fallback楷书SVG - 音频回退:CDN音频失败 → TTS合成,
_fallbackUsedflag防止重复TTS
十四、安全设计
14.1 密码安全
- 密码使用SHA-256哈希存储,不明文保存
- 利用Web Crypto API实现,无需额外依赖
- 3次错误锁定60秒,防暴力破解
14.2 数据安全
- 所有数据存储于localStorage,无后端交互
- 关键状态持久化(锁定时间、尝试次数)防刷新绕过
- 积分日志完整记录每次变动,可追溯
十五、性能优化
15.1 已实施优化
| 优化项 | 方案 |
|---|---|
| CDN请求去重 | pending Promise Map,同汉字只发一次请求 |
| 字源预检 | 先查index.json,跳过缺失阶段,减少无效请求 |
| 路由懒加载 | 所有页面组件动态import |
| 星球地图预加载 | planet-map和planet-detail使用webpackPrefetch |
| LRU缓存 | 资源缓存最大50条,避免重复加载 |
| 音频回退控制 | _fallbackUsed flag防止重复TTS |
15.2 布局约束
- 星球地图禁止滚动:
touch-action: none; overflow: hidden - 星球地图弹性布局:
flex: 1; min-height: 0自动填充 - 进度条悬浮:
position: sticky; top: 48px+ IntersectionObserver - 图标横向滚动:
flex-shrink: 0保持64×64正方形 - 图标下拉展开:3列布局,
max-height: 160px内部滚动
十六、关键设计决策
16.1 已实现的重构
| 维度 | 重构前 | 重构后 |
|---|---|---|
| 复习页面 | 3个(review-mode + review-today + review-stats) | 2个(review-today + review-stats) |
| 导航深度 | 4跳(首页→review-mode→review-today→write) | 3跳(首页→review-today→write) |
| 认读评估 | 主观自评(无record) | 客观选择题(有record) |
| 艾宾浩斯 | 只看首次学习日期 | 阶段追踪制(reviewStages) |
| 复习间隔定义 | 3处重复(user.js + review-today.vue + character.json) | 1处(useReviewScheduler.js) |
| 每日复习奖励 | 未实现 | 已实现(80%/100%两档) |
| 复习统计 | 假数据混合 | 仅真实数据 |
16.2 设计原则符合性
- 一致性:所有奖励通过reward-service统一入口
- 简洁性:复习间隔单一定义点,双源CDN统一访问
- 可读性:useReviewScheduler纯函数可独立测试
- 可测试性:score-calculator独立测试,覆盖正常/边界/异常
- 可逆性:数据迁移自动执行(learned[]→reviewStages),不影响存量用户
附:文件清单
源码统计
| 类别 | 数量 | 说明 |
|---|---|---|
| 页面 | 22个 | 不含已删除的review-mode |
| Store | 5个 | user, achievement, character, game, shop(TypeScript) |
| Service | 5个 | api-service, reward-service, resource-service, resource-cache, storage-service |
| Mock API | 39个 | RESTful接口,按模块分类(auth/user/character/game/achievement/shop/planet) |
| Composable | 4个 | useCharFilter, useReviewScheduler, useGameTimer, useDragInteraction |
| 全局组件 | 5个 | AppNavBar, FooterCredit, EtymologyViewer, StrokeAnimationCanvas, WritingPracticeCanvas |
| 书写模块 | 7个文件 | 3个页面 + 4个组件 + score-calculator |
| 星球地图 | 10个文件 | 3个页面 + 4个组件 + 2个shader + 1个shader index |
| 游戏模块 | 9个文件 | 3个游戏 + 1个菜单 + 5个共享组件 |
| 工具函数 | 6个 | char-utils, date-utils, format-utils, array-utils, logger, index(TypeScript) |
| 配置文件 | 3个 | config.ts, constants.ts, planet-visuals.ts |
| 数据文件 | 4个 | character.json, categories.json, planets.json, games.json |
| 测试文件 | 140个 | vitest 测试用例 |