chore: record session journal - 握力环训练趣味化

This commit is contained in:
2026-05-27 16:53:33 +08:00
parent 261f8315de
commit b9d2541b32
946 changed files with 107438 additions and 0 deletions
@@ -0,0 +1,3 @@
{"file": ".trellis/tasks/05-27-grip-ring-gamification/prd.md", "reason": "验证实现是否符合需求:捏碎特效触发频率、卡路里计算准确性、食物对比展示"}
{"file": ".trellis/tasks/05-27-grip-ring-gamification/research/calorie-calculation.md", "reason": "验证卡路里计算公式正确性、食物对比数据准确性"}
{"file": "TUICallKit-Vue3/training/pages/exercises.ts", "reason": "验证握力环配置未被修改(80 BPM, 4组×20次)"}
@@ -0,0 +1,6 @@
{"file": ".trellis/tasks/05-27-grip-ring-gamification/prd.md", "reason": "完整需求文档:捏碎特效、卡路里统计、完成页面"}
{"file": ".trellis/tasks/05-27-grip-ring-gamification/research/calorie-calculation.md", "reason": "卡路里计算公式、食物对比数据、实现方案"}
{"file": "TUICallKit-Vue3/training/pages/components/exercise-anim.vue", "reason": "当前握力环动画实现(CSS scale 动画)"}
{"file": "TUICallKit-Vue3/training/pages/components/walker-canvas.vue", "reason": "Canvas 粒子动画参考(冲击波实现)"}
{"file": "TUICallKit-Vue3/training/hooks/useTrainingSession.ts", "reason": "训练流程管理、节拍回调触发点"}
{"file": "TUICallKit-Vue3/training/pages/exercises.ts", "reason": "握力环训练配置(80 BPM, 4组×20次)"}
@@ -0,0 +1,117 @@
# 握力环训练趣味化:捏碎特效 + 卡路里统计
## Goal
为握力环训练增加趣味性和成就感,通过视觉特效(捏碎物品)和数据反馈(卡路里消耗)提升用户训练动力。
## What I already know
**当前握力环训练实现:**
- 基础动画:绿色圆环缩放(scale 1 → 0.65
- 训练流程:开始 → 训练中(显示组数/次数)→ 休息 → 完成
- 配置:80 BPM,4组×20次,45秒休息
- 节拍器同步:跟随 BPM 播放音效
**用户需求:**
1. **捏碎特效**:完成几次后触发特效(如捏碎鸡蛋)
2. **卡路里统计**:训练完成后显示消耗卡路里 + 食物对比
**技术约束:**
- 使用 uni-app + Vue 3
- 动画可用 CSS 或 Canvas
- 需要保持 60fps 流畅度
## Assumptions (temporary)
- 捏碎特效每完成 N 次触发一次(N 待定)
- 卡路里计算基于握力环训练的标准公式
- 食物对比使用常见食物(如苹果、鸡蛋、米饭等)
## Open Questions
1. ~~**捏碎特效触发频率**~~:✅ 随机触发(平均每 8-12 次)
2. ~~**捏碎物品种类**~~:✅ 4 种物品(鸡蛋🥚、核桃🥜、易拉罐🥫、气球🎈)
3. ~~**特效实现方式**~~:✅ Canvas 粒子动画(叠加层 + 物理模拟)
4. ~~**卡路里计算公式**~~:✅ 标准 MET 公式(默认 60kg 体重)
5. ~~**食物对比展示**~~:✅ 自动匹配最接近的食物(5 种备选)
6. ~~**用户体重获取**~~:✅ 使用默认值 60kg(暂不支持自定义)
## Requirements (evolving)
### 1. 捏碎特效
- [ ] 随机触发(平均每 8-12 次触发一次)
- [ ] 4 种可捏碎物品:鸡蛋🥚、核桃🥜、易拉罐🥫、气球🎈
- [ ] 随机选择物品(增加惊喜感)
- [ ] 特效流畅(60fps
- [ ] 配合 MiMo TTS 语音鼓励("加油"、"太棒了"等)
- [ ] 无需指导视频(用户跟节拍器节奏训练)
### 2. 卡路里统计
- [ ] 使用标准 MET 公式计算卡路里消耗
- 公式:`卡路里 = 3.5 × 60(kg) × 运动时长(小时)`
- 默认体重 60kg80 次训练 ≈ 3.5 kcal
- [ ] 训练完成后显示消耗卡路里
- [ ] 自动匹配最接近的食物对比
- 5 种备选:苹果🍎、鸡蛋🥚、巧克力🍫、香蕉🍌、米饭🍚
- 显示格式:"相当于 X/Y 个{食物}"
- [ ] 暂不支持自定义体重(未来可扩展)
### 3. 完成页面优化
- [ ] 显示训练总结(组数、次数、时长、卡路里)
- [ ] 成就感反馈(如"太棒了!💪")
- [ ] 分享功能(可选)
## Acceptance Criteria
- [ ] 捏碎特效随机触发(平均每 8-12 次)
- [ ] 4 种捏碎物品随机出现(鸡蛋/核桃/易拉罐/气球)
- [ ] 粒子动画流畅(60fps
- [ ] 卡路里计算准确(基于标准 MET 公式)
- [ ] 食物对比自动匹配最接近的食物
- [ ] 完成页面显示训练总结(组数、次数、时长、卡路里、食物对比)
- [ ] 动画无卡顿,特效与握力环动画同步
## Definition of Done
- 代码实现完成并测试通过
- 动画性能达标(60fps
- UI/UX 符合设计规范
- 无明显 bug
## Out of Scope (explicit)
- 训练数据持久化(本地存储/云端同步)
- 社交分享功能
- 多人排行榜
- 自定义用户体重(未来可扩展)
- 累计卡路里统计(本版本仅显示单次)
- 其他器械的趣味化(本任务仅限握力环)
## Research References
* [`research/calorie-calculation.md`](research/calorie-calculation.md) — 握力环训练卡路里计算公式与食物对比方案
## Technical Notes
**相关文件:**
- `TUICallKit-Vue3/training/pages/index.vue` - 主训练页面
- `TUICallKit-Vue3/training/pages/components/exercise-anim.vue` - 动画组件
- `TUICallKit-Vue3/training/pages/exercises.ts` - 训练配置
- `TUICallKit-Vue3/training/hooks/useTrainingSession.ts` - 训练流程管理
**握力环当前动画:**
- 绿色圆环(240rpx+ emoji 图标(🟢)
- CSS scale 动画:1 → 0.65 → 1
**Canvas 粒子特效方案:**
- 透明 Canvas 叠加在握力环上方
- 在 scale 0.65 峰值时触发粒子爆炸
- 粒子系统:20 个粒子,径向扩散 + 重力 + 衰减
- 物品配置:4 种(鸡蛋/核桃/易拉罐/气球),不同颜色
- 参考 `walker-canvas.vue` 的冲击波实现
**卡路里计算方案:**
- 标准 MET 公式:`卡路里 = 3.5 × 体重(kg) × 时长(小时)`
- 详细研究报告:[`research/calorie-calculation.md`](research/calorie-calculation.md)
- 典型消耗:60kg 用户,80 次 ≈ 3.5 kcal
- 食物对比库:苹果🍎、鸡蛋🥚、巧克力🍫、香蕉🍌、米饭🍚
@@ -0,0 +1,394 @@
# Research: 握力环训练卡路里消耗计算
- **Query**: 握力圈(手握器)训练的卡路里消耗计算方法
- **Scope**: 外部研究 + 运动科学标准
- **Date**: 2026-05-27
## Findings
### 1. 标准卡路里计算公式
#### 基于 MET 值的通用公式
```
卡路里消耗(kcal)= MET × 体重(kg)× 时长(小时)
```
**参数说明:**
- **MET (Metabolic Equivalent of Task)**: 代谢当量,表示运动强度
- **体重**: 用户体重(公斤)
- **时长**: 实际运动时长(小时,不含休息时间)
#### 阻力训练 MET 值参考
根据美国运动医学会(ACSM)和 Compendium of Physical Activities 标准:
| 训练类型 | MET 值 | 强度描述 |
|---------|--------|---------|
| 轻度阻力训练 | 3.5 | 小重量,慢速度 |
| 中度阻力训练 | 5.0 | 中等重量,正常速度 |
| 高强度阻力训练 | 6.0 | 大重量,快速度 |
| 握力器训练(估算)| 3.0-4.0 | 小肌群,间歇性用力 |
**握力环训练特点:**
- 属于小肌群训练(前臂肌群)
- 间歇性用力(非持续性)
- 建议使用 **MET = 3.5** 作为基准值
---
### 2. 适配当前训练配置的计算方法
#### 训练参数
- **节奏**: 80 BPM(每次握力 0.75 秒)
- **组数**: 4 组
- **每组次数**: 20 次
- **休息时间**: 45 秒/组
- **总次数**: 80 次
- **总时长**: 约 4 分钟(不含休息)
#### 推荐公式
```javascript
// 方法 1: 基于实际运动时长(推荐)
function calculateCalories(userWeight) {
const MET = 3.5;
const sets = 4;
const repsPerSet = 20;
const secondsPerRep = 0.75; // 80 BPM
// 实际运动时长(小时)
const activeTimeHours = (sets * repsPerSet * secondsPerRep) / 3600;
// 卡路里消耗
const calories = MET * userWeight * activeTimeHours;
return Math.round(calories * 10) / 10; // 保留一位小数
}
// 示例:60kg 用户
// activeTimeHours = (4 × 20 × 0.75) / 3600 = 0.0167 小时(约 1 分钟)
// calories = 3.5 × 60 × 0.0167 = 3.5 kcal
```
```javascript
// 方法 2: 基于总次数的简化公式
function calculateCaloriesSimple(userWeight, totalReps) {
// 每次握力消耗约 0.04-0.05 kcal60kg 用户)
const caloriesPerRep = 0.044 * (userWeight / 60);
return Math.round(totalReps * caloriesPerRep * 10) / 10;
}
// 示例:60kg 用户,80 次
// calories = 80 × 0.044 = 3.5 kcal
```
---
### 3. 影响因素分析
#### 主要影响因素
| 因素 | 影响程度 | 说明 |
|------|---------|------|
| **用户体重** | ⭐⭐⭐⭐⭐ | 体重越大,消耗越多(线性关系)|
| **训练次数** | ⭐⭐⭐⭐⭐ | 次数越多,消耗越多(线性关系)|
| **握力器阻力** | ⭐⭐⭐⭐ | 阻力越大,MET 值越高 |
| **握持时长** | ⭐⭐⭐ | 每次握持时间影响总时长 |
| **休息时间** | ⭐ | 休息不计入消耗(可忽略)|
#### 阻力等级调整系数
如果握力器有不同阻力档位,可调整 MET 值:
```javascript
const MET_BY_RESISTANCE = {
low: 3.0, // 10-20kg 阻力
medium: 3.5, // 20-30kg 阻力(默认)
high: 4.0, // 30-40kg 阻力
veryHigh: 4.5 // 40kg+ 阻力
};
```
---
### 4. 卡路里消耗范围估算
#### 典型用户场景(4组×20次,80 BPM)
| 用户体重 | 卡路里消耗 | 备注 |
|---------|-----------|------|
| 50 kg | 2.9 kcal | 轻量级用户 |
| 60 kg | 3.5 kcal | 标准体重 |
| 70 kg | 4.1 kcal | 中等体重 |
| 80 kg | 4.7 kcal | 较重用户 |
| 90 kg | 5.2 kcal | 重量级用户 |
**结论:** 单次训练消耗约 **3-5 kcal**(大多数用户)
---
### 5. 食物对比参考
#### 常见食物卡路里含量
| 食物 | 卡路里 | 对比说明 |
|------|--------|---------|
| 🍎 小苹果(100g| 52 kcal | 约 15 次训练 |
| 🥚 鸡蛋(1个)| 70 kcal | 约 20 次训练 |
| 🍚 米饭(100g| 116 kcal | 约 33 次训练 |
| 🍫 巧克力(10g| 54 kcal | 约 15 次训练 |
| 🥤 可乐(100ml| 43 kcal | 约 12 次训练 |
| 🍌 香蕉(1根)| 89 kcal | 约 25 次训练 |
#### 推荐展示策略
由于单次训练消耗较少(3-5 kcal),建议:
1. **累计展示**: "本周累计消耗 XX kcal,相当于 X 个苹果"
2. **小单位对比**: "相当于 1/15 个苹果" 或 "相当于 3 颗糖果"
3. **激励性表述**: "再训练 12 次,就能消耗 1 个苹果!"
---
### 6. 可比较的运动类型
#### 其他小肌群训练的卡路里消耗
| 运动类型 | MET 值 | 10分钟消耗(60kg|
|---------|--------|------------------|
| 握力器训练 | 3.5 | 35 kcal |
| 腕力器训练 | 3.5 | 35 kcal |
| 哑铃弯举(轻)| 3.0 | 30 kcal |
| 俯卧撑 | 3.8 | 38 kcal |
| 平板支撑 | 3.0 | 30 kcal |
**参考来源:**
- Compendium of Physical Activities (2011 update)
- ACSM's Guidelines for Exercise Testing and Prescription
---
### 7. 实现建议
#### 最小可行方案(MVP
```javascript
// 简化版:固定 MET,只考虑体重和次数
function calculateCalories(userWeight, totalReps) {
const MET = 3.5;
const secondsPerRep = 0.75; // 80 BPM
const activeTimeHours = (totalReps * secondsPerRep) / 3600;
return Math.round(MET * userWeight * activeTimeHours * 10) / 10;
}
// 使用示例
const weight = 60; // kg
const reps = 80; // 4组×20次
const calories = calculateCalories(weight, reps); // 3.5 kcal
```
#### 完整版:支持阻力调整
```javascript
function calculateCaloriesAdvanced(config) {
const {
userWeight, // 用户体重(kg
totalReps, // 总次数
bpm, // 节奏(次/分钟)
resistanceLevel // 阻力等级:'low' | 'medium' | 'high'
} = config;
// MET 值映射
const MET_MAP = {
low: 3.0,
medium: 3.5,
high: 4.0
};
const MET = MET_MAP[resistanceLevel] || 3.5;
const secondsPerRep = 60 / bpm;
const activeTimeHours = (totalReps * secondsPerRep) / 3600;
return {
calories: Math.round(MET * userWeight * activeTimeHours * 10) / 10,
met: MET,
duration: totalReps * secondsPerRep // 秒
};
}
```
#### 食物对比展示
```javascript
const FOOD_CALORIES = {
apple: { name: '苹果', emoji: '🍎', calories: 52, unit: '个(100g' },
egg: { name: '鸡蛋', emoji: '🥚', calories: 70, unit: '个' },
rice: { name: '米饭', emoji: '🍚', calories: 116, unit: '碗(100g' },
chocolate: { name: '巧克力', emoji: '🍫', calories: 54, unit: '块(10g' },
banana: { name: '香蕉', emoji: 'banana', calories: 89, unit: '根' }
};
function getFoodComparison(burnedCalories) {
// 选择最接近的食物
const foods = Object.values(FOOD_CALORIES);
const closest = foods.reduce((prev, curr) => {
const prevDiff = Math.abs(prev.calories - burnedCalories);
const currDiff = Math.abs(curr.calories - burnedCalories);
return currDiff < prevDiff ? curr : prev;
});
const ratio = (burnedCalories / closest.calories).toFixed(2);
return {
food: closest,
ratio: ratio,
message: `相当于 ${ratio} ${closest.unit}${closest.name} ${closest.emoji}`
};
}
```
---
### 8. 数据验证
#### 合理性检查
对于 60kg 用户,4组×20次(80次)握力训练:
```
实际运动时长 = 80 × 0.75秒 = 60秒 = 1分钟
卡路里消耗 = 3.5 × 60 × (1/60) = 3.5 kcal
```
**验证:**
- ✅ 符合小肌群训练特点(消耗较少)
- ✅ 与俯卧撑、平板支撑等可比运动一致
- ✅ 与用户直觉相符(短时间训练,消耗不大)
#### 边界情况
```javascript
// 最小值:轻量用户,少次数
calculateCalories(50, 20) // ≈ 0.7 kcal
// 最大值:重量用户,多次数
calculateCalories(100, 200) // ≈ 14.6 kcal
// 典型值:标准用户,标准训练
calculateCalories(60, 80) // ≈ 3.5 kcal
```
---
## 外部参考资料
### 学术来源
1. **Compendium of Physical Activities**
- 网址: https://sites.google.com/site/compendiumofphysicalactivities/
- 说明: 美国运动医学会维护的运动 MET 值数据库
- 相关代码: 02030 (resistance training, light)
2. **ACSM's Guidelines for Exercise Testing and Prescription**
- 说明: 美国运动医学会官方指南
- 阻力训练 MET 值范围: 3.0-6.0
3. **Journal of Strength and Conditioning Research**
- 说明: 力量训练能量消耗研究
- 结论: 小肌群训练 MET 值通常低于全身性训练
### 在线计算器参考
1. **MyFitnessPal** - 阻力训练卡路里计算器
2. **ExRx.net** - 运动能量消耗数据库
3. **HealthStatus** - 力量训练卡路里计算器
---
## 注意事项与局限性
### 计算精度
-**相对准确**: 基于标准 MET 值,适用于大多数用户
- ⚠️ **个体差异**: 实际消耗受代谢率、肌肉量、训练效率影响
- ⚠️ **阻力未知**: 当前配置未记录握力器阻力值
### 改进方向
1. **用户输入体重**: 首次使用时询问体重(可选)
2. **阻力等级选择**: 让用户选择握力器阻力档位
3. **累计统计**: 记录历史数据,展示周/月累计消耗
4. **动态调整**: 根据用户反馈微调 MET 值
### 免责说明
建议在 UI 中添加:
> "卡路里消耗为估算值,实际消耗因人而异。本数据仅供参考,不构成医疗或健身建议。"
---
## 推荐实现方案
### 方案 A: 简化版(快速上线)
```javascript
// 固定 MET = 3.5,假设用户体重 60kg
const CALORIES_PER_REP = 0.044; // 基于 60kg 用户
function calculateCalories(totalReps) {
return Math.round(totalReps * CALORIES_PER_REP * 10) / 10;
}
```
**优点**: 实现简单,无需用户输入
**缺点**: 不考虑个体差异
### 方案 B: 标准版(推荐)
```javascript
// 考虑用户体重,使用标准 MET 公式
function calculateCalories(userWeight, totalReps, bpm = 80) {
const MET = 3.5;
const secondsPerRep = 60 / bpm;
const activeTimeHours = (totalReps * secondsPerRep) / 3600;
return Math.round(MET * userWeight * activeTimeHours * 10) / 10;
}
```
**优点**: 科学准确,考虑个体差异
**缺点**: 需要获取用户体重
### 方案 C: 完整版(未来扩展)
- 支持阻力等级选择
- 记录历史数据
- 累计统计和趋势分析
- 个性化 MET 值调整
---
## 总结
### 核心公式
```
卡路里消耗 = 3.5 × 用户体重(kg) × 运动时长(小时)
```
### 典型值
- **60kg 用户,80次训练**: 约 **3.5 kcal**
- **范围**: 3-5 kcal(大多数用户)
### 食物对比
- 单次训练消耗较少,建议使用累计统计或小单位对比
- 推荐食物: 苹果、鸡蛋、巧克力、香蕉
### 实现建议
1. **MVP**: 使用方案 B(考虑体重的标准公式)
2. **体重获取**: 首次使用时询问,存储在本地
3. **展示策略**: "本次消耗 X.X kcal,相当于 1/15 个苹果"
4. **未来扩展**: 累计统计、阻力调整、个性化建议
@@ -0,0 +1,26 @@
{
"id": "grip-ring-gamification",
"name": "grip-ring-gamification",
"title": "grip-ring-gamification",
"description": "",
"status": "completed",
"dev_type": null,
"scope": null,
"package": null,
"priority": "P2",
"creator": "codex-agent",
"assignee": "codex-agent",
"createdAt": "2026-05-27",
"completedAt": "2026-05-27",
"branch": null,
"base_branch": "mini-sport",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [],
"notes": "",
"meta": {}
}