# 绿篮子双十一 · 刮一刮赢好礼

> 活页公开模板 `sample-scratch-card` · 场景: 互动玩法 · 行业: 零售门店 / 餐饮茶饮
> 任何人、任何 Agent 都可以读、照着改，不需要账号。示例内容均为虚构。
> 真页面: https://space.24haowan.com/s/PRFLkd6vsyid · 详情: https://space.24haowan.com/examples/sample-scratch-card

## 这是什么

会员刮刮卡 · 节日大促、会员日发到群里刮一张

## 什么时候用

超市、生鲜店、餐饮门店做双十一、店庆、会员日，想让会员在群里每天刮一张卡：奖品每天限量、要显示今天还剩多少、刮中的到店自提或结账抵扣，没中也送一张兜底券，选它。想要转起来的仪式感、奖品不分每日份额选 sample-lucky-wheel；年会、发布会现场大屏抽人选 sample-annual-draw；只收报名、按场次分名额选 sample-event-signup；不抽奖、只想让人先领一张开业券选 sample-store-opening。

## 用户对助手说的原话

帮我给我们生鲜超市的双十一会员活动做一个刮刮卡，发成一个网页链接到会员群：首屏是一张大刮刮卡，卡框是品牌色，中间一块用 canvas 画的银色涂层（带细颗粒纹理和斜向反光，写着「刮开这里」），手指或鼠标按住来回刮就擦掉涂层、掉一点银屑粒子、有轻轻的沙沙声，卡下面一条「已刮 N%」进度，刮开超过 45% 就整张自动揭开；中奖时卡面盖一个「中奖」章、撒彩带、手机轻震、响一声合成的音效（点了才响，右上角有静音键），没中就写一句安慰并送一张满 39 减 3 的兜底券；然后弹出一张领奖券：奖品、插画、券码、有效期、哪个门店自提，下面填称呼点收下，存进一张数据表（name / prize / code）。卡上面是店名、活动日期、一句大标题和店长一句话；卡下面一个「不想刮，直接揭开」、一行「今日已刮 N 次 · 剩余奖品 N 份」、一条读这张表的最近中奖滚动条、一排五样奖品的小插画和剩余。往下是今日奖池：每天多少张卡、一条已刮 / 剩余有奖 / 剩余送券的分段条、每样奖品的每日数量、剩余和此刻概率（概率 = 剩余 ÷ 今天剩余的卡数），再是活动规则和自提门店（地址带复制按钮）。手机竖屏一屏看完首屏，电脑上中间一块手机比例的舞台、左边活动规则和门店、右边今日奖池；减少动态时直接停在结果，脚本不跑时也能看到奖池、规则和一张登记表单。活动期间有变化就更新同一个链接。

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

## 照着做一份

1. 读入口文件 https://space.24haowan.com/examples/sample-scratch-card/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-scratch-card ，返回预览链接、7 天分享与认领链接（登录后保留、链接不变）。

## 页面结构

- 刮一张
- 今日奖池
- 活动规则
- 自提门店

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

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

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

- canvas 现画的银色刮层（渐变 + 细颗粒 + 斜向反光），手指 / 鼠标 destination-out 擦除，刮的时候掉银屑粒子、配沙沙声；刮开过 45% 自动揭晓
- 中奖彩带 + 轻震 + Web Audio 合成音（点按后才发声，可静音），没中给一句安慰和一张兜底券，随后弹出一张值得截图的领奖券
- 领奖券里填称呼写回数据表（原生表单 POST ./_data/scratches），页面读回「今日已刮 N 次 · 剩余奖品」、扣减奖池、滚动显示最近中奖
- 电脑上舞台两侧放活动规则、今日奖池与自提门店；同一链接活动期间持续更新；微信卡片（share.title / share.desc）

## 发之前要备好

- 数据表 scratches（列 name / prize / code，append_open=true）：领奖券里的收下写进这里，页面读回今天的条数算「今日已刮」、扣减奖池、显示最近中奖；发布前先用 set_data 建好，活动结束把 append_open 关掉
- 门店纸质卡的已刮数写在奖池表的 data-store 里，店里每天中午和傍晚各更新一次页面（同一个链接）

## 模板说明（README）

模板市场「富媒体 H5」样例（总览见 `core/space/examples/README.md`，品质标准见 `core/space/examples/QUALITY.md`）。虚构生鲜超市「绿篮子」桂园路店的双十一会员活动，店长发到会员群。示例数据均为虚构。

## 演示哪个特色

**一张在微信里点开就想用手指刮的刮刮卡，刮出的结果写回数据表，页面读回今日已刮与剩余奖品。**

- **记忆点**是首屏那张大刮刮卡：绿色卡框（两侧打孔）+ 一块 `<canvas>` 银色涂层，涂层是脚本现画的 —— 五段金属渐变、逐像素的细颗粒、斜向反光条、虚线框和「刮开这里」。一枚金币在卡上来回划，提示「这能刮」。
- 刮：`pointerdown / pointermove` 用 `destination-out` 的粗圆头线擦掉涂层（`touch-action:none`，刮的时候页面不跟着滚），每次移动在全屏粒子层掉几粒银屑，配一声带通滤波的噪声「沙沙」（**只在点按后**发声，右上角静音键，记在本机）。每 140ms 抽样一次涂层透明像素，卡下进度条显示「已刮 N%」，**过 45% 自动整张揭开**。
- 揭晓：中奖 = 卡面盖「中奖」章 + 彩带粒子 + `navigator.vibrate` 轻震 + 四音上行；没中 = 一句安慰 + 满 39 减 3 兜底券 + 一声轻的下行再上行。1.4 秒后弹出领奖券：奖品插画、奖级、券码（`LB11-月日-四位`）、有效期、自提门店 —— 一张值得截图的结果画面。卡下还有「不想刮，直接揭开」（键盘与读屏可用）。
- 发出去之后：领奖券里填称呼点「收下」= 原生表单 `POST ./_data/scratches`（列 `name / prize / code`），脚本在时页内提交。页面读 `./_data/scratches.json`：今天的条数计入「今日已刮 N 次」、从各奖品剩余里扣掉，最新的中奖进「最近中奖」滚动条（名字只露第一个字）。
- **奖池、概率、规则三处自洽**：每天 1000 张卡（门店纸质卡与本页共用），256 张有奖（特等 1 · 一等 5 · 二等 20 · 三等 80 · 四等 150），其余 744 张送兜底券。刮中某样的概率 = 它今天的剩余 ÷ 今天剩余的卡数，页面上「今日奖池」里的百分比就是此刻的抽签权重。剩余 = 每日数量 − 门店纸质卡已刮中（写在页面里）− 群里今天已收下（读表）。
- 每人每天 1 张只用 `localStorage` 做提示（刮过后直接亮出结果、按钮变「再看一眼我的券」），读不到就当没刮过；真正的限次在到店自提时按会员手机号。
- `prefers-reduced-motion`：金币不划、滚动条不翻、不掉银屑不放彩带，揭晓直接到终态。
- 脚本不跑时：首屏换成静态页头，奖池表、规则、门店照常显示，页末出现「纸质卡刮中后登记」表单（同一张表 `scratches`）。
- 电脑上：中间一块手机比例的舞台，左边活动规则和自提门店，右边今日奖池（分段条 + 六行奖品），不是大片留白。

## 改哪里变成我的

| 位置 | 改什么 |
|---|---|
| 首屏 `.shop` / `h1` / `.boss` | 店名、活动名与日期、一句店长的话 |
| 卡 `.c-head` | 卡名与卡号；涂层上的字在脚本 `paintCoat()` 里 |
| 奖池表 `.prizes li` | `data-k`（奖品键，与首屏 `.chips li`、表单 `<option>` 三处一致）、`data-tier` 奖级、`data-icon`（插画，`<symbol id="i-…">` 里现成 6 种）、`data-win`（0 = 兜底券）、`data-daily` 每日数量、`data-store` 门店纸质卡今天已刮中；名称与一句说明。`剩 N / 每日`、百分比是不跑脚本时显示的值（脚本会按表重算），一起改 |
| `#prizes` 的 `data-cards` | 每天多少张卡（= 各奖品 `data-daily` 之和） |
| `.stats` / `.sumline` / 分段条 | 今日已刮、剩余有奖、剩余送券（静态值要和奖池表加起来对得上） |
| `.ticker` 里的「门店 · …」 | 门店纸质卡刮中的几条（群里的由读表自动补上） |
| 活动规则 `ol.rules` | 时间、次数、奖池口径、概率、领取、自提与用券、联系人 |
| 自提门店 `.store` | 店名、地址、自提点、营业时间、怎么到、电话 |
| 领奖券 `.t-meta` | 有效期、自提地点；券码前缀在脚本 `code()` 里 |
| 页脚 | 平台标志与名称（与 `core/space/src/theme.ts` 的 `MARK_SVG` / `PUBLIC_NAME` 逐字一致，测试咬着）+ 一句适用场景；发自己的活动时整段删掉 |
| `manifest.json` | `title` / `share.title` / `share.desc`（微信卡片上的字） |

门店纸质卡的已刮数（`data-store`）每天中午和傍晚改一次、更新同一个链接；第二天开始时把它们清零。

## 数据表

收下写进数据表 `scratches`（一次一行，`append_open=true`）。发之前先建表：

```
set_data  proposal_id: <id>  table: "scratches"  columns: ["name","prize","code"]  rows: []  append_open: true  revision: 0
```

店员自提核券时用 `list_data_rows table=scratches` 读回、按券码对；活动结束把 `append_open` 关掉。本地 `space-cli serve` 会把提交写进包里的 `_data/scratches.json`，试完记得改回 `[]`。

## 怎么发出去

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

没有终端时也可以 MCP `publish_file`（`filename: "index.html"`、`content` 为全文、`manifest` 为 manifest.json 去掉 entry、`hold: true`），再按上面建表。
给谁看：默认仅自己可见；发到会员群前用 `set_visibility` 改成 `public`（或 `passcode` 只给会员）。

## 素材

- 没有位图：店标、奖品插画、金币、刮层、彩带全部是内联 SVG 或 canvas 现画；店名、地址、电话、人名均为虚构。
- `thumb.webp` / `phone.webp`：画廊缩略图与手机首屏图，由 `examples/verify-shots.mjs --write-thumb --write-phone` 从成品截出，不进发布包。
