${escapeHTML(m.text||'正在回应…')}
${m.status==='cancelled'?'已取消 · 这是未完成片段':''}此 刻
书翻到一半,
窗外的雨声不大。
安静,有点倦 · 你们最近挺熟络
+ + + +我在。你想说什么?
+diff --git a/prototypes/hel-790/README.md b/prototypes/hel-790/README.md new file mode 100644 index 0000000..0af09e0 --- /dev/null +++ b/prototypes/hel-790/README.md @@ -0,0 +1,49 @@ +# 月光里的相处 · HEL-790 独立动态小样 + +下载 `index.html`,用浏览器直接打开;图片、文字、样式和交互都在这一个文件里,不需要安装或联网。`evidence/` 是这份真实界面的截图、录屏与检查记录。此目录没有被产品入口导入。 + +这次请只判断对话的呈现和整体空间的感觉。两套主题都保留。所有人物画面是此前获批静帧,文字、生活、回忆和天气都是虚构示例;没有连接模型、麦克风、摄像头、生活或备份服务。 + +## 怎样试 + +1. 相处页保留右侧独立人物窗、左侧少量近况和底部透光导航。点击「和她说话」,看人物窗怎样在同一片空间里展开,再点「回到此刻」。 +2. 点击右上角「独立小样 · 演示数据」,选择「一段长回复」。当前只呈现一句;用左右箭头逐句读完,也可以选「自动续读」。点击「展开全文」或输入区左边的记录按钮,查看完整内容,关闭后回到刚才那一句。 +3. 同一试用浮层还可以体验短句、连续来两段话、生成中与取消。新来句会排在后面,不抢走正在读的内容。取消后已出现的片段明确标为未完成。 +4. 切换月光/雾光,再进入「日子」「我们的回忆」「设置」。从一条已分享生活进入对应聊天,可以返回这一天。新建临时演示身份后,这些区域为空。 +5. 手机可直接打开同一 HTML。收起或弹出键盘时,布局按可视高度重新给人物与正文分配空间。本次只验证了缩小视口,未在真实手机软键盘、iOS 或 Safari 上验证。 + +## 本次交互提案,仍待用户验收 + +- 默认手动续读;自动续读为可选,每句至少停留 3.8 秒,并随文字长度延长。输入、选择文字、打开记录或切到后台都会停止自动续读。 +- 句子按标点、可读长度分段,长句不会丢字;空间很小时段落会更短。上一句/下一句同时覆盖本轮用户与她的文字。身份每句注明。 +- 本原型按完整句子逐步模拟生成,不等同于已连接真实 SSE。真实词元流如何缓存成可读分句,需要在正式接入时验证。 +- 人物展开、浮层和背景的空间推进均可逆;文本以 100ms 退场、160ms 进入过渡,流式追加的同一句不重播整段动画。移动采用已有缓动与 280ms 预算。 +- 月光是打开小样的临时初始值,不代表用户已经选择产品默认主题。 + +## Before / After / Why + +对照对象是 PR#4 开始时实际 head `db571ba204c8372989f96e1ed9b5cd00d3a306c7` 的代码、8310 静态壳,以及 HEL-744/746 获批原型。访问 8310 时拦截全部 API,未请求真实档案与聊天;因此没有声称亲测真实聊天内容或模型表现。 + +| Before | After | Why | +| --- | --- | --- | +| 当前主区 `dialog-scroll` 同时容纳完整长消息 | 主区当前一句,前后查看;全文与历史独立按需展开 | 长回复完整保留,同时兑现 VIS-013 的人物为主 | +| 曾以局部文字效果和滚动修补作为主要验收依据 | 一个持续存在的人物窗,展开/收回、进入日子与设置都与背景共同改变层次 | 对照 VIS-001/006/007,验证整个相处空间 | +| 矮屏的固定人物高度会逼近正文 | 按真实正文位置计算人物窗剩余高度;缩小视口后重新分配空间 | 正文、身份、输入和导航互不覆盖 | +| 逐次替换文字可能产生生硬跳变 | 旧句先退、新句再进;同一句追加不重播;迟到内容受取消标记约束 | UX-002,阅读连续且取消可信 | +| 全局新旧状态容易争抢阅读位置 | 新来句排队,全文/历史开合保持当前位置 | 用户掌握阅读速度 | +| 组件逐块换色,容易脱离整体氛围 | 同一布局下同时切换天空、光雾、景物、阅读材质与微光 | 保留已认可的两主题,避免改变视觉方向 | + +## 复现与范围 + +```bash +python3 prototypes/hel-790/build.py +node --check prototypes/hel-790/src/space.js +python3 prototypes/hel-790/verify.py +python3 prototypes/hel-790/record.py +``` + +构建只用 Python 标准库,复用 `web/public/assets/her-room.jpg` 和 `her-talk.jpg`。验证与录屏使用环境已有的 Python Playwright / Chromium;必要的已有共享库路径由脚本检测,仅作用于本次进程。没有新增产品依赖。 + +结构化需求交接见 `handoff.json`,逐项映射与实际证据见 `REVIEW.md`。开始时从需求治理 PR#5 读取基准;交付前它已独立合入 main。本卡随后快进到 main `4242f8377e350e5f17e836d275c15b0f099bf109`,逐字节复核必读文件一致,并在本分支直接执行需求检查。相对 main 的改动只在本目录,不夹带产品 PR#4。 + +本小样未更换正式界面,未部署、未合并,也未改用户档案、出生底色、聊天与记忆。R1 的人格诠释/成长缺口、R2–R7 的真实功能接入和独立口型研究仍须后续完成。整项目 HEL-697 持续保留。 diff --git a/prototypes/hel-790/REVIEW.md b/prototypes/hel-790/REVIEW.md new file mode 100644 index 0000000..69e6845 --- /dev/null +++ b/prototypes/hel-790/REVIEW.md @@ -0,0 +1,64 @@ +# HEL-790 交接与体验自查 + +## 需求与来源 + +- 完整基准 v1.7;读取提交 `97aaefe5fac77e9746a4ce52d3af94adad15efc1`(需求治理 PR#5)。当时 `origin/main` 为 `498429399812a0776dadd4b56662d31b455a9ea5`,尚无需求入口。 +- 已读该提交的 AGENTS.md、需求 README/current/coverage、交接模板、原始产品与视觉访谈 `sources/comment-evidence.json`、获批视觉确认、完整设计规范、设计裁定和 R1–R7 接入方案。 +- 交付前 PR#5 已独立合入 main;快进到 `4242f8377e350e5f17e836d275c15b0f099bf109`,核对必读文件与已读版本逐字节一致。最终交接以此 main 提交为准,相对 main 只新增本原型目录。 +- 用户批准来源:HEL-697 评论 `01a1635b-b47c-79ed-ac66-9408c7905af9`;原两主题与首页比例批准 `01a15f1f-5a71-783c-a458-b326a0073d69`;完整页面与分享/关系/起名裁定 `01a15f42-2781-700e-b75a-3ae4b023f46c`。这些决定不重新提问。 +- 取回 HEL-744 两张获批实际样图、HEL-746 完整原型 R2 并实际查看;两个人物素材与仓库文件逐字节相同。没有新增生成图片。 +- 开始前经现有合法 SSH 身份认证 Gitea,重查产品 PR#4 实际 head:`db571ba204c8372989f96e1ed9b5cd00d3a306c7`,base main,open、未合并。仅 fetch/读取,不在其分支修改。 +- 实际打开 8310 页面时拦截全部 `/api/**`,只有 health 尝试被拦截,没有读取用户档案或聊天。当前长消息行为对照来自上述 head 的 `ChatPanel.tsx` 与样式,未冒充真实聊天实测。 + +`handoff.json` 逐条列出本卡关联编号、完整原意和来源评论,及本次可观察证据。 + +## 本次交付 + +`index.html` 是可离线打开的真实 DOM 原型,构建只复用获批静帧。相处 → 交流 → 全文/历史 → 收回交流 → 日子/回忆/设置 → 相处都可以实际操作。 + +首页的 30px 轻标题、右侧 27vw 拱窗、14vw 右边距和小巧底部导航沿用获批几何。交流的人物尺寸按可视高度和实际正文占用分配,不让长名字或缩高视口把文字挤到照片里。生活与设置用透光阅读浮层;人物窗和远近环境在同一空间里后退。 + +两套主题使用相同 DOM、入口与位置;月光有月面、月路和冷雾,雾光有蓝紫流光和更柔软的雾层,景物、材质与关键微光一起变化。没有新增粒子堆叠或整屏卧室背景。 + +## 动效自查(Before / After / Why) + +| Before | After | Why | +| --- | --- | --- | +| 第一轮试制的固定人物高度在小屏接近正文 | 按正文的实际边界分配人物窗高度 | 优先保证身份、正文、输入和导航不互挡 | +| 第一轮试制的图片默认居中,人物取景偏了 | 恢复获批 `88% 42%` 取景与 1.16 静态裁切 | 人物在相处状态也必须看得见 | +| 试制浮层的退出动画可能留下透明填充状态 | 关闭时取消该节点的全部动画,再恢复空间与焦点 | 反复展开记录仍可见、可操作 | +| 突然替换当前文字 | 100ms 退场、160ms 进入;相同句子追加不重播 | 过渡服务于语义变化,不让生成重复闪动 | +| 对几何属性直接做过渡会逐帧触发布局 | 几何一次落位,再用 FLIP 的 transform 运动 | 背景、人物和浮层的动效只播放 transform/opacity | +| 键盘操作也可能播放切换动效 | 键盘操作不启动位置动画;系统减少动效停止循环 | 遵守频率和可访问性约束 | + +入口与退出用已有 `cubic-bezier(.22,1,.36,1)`;空间移动与浮层进入 280ms、退出 180ms。背景的 32–64 秒循环只承担舒缓流动,在减少动效或页面隐藏时停止。正常关闭中可以重新打开,人物窗中途反向从当前可见位置衔接。没有 `transition: all`、零尺寸弹入、ease-in 进入或逐帧宽高动画。 + +工程自查结论:完成本卡的独立设计原型;视觉和阅读节奏仍待白栖知体验裁定,不能以自查代替认可。性能没有做帧率或低端设备实测,不声称稳定 60fps。 + +## 验证证据 + +- `evidence/verification.json`:浏览器验证的逐项结果,包含真实 DOM 逐句读取与完整原文比对、全文末句、连续来句不抢阅读位置、取消迟到消息、长名字、长输入、焦点与反复开合、两主题及可视区域边界。 +- 电脑四张:`desktop-home-moon/fog.png`、`desktop-talk-moon/fog.png`,1440×900。 +- 手机四张:`mobile-home-moon/fog.png`、`mobile-talk-moon/fog.png`,390×844。 +- 补充:长回复末尾、全文末尾、生活详情、共同回忆、设置,以及 `simulated-viewport-*.png`。 +- 动态:`desktop-walkthrough.webm` 与 `mobile-walkthrough.webm`,实际点击原型录制,展示对话、长回复、全文、记录、往返、主题、日子/回忆和设置。 +- Chromium / Linux;验证尺寸包括 1440×900、1280×720、844×390、390×844、390×600、390×420、360×400、320×568、320×360;两主题均做正文/输入/导航边界检查。缩小视口是等效模拟,不是真机键盘测试。 +- JavaScript 语法检查;标准库构建。运行环境已有浏览器共享库只设置到本次进程,没有更改全局库、认证或服务。 +- 离线原型用 CSP 禁止网络连接,浏览器检查 HTTP/WebSocket 请求为零,不调用媒体权限,不使用真实或浏览器既有产品存储。 +- 需求检查在已快进到最新 main 的本工作树运行,实际目标 `origin/main`;执行记录在 `evidence/requirements-check.txt`。没有把治理 PR 或产品 PR#4 搬进本小样分支。 + +## 本次不能作为完成结论的事项 + +1. 分句长度、默认手动翻看、自动续读的停留时长、过渡强度,是这次提出供用户验收的交互方案,不是此前已确认的产品规则。 +2. 文字生成只是完整句子的模拟,没有接入真实词元流;正式接入须继续验证流缓存、取消、重连、错误及阅读位置。 +3. 照片只证明同一人物/房间/衣服的展示关系,不证明真人活动、视频衔接、口型或语音同步已经实现。 +4. 四类入口和关系保留。出生排盘/底色、外观导入、备份恢复和外接服务在本卡主要保留入口与未接入说明;没有重做旧 R2 的所有五十多个状态,更不声称完整功能已补齐。后续正式界面继续继承 R2 完整范围及新小样认可结果。 +5. 演示生活只有两条已分享记录,没有携带任何未分享记录,也不模拟服务器权限已完成。R2/R3 仍须在响应前裁剪生活、记忆和关联引用。 +6. 临时演示身份只供测试长名字与关系选择;正式创建的出生、底色、关系确认、异常恢复等完整流程仍由原方案约束。本卡未改变、重建真实伴侣。 +7. 真机软键盘、Safari/iOS、屏幕阅读器的实际朗读、触摸手势与低端设备性能仍待验证。 + +## 未完成承接与下一道关卡 + +先由白栖知只验收这次的对话与空间小样。认可后才能安排正式界面实现、独立审核及测试环境发布;本卡没有部署或合并授权。 + +主卡 HEL-697 保留完整项目追踪。R1 的出生底色深度、模型诠释、初始喜好与持续成长仍有缺口;R2 生活、R3 记忆、R4 主动消息、R5 连续语音、R6 天气/素材/备份、R7 视觉观察及口型独立线继续按已有前置承接。没有新增、删除或降低产品需求,`requirement_changes` 为空。 diff --git a/prototypes/hel-790/build.py b/prototypes/hel-790/build.py new file mode 100644 index 0000000..39bb4f8 --- /dev/null +++ b/prototypes/hel-790/build.py @@ -0,0 +1,14 @@ +"""Build an offline, single-file prototype. No dependencies or network access.""" +import base64 +from pathlib import Path + +ROOT = Path(__file__).resolve().parent +html = (ROOT / 'src/shell.html').read_text() +for key, filename in [('STYLE', 'space.css'), ('SCRIPT', 'space.js')]: + html = html.replace('{{' + key + '}}', (ROOT / 'src' / filename).read_text()) +for key, filename in [('ROOM', 'her-room.jpg'), ('TALK', 'her-talk.jpg')]: + data = (ROOT.parents[1] / 'web/public/assets' / filename).read_bytes() + html = html.replace('{{' + key + '}}', 'data:image/jpeg;base64,' + base64.b64encode(data).decode()) +assert '{{' not in html +(ROOT / 'index.html').write_text(html) +print(f'Built offline index.html ({len(html.encode()):,} bytes)') diff --git a/prototypes/hel-790/evidence/desktop-home-fog.png b/prototypes/hel-790/evidence/desktop-home-fog.png new file mode 100644 index 0000000..9b76d70 Binary files /dev/null and b/prototypes/hel-790/evidence/desktop-home-fog.png differ diff --git a/prototypes/hel-790/evidence/desktop-home-moon.png b/prototypes/hel-790/evidence/desktop-home-moon.png new file mode 100644 index 0000000..3579e74 Binary files /dev/null and b/prototypes/hel-790/evidence/desktop-home-moon.png differ diff --git a/prototypes/hel-790/evidence/desktop-life-moon.png b/prototypes/hel-790/evidence/desktop-life-moon.png new file mode 100644 index 0000000..1a96869 Binary files /dev/null and b/prototypes/hel-790/evidence/desktop-life-moon.png differ diff --git a/prototypes/hel-790/evidence/desktop-management-fog.png b/prototypes/hel-790/evidence/desktop-management-fog.png new file mode 100644 index 0000000..0ccbe6c Binary files /dev/null and b/prototypes/hel-790/evidence/desktop-management-fog.png differ diff --git a/prototypes/hel-790/evidence/desktop-memory-fog.png b/prototypes/hel-790/evidence/desktop-memory-fog.png new file mode 100644 index 0000000..d3b4503 Binary files /dev/null and b/prototypes/hel-790/evidence/desktop-memory-fog.png differ diff --git a/prototypes/hel-790/evidence/desktop-playback-contact.png b/prototypes/hel-790/evidence/desktop-playback-contact.png new file mode 100644 index 0000000..042ac1d Binary files /dev/null and b/prototypes/hel-790/evidence/desktop-playback-contact.png differ diff --git a/prototypes/hel-790/evidence/desktop-talk-fog.png b/prototypes/hel-790/evidence/desktop-talk-fog.png new file mode 100644 index 0000000..71f2a87 Binary files /dev/null and b/prototypes/hel-790/evidence/desktop-talk-fog.png differ diff --git a/prototypes/hel-790/evidence/desktop-talk-moon.png b/prototypes/hel-790/evidence/desktop-talk-moon.png new file mode 100644 index 0000000..7957775 Binary files /dev/null and b/prototypes/hel-790/evidence/desktop-talk-moon.png differ diff --git a/prototypes/hel-790/evidence/desktop-walkthrough.webm b/prototypes/hel-790/evidence/desktop-walkthrough.webm new file mode 100644 index 0000000..62ff4de Binary files /dev/null and b/prototypes/hel-790/evidence/desktop-walkthrough.webm differ diff --git a/prototypes/hel-790/evidence/mobile-full-end-fog.png b/prototypes/hel-790/evidence/mobile-full-end-fog.png new file mode 100644 index 0000000..8883b39 Binary files /dev/null and b/prototypes/hel-790/evidence/mobile-full-end-fog.png differ diff --git a/prototypes/hel-790/evidence/mobile-home-fog.png b/prototypes/hel-790/evidence/mobile-home-fog.png new file mode 100644 index 0000000..618b9f5 Binary files /dev/null and b/prototypes/hel-790/evidence/mobile-home-fog.png differ diff --git a/prototypes/hel-790/evidence/mobile-home-moon.png b/prototypes/hel-790/evidence/mobile-home-moon.png new file mode 100644 index 0000000..4e000f8 Binary files /dev/null and b/prototypes/hel-790/evidence/mobile-home-moon.png differ diff --git a/prototypes/hel-790/evidence/mobile-long-end-fog.png b/prototypes/hel-790/evidence/mobile-long-end-fog.png new file mode 100644 index 0000000..567479a Binary files /dev/null and b/prototypes/hel-790/evidence/mobile-long-end-fog.png differ diff --git a/prototypes/hel-790/evidence/mobile-playback-contact.png b/prototypes/hel-790/evidence/mobile-playback-contact.png new file mode 100644 index 0000000..c782a96 Binary files /dev/null and b/prototypes/hel-790/evidence/mobile-playback-contact.png differ diff --git a/prototypes/hel-790/evidence/mobile-talk-fog.png b/prototypes/hel-790/evidence/mobile-talk-fog.png new file mode 100644 index 0000000..66f9047 Binary files /dev/null and b/prototypes/hel-790/evidence/mobile-talk-fog.png differ diff --git a/prototypes/hel-790/evidence/mobile-talk-moon.png b/prototypes/hel-790/evidence/mobile-talk-moon.png new file mode 100644 index 0000000..8dd108f Binary files /dev/null and b/prototypes/hel-790/evidence/mobile-talk-moon.png differ diff --git a/prototypes/hel-790/evidence/mobile-walkthrough.webm b/prototypes/hel-790/evidence/mobile-walkthrough.webm new file mode 100644 index 0000000..27f6da8 Binary files /dev/null and b/prototypes/hel-790/evidence/mobile-walkthrough.webm differ diff --git a/prototypes/hel-790/evidence/requirements-check.txt b/prototypes/hel-790/evidence/requirements-check.txt new file mode 100644 index 0000000..4e614fd --- /dev/null +++ b/prototypes/hel-790/evidence/requirements-check.txt @@ -0,0 +1,4 @@ +$ python3 scripts/check_requirements.py --base-ref origin/main +需求结构检查通过:58项;来源和覆盖完整。仍须人工核对授权语义与实际体验。 +$ python3 scripts/check_requirements.py --base-ref origin/main --handoff prototypes/hel-790/handoff.json +需求结构检查通过:58项;来源和覆盖完整。仍须人工核对授权语义与实际体验。 diff --git a/prototypes/hel-790/evidence/simulated-viewport-320-360.png b/prototypes/hel-790/evidence/simulated-viewport-320-360.png new file mode 100644 index 0000000..9caeeab Binary files /dev/null and b/prototypes/hel-790/evidence/simulated-viewport-320-360.png differ diff --git a/prototypes/hel-790/evidence/simulated-viewport-360-400.png b/prototypes/hel-790/evidence/simulated-viewport-360-400.png new file mode 100644 index 0000000..6931dcc Binary files /dev/null and b/prototypes/hel-790/evidence/simulated-viewport-360-400.png differ diff --git a/prototypes/hel-790/evidence/simulated-viewport-390-420.png b/prototypes/hel-790/evidence/simulated-viewport-390-420.png new file mode 100644 index 0000000..6746206 Binary files /dev/null and b/prototypes/hel-790/evidence/simulated-viewport-390-420.png differ diff --git a/prototypes/hel-790/evidence/verification.json b/prototypes/hel-790/evidence/verification.json new file mode 100644 index 0000000..1797381 --- /dev/null +++ b/prototypes/hel-790/evidence/verification.json @@ -0,0 +1,2227 @@ +{ + "browser": "Chromium / Linux", + "checks": [ + { + "check": "1440×900 moon 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 240.00985717773438, + "y": 78.00181579589844, + "w": 959.99072265625, + "h": 500.00006103515625, + "b": 578.0018768310547, + "r": 1200.0005798339844 + }, + "reading": { + "x": 350, + "y": 592.9064331054688, + "w": 740, + "h": 90, + "b": 682.9064331054688, + "r": 1090 + }, + "sentence": { + "x": 376, + "y": 634.5939331054688, + "w": 688, + "h": 35, + "b": 669.5939331054688, + "r": 1064 + }, + "composer": { + "x": 350, + "y": 745.0001831054688, + "w": 740, + "h": 60, + "b": 805.0001831054688, + "r": 1090 + }, + "nav": { + "x": 578, + "y": 819, + "w": 284, + "h": 63, + "b": 882, + "r": 862 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 1440, + "h": 900, + "b": 900, + "r": 1440 + }, + "speaker": { + "x": 701.984375, + "y": 606.2033081054688, + "w": 24.015625, + "h": 20.390625, + "b": 626.5939331054688, + "r": 726 + } + } + }, + { + "check": "1440×900 moon 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "1440×900 moon 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "1440×900 moon 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "1440×900 moon 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "1440×900 fog 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 242.99102783203125, + "y": 78.55094146728516, + "w": 957.1974487304688, + "h": 500.0265808105469, + "b": 578.577522277832, + "r": 1200.1884765625 + }, + "reading": { + "x": 350, + "y": 592.955322265625, + "w": 740, + "h": 90, + "b": 682.955322265625, + "r": 1090 + }, + "sentence": { + "x": 376, + "y": 634.642822265625, + "w": 688, + "h": 35, + "b": 669.642822265625, + "r": 1064 + }, + "composer": { + "x": 350, + "y": 745.049072265625, + "w": 740, + "h": 60, + "b": 805.049072265625, + "r": 1090 + }, + "nav": { + "x": 578, + "y": 819, + "w": 284, + "h": 63, + "b": 882, + "r": 862 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 1440, + "h": 900, + "b": 900, + "r": 1440 + }, + "speaker": { + "x": 701.984375, + "y": 606.252197265625, + "w": 24.015625, + "h": 20.390625, + "b": 626.642822265625, + "r": 726 + } + } + }, + { + "check": "1440×900 fog 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "1440×900 fog 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "1440×900 fog 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "1440×900 fog 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "390×844 moon 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 12, + "y": 68, + "w": 366, + "h": 449, + "b": 517, + "r": 378 + }, + "reading": { + "x": 12, + "y": 531.90625, + "w": 366, + "h": 115, + "b": 646.90625, + "r": 378 + }, + "sentence": { + "x": 26, + "y": 586.796875, + "w": 338, + "h": 30.59375, + "b": 617.390625, + "r": 364 + }, + "composer": { + "x": 12, + "y": 702, + "w": 366, + "h": 51, + "b": 753, + "r": 378 + }, + "nav": { + "x": 58, + "y": 772, + "w": 274, + "h": 57, + "b": 829, + "r": 332 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 390, + "h": 844, + "b": 844, + "r": 390 + }, + "speaker": { + "x": 176.984375, + "y": 561.40625, + "w": 24.015625, + "h": 20.390625, + "b": 581.796875, + "r": 201 + } + } + }, + { + "check": "390×844 moon 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "390×844 moon 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "390×844 moon 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "390×844 moon 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "390×844 fog 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 12, + "y": 68, + "w": 366, + "h": 449, + "b": 517, + "r": 378 + }, + "reading": { + "x": 12, + "y": 531.90625, + "w": 366, + "h": 115, + "b": 646.90625, + "r": 378 + }, + "sentence": { + "x": 26, + "y": 586.796875, + "w": 338, + "h": 30.59375, + "b": 617.390625, + "r": 364 + }, + "composer": { + "x": 12, + "y": 702, + "w": 366, + "h": 51, + "b": 753, + "r": 378 + }, + "nav": { + "x": 58, + "y": 772, + "w": 274, + "h": 57, + "b": 829, + "r": 332 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 390, + "h": 844, + "b": 844, + "r": 390 + }, + "speaker": { + "x": 176.984375, + "y": 561.40625, + "w": 24.015625, + "h": 20.390625, + "b": 581.796875, + "r": 201 + } + } + }, + { + "check": "390×844 fog 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "390×844 fog 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "390×844 fog 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "390×844 fog 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "逐句点击后的真实 DOM 文字与完整原文一致", + "passed": true, + "details": null + }, + { + "check": "长回复分句完整无缺字", + "passed": true, + "details": null + }, + { + "check": "长回复没有空白翻页", + "passed": true, + "details": null + }, + { + "check": "长回复末尾可从主界面翻到", + "passed": true, + "details": 13 + }, + { + "check": "全文保留末句", + "passed": true, + "details": null + }, + { + "check": "收回全文保持句子位置", + "passed": true, + "details": null + }, + { + "check": "记录第 1 次打开可见", + "passed": true, + "details": null + }, + { + "check": "浮层焦点在原生对话框内", + "passed": true, + "details": null + }, + { + "check": "Tab 保持在浮层内", + "passed": true, + "details": null + }, + { + "check": "收回记录保持句子位置", + "passed": true, + "details": null + }, + { + "check": "记录第 2 次打开可见", + "passed": true, + "details": null + }, + { + "check": "浮层焦点在原生对话框内", + "passed": true, + "details": null + }, + { + "check": "Tab 保持在浮层内", + "passed": true, + "details": null + }, + { + "check": "收回记录保持句子位置", + "passed": true, + "details": null + }, + { + "check": "记录第 3 次打开可见", + "passed": true, + "details": null + }, + { + "check": "浮层焦点在原生对话框内", + "passed": true, + "details": null + }, + { + "check": "Tab 保持在浮层内", + "passed": true, + "details": null + }, + { + "check": "收回记录保持句子位置", + "passed": true, + "details": null + }, + { + "check": "连续来句不抢走正在读的句子", + "passed": true, + "details": null + }, + { + "check": "两段来句均保留", + "passed": true, + "details": null + }, + { + "check": "取消后迟到内容不再写入", + "passed": true, + "details": null + }, + { + "check": "未完成片段明确标注", + "passed": true, + "details": null + }, + { + "check": "新一轮不混入取消的长回复", + "passed": true, + "details": null + }, + { + "check": "长用户输入与表情完整保留", + "passed": true, + "details": null + }, + { + "check": "1440×900 长名 moon 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 240, + "y": 78, + "w": 960, + "h": 500, + "b": 578, + "r": 1200 + }, + "reading": { + "x": 350, + "y": 592.90625, + "w": 740, + "h": 90, + "b": 682.90625, + "r": 1090 + }, + "sentence": { + "x": 376, + "y": 634.59375, + "w": 688, + "h": 35, + "b": 669.59375, + "r": 1064 + }, + "composer": { + "x": 350, + "y": 745, + "w": 740, + "h": 60, + "b": 805, + "r": 1090 + }, + "nav": { + "x": 578, + "y": 819, + "w": 284, + "h": 63, + "b": 882, + "r": 862 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 1440, + "h": 900, + "b": 900, + "r": 1440 + }, + "speaker": { + "x": 547.015625, + "y": 606.203125, + "w": 252.015625, + "h": 20.390625, + "b": 626.59375, + "r": 799.03125 + } + } + }, + { + "check": "1440×900 长名 moon 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "1440×900 长名 moon 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "1440×900 长名 moon 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "1440×900 长名 moon 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "1440×900 长名 fog 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 240, + "y": 78, + "w": 960, + "h": 500, + "b": 578, + "r": 1200 + }, + "reading": { + "x": 350, + "y": 592.90625, + "w": 740, + "h": 90, + "b": 682.90625, + "r": 1090 + }, + "sentence": { + "x": 376, + "y": 634.59375, + "w": 688, + "h": 35, + "b": 669.59375, + "r": 1064 + }, + "composer": { + "x": 350, + "y": 745, + "w": 740, + "h": 60, + "b": 805, + "r": 1090 + }, + "nav": { + "x": 578, + "y": 819, + "w": 284, + "h": 63, + "b": 882, + "r": 862 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 1440, + "h": 900, + "b": 900, + "r": 1440 + }, + "speaker": { + "x": 547.015625, + "y": 606.203125, + "w": 252.015625, + "h": 20.390625, + "b": 626.59375, + "r": 799.03125 + } + } + }, + { + "check": "1440×900 长名 fog 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "1440×900 长名 fog 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "1440×900 长名 fog 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "1440×900 长名 fog 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "1280×720 长名 moon 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 179.203125, + "y": 78, + "w": 921.59375, + "h": 320, + "b": 398, + "r": 1100.796875 + }, + "reading": { + "x": 270, + "y": 412.90625, + "w": 740, + "h": 90, + "b": 502.90625, + "r": 1010 + }, + "sentence": { + "x": 296, + "y": 454.59375, + "w": 688, + "h": 35, + "b": 489.59375, + "r": 984 + }, + "composer": { + "x": 270, + "y": 565, + "w": 740, + "h": 60, + "b": 625, + "r": 1010 + }, + "nav": { + "x": 498, + "y": 639, + "w": 284, + "h": 63, + "b": 702, + "r": 782 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 1280, + "h": 720, + "b": 720, + "r": 1280 + }, + "speaker": { + "x": 467.015625, + "y": 426.203125, + "w": 252.015625, + "h": 20.390625, + "b": 446.59375, + "r": 719.03125 + } + } + }, + { + "check": "1280×720 长名 moon 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "1280×720 长名 moon 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "1280×720 长名 moon 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "1280×720 长名 moon 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "1280×720 长名 fog 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 179.203125, + "y": 78, + "w": 921.59375, + "h": 320, + "b": 398, + "r": 1100.796875 + }, + "reading": { + "x": 270, + "y": 412.90625, + "w": 740, + "h": 90, + "b": 502.90625, + "r": 1010 + }, + "sentence": { + "x": 296, + "y": 454.59375, + "w": 688, + "h": 35, + "b": 489.59375, + "r": 984 + }, + "composer": { + "x": 270, + "y": 565, + "w": 740, + "h": 60, + "b": 625, + "r": 1010 + }, + "nav": { + "x": 498, + "y": 639, + "w": 284, + "h": 63, + "b": 702, + "r": 782 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 1280, + "h": 720, + "b": 720, + "r": 1280 + }, + "speaker": { + "x": 467.015625, + "y": 426.203125, + "w": 252.015625, + "h": 20.390625, + "b": 446.59375, + "r": 719.03125 + } + } + }, + { + "check": "1280×720 长名 fog 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "1280×720 长名 fog 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "1280×720 长名 fog 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "1280×720 长名 fog 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "844×390 长名 moon 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 118.1640625, + "y": 57, + "w": 607.671875, + "h": 73, + "b": 130, + "r": 725.8359375 + }, + "reading": { + "x": 92.84375, + "y": 144.90625, + "w": 658.3125, + "h": 68, + "b": 212.90625, + "r": 751.15625 + }, + "sentence": { + "x": 100.84375, + "y": 177.53125, + "w": 642.3125, + "h": 24.75, + "b": 202.28125, + "r": 743.15625 + }, + "composer": { + "x": 92.84375, + "y": 261, + "w": 658.3125, + "h": 54, + "b": 315, + "r": 751.15625 + }, + "nav": { + "x": 280, + "y": 321.609375, + "w": 284, + "h": 60.390625, + "b": 382, + "r": 564 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 844, + "h": 390, + "b": 390, + "r": 844 + }, + "speaker": { + "x": 259.53125, + "y": 156.1875, + "w": 231, + "h": 18.6875, + "b": 174.875, + "r": 490.53125 + } + } + }, + { + "check": "844×390 长名 moon 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "844×390 长名 moon 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "844×390 长名 moon 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "844×390 长名 moon 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "844×390 长名 fog 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 118.1640625, + "y": 57, + "w": 607.671875, + "h": 73, + "b": 130, + "r": 725.8359375 + }, + "reading": { + "x": 92.84375, + "y": 144.90625, + "w": 658.3125, + "h": 68, + "b": 212.90625, + "r": 751.15625 + }, + "sentence": { + "x": 100.84375, + "y": 177.53125, + "w": 642.3125, + "h": 24.75, + "b": 202.28125, + "r": 743.15625 + }, + "composer": { + "x": 92.84375, + "y": 261, + "w": 658.3125, + "h": 54, + "b": 315, + "r": 751.15625 + }, + "nav": { + "x": 280, + "y": 321.609375, + "w": 284, + "h": 60.390625, + "b": 382, + "r": 564 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 844, + "h": 390, + "b": 390, + "r": 844 + }, + "speaker": { + "x": 259.53125, + "y": 156.1875, + "w": 231, + "h": 18.6875, + "b": 174.875, + "r": 490.53125 + } + } + }, + { + "check": "844×390 长名 fog 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "844×390 长名 fog 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "844×390 长名 fog 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "844×390 长名 fog 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "390×844 长名 moon 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 12, + "y": 68, + "w": 366, + "h": 449, + "b": 517, + "r": 378 + }, + "reading": { + "x": 12, + "y": 531.90625, + "w": 366, + "h": 115, + "b": 646.90625, + "r": 378 + }, + "sentence": { + "x": 26, + "y": 597, + "w": 338, + "h": 30.59375, + "b": 627.59375, + "r": 364 + }, + "composer": { + "x": 12, + "y": 702, + "w": 366, + "h": 51, + "b": 753, + "r": 378 + }, + "nav": { + "x": 58, + "y": 772, + "w": 274, + "h": 57, + "b": 829, + "r": 332 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 390, + "h": 844, + "b": 844, + "r": 390 + }, + "speaker": { + "x": 26, + "y": 551.21875, + "w": 244.0625, + "h": 40.78125, + "b": 592, + "r": 270.0625 + } + } + }, + { + "check": "390×844 长名 moon 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "390×844 长名 moon 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "390×844 长名 moon 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "390×844 长名 moon 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "390×844 长名 fog 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 12, + "y": 68, + "w": 366, + "h": 449, + "b": 517, + "r": 378 + }, + "reading": { + "x": 12, + "y": 531.90625, + "w": 366, + "h": 115, + "b": 646.90625, + "r": 378 + }, + "sentence": { + "x": 26, + "y": 597, + "w": 338, + "h": 30.59375, + "b": 627.59375, + "r": 364 + }, + "composer": { + "x": 12, + "y": 702, + "w": 366, + "h": 51, + "b": 753, + "r": 378 + }, + "nav": { + "x": 58, + "y": 772, + "w": 274, + "h": 57, + "b": 829, + "r": 332 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 390, + "h": 844, + "b": 844, + "r": 390 + }, + "speaker": { + "x": 26, + "y": 551.21875, + "w": 244.0625, + "h": 40.78125, + "b": 592, + "r": 270.0625 + } + } + }, + { + "check": "390×844 长名 fog 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "390×844 长名 fog 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "390×844 长名 fog 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "390×844 长名 fog 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "390×600 长名 moon 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 12, + "y": 57, + "w": 366, + "h": 288, + "b": 345, + "r": 378 + }, + "reading": { + "x": 12, + "y": 359.3125, + "w": 366, + "h": 68, + "b": 427.3125, + "r": 378 + }, + "sentence": { + "x": 20, + "y": 391.9375, + "w": 350, + "h": 24.75, + "b": 416.6875, + "r": 370 + }, + "composer": { + "x": 12, + "y": 475.40625, + "w": 366, + "h": 49.59375, + "b": 525, + "r": 378 + }, + "nav": { + "x": 58, + "y": 538.3125, + "w": 274, + "h": 53.6875, + "b": 592, + "r": 332 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 390, + "h": 600, + "b": 600, + "r": 390 + }, + "speaker": { + "x": 32.53125, + "y": 370.59375, + "w": 231, + "h": 18.6875, + "b": 389.28125, + "r": 263.53125 + } + } + }, + { + "check": "390×600 长名 moon 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "390×600 长名 moon 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "390×600 长名 moon 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "390×600 长名 moon 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "390×600 长名 fog 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 12, + "y": 57, + "w": 366, + "h": 288, + "b": 345, + "r": 378 + }, + "reading": { + "x": 12, + "y": 359.3125, + "w": 366, + "h": 68, + "b": 427.3125, + "r": 378 + }, + "sentence": { + "x": 20, + "y": 391.9375, + "w": 350, + "h": 24.75, + "b": 416.6875, + "r": 370 + }, + "composer": { + "x": 12, + "y": 475.40625, + "w": 366, + "h": 49.59375, + "b": 525, + "r": 378 + }, + "nav": { + "x": 58, + "y": 538.3125, + "w": 274, + "h": 53.6875, + "b": 592, + "r": 332 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 390, + "h": 600, + "b": 600, + "r": 390 + }, + "speaker": { + "x": 32.53125, + "y": 370.59375, + "w": 231, + "h": 18.6875, + "b": 389.28125, + "r": 263.53125 + } + } + }, + { + "check": "390×600 长名 fog 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "390×600 长名 fog 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "390×600 长名 fog 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "390×600 长名 fog 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "390×420 长名 moon 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 12, + "y": 57, + "w": 366, + "h": 108, + "b": 165, + "r": 378 + }, + "reading": { + "x": 12, + "y": 179.3125, + "w": 366, + "h": 68, + "b": 247.3125, + "r": 378 + }, + "sentence": { + "x": 20, + "y": 211.9375, + "w": 350, + "h": 24.75, + "b": 236.6875, + "r": 370 + }, + "composer": { + "x": 12, + "y": 295.40625, + "w": 366, + "h": 49.59375, + "b": 345, + "r": 378 + }, + "nav": { + "x": 58, + "y": 358.3125, + "w": 274, + "h": 53.6875, + "b": 412, + "r": 332 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 390, + "h": 420, + "b": 420, + "r": 390 + }, + "speaker": { + "x": 32.53125, + "y": 190.59375, + "w": 231, + "h": 18.6875, + "b": 209.28125, + "r": 263.53125 + } + } + }, + { + "check": "390×420 长名 moon 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "390×420 长名 moon 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "390×420 长名 moon 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "390×420 长名 moon 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "390×420 长名 fog 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 12, + "y": 57, + "w": 366, + "h": 108, + "b": 165, + "r": 378 + }, + "reading": { + "x": 12, + "y": 179.3125, + "w": 366, + "h": 68, + "b": 247.3125, + "r": 378 + }, + "sentence": { + "x": 20, + "y": 211.9375, + "w": 350, + "h": 24.75, + "b": 236.6875, + "r": 370 + }, + "composer": { + "x": 12, + "y": 295.40625, + "w": 366, + "h": 49.59375, + "b": 345, + "r": 378 + }, + "nav": { + "x": 58, + "y": 358.3125, + "w": 274, + "h": 53.6875, + "b": 412, + "r": 332 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 390, + "h": 420, + "b": 420, + "r": 390 + }, + "speaker": { + "x": 32.53125, + "y": 190.59375, + "w": 231, + "h": 18.6875, + "b": 209.28125, + "r": 263.53125 + } + } + }, + { + "check": "390×420 长名 fog 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "390×420 长名 fog 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "390×420 长名 fog 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "390×420 长名 fog 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "360×400 长名 moon 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 12, + "y": 57, + "w": 336, + "h": 88, + "b": 145, + "r": 348 + }, + "reading": { + "x": 12, + "y": 159.3125, + "w": 336, + "h": 68, + "b": 227.3125, + "r": 348 + }, + "sentence": { + "x": 20, + "y": 200.625, + "w": 320, + "h": 24.75, + "b": 225.375, + "r": 340 + }, + "composer": { + "x": 12, + "y": 275.40625, + "w": 336, + "h": 49.59375, + "b": 325, + "r": 348 + }, + "nav": { + "x": 43, + "y": 338.3125, + "w": 274, + "h": 53.6875, + "b": 392, + "r": 317 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 360, + "h": 400, + "b": 400, + "r": 360 + }, + "speaker": { + "x": 20, + "y": 161.25, + "w": 226.0625, + "h": 37.375, + "b": 198.625, + "r": 246.0625 + } + } + }, + { + "check": "360×400 长名 moon 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "360×400 长名 moon 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "360×400 长名 moon 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "360×400 长名 moon 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "360×400 长名 fog 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 12, + "y": 57, + "w": 336, + "h": 88, + "b": 145, + "r": 348 + }, + "reading": { + "x": 12, + "y": 159.3125, + "w": 336, + "h": 68, + "b": 227.3125, + "r": 348 + }, + "sentence": { + "x": 20, + "y": 200.625, + "w": 320, + "h": 24.75, + "b": 225.375, + "r": 340 + }, + "composer": { + "x": 12, + "y": 275.40625, + "w": 336, + "h": 49.59375, + "b": 325, + "r": 348 + }, + "nav": { + "x": 43, + "y": 338.3125, + "w": 274, + "h": 53.6875, + "b": 392, + "r": 317 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 360, + "h": 400, + "b": 400, + "r": 360 + }, + "speaker": { + "x": 20, + "y": 161.25, + "w": 226.0625, + "h": 37.375, + "b": 198.625, + "r": 246.0625 + } + } + }, + { + "check": "360×400 长名 fog 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "360×400 长名 fog 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "360×400 长名 fog 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "360×400 长名 fog 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "320×568 长名 moon 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 12, + "y": 57, + "w": 296, + "h": 256, + "b": 313, + "r": 308 + }, + "reading": { + "x": 12, + "y": 327.3125, + "w": 296, + "h": 68, + "b": 395.3125, + "r": 308 + }, + "sentence": { + "x": 20, + "y": 368.625, + "w": 280, + "h": 24.75, + "b": 393.375, + "r": 300 + }, + "composer": { + "x": 12, + "y": 443.40625, + "w": 296, + "h": 49.59375, + "b": 493, + "r": 308 + }, + "nav": { + "x": 23, + "y": 506.3125, + "w": 274, + "h": 53.6875, + "b": 560, + "r": 297 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 320, + "h": 568, + "b": 568, + "r": 320 + }, + "speaker": { + "x": 20, + "y": 329.25, + "w": 186.0625, + "h": 37.375, + "b": 366.625, + "r": 206.0625 + } + } + }, + { + "check": "320×568 长名 moon 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "320×568 长名 moon 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "320×568 长名 moon 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "320×568 长名 moon 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "320×568 长名 fog 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 12, + "y": 57, + "w": 296, + "h": 256, + "b": 313, + "r": 308 + }, + "reading": { + "x": 12, + "y": 327.3125, + "w": 296, + "h": 68, + "b": 395.3125, + "r": 308 + }, + "sentence": { + "x": 20, + "y": 368.625, + "w": 280, + "h": 24.75, + "b": 393.375, + "r": 300 + }, + "composer": { + "x": 12, + "y": 443.40625, + "w": 296, + "h": 49.59375, + "b": 493, + "r": 308 + }, + "nav": { + "x": 23, + "y": 506.3125, + "w": 274, + "h": 53.6875, + "b": 560, + "r": 297 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 320, + "h": 568, + "b": 568, + "r": 320 + }, + "speaker": { + "x": 20, + "y": 329.25, + "w": 186.0625, + "h": 37.375, + "b": 366.625, + "r": 206.0625 + } + } + }, + { + "check": "320×568 长名 fog 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "320×568 长名 fog 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "320×568 长名 fog 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "320×568 长名 fog 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "320×360 长名 moon 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 12, + "y": 57, + "w": 296, + "h": 48, + "b": 105, + "r": 308 + }, + "reading": { + "x": 12, + "y": 119.3125, + "w": 296, + "h": 68, + "b": 187.3125, + "r": 308 + }, + "sentence": { + "x": 20, + "y": 160.625, + "w": 280, + "h": 24.75, + "b": 185.375, + "r": 300 + }, + "composer": { + "x": 12, + "y": 235.40625, + "w": 296, + "h": 49.59375, + "b": 285, + "r": 308 + }, + "nav": { + "x": 23, + "y": 298.3125, + "w": 274, + "h": 53.6875, + "b": 352, + "r": 297 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 320, + "h": 360, + "b": 360, + "r": 320 + }, + "speaker": { + "x": 20, + "y": 121.25, + "w": 186.0625, + "h": 37.375, + "b": 158.625, + "r": 206.0625 + } + } + }, + { + "check": "320×360 长名 moon 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "320×360 长名 moon 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "320×360 长名 moon 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "320×360 长名 moon 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "320×360 长名 fog 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 12, + "y": 57, + "w": 296, + "h": 48, + "b": 105, + "r": 308 + }, + "reading": { + "x": 12, + "y": 119.3125, + "w": 296, + "h": 68, + "b": 187.3125, + "r": 308 + }, + "sentence": { + "x": 20, + "y": 160.625, + "w": 280, + "h": 24.75, + "b": 185.375, + "r": 300 + }, + "composer": { + "x": 12, + "y": 235.40625, + "w": 296, + "h": 49.59375, + "b": 285, + "r": 308 + }, + "nav": { + "x": 23, + "y": 298.3125, + "w": 274, + "h": 53.6875, + "b": 352, + "r": 297 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 320, + "h": 360, + "b": 360, + "r": 320 + }, + "speaker": { + "x": 20, + "y": 121.25, + "w": 186.0625, + "h": 37.375, + "b": 158.625, + "r": 206.0625 + } + } + }, + { + "check": "320×360 长名 fog 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "320×360 长名 fog 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "320×360 长名 fog 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "320×360 长名 fog 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "紧凑视口不丢失长回复文字", + "passed": true, + "details": null + }, + { + "check": "日子关联到对应的已分享对话", + "passed": true, + "details": null + }, + { + "check": "关联聊天能返回原来的一天", + "passed": true, + "details": null + }, + { + "check": "演示关系保存有明确反馈", + "passed": true, + "details": null + }, + { + "check": "初次创建关系不预选", + "passed": true, + "details": null + }, + { + "check": "名字复用已批准规则,拒绝尖括号", + "passed": true, + "details": null + }, + { + "check": "用户给的名字贯穿身份显示且按文字处理", + "passed": true, + "details": null + }, + { + "check": "语音演示持续标注没有收音", + "passed": true, + "details": null + }, + { + "check": "语音演示 人物与正文分开", + "passed": true, + "details": { + "portal": { + "x": 264.9891662597656, + "y": 84.19111633300781, + "w": 939.0146484375, + "h": 465.567626953125, + "b": 549.7587432861328, + "r": 1204.0038146972656 + }, + "reading": { + "x": 350, + "y": 563.80322265625, + "w": 740, + "h": 90, + "b": 653.80322265625, + "r": 1090 + }, + "sentence": { + "x": 376, + "y": 605.49072265625, + "w": 688, + "h": 35, + "b": 640.49072265625, + "r": 1064 + }, + "composer": { + "x": 350, + "y": 745.28759765625, + "w": 740, + "h": 60, + "b": 805.28759765625, + "r": 1090 + }, + "nav": { + "x": 578, + "y": 819, + "w": 284, + "h": 63, + "b": 882, + "r": 862 + }, + "viewport": { + "x": 0, + "y": 0, + "w": 1440, + "h": 900, + "b": 900, + "r": 1440 + }, + "speaker": { + "x": 695.984375, + "y": 577.10009765625, + "w": 36.015625, + "h": 20.390625, + "b": 597.49072265625, + "r": 732 + } + } + }, + { + "check": "语音演示 正文与输入分开", + "passed": true, + "details": null + }, + { + "check": "语音演示 输入与导航分开", + "passed": true, + "details": null + }, + { + "check": "语音演示 导航在可视范围", + "passed": true, + "details": null + }, + { + "check": "语音演示 无横向溢出", + "passed": true, + "details": null + }, + { + "check": "390×600 相处页人物不挡近况", + "passed": true, + "details": { + "title": { + "x": 24, + "y": 70, + "b": 130.78125, + "r": 226 + }, + "portal": { + "x": 246, + "y": 70, + "b": 210, + "r": 366 + }, + "actions": { + "x": 24, + "y": 466, + "b": 510, + "r": 206 + }, + "nav": { + "x": 58, + "y": 538.3125, + "b": 592, + "r": 332 + } + } + }, + { + "check": "390×600 相处入口不挡导航", + "passed": true, + "details": null + }, + { + "check": "390×420 相处页人物不挡近况", + "passed": true, + "details": { + "title": { + "x": 24, + "y": 70, + "b": 130.78125, + "r": 226 + }, + "portal": { + "x": 246, + "y": 70, + "b": 210, + "r": 366 + }, + "actions": { + "x": 24, + "y": 286, + "b": 330, + "r": 206 + }, + "nav": { + "x": 58, + "y": 358.3125, + "b": 412, + "r": 332 + } + } + }, + { + "check": "390×420 相处入口不挡导航", + "passed": true, + "details": null + }, + { + "check": "320×568 相处页人物不挡近况", + "passed": true, + "details": { + "title": { + "x": 24, + "y": 70, + "b": 161.171875, + "r": 156 + }, + "portal": { + "x": 176, + "y": 70, + "b": 210, + "r": 296 + }, + "actions": { + "x": 24, + "y": 434, + "b": 478, + "r": 206 + }, + "nav": { + "x": 23, + "y": 506.3125, + "b": 560, + "r": 297 + } + } + }, + { + "check": "320×568 相处入口不挡导航", + "passed": true, + "details": null + }, + { + "check": "320×360 相处页人物不挡近况", + "passed": true, + "details": { + "title": { + "x": 24, + "y": 70, + "b": 161.171875, + "r": 156 + }, + "portal": { + "x": 176, + "y": 70, + "b": 210, + "r": 296 + }, + "actions": { + "x": 24, + "y": 226, + "b": 270, + "r": 206 + }, + "nav": { + "x": 23, + "y": 298.3125, + "b": 352, + "r": 297 + } + } + }, + { + "check": "320×360 相处入口不挡导航", + "passed": true, + "details": null + }, + { + "check": "自动续读明确由用户选择", + "passed": true, + "details": null + }, + { + "check": "输入时停止自动续读", + "passed": true, + "details": null + }, + { + "check": "系统减少动效停止背景循环", + "passed": true, + "details": null + }, + { + "check": "减少动效不播放空间移动", + "passed": true, + "details": null + }, + { + "check": "无浏览器脚本错误", + "passed": true, + "details": [] + }, + { + "check": "离线原型没有 HTTP / WebSocket 请求", + "passed": true, + "details": [] + } + ], + "limitations": [ + "未测试真机软键盘", + "未测试 Safari / iOS", + "视口缩小是等效模拟", + "人物为获批静帧;服务全部未接入" + ] +} \ No newline at end of file diff --git a/prototypes/hel-790/evidence/video-review.json b/prototypes/hel-790/evidence/video-review.json new file mode 100644 index 0000000..7b6d159 --- /dev/null +++ b/prototypes/hel-790/evidence/video-review.json @@ -0,0 +1,26 @@ +[ + { + "file": "desktop-walkthrough.webm", + "duration": 35.84, + "currentTime": 35.84, + "ended": true, + "decodedCallbacks": 895, + "totalVideoFrames": 896, + "droppedVideoFrames": 0, + "videoWidth": 1280, + "videoHeight": 800, + "inspection": "完整浏览器播放至结束,每2秒取一帧供逐段检视;此统计不是产品性能测试。" + }, + { + "file": "mobile-walkthrough.webm", + "duration": 34.84, + "currentTime": 34.84, + "ended": true, + "decodedCallbacks": 870, + "totalVideoFrames": 871, + "droppedVideoFrames": 0, + "videoWidth": 390, + "videoHeight": 844, + "inspection": "完整浏览器播放至结束,每2秒取一帧供逐段检视;此统计不是产品性能测试。" + } +] diff --git a/prototypes/hel-790/handoff.json b/prototypes/hel-790/handoff.json new file mode 100644 index 0000000..0506638 --- /dev/null +++ b/prototypes/hel-790/handoff.json @@ -0,0 +1,328 @@ +{ + "baseline_version": "1.7", + "read_commit": "4242f8377e350e5f17e836d275c15b0f099bf109", + "requirement_ids": [ + "CG-004", + "CG-018", + "CG-024", + "CG-031", + "VIS-001", + "VIS-002", + "VIS-003", + "VIS-004", + "VIS-005", + "VIS-006", + "VIS-007", + "VIS-008", + "VIS-009", + "VIS-010", + "VIS-011", + "VIS-012", + "VIS-013", + "UX-001", + "UX-002", + "UX-003", + "UX-005", + "UX-006", + "AM-001", + "AM-002", + "AM-003", + "GOV-001", + "GOV-002", + "GOV-003", + "GOV-004", + "DEL-001" + ], + "deliverable": "HEL-790:独立离线HTML、两主题电脑/手机真实截图、实际动态录屏、可审查PR及本结构化交接。", + "acceptance": [ + "相处→交流→全文/历史→收回→生活/回忆/管理→相处的连续空间关系。", + "当前一句身份清楚、柔和进出;长回复可逐句读到末尾,全文与历史按需展开并保留阅读位置。", + "多视口两主题的人物/正文/输入/导航不互挡,明确未测真机键盘。", + "四类入口保留;未接入能力说明;用户只验收小样,不代表完整产品通过。" + ], + "deferred": [ + "正式界面实现和测试部署:小样认可后再安排独立审核发布。", + "R1出生底色深度、模型诠释、少量初始喜好与持续成长仍有缺口。", + "R2生活与未分享裁剪、R3记忆、R4主动消息、R5连续语音、R6天气/素材/备份、R7视觉观察及独立口型线。", + "R2旧完整设计的所有状态继续继承;本卡聚焦对话和整体空间,部分管理项仅入口说明。", + "真机软键盘、Safari/iOS、屏幕阅读器、低端设备性能未测。" + ], + "requirement_changes": [], + "verification": [ + "标准库离线构建;node --check语法通过。", + "verify.py真实浏览器检查,实际逐句DOM文字与完整原文比较、多视口遮挡/取消/身份/记录/焦点/离线隔离等;详evidence/verification.json。", + "电脑4张、手机4张两主题主要截图,以及长句/全文末尾/生活回忆/管理/缩小视口补图。", + "实际桌面与手机walkthrough录屏;复放检查另记evidence/video-review.json。", + "需求检查在快进到PR#5已合入的main之后,本分支直接执行--base-ref origin/main,含--handoff;详evidence/requirements-check.txt。", + "体验待白栖知验收。" + ], + "requirement_mapping": [ + { + "id": "CG-004", + "meaning": "日常可看她在环境中生活;交谈时允许自然切近到同一人物、同一房间、同一套衣服的半身或脸部。", + "source_comment_ids": [ + "01a15724-dcaa-7d2b-ae23-430f24ca36b9", + "01a15726-e178-72b0-9a3c-8b2041538730" + ], + "this_delivery": "同一持续存在的人物窗展开,复用同一人物/房间/衣服的获批静帧;录屏验证,非真人动态能力结论。" + }, + { + "id": "CG-018", + "meaning": "主要在电脑使用,优先大画面沉浸体验;适配手机看画面、文字聊天和连续语音,使用同一伴侣和同一份记忆。", + "source_comment_ids": [ + "01a1577b-b65c-787a-b436-b0a74c38fea4", + "01a1577c-d10f-7513-8f58-62b3b387240a" + ], + "this_delivery": "9种电脑/手机/矮屏/横屏视口,两个主题,人物/正文/输入/导航分别验证;真机与Safari未测。" + }, + { + "id": "CG-024", + "meaning": "先确认人物与房间的写实样图,再验收写实动态小样;验证环境与人物独立变化、同一人物连续性、动作循环衔接、半身/近景交谈与口型语音。用户认可后,再逐步接完整功能,并分别验收。", + "source_comment_ids": [ + "01a157a9-bd18-7533-9b21-e5f4c3a90d7c", + "01a157ab-209c-7c8f-956c-40ebb3340f4e", + "01a1582c-7386-7515-bf62-89dfadfea3d3", + "01a1599b-f137-71cc-8af2-a265499b4b6e", + "01a15e92-e689-754a-aad3-4566100962b3" + ], + "this_delivery": "仅独立设计小样与实际截图录屏,不把设计通过当实时口型或完整产品通过。" + }, + { + "id": "CG-031", + "meaning": "完整前端应覆盖四类要素:相处主界面、交流界面、她的生活与共同回忆、创建与管理。设计需建立在对整个项目的充分理解之上;此前认可的人物和高层卧室图片只属于人物/场景/口型等视觉子模块的参考,不能作为整体前端的固定基座,不能据此先铺满场景再往上叠界面。", + "source_comment_ids": [ + "01a15e8d-91ab-739e-84f9-fc4026bfcd70", + "01a15e92-e689-754a-aad3-4566100962b3" + ], + "this_delivery": "四类区域均有入口和返回关系;空间背景独立于人物/卧室,非全屏房间叠按钮。" + }, + { + "id": "VIS-001", + "meaning": "整体像只属于两人的数字空间,人物、交流、回忆融在其中。", + "source_comment_ids": [ + "01a15f09-db1e-705c-8baf-cde63c7651fb", + "01a15f1f-5a71-783c-a458-b326a0073d69" + ], + "this_delivery": "人物、对话和回忆在同一环境连续开合。" + }, + { + "id": "VIS-002", + "meaning": "静谧梦幻、安静亲密,有空间深度和柔和微光。", + "source_comment_ids": [ + "01a15f09-db1e-705c-8baf-cde63c7651fb", + "01a15f1f-5a71-783c-a458-b326a0073d69" + ], + "this_delivery": "静谧夜色、远近景物、柔和微光,等待用户亲眼验收。" + }, + { + "id": "VIS-003", + "meaning": "切换主题同时改变配色、背景、光影、材质和动效;页面结构与操作位置一致。", + "source_comment_ids": [ + "01a15f09-db1e-705c-8baf-cde63c7651fb", + "01a15f1f-5a71-783c-a458-b326a0073d69" + ], + "this_delivery": "同一DOM与入口,天空/光雾/材质/微光随主题整体改变。" + }, + { + "id": "VIS-004", + "meaning": "靛蓝月光与蓝紫雾光两套都保留;不把原型临时默认主题当成用户指定默认。", + "source_comment_ids": [ + "01a15f09-db1e-705c-8baf-cde63c7651fb", + "01a15f1f-5a71-783c-a458-b326a0073d69" + ], + "this_delivery": "月光与雾光均保留,临时初始主题不作为默认选择。" + }, + { + "id": "VIS-005", + "meaning": "首页只留少量当前状态与入口,其余内容按需展开,完整功能仍保留。", + "source_comment_ids": [ + "01a15f09-db1e-705c-8baf-cde63c7651fb", + "01a15f1f-5a71-783c-a458-b326a0073d69" + ], + "this_delivery": "首页只保留一句近况、已分享留言与入口,保留获批比例。" + }, + { + "id": "VIS-006", + "meaning": "光雾、景深与若隐若现的景物融合;具体画面通过样图验证。", + "source_comment_ids": [ + "01a15f09-db1e-705c-8baf-cde63c7651fb", + "01a15f1f-5a71-783c-a458-b326a0073d69" + ], + "this_delivery": "远近天际线、光路和两层雾构成独立背景,不铺满卧室。" + }, + { + "id": "VIS-007", + "meaning": "平时舒缓流动与景物微动;操作时有明显景深变化和空间过渡。", + "source_comment_ids": [ + "01a15f09-db1e-705c-8baf-cde63c7651fb", + "01a15f1f-5a71-783c-a458-b326a0073d69" + ], + "this_delivery": "一个人物窗通过FLIP连贯移动,背景共同推进;减少动效与隐藏页暂停。" + }, + { + "id": "VIS-008", + "meaning": "内容采用透光浮层,背后保留空间光影,文字清晰可读。", + "source_comment_ids": [ + "01a15f09-db1e-705c-8baf-cde63c7651fb", + "01a15f1f-5a71-783c-a458-b326a0073d69" + ], + "this_delivery": "日子/回忆/设置/历史都用主题透光阅读浮层,原生dialog管理焦点。" + }, + { + "id": "VIS-009", + "meaning": "现代轻盈、字形简洁、标题克制,正文易读。", + "source_comment_ids": [ + "01a15f09-db1e-705c-8baf-cde63c7651fb", + "01a15f1f-5a71-783c-a458-b326a0073d69" + ], + "this_delivery": "沿用30px轻标题和轻盈字体,正文清楚。" + }, + { + "id": "VIS-010", + "meaning": "少量微光集中于关键操作和选中状态,两主题各有强调色。", + "source_comment_ids": [ + "01a15f09-db1e-705c-8baf-cde63c7651fb", + "01a15f1f-5a71-783c-a458-b326a0073d69" + ], + "this_delivery": "微光仅集中于关键入口与选中状态。" + }, + { + "id": "VIS-011", + "meaning": "人物平时作为空间中独立视窗;交流时自然放大。已认可的人物位置、分量与首页文字分量沿用。", + "source_comment_ids": [ + "01a15f09-db1e-705c-8baf-cde63c7651fb", + "01a15f1f-5a71-783c-a458-b326a0073d69" + ], + "this_delivery": "右侧27vw拱窗与14vw右边距,恢复获批取景;交流时放大。" + }, + { + "id": "VIS-012", + "meaning": "底部小巧透光导航,图标配简短文字,选中亮起微光。", + "source_comment_ids": [ + "01a15f09-db1e-705c-8baf-cde63c7651fb", + "01a15f1f-5a71-783c-a458-b326a0073d69" + ], + "this_delivery": "底部四入口、图标与简短文字,两主题同布局。" + }, + { + "id": "VIS-013", + "meaning": "交流展开后以人物为主,只呈现当前一两句对话;完整记录按需展开,文字输入和语音操作均保留。", + "source_comment_ids": [ + "01a15f09-db1e-705c-8baf-cde63c7651fb", + "01a15f1f-5a71-783c-a458-b326a0073d69" + ], + "this_delivery": "当前一句,前后翻看,全文/历史按需展开,长回复完整保留;细节仍待用户验收。" + }, + { + "id": "UX-001", + "meaning": "手机对话不被人物、导航、底部区域遮挡,长句和键盘弹出时仍能阅读与输入;等效视口测试不能冒充真机验证。", + "source_comment_ids": [ + "01a162eb-1eab-7dad-8eff-66e0954f5e0b", + "01a16353-c93a-7745-8efa-2586f0ea3eee" + ], + "this_delivery": "当前正文实际边界决定剩余人物高度;多尺寸零重叠。键盘只做缩小视口等效验证。" + }, + { + "id": "UX-002", + "meaning": "文字有柔和的进入和退场,流式更新不重复闪烁;动态效果必须实际演示,不以 CSS 存在代替验收。", + "source_comment_ids": [ + "01a162eb-1eab-7dad-8eff-66e0954f5e0b", + "01a16353-c93a-7745-8efa-2586f0ea3eee" + ], + "this_delivery": "退场100ms/进入160ms;同一句追加不重播;真实DOM逐句完整读回并有动态录屏。" + }, + { + "id": "UX-003", + "meaning": "记录、详情、管理、首建等滚动区域与两套主题协调,保留清晰可操作性。", + "source_comment_ids": [ + "01a162eb-1eab-7dad-8eff-66e0954f5e0b", + "01a16353-c93a-7745-8efa-2586f0ea3eee" + ], + "this_delivery": "全文、记录、设置与日子同用主题scrollbar;两主题实际截图。" + }, + { + "id": "UX-005", + "meaning": "用户与实际起名的伴侣身份明确,当前对话与完整记录一致,不只依靠位置或颜色猜。", + "source_comment_ids": [ + "01a162eb-1eab-7dad-8eff-66e0954f5e0b", + "01a16353-c93a-7745-8efa-2586f0ea3eee" + ], + "this_delivery": "每句显示你或实际演示名字;历史身份相同;长名字验证。" + }, + { + "id": "UX-006", + "meaning": "按已认可的完整前端设计补齐功能和页面结构,未接通能力说明真实边界,不删成空壳也不伪造已运行。", + "source_comment_ids": [ + "01a162eb-1eab-7dad-8eff-66e0954f5e0b", + "01a16353-c93a-7745-8efa-2586f0ea3eee" + ], + "this_delivery": "保留相处/交流/生活回忆/创建管理入口和返回关系;未接功能有说明,R2完整状态及真实接入继续承接。" + }, + { + "id": "AM-001", + "meaning": "等她讲过才显示,覆盖列表、详情、摘要、关联回忆与消息引用;未知分享状态不展示,不能用链接或搜索绕开。真实接入必须在服务器响应前裁剪,前端过滤不能冒充权限控制。", + "source_comment_ids": [ + "01a15f42-2781-700e-b75a-3ae4b023f46c" + ], + "this_delivery": "离线包仅两条已经分享的虚构生活,关联聊天一致;新建临时身份后空生活。没有未分享数据;后端权限仍待R2/R3。" + }, + { + "id": "AM-002", + "meaning": "创建时由用户选择关系,不预选、不替用户决定;以后改变关系保留记忆与信任,底色不变。覆盖旧记录 T-02 中关系初始值仍待定的部分。", + "source_comment_ids": [ + "01a15f42-2781-700e-b75a-3ae4b023f46c" + ], + "this_delivery": "演示首建关系无预选,确认后进入小样;正式完整创建沿用原方案。" + }, + { + "id": "AM-003", + "meaning": "首次创建由用户提供有效名字,主页、交流、首建与设置统一;参考名不能硬编码成真实身份,不额外新增改名流程。", + "source_comment_ids": [ + "01a15f42-2781-700e-b75a-3ae4b023f46c" + ], + "this_delivery": "演示名字由用户输入并校验,在顶部、当前句子和历史复用;不新增正式改名流程。" + }, + { + "id": "GOV-001", + "meaning": "所有新卡、续办卡、设计卡、施工卡、审核卡从同一完整需求入口开始,不依赖会话记忆或最近一条反馈;现有未完成卡补齐对照项。", + "source_comment_ids": [ + "01a1635b-b47c-79ed-ac66-9408c7905af9" + ], + "this_delivery": "完整读取v1.7及原话来源,记录精确提交和对应编号。" + }, + { + "id": "GOV-002", + "meaning": "只有白栖知明确的新决定可以覆盖原要求,保留原话来源、旧结论、新结论及影响;不能把技术困难、阶段减项、智能体建议或演示通过当成需求修改。", + "source_comment_ids": [ + "01a1635b-b47c-79ed-ac66-9408c7905af9" + ], + "this_delivery": "没有产品需求变更;分句、速度明确是待用户验收提案。" + }, + { + "id": "GOV-003", + "meaning": "每卡列基准版本及提交位置、关联要求编号、交付验收、未完成承接、需求变更和验证证据;自动检查缺项,人工核对含义,用户验收体验。", + "source_comment_ids": [ + "01a1635b-b47c-79ed-ac66-9408c7905af9" + ], + "this_delivery": "结构化交接、真实截图/录屏/检查与未完成承接;结构检查不代替审美验收。" + }, + { + "id": "GOV-004", + "meaning": "先落实需求继承约束,再制作对话显示和整体沉浸界面的电脑/手机样图与可操作动态小样;小样认可前不替换正式界面,不合并当前产品 PR,不改现有伴侣和聊天数据,不切换队员全局模型。", + "source_comment_ids": [ + "01a1635b-b47c-79ed-ac66-9408c7905af9" + ], + "this_delivery": "独立原型分支,不改正式界面、不合并PR#4、不触碰真实档案和全局认证/模型。" + }, + { + "id": "DEL-001", + "meaning": "前端演示通过只代表该阶段通过;主卡保留追踪完整真实功能,后续接入按已批准 R1–R7 依赖顺序推进。阶段和技术方案不能降低完整需求。", + "source_comment_ids": [ + "01a161a4-842f-7c26-9be0-1812b720976a", + "01a1629c-732f-7559-8417-6f2ea05c7151" + ], + "this_delivery": "主项目不归档,R1修正与R2–R7及口型独立线保留;本卡无部署/合并/真实数据写入。" + } + ], + "initial_read_commit": "97aaefe5fac77e9746a4ce52d3af94adad15efc1" +} diff --git a/prototypes/hel-790/index.html b/prototypes/hel-790/index.html new file mode 100644 index 0000000..b54a388 --- /dev/null +++ b/prototypes/hel-790/index.html @@ -0,0 +1,427 @@ + + +
+ + + +此 刻
安静,有点倦 · 你们最近挺熟络
+ + + +我在。你想说什么?
+此 刻
安静,有点倦 · 你们最近挺熟络
+ + + +我在。你想说什么?
+本小样中的文字均为虚构。内容完整保留;关闭后回到刚才那一句。
'+messages.map(m=>``).join(''); + content.scrollTop=previousScroll; +} +function showHistory(){showSheet('history','你们说过的话','完整记录 · 演示', '');renderHistory();} +function showFull(){ + const current=pages()[state.cursor];if(!current)return; + const m=current.message; + showSheet('full','这一段,慢慢看',`${m.role==='user'?'你':state.name} · 演示全文`,`这里可以滚动读完整段。返回后仍停在刚才那一句。
`); +} +function showDays(memory=false){ + state.memoryTab=memory; + if(state.createdNew){showSheet('days',memory?'我们的回忆':'她的日子','初次见面 · 演示',`刚刚见面,还没有分享过的日子与共同回忆。
真实生活和记忆尚未接入,小样不会自动编出她未分享的经历。
`);return;} + showSheet('days','留在日子里的微光','生活与共同回忆 · 演示',`只放她已经向你分享的事。以下两条都是虚构的演示记录。
${FIXTURES.map((f,i)=>``).join('')}更多真实生活、记忆和成长,等待后续功能接入。
`); +} +function eventDetail(index){ + const f=FIXTURES[index];if(!f)return; + showSheet('event',f.title,'已分享的生活 · 演示',`${f.time}
${f.memory}
演示故事,不是真实的后台生活。
`); +} +function showManage(){ + showSheet('manage','慢慢安排你们的世界','设置 · 演示',`这里只体验入口和操作关系。所有更改只在这次小样中保留。
`); +} +function showInfo(kind){ + const info={ + profile:['她与最初的底色','出生资料在创建后保留为只读底色,每轮重新提供给模型。个性的诠释、少量初始喜好与后来的成长分别保留。','本小样不生成排盘、性格或成长,也不读取真实档案。相关真实能力仍须后续补齐。'], + appearance:['外观素材','替换外观前应先检查素材、预览新旧效果,再明确启用。记忆、生日、关系和成长仍属于同一个她。','本小样只使用已认可的两张参考静帧,没有导入素材或实时口型。'], + backup:['备份与恢复','产品仍需每日自动备份,并支持包含人物、场景、设定与记忆的完整导出和恢复。','备份尚未接入。本小样没有执行或伪装任何导出、备份、恢复操作。'], + services:['语音与视觉观察','语音由你主动开启,结束后停止收音。视觉观察可关闭,过期观察不再当作眼前事实。','本小样不申请麦克风或摄像头权限,不采集声音与影像。'], + }[kind]; + showSheet(kind,info[0],'入口示意 · 尚未接入',`${info[1]}
${info[2]}
${kind==='services'?'':''}`); +} +function showRelationship(){ + showSheet('relationship','你们的关系','演示表单',``); +} +function showCity(){ + showSheet('city','她窗外的城市','城市选择 · 演示',``); +} +function showDisplay(){ + showSheet('display','空间与显示','显示偏好 · 小样',`保留同一布局,切换整片空间的光与材质。
系统的“减少动态效果”同样生效。切换主题不会移动入口。
`); +} +function showRehearsal(){ + showSheet('rehearsal','试试这些相处片段','小样试用 · 全部为演示',`先回到此刻,再和她说话。也可以从下面选择一段情境。
回复分句保留,可手动前后翻看,也可选自动续读。分句方式、停留时间和整体动效都是本次待你验收的交互方案。
只创建临时演示身份,不连接或重置现有伴侣。
人物为获批参考静帧;文字、生活与回忆都是虚构。没有连接模型、语音、摄像头、天气或备份服务。
缩小浏览器高度只能模拟键盘占用后的视口,不能证明真机键盘已通过。电脑与手机两套主题均可操作。
“独立小样 · 演示数据”随时可以再打开这里。
`); +} +function showCreation(){ + showSheet('create','先给她一个名字','初次创建 · 临时演示',``); +} +function showVoice(){ + showSheet('voice','体验语音界面','没有收音的演示',`这里仅演示语音开启、取消与结束的界面。不会申请麦克风权限,也不会播放或识别声音。
`); +} +function runScenario(kind){ + finishClose();openTalk(); + if(kind==='incoming'){ + beginReply('你刚才想和我说什么?','窗边的花开了一点。',()=>streamReply('还有,今天的雨声很轻。我想把这片安静也分一点给你。')); + }else if(kind==='long')beginReply('慢慢讲,我想听听你今天的想法。',LONG); + else if(kind==='waiting')beginReply('可以和我多说一会儿吗?',LONG); + else beginReply('你在做什么?',SHORT); +} +function applyTheme(theme){ + if(!['moon','fog'].includes(theme))return; + html.dataset.theme=theme;$$('[data-theme]').filter(n=>n.tagName==='BUTTON').forEach(n=>n.setAttribute('aria-pressed',String(n.dataset.theme===theme))); +} + +document.addEventListener('click',e=>{ + const button=e.target.closest('button');if(!button)return; + if(button.dataset.theme){applyTheme(button.dataset.theme);return;} + if(button.dataset.nav){ + const mode=button.dataset.nav; + if(sheet.open){finishClose();} + if(mode==='home'){setMode('home');}else if(mode==='talk')openTalk();else if(mode==='days')showDays();else showManage();return; + } + if(button.dataset.event!==undefined){eventDetail(Number(button.dataset.event));return;} + if(button.dataset.eventHistory!==undefined){ + const index=Number(button.dataset.eventHistory);showHistory(); + content.insertAdjacentHTML('afterbegin',``); + content.querySelector(`[data-life="${index}"]`)?.scrollIntoView({block:'center'});return; + } + if(button.dataset.scenario){runScenario(button.dataset.scenario);return;} + const action=button.dataset.action; + const actions={days:()=>showDays(),memories:()=>showDays(true),manage:showManage,relationship:showRelationship,city:showCity,display:showDisplay,create:showCreation,voice:showVoice,dismiss:closeSheet, + motion:()=>{html.classList.toggle('no-motion');showDisplay();}, + related:()=>{showHistory();const target=[...content.querySelectorAll('.message')][0];target?.scrollIntoView({block:'start'});}, + 'start-voice':()=>{finishClose();openTalk();state.voice=true;document.body.classList.add('has-voice');$('#voice-row').hidden=false;renderSentence(true);} + }; + if(actions[action])actions[action]();else if(['profile','appearance','backup','services'].includes(action))showInfo(action); +}); +$('#start-talk').onclick=()=>openTalk();$('#shared-note').onclick=()=>{openTalk();showHistory();};$('#days-link').onclick=()=>showDays();$('#close-talk').onclick=()=>setMode('home'); +$('#history').onclick=showHistory;$('#read-all').onclick=showFull;$('#close-sheet').onclick=closeSheet;$('#rehearse').onclick=showRehearsal; +$('#home-voice').onclick=showVoice;$('#voice').onclick=showVoice;$('#end-voice').onclick=()=>{state.voice=false;document.body.classList.remove('has-voice');$('#voice-row').hidden=true;cancelReply();}; +$('#previous').onclick=()=>{pauseAuto();movePage(-1);};$('#next').onclick=()=>{pauseAuto();movePage(1);};$('#autoplay').onclick=()=>{state.auto=!state.auto;updateControls(pages());scheduleAuto();};$('#stop').onclick=cancelReply; +$('#composer').addEventListener('submit',e=>{e.preventDefault();const text=$('#draft').value.trim();if(!text)return;$('#draft').value='';beginReply(text,/长|故事|慢慢|完整/.test(text)?LONG:SHORT);}); +$('#draft').addEventListener('keydown',e=>{if(e.key==='Enter'&&!e.shiftKey&&!e.isComposing&&e.keyCode!==229){e.preventDefault();$('#composer').requestSubmit();}}); +$('#draft').addEventListener('focus',pauseAuto); +document.addEventListener('selectionchange',()=>{if(String(getSelection()).length)pauseAuto();}); +sheet.addEventListener('cancel',e=>{e.preventDefault();closeSheet();}); +document.addEventListener('submit',e=>{ + if(e.target.id==='relation-form'){ + e.preventDefault();state.relation=$('#relation').value;state.boundaries=$('#boundaries').value;$('#form-status').textContent='演示选择已确认。记忆和底色保持原样。'; + }else if(e.target.id==='city-form'){ + e.preventDefault();$('.weather').innerHTML=`${escapeHTML($('#city').value)} · 小雨 14° 示例`;$('#form-status').textContent='已保存演示选择;这里没有查询真实天气。'; + }else if(e.target.id==='create-form'){ + e.preventDefault();const name=$('#new-name').value.trim(),relation=$('#new-relation').value; + if(!name||Array.from(name).length>20||/[<>\x00-\x1f\x7f]/.test(name)||!relation){$('#creation-error').textContent='名字请用 1–20 字,不含尖括号和控制符,并选择关系。';return;} + cancelReply();messages=[];state.createdNew=true;state.turn++;messages.push({id:nextId++,turn:state.turn,role:'her',text:'你好。很高兴在这里见到你。',status:'complete'});state.cursor=0;state.relation=relation;setName(name);finishClose();openTalk(); + } +}); +document.addEventListener('keydown',e=>{ + html.classList.add('keyboard-action'); + if(e.key==='Escape'&&!sheet.open&&state.mode==='talk'){setMode('home');$('#start-talk').focus();} +}); +document.addEventListener('pointerdown',()=>html.classList.remove('keyboard-action')); +document.addEventListener('visibilitychange',()=>{ + document.body.classList.toggle('suspended',document.hidden); + if(document.hidden)pauseAuto(); +}); +function fitViewport(){ + const viewport=window.visualViewport,h=viewport?.height||innerHeight,t=viewport?.offsetTop||0; + html.style.setProperty('--view-h',`${h}px`);html.style.setProperty('--view-top',`${t}px`); + document.body.classList.toggle('compact',h<610); + document.body.classList.toggle('micro',h<400); + // Keep the same content offset when wrapping changes; never drop characters. + const current=pages()[state.cursor];const anchor=current?{id:current.message.id,offset:chunks(current.message.text).slice(0,current.index).join('').length}:null; + requestAnimationFrame(()=>{ + if(anchor){const list=pages();let consumed=0;for(let i=0;i