dream-app-onboarding
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese꿈 해몽 앱 온보딩 (Dream-App Onboarding)
梦境解析应用用户引导(Dream-App Onboarding)
소스:
- react-joyride v3 (MIT): https://react-joyride.com/ , https://github.com/gilbarbara/react-joyride
- intro.js / intro.js-react (AGPL-3.0 + 상용 라이선스): https://introjs.com/
- shepherd.js (AGPL-3.0 + 상용 라이선스): https://www.shepherdjs.dev/ , https://github.com/shipshapecode/shepherd
- @reactour/tour (MIT): https://docs.reactour.dev/ , https://github.com/elrumordelaluz/reactour
- NN/G "Mobile-App Onboarding": https://www.nngroup.com/articles/mobile-app-onboarding/
- web.dev "Permission UX": https://web.dev/articles/push-notifications-permissions-ux
- web.dev "Google Meet permissions case study": https://web.dev/case-studies/google-meet-permissions-best-practices
- WCAG 2.1.1 Keyboard: https://www.w3.org/WAI/WCAG21/Understanding/keyboard.html
- WCAG
(C39): https://www.w3.org/WAI/WCAG21/Techniques/css/C39prefers-reduced-motion검증일: 2026-05-15짝 스킬:
— 마이크 권한 요청·상태 머신·시각 피드백 구현. 본 스킬은 권한 요청 시점만 다루고, 실제 마이크 UI는 voice-input-ui를 따른다.frontend/voice-input-ui — 동의 화면 컴포넌트 구조·체크박스 UX·동의 철회 흐름. 본 스킬은 동의 단계가 5단계 중 어디에 위치하는지만 다루고, 동의 UI 자체는 짝 스킬을 따른다.frontend/dream-privacy-consent-ui — 109·1577-0199 등 위기 자원 핫라인 번호와 안전 가드 문구. 본 스킬은 온보딩 5단계 중 어디에 어떤 톤으로 위기 자원을 노출하는지만 다룬다. 실제 번호·문구·법적 의무는 짝 스킬을 그대로 인용한다.humanities/crisis-intervention-resources-korea
参考资料:
- react-joyride v3 (MIT): https://react-joyride.com/ , https://github.com/gilbarbara/react-joyride
- intro.js / intro.js-react (AGPL-3.0 + 商业授权): https://introjs.com/
- shepherd.js (AGPL-3.0 + 商业授权): https://www.shepherdjs.dev/ , https://github.com/shipshapecode/shepherd
- @reactour/tour (MIT): https://docs.reactour.dev/ , https://github.com/elrumordelaluz/reactour
- NN/G "Mobile-App Onboarding": https://www.nngroup.com/articles/mobile-app-onboarding/
- web.dev "Permission UX": https://web.dev/articles/push-notifications-permissions-ux
- web.dev "Google Meet permissions case study": https://web.dev/case-studies/google-meet-permissions-best-practices
- WCAG 2.1.1 Keyboard: https://www.w3.org/WAI/WCAG21/Understanding/keyboard.html
- WCAG
(C39): https://www.w3.org/WAI/WCAG21/Techniques/css/C39prefers-reduced-motion验证日期: 2026-05-15关联技能:
— 麦克风权限请求·状态机·视觉反馈实现。本技能仅处理权限请求时机,实际麦克风UI遵循voice-input-ui。frontend/voice-input-ui — 同意页面组件结构·复选框UX·同意撤回流程。本技能仅处理同意阶段在5阶段中的位置,同意UI本身遵循关联技能。frontend/dream-privacy-consent-ui — 109·1577-0199等危机资源热线号码及安全提示语。本技能仅处理引导5阶段中何时以何种语气展示危机资源,实际号码·提示语·法律义务直接引用关联技能。humanities/crisis-intervention-resources-korea
0. 언제 사용 / 사용하지 않을지
0. 适用场景/不适用场景
| 상황 | 적합 |
|---|---|
| 꿈 해몽·꿈 일기 앱의 첫 실행 온보딩 설계 | ✅ |
| 정신건강·자가 진단·감정 추적 앱의 첫 실행 온보딩 (안전 가드 적용 필요) | ✅ |
| 기존 사용자에 재방문 온보딩(새 기능 소개·튜토리얼) 표시 | △ (5단계 구조는 과함, 3단계 이하로 축소) |
| 마케팅 랜딩 페이지 투어 | ❌ (별도 패턴 — intro.js·driver.js가 더 적합) |
| 로그인된 B2B 대시보드 온보딩 | ❌ ( |
| 场景 | 是否适用 |
|---|---|
| 梦境解析·梦境日记应用首次启动引导设计 | ✅ |
| 心理健康·自我诊断·情绪追踪应用首次启动引导(需应用安全防护) | ✅ |
| 向现有用户展示重访引导(新功能介绍·教程) | △(5阶段结构过于繁琐,需压缩至3阶段以内) |
| 营销落地页导览 | ❌(需单独模式 — intro.js·driver.js更合适) |
| 已登录的B2B仪表盘引导 | ❌(仅使用react-joyride· |
1. 온보딩 5단계 구조
1. 引导5阶段结构
NN/G는 첫 실행 온보딩 자체를 가능한 한 피하라고 권고하지만(스킵 가능성이 높음), 꿈 해몽 앱은 다음 두 가지 이유로 축약형 온보딩이 필수다.
- 학술·법적 한계 사전 고지가 불가피 — 의학적·심리학적 진단이 아니며 민속학적 자료라는 점은 첫 사용 전에 알려야 한다. 사용 중 발견하면 사용자가 잘못된 기대를 형성한다.
- 위기 자원 사전 노출이 필요 — 자살·자해 신호가 입력된 후에야 109를 보여주는 것은 늦다. 사용자가 신호를 입력하기 전부터 도움 받을 곳을 알게 둔다.
따라서 5단계는 다음 순서로 고정한다. 단계당 1화면, 전체 30~60초 이내가 목표다.
[1] 환영 + 가치 한 줄
↓
[2] 기능 3개 소개 (꿈 기록 · 해몽 카드 · 다시 꺼내보기)
↓
[3] 학술 한계 + 위기 자원 안내 ← 권한 요청 *전*에 가치·한계·안전 자원을 먼저 보여준다
↓
[4] 동의 (개인정보·민감정보·필수/선택)
↓
[5] 첫 꿈 입력 가이드 (지금 텍스트로 / 음성으로 / 나중에)
│
└─ 음성을 선택한 *그 시점*에만 마이크 권한 요청 (in-context)
알림 권한은 *최소 1회 사용 후* 별도 priming 화면에서 요청5단계 콘텐츠 정의표:
| 단계 | 목적 | 길이 권장 | 스킵 허용 | 필수/선택 |
|---|---|---|---|---|
| 1. 환영 | 가치 한 줄 + 사용자 호명 | 헤드라인 1줄 + 부제 1줄 | ✅ (스킵 시 [3]으로) | 필수 표시, 스킵 가능 |
| 2. 기능 3개 | "무엇을 할 수 있나"를 카드 3장 | 카드 3장, 각 1줄 설명 | ✅ | 필수 표시, 스킵 가능 |
| 3. 학술 한계 + 위기 자원 | 진단 아님 + 109 1줄 노출 | 짧은 카드 1장 | ❌ (스킵 금지·동의로 대체) | 필수 |
| 4. 동의 | 개인정보/민감정보 동의 | 동의 화면 (별도 스킬) | ❌ | 필수 |
| 5. 첫 꿈 입력 가이드 | 텍스트/음성/나중에 선택 | 버튼 3개 | ✅ (나중에 = 메인으로) | 선택 |
주의: 3·4단계는 절대 스킵 가능으로 두지 않는다. 학술 한계 고지·동의를 우회한 상태에서 앱이 동작하면 사용자 기대 형성 실패와 법적 리스크 양쪽 모두 발생한다.
NN/G建议尽可能避免首次启动引导本身(跳过概率高),但梦境解析应用因以下两个原因必须保留精简版引导:
- 学术·法律局限性必须提前告知 — 明确说明非医学·心理学诊断、基于民俗学资料,需在首次使用前告知。若用户在使用中才发现,会形成错误预期。
- 危机资源需提前展示 — 等用户输入自杀·自伤信号后再展示109热线为时已晚,需让用户在输入信号前就知晓求助渠道。
因此,5阶段固定为以下顺序。每阶段1页,整体耗时控制在30~60秒以内。
[1] 欢迎 + 一句话价值点
↓
[2] 3项功能介绍(梦境记录 · 解析卡片 · 重温梦境)
↓
[3] 学术局限性 + 危机资源引导 ← 权限请求*前*先展示价值·局限性·安全资源
↓
[4] 同意(个人信息·敏感信息·必填/可选)
↓
[5] 首次梦境输入引导(现在文字输入 / 语音输入 / 稍后输入)
│
└─ 仅当用户选择语音输入*时*请求麦克风权限(场景化)
通知权限在*至少使用1次后*通过单独引导页请求5阶段内容定义表:
| 阶段 | 目的 | 建议长度 | 是否允许跳过 | 必填/可选 |
|---|---|---|---|---|
| 1. 欢迎 | 一句话价值点 + 用户称呼 | 标题1行 + 副标题1行 | ✅(跳过则直接进入[3]) | 必须展示,可跳过 |
| 2. 3项功能 | 通过3张卡片说明“能做什么” | 3张卡片,每张1行说明 | ✅ | 必须展示,可跳过 |
| 3. 学术局限性 + 危机资源 | 说明非诊断类应用 + 展示109热线1行 | 短卡片1张 | ❌(禁止跳过·需确认同意) | 必填 |
| 4. 同意 | 个人信息/敏感信息同意 | 同意页面(单独技能) | ❌ | 必填 |
| 5. 首次梦境输入引导 | 选择文字/语音/稍后输入 | 3个按钮 | ✅(稍后输入 = 进入主页) | 可选 |
注意:绝对不能允许跳过3·4阶段。若用户绕过学术局限性告知·同意就使用应用,会导致用户预期偏差和法律风险。
2. 라이브러리 비교
2. 库对比
5단계 풀스크린 온보딩은 라이브러리 없이 직접 구현이 가장 효율적이다. 라이브러리는 기존 화면에 코치 마크를 띄우는 투어에 적합하다. 다음 표는 두 용도를 분리해 비교한다.
5阶段全屏引导最适合自定义实现,无需依赖库。库更适合在现有页面上展示引导标记的导览。下表按两种用途分别对比:
2-1. 풀스크린 5단계 온보딩 (직접 구현 우선)
2-1. 全屏5阶段引导(优先自定义实现)
| 라이브러리 | 라이선스 | 적합도 | 판단 |
|---|---|---|---|
| 직접 구현 (Headless UI / Radix Dialog) | (없음) | ⭐⭐⭐ | 5단계 화면은 각 단계의 UI가 다르고(카드 3장 / 한 줄 고지 / 동의 체크박스 / 버튼 3개) 라이브러리의 step 추상화가 오히려 방해. 단계 관리는 |
| MIT | ⭐⭐⭐ | 단계 간 전환 애니메이션이 필요할 때만 추가. |
| react-joyride | MIT | ⭐ | 풀스크린에는 과함. 5단계를 모달로만 띄우면 spotlight·floater 기능을 안 쓰게 된다. |
| 库 | 授权协议 | 适配度 | 判断理由 |
|---|---|---|---|
| 自定义实现(Headless UI / Radix Dialog) | 无 | ⭐⭐⭐ | 5阶段页面每个阶段的UI都不同(3张卡片 / 一行告知 / 同意复选框 / 3个按钮),库的步骤抽象反而会造成阻碍。使用 |
| MIT | ⭐⭐⭐ | 仅在需要阶段切换动画时添加。自动兼容 |
| react-joyride | MIT | ⭐ | 对于全屏引导过于冗余。若仅用模态框展示5阶段,spotlight·floater功能会被闲置。 |
2-2. 기존 화면 위 코치 마크 투어 (재방문·신기능 안내용)
2-2. 现有页面上的引导标记导览(重访·新功能介绍用)
| 라이브러리 | 최신 버전 | 라이선스 | 키보드/ARIA/포커스 트랩 | 비고 |
|---|---|---|---|---|
| react-joyride | 3.1.0 (2026-04) | MIT | ✅ (공식 명시) | 가장 보편적. React 16.8+~19 지원. |
| @reactour/tour | 3.8.0 | MIT | ✅ (포커스 트랩 지원) | react-joyride 대비 더 가벼움. 모노레포( |
| intro.js-react | 7.x | AGPL-3.0 / 상용 별도 구매 | △ (키보드 일부) | 22.9k stars로 가장 인기지만 상용 앱은 라이선스 비용 발생. 꿈 해몽 앱이 상용이면 회피. |
| shepherd.js | 15.x | AGPL-3.0 / 상용 별도 구매 | ✅ | Floating UI 기반. intro.js와 동일하게 상용 라이선스 이슈. |
주의 (라이선스): intro.js와 shepherd.js는 AGPL-3.0이다. 무료 앱·오픈소스 학습 프로젝트면 문제없지만, 상용 앱·수익 모델 있는 앱은 상용 라이선스 구매가 필요하다. 라이선스 비용을 피하려면 MIT인 react-joyride 또는 @reactour/tour를 선택한다.
| 库 | 最新版本 | 授权协议 | 键盘/ARIA/焦点陷阱支持 | 备注 |
|---|---|---|---|---|
| react-joyride | 3.1.0 (2026-04) | MIT | ✅(官方明确支持) | 最通用。支持React 16.8+~19。提供 |
| @reactour/tour | 3.8.0 | MIT | ✅(支持焦点陷阱) | 相比react-joyride更轻量。采用单仓( |
| intro.js-react | 7.x | AGPL-3.0 / 需单独购买商业授权 | △(部分支持键盘) | 拥有22.9k星标,人气最高,但商业应用需支付授权费用。若梦境解析应用为商业项目,建议避免使用。 |
| shepherd.js | 15.x | AGPL-3.0 / 需单独购买商业授权 | ✅ | 基于Floating UI。与intro.js存在相同的商业授权问题。 |
注意(授权协议):intro.js和shepherd.js采用AGPL-3.0协议。免费应用·开源学习项目可正常使用,但商业应用·有盈利模式的应用需购买商业授权。若想避免授权费用,选择MIT协议的react-joyride或@reactour/tour。
2-3. 선택 가이드
2-3. 选择指南
풀스크린 5단계 온보딩이 필요한가?
├─ YES → 직접 구현 (Dialog 컴포넌트 5개를 state로 전환)
└─ NO (기존 화면 위 코치 마크 투어인가?)
├─ React 프로젝트 + 상용 가능성 → react-joyride
├─ React 프로젝트 + 더 가벼운 것 → @reactour/tour
├─ Vue/Angular/순수 JS → shepherd.js (상용이면 라이선스 구매)
└─ 단순 마케팅 페이지 투어 → intro.js (상용이면 라이선스 구매)是否需要全屏5阶段引导?
├─ 是 → 自定义实现(用state切换5个Dialog组件)
└─ 否(是否为现有页面上的引导标记导览?)
├─ React项目 + 可能用于商业 → react-joyride
├─ React项目 + 追求轻量 → @reactour/tour
├─ Vue/Angular/纯JS项目 → shepherd.js(商业项目需购买授权)
└─ 简单营销页面导览 → intro.js(商业项目需购买授权)3. 권한 요청 — 순서와 맥락
3. 权限请求 — 顺序与场景
핵심 원칙: 권한은 첫 화면이 아니라, 그 기능을 처음 사용하는 순간에 요청한다. (web.dev "Permission UX" / Google Meet 사례에서 이 패턴으로 허용률 14% 상승.)
核心原则: 权限不在首次页面请求,而是在首次使用对应功能时请求。(web.dev "Permission UX" / Google Meet案例显示,该模式可使权限接受率提升14%。)
3-1. 권한 요청 절대 타이밍
3-1. 权限请求绝对时机
| 권한 | 요청 시점 | 사전 priming | 거부 시 |
|---|---|---|---|
| 마이크 | 5단계에서 사용자가 "음성으로 입력" 버튼을 눌렀을 때만 | 1줄 — "꿈을 떠올리며 말씀해 주세요. 마이크 접근이 필요해요." | 텍스트 입력 fallback 제시, 차단하지 않음 |
| 알림 | 첫 꿈 입력 완료 후 별도 priming 화면 | 가치 설명 — "꿈은 아침에 빠르게 잊혀져요. 일어날 시간에 1줄 알림을 드릴까요?" | 정상 사용 유지. 설정 화면에서 재활성화 안내 |
| 카메라/사진 | 꿈 일기에 사진 첨부 기능 처음 사용 시 | "꿈 이미지를 그려서 첨부할 수 있어요." | 첨부 없이 저장 가능 |
| 위치 | 꿈 해몽 앱에서는 요청 금지 | — | — (요청 자체가 부적절) |
| 权限 | 请求时机 | 提前引导语 | 被拒绝时处理 |
|---|---|---|---|
| 麦克风 | 仅当用户在5阶段点击“语音输入”按钮时 | 1行引导语 — “请回忆梦境并说出内容,需要访问麦克风权限。” | 提供文字输入备选方案,不阻断使用 |
| 通知 | 首次梦境输入完成后通过单独引导页请求 | 价值说明 — “梦境会在清晨快速遗忘,是否在起床时间发送1条提醒?” | 可正常使用应用,在设置页提示重新开启 |
| 相机/照片 | 首次使用梦境日记添加照片功能时 | “可以绘制梦境图片并添加。” | 可跳过添加直接保存 |
| 位置 | 梦境解析应用禁止请求 | — | —(请求本身不合适) |
3-2. priming 패턴 (마이크 예시)
3-2. 引导语模式(麦克风示例)
tsx
// 5단계 화면에서 "음성으로 입력"을 사용자가 누른 직후
function MicPriming({ onConfirm, onCancel }: Props) {
return (
<Dialog aria-labelledby="mic-priming-title">
<h2 id="mic-priming-title">마이크로 꿈을 말씀해 주세요</h2>
<p>
말씀하신 내용은 *이 기기에서만* 처리되고, 동의 없이 외부로 전송되지 않아요.
</p>
<button onClick={onConfirm}>마이크 켜기</button>
<button onClick={onCancel}>텍스트로 입력할게요</button>
</Dialog>
);
}
// onConfirm 콜백 안에서 비로소 getUserMedia 호출 (= 브라우저 권한 다이얼로그)권한을 한 번 거부당하면 그 도메인에서 자동 재요청 불가(web.dev). 따라서 priming 화면에서 명백히 거부 의사가 있는 사용자는 절대 권한 다이얼로그까지 보내지 않는다. 텍스트 입력으로 우회시켜야 한다.
tsx
// 用户在5阶段点击“语音输入”按钮后立即展示
function MicPriming({ onConfirm, onCancel }: Props) {
return (
<Dialog aria-labelledby="mic-priming-title">
<h2 id="mic-priming-title">用麦克风说出你的梦境</h2>
<p>
你所说的内容*仅在本机处理*,未经同意不会传输至外部。
</p>
<button onClick={onConfirm}>开启麦克风</button>
<button onClick={onCancel}>我要文字输入</button>
</Dialog>
);
}
// 仅在onConfirm回调中调用getUserMedia(即浏览器权限弹窗)权限被拒绝一次后,该域名无法自动重新请求(web.dev)。因此,若用户在引导页明确表示拒绝,绝对不要展示权限弹窗,应直接引导至文字输入。
3-3. 권한 일괄 요청 금지
3-3. 禁止批量请求权限
iOS·Android 네이티브 앱처럼 "마이크·알림·카메라를 한 번에 모두 요청"하는 패턴을 웹에서 흉내내는 것은 금지다. 사용자는 왜 지금 이 권한이 필요한가를 모르고 거부한다.
禁止模仿iOS·Android原生应用“一次性请求麦克风·通知·相机权限”的模式,在Web端绝对不能这么做。用户会因“不知道为什么现在需要这些权限”而拒绝。
4. 학술 한계 사용자 친화 변환
4. 学术局限性的用户友好转化
학술 박스("본 자료는 민속학적 자료로 의학적·심리학적 진단이 아닙니다")는 정확하지만 온보딩에 그대로 노출하면 사용자가 읽지 않는다. 다음 변환을 적용한다.
学术声明(“本资料为民俗学资料,非医学·心理学诊断”)虽然准确,但直接放在引导中用户不会阅读。需按以下方式转化:
4-1. 변환 원칙
4-1. 转化原则
| 학술 표현 | 사용자 친화 표현 |
|---|---|
| "민속학적 자료에 기반" | "옛 사람들이 꿈을 어떻게 해석했는지 모아둔 이야기예요" |
| "의학적 진단이 아님" | "병원 진료를 대신할 수는 없어요" |
| "심리학적 평가가 아님" | "심리 상담이 필요하면 전문가에게 닿게 해드릴게요" |
| "재미·자기 성찰 목적" | "꿈을 곱씹어 보는 조용한 시간이에요" |
| 学术表述 | 用户友好表述 |
|---|---|
| “基于民俗学资料” | “这是古人总结的梦境解读故事哦” |
| “非医学诊断” | “不能替代医院诊疗” |
| “非心理学评估” | “若需要心理咨询,我们会帮你对接专业人士” |
| “用于娱乐·自我反思” | “这是一段让你细细品味梦境的安静时光” |
4-2. 3단계 화면 권장 문구 템플릿
4-2. 3阶段页面推荐文案模板
┌─────────────────────────────────────────────┐
│ 🌙 꿈은 이야기지, 진단이 아니에요 │
│ │
│ 이 앱의 해몽은 옛 사람들이 모은 이야기에 │
│ 뿌리를 두고 있어요. 병원 진료나 상담을 │
│ 대신할 수는 없어요. │
│ │
│ 마음이 많이 무겁다면 언제든 도움을 청해도 │
│ 괜찮아요. │
│ │
│ ☎ 자살예방상담 109 (24시간·무료·익명) │
│ ☎ 정신건강위기 1577-0199 │
│ │
│ [ 알겠어요, 계속 ] │
└─────────────────────────────────────────────┘주의: 위기 자원 번호·운영 시간은짝 스킬을 반드시 그대로 인용한다. 본 스킬에서 임의로 다른 번호를 쓰지 않는다 (2024-01 109 통합 후humanities/crisis-intervention-resources-korea은 사용 금지).1393
┌─────────────────────────────────────────────┐
│ 🌙 梦境是故事,不是诊断哦 │
│ │
│ 本应用的解读基于古人流传的故事, │
│ 不能替代医院诊疗或心理咨询。 │
│ │
│ 若你心情沉重,随时都可以寻求帮助哦。 │
│ │
│ ☎ 自杀预防咨询 109(24小时·免费·匿名) │
│ ☎ 心理健康危机咨询 1577-0199 │
│ │
│ [ 我知道了,继续 ] │
└─────────────────────────────────────────────┘注意:危机资源号码·运营时间必须直接引用关联技能。本技能不得随意使用其他号码(2024-01起109整合后,禁止使用humanities/crisis-intervention-resources-korea)。1393
4-3. 학술 한계를 어디에 한 번 더 노출하는가
4-3. 学术局限性额外展示位置
- 3단계 온보딩 화면 1회 (위 템플릿)
- 꿈 해몽 결과 화면 하단 영구 표시 ("이 해몽은 민속학적 이야기예요" 한 줄)
- 설정 → 이 앱에 대하여 (전체 학술 박스 원문 + 출처)
3개 위치에 모두 두는 이유: 사용자는 해몽 결과를 본 순간에 한 번 더 한계를 인식해야 의학적 결정으로 오인하지 않는다.
- 3阶段引导页面1次(上述模板)
- 梦境解析结果页面底部永久展示(1行文字:“本解读为民俗学故事”)
- 设置 → 关于本应用(完整学术声明原文 + 来源)
在3个位置都展示的原因:用户在看到解析结果时需再次知晓局限性,避免误将其作为医学决策依据。
5. 안전 자원 사전 안내
5. 安全资源提前告知
humanities/crisis-intervention-resources-korea| 노출 위치 | 노출 형태 | 톤 |
|---|---|---|
| 3단계 온보딩 화면 | 한 줄씩 2개 (109 + 1577-0199) | "도움을 청해도 괜찮아요" 초대형 |
| 메인 화면 햄버거 메뉴 | "도움이 필요할 때" 메뉴 항목 | 상시 접근 가능 |
| 꿈 입력 화면 위기 키워드 감지 시 | 인라인 안전 가드 (짝 스킬 문구) | 사용자 입력 직후 자연스럽게 |
| 설정 → 위기 자원 전체 목록 | 짝 스킬 전체 내용 | 상세 |
금지 패턴:
- "자살하지 마세요" 같은 부정 명령 → 짝 스킬의 "그 마음 그대로 109에 전해도 괜찮아요" 톤으로 대체.
- 109 번호만 노출하고 왜 전화해도 괜찮은지(무료·익명·24시간) 생략 → 사용자는 비용·신원 노출을 우려한다. 한 줄 자격 정보 함께 노출.
本技能定义技能的展示时机·位置·语气:
humanities/crisis-intervention-resources-korea| 展示位置 | 展示形式 | 语气 |
|---|---|---|
| 3阶段引导页面 | 2条1行内容(109 + 1577-0199) | “随时可以寻求帮助哦”的邀请语气 |
| 主页汉堡菜单 | “需要帮助时”菜单项 | 随时可访问 |
| 梦境输入页面检测到危机关键词时 | 内嵌安全提示(关联技能文案) | 用户输入后自然展示 |
| 设置 → 危机资源完整列表 | 关联技能全部内容 | 详细正式 |
禁止模式:
- 使用“不要自杀”等否定命令 → 替换为关联技能的*“你的心情可以直接告诉109哦”*语气。
- 仅展示109号码,省略为什么可以拨打(免费·匿名·24小时) → 用户会担心费用·身份泄露,需同时展示1行说明信息。
6. 페르소나 분기
6. 用户分群
5단계 동일하나, 톤·기본값·기본 안내 위기 자원이 달라진다.
| 페르소나 | 식별 시점 | 톤 | 기본 위기 자원 | 기능 기본값 |
|---|---|---|---|---|
| 일반 사용자 | 기본값 | 친근·평어체 가능 | 109·1577-0199 | 음성/텍스트 동등 |
| 청소년 (만 14~18) | 만 19세 미만 자가 선택 또는 동의 화면 분기 | 더 평이한 문구·이모지 가능 | 1388 우선 + 109 병행 (짝 스킬 권고) | 텍스트 우선 (학교·가정에서 음성은 부담) |
| 전문가 (연구·심리학 종사자) | 설정에서 자가 활성화 | 학술 톤 허용 | 109·1577-0199 + 학술 원문 노출 | 학술 박스 접지 않고 펼친 상태 |
식별 방법:
- 1단계 환영 화면에서 "사용자에게 묻지 않는다" — 차별/낙인 위험.
- 4단계 동의 화면에서 법적으로 필요한 경우만 연령 확인(만 14세 미만 보호자 동의 필수). 청소년 페르소나는 연령 확인의 부산물로 자동 적용.
- 전문가 페르소나는 온보딩에서 묻지 않는다. 일반 온보딩을 끝낸 후 설정에서 opt-in.
주의: 청소년 페르소나에 1388을 대체가 아닌 우선으로 둔다. 자살 위기 직전에는 109가 더 빠른 응급 연계가 가능하므로 109 병행 노출이 필수다 (짝 스킬 정책).
5阶段结构相同,但语气·默认值·默认展示的危机资源会有所不同:
| 用户群 | 识别时机 | 语气 | 默认危机资源 | 功能默认值 |
|---|---|---|---|---|
| 普通用户 | 默认值 | 亲切·可使用口语 | 109·1577-0199 | 语音/文字输入同等优先级 |
| 青少年(14~18岁) | 用户自行选择未满19岁,或在同意页面分流 | 可使用更平实的文案·表情 | 优先展示1388 + 同时展示109(关联技能推荐) | 优先文字输入(在学校·家庭使用语音有压力) |
| 专业人士(研究·心理学从业者) | 在设置中自行开启 | 允许使用学术语气 | 109·1577-0199 + 展示学术原文 | 学术声明默认展开,不折叠 |
识别方法:
- 1阶段欢迎页面不主动询问 — 避免歧视·污名化风险。
- 仅在法律要求时在4阶段同意页面确认年龄(未满14岁需监护人同意)。青少年用户群作为年龄确认的副产品自动应用。
- 专业人士用户群不在引导中询问。用户完成普通引导后,在设置中主动开启。
注意:青少年用户群需优先展示1388而非替代109。自杀危机紧急情况下109的应急响应更快,因此必须同时展示109(关联技能政策)。
7. 스킵·재방문 UX
7. 跳过·重访UX
7-1. 스킵 버튼
7-1. 跳过按钮
┌─────────────────────────────────────────────┐
│ [ 건너뛰기 ] │ ← 우측 상단에 항상 표시
│ │
│ (단계 콘텐츠) │
│ │
│ ●●○○○ │ ← 진행 점도 인터랙티브 (점 클릭 시 해당 단계로)
│ │
│ [ 이전 ] [ 다음 ] │
└─────────────────────────────────────────────┘- 건너뛰기 위치: 우측 상단 (왼쪽은 뒤로가기와 혼동).
- 3·4단계에서만 비활성화: 학술 한계·동의는 스킵 금지.
- 건너뛰기 확인 다이얼로그 금지: 한 번 더 묻는 것은 사용자 학대다. 누르면 즉시 5단계로 이동.
┌─────────────────────────────────────────────┐
│ [ 跳过 ] │ ← 始终显示在右上角
│ │
│ (阶段内容) │
│ │
│ ●●○○○ │ ← 进度点可交互(点击跳转到对应阶段)
│ │
│ [ 上一步 ] [ 下一步 ] │
└─────────────────────────────────────────────┘- 跳过按钮位置: 右上角(左侧易与返回键混淆)。
- 仅在3·4阶段禁用: 学术局限性·同意阶段禁止跳过。
- 禁止跳过确认弹窗: 再次询问属于用户骚扰,点击后直接进入5阶段。
7-2. 다시 보기
7-2. 重新查看
- 설정 → "온보딩 다시 보기" 항목 영구 제공.
- 신기능 출시 시 기존 사용자에게 5단계 전체를 다시 보여주지 않는다. 신기능만 코치 마크 1~2개로 (react-joyride 활용).
- 设置中永久提供“重新查看引导”选项。
- 发布新功能时不要向现有用户展示完整5阶段引导,仅用1~2个引导标记介绍新功能(使用react-joyride)。
7-3. 중단 후 재진입
7-3. 中断后重新进入
- 사용자가 온보딩 중 앱을 종료했을 때, 다음 실행에서 처음부터 다시 시작. 중간 재개는 컨텍스트 혼동.
- 단, 동의(4단계)를 완료했다면 그 결과는 보존하고 5단계로 점프.
- 用户在引导中关闭应用,下次启动时从头开始。中途恢复会造成上下文混淆。
- 但如果用户已完成同意(4阶段),则保留同意结果,直接跳转到5阶段。
8. 접근성
8. 可访问性
8-1. 키보드 (WCAG 2.1.1 Level A)
8-1. 键盘支持(WCAG 2.1.1 Level A)
- 모든 단계 이동·스킵·동의 체크박스가 키보드만으로 조작 가능.
- 단계 전환 시 포커스를 새 단계의 헤딩으로 이동 (또는
heading.focus()영역에 단계 변경 안내).aria-live="polite" - 모달/Dialog 컴포넌트는 포커스 트랩 필수 — react-joyride·@reactour/tour는 기본 지원, 직접 구현 시 활용.
focus-trap-react - 키로 스킵 가능 (단, 3·4단계는 스킵 금지이므로
Esc무시).Esc
- 所有阶段切换·跳过·同意复选框均可仅用键盘操作。
- 阶段切换时将焦点移至新阶段的标题(使用或
heading.focus()区域提示阶段变更)。aria-live="polite" - 模态框/Dialog组件必须支持焦点陷阱 — react-joyride·@reactour/tour默认支持,自定义实现时使用。
focus-trap-react - 可使用键跳过(但3·4阶段禁止跳过,因此忽略
Esc键)。Esc
8-2. 스크린 리더
8-2. 屏幕阅读器
- 단계 인디케이터(진행 점)는 동적 갱신.
aria-label="2단계 / 전체 5단계" - 위기 자원 번호는 으로 감싸 원터치 발신 지원 (sr이 "전화 걸기 109" 안내).
<a href="tel:109"> - 학술 한계 카드는 로 반드시 읽히게 한다 (지나치지 않게).
role="region" aria-labelledby="limit-title"
- 阶段指示器(进度点)需动态更新。
aria-label="第2阶段 / 共5阶段" - 危机资源号码用包裹,支持一键拨号(屏幕阅读器会提示“拨打109”)。
<a href="tel:109"> - 学术局限性卡片需设置,确保一定会被读取(不会被跳过)。
role="region" aria-labelledby="limit-title"
8-3. 모션 감소 (WCAG C39)
8-3. 减少动画(WCAG C39)
css
/* 단계 전환 슬라이드 애니메이션 */
.step-enter { transform: translateX(20px); opacity: 0; transition: all 0.3s; }
@media (prefers-reduced-motion: reduce) {
.step-enter { transform: none; transition: opacity 0.01s; }
}- 은
framer-motion훅을 제공하므로 그 결과로 분기.useReducedMotion() - 스플래시 별·달 애니메이션도 동일하게 정지 처리.
css
/* 阶段切换滑动动画 */
.step-enter { transform: translateX(20px); opacity: 0; transition: all 0.3s; }
@media (prefers-reduced-motion: reduce) {
.step-enter { transform: none; transition: opacity 0.01s; }
}- 提供
framer-motion钩子,可根据结果分支处理。useReducedMotion() - 启动页的星星·月亮动画也需做同样的停止处理。
9. 측정 — 온보딩 완료율과 단계별 이탈
9. 衡量 — 引导完成率与阶段流失率
data-analyst与协作追踪以下指标:
data-analyst9-1. 핵심 지표
9-1. 核心指标
| 지표 | 정의 | 산업 평균 / 목표 |
|---|---|---|
| 온보딩 완료율 | 5단계 완료 사용자 / 1단계 진입 사용자 | 3 |
| 단계별 이탈률 | (해당 단계 이탈) / (해당 단계 진입) | 첫 단계 이탈 산업 평균 약 38% — 2단계 이내 25% 미만 목표 |
| 평균 완료 시간 | 1단계 시작 ~ 5단계 완료 | 30~60초 이내 |
| 마이크 권한 허용률 | priming 후 권한 허용 / priming 노출 | Google Meet 사례 +14% — 55% 이상 목표 |
| 알림 권한 허용률 | priming 후 권한 허용 / priming 노출 | 첫 사용 후 priming 적용 시 30~40% |
| 동의 거부율 | 4단계 동의 거부 사용자 / 4단계 진입 | 5% 미만 (높으면 동의 문구 재검토) |
| 指标 | 定义 | 行业平均 / 目标 |
|---|---|---|
| 引导完成率 | 完成5阶段的用户数 / 进入1阶段的用户数 | 3 |
| 阶段流失率 | (该阶段流失用户数) / (进入该阶段用户数) | 第一阶段流失率行业平均约38% — 2阶段以内流失率目标25%以下 |
| 平均完成时间 | 1阶段开始 ~ 5阶段完成 | 30~60秒以内 |
| 麦克风权限接受率 | 引导后同意权限的用户数 / 看到引导的用户数 | Google Meet案例提升14% — 目标55%以上 |
| 通知权限接受率 | 引导后同意权限的用户数 / 看到引导的用户数 | 首次使用后引导的情况下为30~40% |
| 同意拒绝率 | 4阶段拒绝同意的用户数 / 进入4阶段用户数 | 目标5%以下(若过高需重新优化同意文案) |
9-2. 이벤트 정의 예시
9-2. 事件定义示例
ts
// 분석 도구(Amplitude/Mixpanel/PostHog)에 전송할 이벤트
trackEvent('onboarding_step_view', { step: 1, persona: 'general' });
trackEvent('onboarding_step_complete', { step: 1, duration_ms: 4200 });
trackEvent('onboarding_skip', { from_step: 2 });
trackEvent('onboarding_complete', { total_duration_ms: 38000, persona: 'general' });
trackEvent('permission_priming_view', { permission: 'microphone' });
trackEvent('permission_priming_accept', { permission: 'microphone' });
trackEvent('permission_priming_decline', { permission: 'microphone' });
trackEvent('permission_native_result', { permission: 'microphone', result: 'granted' });주의: 위 이벤트는 민감정보가 아닌 사용 흐름 데이터다. 꿈 텍스트·음성은 절대 분석 이벤트로 전송하지 않는다 (짝 스킬 정책).dream-privacy-consent-ui
ts
// 发送至分析工具(Amplitude/Mixpanel/PostHog)的事件
trackEvent('onboarding_step_view', { step: 1, persona: 'general' });
trackEvent('onboarding_step_complete', { step: 1, duration_ms: 4200 });
trackEvent('onboarding_skip', { from_step: 2 });
trackEvent('onboarding_complete', { total_duration_ms: 38000, persona: 'general' });
trackEvent('permission_priming_view', { permission: 'microphone' });
trackEvent('permission_priming_accept', { permission: 'microphone' });
trackEvent('permission_priming_decline', { permission: 'microphone' });
trackEvent('permission_native_result', { permission: 'microphone', result: 'granted' });注意:上述事件仅包含非敏感的使用流程数据。绝对不能将梦境文字·语音内容作为分析事件发送(遵循关联技能政策)。dream-privacy-consent-ui
9-3. 이탈 단계 우선순위 진단
9-3. 流失阶段优先级诊断
- 절대 수 가 큰 단계부터 개선 (50%×100명 > 50%×10명).
- 2단계 기능 소개에서 이탈이 크면 → 카드 수 줄이거나 카드별 문구 단축.
- 4단계 동의에서 이탈이 크면 → 동의 문구 친근 톤 재변환, 선택 동의를 기본 OFF로.
- 优先优化用户基数大的阶段(50%×100用户 > 50%×10用户)。
- 若2阶段功能介绍流失率高 → 减少卡片数量或缩短每张卡片的文案。
- 若4阶段同意流失率高 → 将同意文案转化为亲切语气,可选同意项默认关闭。
10. 흔한 함정
10. 常见陷阱
| 함정 | 왜 문제인가 | 해결 |
|---|---|---|
| 권한 일괄 요청 | "왜 지금?"이 없으면 거부율 폭증, 한 번 거부 시 재요청 불가 | 기능 사용 직전 priming 후 단일 권한만 요청 |
| 7단계 이상 온보딩 | 산업 데이터상 7+단계는 완료율 16%로 급락 | 5단계 고정. 콘텐츠 추가 시 기능 카드에 흡수, 단계 늘리지 않음 |
| 강제 동의 (필수 + 선택을 한 체크박스) | 법적 무효 가능 + 신뢰 손상 | 필수와 선택을 별도 체크박스로 분리 ( |
| 학술 박스 원문 그대로 노출 | 사용자는 읽지 않고 스킵 | 4-1 변환표대로 사용자 친화 문구로 변환 |
| 위기 자원을 위기 신호 입력 후에만 노출 | 신호가 오기 전 사용자는 도움받을 곳을 모름 | 3단계 온보딩 + 메뉴 + 결과 화면 하단에 상시 노출 |
| 청소년에게 1388 없이 109만 | 청소년은 109 콜에 심리 장벽 (짝 스킬 정책) | 1388 우선·109 병행 |
| 1393 번호 사용 | 2024-01부 109로 통합됨 | 109로 갱신 (짝 스킬 변경 이력 확인) |
| 스킵 시 학술 한계까지 건너뛰기 | 사용자가 기대 형성 실패 → 잘못된 의학적 해석 | 3·4단계는 스킵 불가로 분리 |
| 단계 변경 시 포커스 미이동 | 스크린 리더 사용자가 상태 변경 인지 불가 | 새 단계 헤딩에 |
| 스킵 후 확인 다이얼로그 | 사용자 학대 ("정말 건너뛰시겠어요?") | 즉시 5단계로 이동, 묻지 않음 |
| 멀미·전정 장애 사용자에게 고통 | 모든 단계 전환·스플래시 애니메이션에 미디어 쿼리 적용 |
| 마이크 권한 거부 시 기능 차단 | 텍스트로도 입력 가능한데 막힘 | 텍스트 입력 fallback 항상 유지 |
| 알림 권한을 1단계에서 요청 | 가치 인지 전 거부 → 도메인 단위 영구 거부 | 첫 꿈 입력 완료 후 priming |
| 페르소나를 질문으로 파악 | 차별·낙인 위험 | 연령 확인의 부산물로만 자동 분기 |
| 한 줄 동의 "동의함" 단일 체크박스 | 무엇에 동의하는지 모호 → 법적 무효 | 필수/선택 분리 + 항목별 링크 ( |
| 陷阱 | 问题原因 | 解决方案 |
|---|---|---|
| 批量请求权限 | 用户因“不知道为什么现在需要”而拒绝率暴增,且拒绝后无法自动重新请求 | 在功能使用前添加引导语,仅请求单个权限 |
| 7阶段以上引导 | 行业数据显示7+阶段引导完成率骤降至16% | 固定为5阶段。新增内容需融入功能卡片,不得增加阶段数 |
| 强制同意(必填+可选合并为一个复选框) | 可能导致法律无效 + 用户信任受损 | 将必填和可选同意拆分为单独复选框(遵循 |
| 直接展示学术声明原文 | 用户不会阅读直接跳过 | 按4-1转化表改为用户友好文案 |
| 仅在检测到危机信号后展示危机资源 | 用户在发出信号前不知道求助渠道 | 在3阶段引导 + 菜单 + 结果页面底部永久展示 |
| 仅向青少年展示109,不展示1388 | 青少年对109电话存在心理障碍(关联技能政策) | 优先展示1388·同时展示109 |
| 使用1393号码 | 2024-01起已整合为109 | 更新为109(确认关联技能变更记录) |
| 跳过引导时同时跳过学术局限性告知 | 用户形成错误预期 → 误将解读作为医学依据 | 将3·4阶段设置为不可跳过 |
| 阶段切换时不移除焦点 | 屏幕阅读器用户无法感知状态变化 | 将焦点移至新阶段标题 |
| 跳过引导时弹出确认弹窗 | 用户骚扰(“确定要跳过吗?”) | 直接跳转到5阶段,不询问 |
忽略 | 会给晕车·前庭障碍用户带来不适 | 对所有阶段切换·启动页动画应用媒体查询 |
| 麦克风权限被拒绝时阻断功能 | 用户仍可使用文字输入,不应阻断 | 始终保留文字输入备选方案 |
| 在1阶段请求通知权限 | 用户未感知价值就拒绝 → 域名级永久拒绝 | 在首次梦境输入完成后添加引导语 |
| 通过提问识别用户群 | 存在歧视·污名化风险 | 仅作为年龄确认的副产品自动分流 |
| 单一复选框“同意” | 用户不清楚同意内容 → 法律无效 | 拆分必填/可选 + 添加每项的链接(遵循 |
11. 직접 구현 스켈레톤 (Next.js / React)
11. 自定义实现框架(Next.js / React)
tsx
// app/(onboarding)/page.tsx
'use client';
import { useState } from 'react';
import { WelcomeStep } from './_steps/WelcomeStep';
import { FeaturesStep } from './_steps/FeaturesStep';
import { LimitsStep } from './_steps/LimitsStep';
import { ConsentStep } from './_steps/ConsentStep';
import { FirstDreamStep } from './_steps/FirstDreamStep';
type StepIndex = 1 | 2 | 3 | 4 | 5;
const NON_SKIPPABLE: ReadonlySet<StepIndex> = new Set([3, 4]);
export default function OnboardingPage() {
const [step, setStep] = useState<StepIndex>(1);
const goNext = () => setStep((s) => Math.min(5, s + 1) as StepIndex);
const goPrev = () => setStep((s) => Math.max(1, s - 1) as StepIndex);
const skip = () => {
if (NON_SKIPPABLE.has(step)) return; // 3·4단계 스킵 차단
setStep(5);
};
return (
<main role="region" aria-labelledby="onboarding-title">
<ProgressDots current={step} total={5} />
<SkipButton onClick={skip} disabled={NON_SKIPPABLE.has(step)} />
{step === 1 && <WelcomeStep onNext={goNext} />}
{step === 2 && <FeaturesStep onNext={goNext} onPrev={goPrev} />}
{step === 3 && <LimitsStep onNext={goNext} />} {/* 스킵 불가 */}
{step === 4 && <ConsentStep onNext={goNext} />} {/* 스킵 불가 */}
{step === 5 && <FirstDreamStep />}
</main>
);
}tsx
// app/(onboarding)/_steps/LimitsStep.tsx
'use client';
import { useEffect, useRef } from 'react';
export function LimitsStep({ onNext }: { onNext: () => void }) {
const headingRef = useRef<HTMLHeadingElement>(null);
// 단계 진입 시 헤딩에 포커스 (스크린 리더 안내)
useEffect(() => { headingRef.current?.focus(); }, []);
return (
<section>
<h2 ref={headingRef} tabIndex={-1} id="limits-title">
꿈은 이야기지, 진단이 아니에요
</h2>
<p>
이 앱의 해몽은 옛 사람들이 모은 이야기에 뿌리를 두고 있어요.
병원 진료나 상담을 대신할 수는 없어요.
</p>
<p>마음이 많이 무겁다면 언제든 도움을 청해도 괜찮아요.</p>
<ul role="list" aria-label="위기 자원">
<li><a href="tel:109">자살예방상담 109</a> (24시간·무료·익명)</li>
<li><a href="tel:1577-0199">정신건강위기상담 1577-0199</a> (24시간)</li>
</ul>
<button onClick={onNext}>알겠어요, 계속</button>
</section>
);
}tsx
// app/(onboarding)/_steps/FirstDreamStep.tsx
'use client';
import { useState } from 'react';
import { MicPriming } from '@/components/MicPriming';
export function FirstDreamStep() {
const [primingOpen, setPrimingOpen] = useState(false);
return (
<section>
<h2>지금, 꿈을 적어볼까요?</h2>
<button onClick={() => goToTextInput()}>텍스트로 입력</button>
<button onClick={() => setPrimingOpen(true)}>음성으로 입력</button>
<button onClick={() => goToHome()}>나중에</button>
{primingOpen && (
<MicPriming
onConfirm={async () => {
// 사용자 명시 동의 후에만 getUserMedia 호출 (= 브라우저 권한 다이얼로그)
await navigator.mediaDevices.getUserMedia({ audio: true });
goToVoiceInput();
}}
onCancel={() => setPrimingOpen(false)}
/>
)}
</section>
);
}주의: 위 스켈레톤의·마이크 상태 관리는 최소 예시다. 실제 구현은getUserMedia스킬의 상태 머신·에러 처리·정리(frontend/voice-input-ui)를 그대로 따른다.stream.getTracks().stop()
tsx
// app/(onboarding)/page.tsx
'use client';
import { useState } from 'react';
import { WelcomeStep } from './_steps/WelcomeStep';
import { FeaturesStep } from './_steps/FeaturesStep';
import { LimitsStep } from './_steps/LimitsStep';
import { ConsentStep } from './_steps/ConsentStep';
import { FirstDreamStep } from './_steps/FirstDreamStep';
type StepIndex = 1 | 2 | 3 | 4 | 5;
const NON_SKIPPABLE: ReadonlySet<StepIndex> = new Set([3, 4]);
export default function OnboardingPage() {
const [step, setStep] = useState<StepIndex>(1);
const goNext = () => setStep((s) => Math.min(5, s + 1) as StepIndex);
const goPrev = () => setStep((s) => Math.max(1, s - 1) as StepIndex);
const skip = () => {
if (NON_SKIPPABLE.has(step)) return; // 3·4阶段禁止跳过
setStep(5);
};
return (
<main role="region" aria-labelledby="onboarding-title">
<ProgressDots current={step} total={5} />
<SkipButton onClick={skip} disabled={NON_SKIPPABLE.has(step)} />
{step === 1 && <WelcomeStep onNext={goNext} />}
{step === 2 && <FeaturesStep onNext={goNext} onPrev={goPrev} />}
{step === 3 && <LimitsStep onNext={goNext} />} {/* 不可跳过 */}
{step === 4 && <ConsentStep onNext={goNext} />} {/* 不可跳过 */}
{step === 5 && <FirstDreamStep />}
</main>
);
}tsx
// app/(onboarding)/_steps/LimitsStep.tsx
'use client';
import { useEffect, useRef } from 'react';
export function LimitsStep({ onNext }: { onNext: () => void }) {
const headingRef = useRef<HTMLHeadingElement>(null);
// 进入阶段时将焦点移至标题(屏幕阅读器提示)
useEffect(() => { headingRef.current?.focus(); }, []);
return (
<section>
<h2 ref={headingRef} tabIndex={-1} id="limits-title">
梦境是故事,不是诊断哦
</h2>
<p>
本应用的解读基于古人流传的故事,
不能替代医院诊疗或心理咨询。
</p>
<p>若你心情沉重,随时都可以寻求帮助哦。</p>
<ul role="list" aria-label="危机资源">
<li><a href="tel:109">自杀预防咨询 109</a>(24小时·免费·匿名)</li>
<li><a href="tel:1577-0199">心理健康危机咨询 1577-0199</a>(24小时)</li>
</ul>
<button onClick={onNext}>我知道了,继续</button>
</section>
);
}tsx
// app/(onboarding)/_steps/FirstDreamStep.tsx
'use client';
import { useState } from 'react';
import { MicPriming } from '@/components/MicPriming';
export function FirstDreamStep() {
const [primingOpen, setPrimingOpen] = useState(false);
return (
<section>
<h2>现在,来记录你的梦境吧?</h2>
<button onClick={() => goToTextInput()}>文字输入</button>
<button onClick={() => setPrimingOpen(true)}>语音输入</button>
<button onClick={() => goToHome()}>稍后再记录</button>
{primingOpen && (
<MicPriming
onConfirm={async () => {
// 仅在用户明确同意后调用getUserMedia(即浏览器权限弹窗)
await navigator.mediaDevices.getUserMedia({ audio: true });
goToVoiceInput();
}}
onCancel={() => setPrimingOpen(false)}
/>
)}
</section>
);
}注意:上述框架中的·麦克风状态管理仅为最简示例。实际实现需完全遵循getUserMedia技能的状态机·错误处理·资源清理(frontend/voice-input-ui)逻辑。stream.getTracks().stop()
12. 체크리스트
12. 检查清单
스킬을 실제 코드에 적용할 때 빠진 항목이 없는지 확인:
- 5단계가 정확히 5개인가 (확장 시 카드 흡수, 단계 추가 금지)
- 3·4단계에서 스킵 버튼이 비활성화되어 있는가
- 학술 한계 문구가 4-1 변환표대로 친근화되었는가
- 109·1577-0199 번호가 짝 스킬 기준과 일치하는가 (없음)
1393 - 마이크 권한이 5단계 버튼 클릭 후에만 요청되는가
- 알림 권한이 온보딩 외부 (첫 사용 후)로 분리되었는가
- 청소년 페르소나에 1388 우선·109 병행이 적용되었는가
- 단계 전환 시 새 헤딩에 포커스가 이동하는가
- 이 모든 애니메이션에 적용되었는가
prefers-reduced-motion - 분석 이벤트에 꿈 텍스트·음성 본문이 포함되지 않는가
- 라이선스 호환성 확인 (intro.js / shepherd.js는 상용 라이선스 필요)
将本技能应用到实际代码时,确认以下项目是否完成:
- 阶段数严格为5个(新增内容融入卡片,不得增加阶段)
- 3·4阶段的跳过按钮已禁用
- 学术局限性文案已按4-1转化表改为用户友好表述
- 109·1577-0199号码与关联技能标准一致(无)
1393 - 麦克风权限仅在5阶段按钮点击后请求
- 通知权限已分离至引导外(首次使用后)
- 青少年用户群已应用优先展示1388·同时展示109的设置
- 阶段切换时焦点已移至新阶段标题
- 已应用到所有动画
prefers-reduced-motion - 分析事件中未包含梦境文字·语音内容
- 已确认授权协议兼容性(intro.js / shepherd.js商业项目需购买授权)