feat(onboarding): no hint toast after the first-chart star convergence
Independent Staging Quality Gate / validate (push) Failing after 10m40s
Independent Staging Quality Gate / publish (push) Skipped

Product 2026-09-29: drop 「这片天空在星盘页可以保存。」. The chart page entry is now replay + share.
Verified: tsc 0, lint 0 errors, npm test 4335/4280/24 (same 24 Docker/DB/deploy names),
quick gate (gate params) passed, / Static, first-screen JS gzip 651,512 -> 651,143.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
This commit is contained in:
Jesse_Chen
2026-09-29 09:24:00 +08:00
co-authored by Claude Opus 5.5
parent f51c830b52
commit 9686dfb945
6 changed files with 24 additions and 29 deletions
+5
View File
@@ -1,5 +1,10 @@
# 印度占星 Skill 更新日志
## 2026-09-29 · 首次建盘过场后不再弹提示
- 群星汇聚过场结束后,首页不再轻提示「这片天空在星盘页可以保存。」(产品决定去掉;星盘页入口已是重放 + 分享)。
- Skill 版本不变。
## 2026-09-29 — 手机上星盘能完整看到、改了出生资料排盘跟着变、「那一刻的天空」改为动画定格、报告去掉星图封面(待验收)
- 手机上星盘页的北印度盘不再被撑出屏幕:盘完整显示在屏幕内,下面的表格在自己的框里左右滑(BUG-1083)。电脑上右侧被裁掉的参数卡和「≡」盘型按钮也一并回来了。
+1 -1
View File
@@ -56,7 +56,7 @@
| 26 | 桌面 Chrome(新账号) | 过场进行中按 Esc | 立刻结束,直接是下一步 | |
| 27 | iPhone(设置 → 辅助功能 → 动态效果 → 减弱动态效果) | 新账号重复 24 | 星星不移动:整张图淡入、停留、淡出 | |
| 28 | 任一 | 网络很慢或断网时保存出生地(手机可开飞行模式后再关、或 DevTools 限速 Slow 3G) | 过场不出现,引导不卡住,没有转圈 | |
| 29 | 任一 | 24 看完之后 | 首页下方轻提示一次「这片天空在星盘页可以保存。」,只出现一次;刷新首页不再出现,也不再放过场 | |
| 29 | 任一 | 24 看完之后 | ~~首页轻提示一次~~(2026-09-29 已去掉):过场结束后**没有任何提示**;刷新首页也不再放过场 | |
| 30 | 任一 | 老账号平时打开首页 | 加载动画和以前一样,没有群星过场 | |
## 第三轮(`TASK-birth-sky-polish-20260928`,2026-09-28)
+1 -1
View File
@@ -1185,6 +1185,6 @@ D40 / D45 / D60 的表格上方,出生时间不是「已校正」时多一句
- **全屏、无按钮:** 原生 `<dialog>`,`createPortal` 挂到 `document.body`(在 `SidebarInset` 之外,不受弹窗打开时的 `inert` 影响,与账户弹窗、兑换弹窗同一做法,BUG-968 / BUG-1080)铺满视口,底色是 `night` 的页底色;画布按视口取最大的 3:4 区域、乘 `devicePixelRatio` 绘制,`requestAnimationFrame` 驱动,卸载时取消。点击、触摸(`pointerdown`)或 Esc 立刻结束,直接进入下一步。
- **减少动态效果:** `prefers-reduced-motion: reduce` 时不汇聚:成品画面整体淡入(600ms)、停留、同一时刻淡出(1 秒),总长同样约 6.5 秒。
- **与兑换弹窗不再同时出现:** 0 点数账户的「解锁完整咨询」兑换弹窗不再在首页出现时自动弹出,改为本页第一次因点数不足发不出消息时弹(见 §账户弹窗「Placement」条),所以建盘后首页只有过场。
- **结束后的提示:** 过场正常结束或被点掉后,首页用已有的 sonner Toaster 轻提示一次「这片天空在星盘页可以保存。」(VOICE.md)。取数失败、超时时没有过场,也没有提示。
- **结束后没有提示:** 过场正常结束或被点掉后直接露出下一步,不弹任何提示(2026-09-29 产品去掉原来的「这片天空在星盘页可以保存。」)。
- **平时的首页加载动画不改。** 这是用户操作之后的一次性结果展示,不是首页加载等待,不违反 §9「首页只揭幕一次」;轨道环揭幕逻辑不动。
- 代码:时序与插值是 `lib/birth-sky/converge.ts` 的纯函数;过场组件 `components/birth-sky/birth-sky-converge.tsx`(懒加载 chunk,含 `draw.ts` 与样式);状态在 `hooks/use-birth-sky-reveal.ts`,`page.tsx` 接线未变(`Home()` 的 `useState` / `useRef` 数不变)。星盘页的「那一刻的天空」弹窗删掉了只给揭幕用的 `is-reveal` 样式与「继续」按钮。
+1 -1
View File
@@ -162,7 +162,7 @@ Jyotisha 的可见文案是产品的一部分。正确性红线(真实性、
重放层文案(2026-09-29 M4,替换静态海报弹层):星盘页按钮字「那一刻的天空」(也是重放层的无障碍名称,层里不显示标题);层里只有定格的画面、左上一个只有图标的关闭(读屏名「关闭」)和右上「分享」。分享失败(极少见,分享与下载都不可用时)写「没能分享,再试一次。」画面的替代文字是主句加事实句。原「保存图片」与「没能保存。长按或右键上面的图,也能存下来。」已不再使用:画面是画布,不能长按存图。
首次建盘的群星汇聚过场(2026-09-28 追加,TASK-birth-sky-followup-20260928)里**没有按钮、没有额外文字**,字就是封面上的主句与事实句;原来弹层上的「继续」已删除。过场结束后首页轻提示一次:「这片天空在星盘页可以保存。」——一句陈述,句号结尾,不加感叹、不加 emoji,不催用户去做。(报告封面 2026-09-29 已去掉。)
首次建盘的群星汇聚过场(2026-09-28 追加,TASK-birth-sky-followup-20260928)里**没有按钮、没有额外文字**,字就是封面上的主句与事实句;原来弹层上的「继续」已删除。过场结束后不再有任何提示(2026-09-29 去掉原提示句)。(报告封面 2026-09-29 已去掉。)
## 七条原则
+4 -16
View File
@@ -1,25 +1,21 @@
"use client";
import { useCallback, useEffect, useRef, useState } from "react";
import { toast } from "sonner";
import { loadBirthSkyRevealSky, startBirthSkyReveal, type BirthSkyRevealSky } from "@/lib/birth-sky/reveal";
/** Shown once on the home page after the convergence ends (VOICE.md). */
export const BIRTH_SKY_REVEAL_HINT = "这片天空在星盘页可以保存。";
/**
* The one-time 「那一刻的天空」 convergence after the reader's own first chart
* (TASK-birth-sky-cover-20260928 T6 → TASK-birth-sky-followup-20260928 F4).
* Owns its state so Home only wires it: `begin` goes to the onboarding hook,
* `cover` / `close` to the overlay. `cover` is the sky plus the serif verdict,
* ready before the first frame. Saving one's own birth place happens once per
* account, so no "seen" flag.
* account, so no "seen" flag. Nothing follows the overlay: the hint toast was
* removed by the product on 2026-09-29.
*/
export function useBirthSkyReveal() {
const [cover, setCover] = useState<BirthSkyRevealSky | null>(null);
const cancel = useRef<(() => void) | null>(null);
const playing = useRef(false);
const begin = useCallback(() => {
cancel.current?.();
@@ -32,19 +28,11 @@ export function useBirthSkyReveal() {
]);
return sky;
},
onReady: (next) => {
playing.current = true;
setCover(next);
},
onReady: (next) => setCover(next),
});
}, []);
const close = useCallback(() => {
if (!playing.current) return;
playing.current = false;
setCover(null);
toast(BIRTH_SKY_REVEAL_HINT);
}, []);
const close = useCallback(() => setCover(null), []);
useEffect(() => () => { cancel.current?.(); }, []);
@@ -105,8 +105,10 @@ test("failure: no overlay, no retry, no error surfaced", async () => {
assert.equal(calls, 2);
assert.deepEqual(shown, []);
assert.doesNotMatch(revealHook, /setError|console\.(error|warn)/);
// The only toast is the hint in `close`, which runs after the overlay has played.
assert.equal(revealHook.match(/toast\(/g)?.length, 1);
// 原值:hook 里恰好 1 处 `toast(`(过场结束后的提示)
// 新值:0 处
// 原因:产品 2026-09-29 去掉过场后的提示句
assert.equal(revealHook.match(/toast\(/g)?.length ?? 0, 0);
});
test("only the reader's own onboarding place save triggers it, after the flow has moved on", () => {
@@ -250,14 +252,14 @@ test("overlay: full screen, no buttons; tap, click or Esc ends it at once; rAF s
assert.match(revealHook, /import\("@\/components\/birth-sky\/birth-sky-converge"\)/);
});
test("the hint is the VOICE line, shown once after the overlay ends", () => {
assert.match(revealHook, /export const BIRTH_SKY_REVEAL_HINT = "这片天空在星盘页可以保存。";/);
assert.match(voice, /这片天空在星盘页可以保存。/);
const close = revealHook.slice(revealHook.indexOf("const close"));
const body = close.slice(0, close.indexOf("}, []);"));
assert.match(body, /if \(!playing\.current\) return;\s*playing\.current = false;/);
assert.match(body, /toast\(BIRTH_SKY_REVEAL_HINT\)/);
assert.match(revealHook, /from "sonner"/, "reuses the app's Toaster, no new component");
// 原值(测试名与断言):the hint is the VOICE line, shown once after the overlay ends——常量「这片天空在星盘页可以保存。」、VOICE 收录、close 里 toast 一次
// 新值:nothing follows the overlay——无常量、无 sonner 引用、close 只清状态、VOICE 不再收录这句
// 原因:产品 2026-09-29「把这个提示去掉」(星盘页入口已改为重放 + 分享,原句也不再准确)
test("nothing follows the overlay: no hint toast after it ends", () => {
assert.doesNotMatch(revealHook, /BIRTH_SKY_REVEAL_HINT|这片天空在星盘页可以保存/);
assert.doesNotMatch(revealHook, /from "sonner"/);
assert.doesNotMatch(voice, /这片天空在星盘页可以保存。/);
assert.match(revealHook, /const close = useCallback\(\(\) => setCover\(null\), \[\]\);/);
});
// 原值(测试名与断言):the chart page dialog no longer has a reveal variant——读 `birth-sky-dialog.tsx` / `birth-sky.css`,不得有「继续」/ is-reveal