# 21 天燃脂挑战 · 第 9 天

> 活页公开模板 `sample-fitness-challenge` · 场景: 每日一练 · 打卡 · 行业: 医疗健康 / 个人家庭
> 任何人、任何 Agent 都可以读、照着改，不需要账号。示例内容均为虚构。
> 真页面: https://space.24haowan.com/s/mBytCys-6R_x · 详情: https://space.24haowan.com/examples/sample-fitness-challenge

## 这是什么

健身打卡挑战 · 跟练计时与群打卡榜

## 什么时候用

健身教练、瑜伽 / 跑步搭子、减脂营要带一个 21 天（或 7 / 30 天）打卡群：每天发同一个链接，群友点开跟着计时器练完当场打卡，群里看头像墙和连续天数榜，选它。一个人备考、自学、按阶段排计划自己打卡，选 sample-study-plan；每天背几个单词、做一道题，选 sample-words-daily；不带训练、只想让大家在地图上点亮去过的地方，选 sample-checkin-map。

## 用户对助手说的原话

帮我给我带的健身打卡群做今天这一页，发成一个网页链接，以后每天更新同一个链接：首屏是深色的训练舞台，顶上是群名、教练和静音键，一个很大的「第 9 天 / 21」和日期，一句今天的主题和时长；下面 2×2 四个动作，每个是用 SVG 画的小人在循环做这个动作（开合跳、深蹲、后撤弓步、臀桥，正在用力的部位标成橙色），配动作名和一句要点；再下面一个大的「开始今日训练」按钮和「群里今天已有 N 人打卡」的一排小头像。点开始进入全屏训练：准备 5 秒，然后 4 个动作 × 3 轮，每个 40 秒、休息 20 秒，中间一个倒计时圆环（练是橙色、休息是绿色），圆环里是小人和秒数，下面是动作名、要点和「接下来做什么」，顶上 12 段进度条，有暂停和跳过；每秒响一声合成的节拍音、最后 3 秒提示音（点了开始才响，能静音）。练完撒彩带，出一张「今日已完成」卡：用时、组数、千卡、21 天进度条，填群昵称就能打卡，存进一张数据表（name / day / minutes）。往下是 21 天进度（7 列 3 行，练过的日子点亮火焰并写那天打卡人数，今天那格轻轻发光，拉伸日用绿色虚线）、「今日已打卡 N 人」头像墙（头像按名字生成的抽象图形）和连续打卡天数榜，都从这张表读回；然后一条今日饮食建议（配一张分好比例的盘子图）、明日预告，页末再放一张打卡表单。手机竖屏为主；电脑上训练舞台居中，左边进度和饮食，右边打卡墙和榜单。系统要求减少动效时小人不动，不跑脚本时动作表、榜单和打卡表单照样能看能交。

如果你还没有活页连接器（MCP），先读 https://space.24haowan.com/for-agents.md ，照里面的说明接入，或不登录直接发布。

## 照着做一份

1. 读入口文件 https://space.24haowan.com/examples/sample-fitness-challenge/source/index.html（它引用的其他文件见下方列表）。
2. 保留结构、版式和交互，把内容**全部**换成用户自己的；模板里的公司、人名、数字都是虚构的，一样都别留。
3. 交付一个自包含的单文件 HTML：样式写在页面里，不引外部字体 / 脚本 / CDN；手机 375 宽和电脑 1440 宽都要好看，模板有暗色就保留暗色。
4. 要发成微信里能打开、改了链接不变的网页：接入活页（https://space.24haowan.com/for-agents.md）后发布；没有账号也可以让用户在 https://space.24haowan.com/quick 上传这个文件。
5. 没有活页工具、但能发 HTTPS 请求：把做好的 HTML 以 Content-Type: text/html POST 到 https://space.24haowan.com/api/quick?client=template-sample-fitness-challenge ，返回预览链接、7 天分享与认领链接（登录后保留、链接不变）。

## 页面结构

- 今日训练
- 21 天进度
- 今日打卡与连续榜
- 今日饮食
- 明日预告
- 打卡

## 文件（公开，纯文本）

- https://space.24haowan.com/examples/sample-fitness-challenge/source/index.html（入口）

## 发成活页之后还能做的

- 首屏 4 个内联 SVG 小人动作循环演示，点开始进入全屏训练：倒计时圆环、休息提示、Web Audio 合成节拍音（点按后才响，可静音）、轻震，练完撒彩带 +「今日已完成」卡
- 打卡写回数据表（原生表单 POST ./_data/checkins），页面读回「今日已打卡 N 人」头像墙（名字现画的抽象 SVG 头像）、连续打卡榜与 21 格进度
- 同一链接每天更新（第几天、今日动作、饮食、明日预告），打卡记录不随版本变
- 微信卡片（share.title / share.desc），发到打卡群

## 发之前要备好

- 数据表 checkins（列 name / day / minutes，append_open=true）：训练完成卡和页末的打卡表单都写进这里，页面读回头像墙、连续打卡榜和 21 格人数；发布前先用 set_data 建好，挑战结束把 append_open 关掉

## 模板说明（README）

模板市场第三轮补齐的样例：教练带的打卡群，每天早上更新同一个链接，群友点开就跟着练、练完在页里打卡。品质标准见 `core/space/examples/QUALITY.md`，总览见 `core/space/examples/README.md`。示例内容均为虚构。

## 演示哪个特色

**首屏就是今天的训练：跟着计时器练完，当场打卡，群里的头像墙和连续榜一起变。**

- **记忆点**是「今日训练」：4 个动作的小人用内联 SVG 路径变形（SMIL `<animate>`）循环演示，正在用力的那条腿 / 躯干标成火焰橙；脚本不跑也会动，系统要求减少动效时停在起始姿势。
- 点「开始今日训练」进入全屏计时：准备 5 秒，然后 4 个动作 × 3 轮（每个 40 秒、歇 20 秒）。倒计时圆环（练是橙、歇是绿、准备是琥珀）、动作名与要点、「接下来」提示、12 段进度条；Web Audio 合成的节拍音（每秒一拍，最后 3 秒提示音，换段有提示，**点了开始才会响**，右上角可静音，两个静音键同步）、手机轻震、可暂停 / 跳过 / 结束；支持的浏览器会请求屏幕常亮。
- 练完撒彩带 +「今日已完成」卡：用时、组数、千卡、21 天进度条，下面填群昵称点「打卡」—— 这一屏是值得截图发群的那张。
- 发出去之后：打卡写进数据表 `checkins`（列 `name / day / minutes`），页面读回 `./_data/checkins.json`，合并进「今日已打卡 N 人」头像墙（头像由名字的哈希现画的抽象 SVG，不用照片）、连续打卡榜（每人 21 格小条）和 21 格进度（每格是那天打卡人数，点某天看明细）。页末另有一张打卡表单，给在健身房或跟别的视频练的人。
- 电脑上三栏：中间是训练舞台，左边 21 天进度与今日饮食，右边头像墙、连续榜与明日预告；手机上一栏按「训练 → 进度 → 打卡墙 → 饮食 → 明日 → 打卡」排。

## 改哪里变成我的

| 位置 | 改什么 |
|---|---|
| 首屏 `.club` / `.dayline` / `h1` / `.meta` | 群名、教练、第几天 / 共几天、日期、今天主题、时长与热量 |
| `.moves` 四个 `<li data-move>` | 动作名（`<b>`）、要点（最后一个 `<span>`）、小人 SVG。计时器直接读这四格，不用另改脚本；每个小人是两组关键姿势之间的 `<animate attributeName="d">` 变形，换动作就换两组坐标 |
| 脚本里 `WORK / REST / ROUNDS` | 每个动作几秒、歇几秒、几轮（准备时长在 `plan` 第一项） |
| 脚本里 `TODAY` / `CREW` / `THEMES` | 今天是第几天、群里多少人、21 天每天的主题；`DATE` 里的 `2026, 9, 19` 是「第 0 天」（开营前一天） |
| 21 格 `.grid` | 已过的天 `button.d.done`（`data-d`、人数），今天 `button.d.today`，以后的 `span.d.later`（拉伸日加 `easy`）；脚本会按数据重算人数 |
| `SEED` | 页里写死的 36 位示例群友（每人 9 位 0/1 = 第 1–9 天有没有打卡）。**发自己的群时把它清成 `[]`**，墙和榜就只来自表里的打卡；静态的头像墙 / 榜单 HTML 也一起换掉 |
| 今日饮食 `#diet` | 盘子图三块的比例与文字、一句建议、喝水提示 |
| 明日预告 `#tomorrow` | 明天的主题、时长和动作清单 |
| 页末打卡 `#checkin` | 原生 `<form action="./_data/checkins">`：字段名就是表的列名；「哪一天」的选项每天改（今天 + 补昨天） |
| 页脚 | 平台标志与名称（与 `core/space/src/theme.ts` 的 `MARK_SVG` / `PUBLIC_NAME` 逐字一致，测试咬着）+ 一句适用场景；发自己的页时整段删掉 |
| `manifest.json` | `title` / `share.title` / `share.desc`（微信卡片上的字），每天跟着改第几天 |

## 数据表

打卡写进数据表 `checkins`（一次一行，`append_open=true`）。发之前先建表：

```
set_data  proposal_id: <id>  table: "checkins"  columns: ["name","day","minutes"]  rows: []  append_open: true  revision: 0
```

用 `list_data_rows table=checkins` 读回（教练晚上点名就看这个）。挑战结束把 `append_open` 关掉。本地 `space-cli serve` 会把提交写进包里的 `_data/checkins.json`，试完记得改回 `[]`。

## 怎么发出去

```bash
export SPACE_TOKEN=sk-space-…            # MCP create_cli_token
node core/space/cli/space-cli.mjs push core/space/examples/sample-fitness-challenge \
  --proposal <proposal_id> --manifest core/space/examples/sample-fitness-challenge/manifest.json --hold
```

没有终端时也可以 MCP `publish_file`（`filename: "index.html"`、`content` 为全文、`manifest` 为 manifest.json 去掉 entry、`hold: true`），再按上面建表。
每天早上改完第几天、动作、饮食和预告，推到**同一个页面**（同一个 `proposal_id`），链接不变，群里那张卡片一直有效；数据表不随版本变，打卡记录一直在。
给谁看：发到打卡群用 `set_visibility` 设 `passcode`（口令写在群公告里）或 `public`。

## 素材

- 没有位图：小人、火焰、头像、盘子图都是内联 SVG，彩带是 canvas 现画，音效是 Web Audio 合成；群名、教练、群友昵称与打卡数据均为虚构，只作示意。
- `thumb.webp` / `phone.webp`：画廊缩略图与手机首屏图，由 `examples/verify-shots.mjs --write-thumb --write-phone` 从成品截出，不进发布包。
