codymaster 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/README.md +285 -0
- package/adapters/antigravity.js +15 -0
- package/adapters/claude-code.js +17 -0
- package/adapters/cursor.js +16 -0
- package/commands/bootstrap.md +49 -0
- package/commands/build.md +48 -0
- package/commands/content.md +48 -0
- package/commands/continuity.md +60 -0
- package/commands/debug.md +51 -0
- package/commands/demo.md +96 -0
- package/commands/deploy.md +51 -0
- package/commands/plan.md +42 -0
- package/commands/review.md +55 -0
- package/commands/track.md +46 -0
- package/commands/ux.md +46 -0
- package/dist/agent-dispatch.js +161 -0
- package/dist/chains/builtin.js +85 -0
- package/dist/continuity.js +385 -0
- package/dist/dashboard.js +926 -0
- package/dist/data.js +122 -0
- package/dist/index.js +2434 -0
- package/dist/judge.js +252 -0
- package/dist/parallel-dispatch.js +359 -0
- package/dist/parallel-quality.js +172 -0
- package/dist/skill-chain.js +258 -0
- package/install.sh +513 -0
- package/package.json +79 -0
- package/skills/.content-factory-state.json +132 -0
- package/skills/.git 2/logs/refs/heads/main +1 -0
- package/skills/.git 2/logs/refs/remotes/origin/main +1 -0
- package/skills/.git 2/objects/02/fb0956734b5f8ba3f918b7defd04a89cfe0076 +0 -0
- package/skills/.git 2/objects/08/1e129d75dc6feac6c02037272e6bd1a04e3324 +0 -0
- package/skills/.git 2/objects/0c/5393416f3c5e01c9a655a802bff0dd52f76f0a +0 -0
- package/skills/.git 2/objects/10/0b9be46978a946a77188f68be725098a122001 +0 -0
- package/skills/.git 2/objects/10/cf041167fc9843610eb3d90259ef3396315fdc +0 -0
- package/skills/.git 2/objects/12/5e19538dd6e1338ffe74f6c4c165b00435bf48 +0 -0
- package/skills/.git 2/objects/16/a9b9d0088d5c1347628b45a2620b479d8ad57c +0 -0
- package/skills/.git 2/objects/17/8c2a9ef93c33ae4eec9d58e82321f9229843a1 +0 -0
- package/skills/.git 2/objects/25/397ae41d09104d763bdcac2695209d85cdea89 +0 -0
- package/skills/.git 2/objects/2f/a836b7947f2d458e1f639788bf4bb0983a3305 +0 -0
- package/skills/.git 2/objects/3a/baaaf0a1c0909c0828335791557125fba911e0 +0 -0
- package/skills/.git 2/objects/42/2924221b81f5ce3c4e4daac9a64a24f9b01f9a +0 -0
- package/skills/.git 2/objects/42/ec0ce707447dc11446a34c9995fb8533801731 +0 -0
- package/skills/.git 2/objects/46/e43ce92866d56ce74b1d750db307cfe6154a15 +0 -0
- package/skills/.git 2/objects/48/5e41b633c63f55b8277bcc59f44f67681f671a +0 -0
- package/skills/.git 2/objects/49/49c596a3a89fa240642acd95dd3258e261eb09 +0 -0
- package/skills/.git 2/objects/50/9d42d8412ef8eaf7f7e138476bac2e4d10ce60 +0 -0
- package/skills/.git 2/objects/55/0c8c389d981b463ef849aeb792d8be3ccb6ec8 +0 -0
- package/skills/.git 2/objects/5d/82d3b18410cdda3ace3677436f0cb599dbe2d2 +0 -0
- package/skills/.git 2/objects/60/0617c58e871a38b33bf29e282d132bb3c381ad +0 -0
- package/skills/.git 2/objects/6a/8369a99c687b7245c92ffaf0e0f0dab9014504 +0 -0
- package/skills/.git 2/objects/79/bea435d40ab531c1aaf6be0432c6a5b7aaed21 +0 -0
- package/skills/.git 2/objects/7e/5ebd79251c2f14e4aceb86c74b6b6daae6b500 +0 -0
- package/skills/.git 2/objects/81/98a822a60178d6d5023ddb3e222cddf048742e +0 -0
- package/skills/.git 2/objects/86/0a0e1943dfe53411d2e499a1f16f46a96ef758 +0 -0
- package/skills/.git 2/objects/86/971fb55fdc081fdbae52376f0f13e57a4e9b04 +0 -0
- package/skills/.git 2/objects/88/b89dd609a0a03f8d4fe8bfde20d5b8fc1d326d +0 -0
- package/skills/.git 2/objects/90/8737edb6b7809e32cc01590b4e08ba42a9d40d +0 -0
- package/skills/.git 2/objects/93/d5a8a9a7d4fb7f11491cb596a6880528725118 +0 -0
- package/skills/.git 2/objects/98/46a2ab81d0c3b3eb00ef88fc56989aa7e9f316 +0 -0
- package/skills/.git 2/objects/9b/d8dd1e49cf274eaf9c555f3ab39dce7af5715e +0 -0
- package/skills/.git 2/objects/a1/13329fb0cec96ae78b222d33a24c3b5bc7fa1f +0 -0
- package/skills/.git 2/objects/a9/e6effe626e8a3aea3a8fc3364b492191c6e7d0 +0 -0
- package/skills/.git 2/objects/ad/6de7e48d9782cca9353d1ff0aa1aab7fe1df85 +0 -0
- package/skills/.git 2/objects/af/54ae316f771ff692e299ffcd8bf2f06b413b59 +0 -0
- package/skills/.git 2/objects/b0/4cb8b0b00dad633e731c1472161419e738d674 +0 -0
- package/skills/.git 2/objects/b3/094abb0b9ed46419b269e4a4e36a459690e3b0 +0 -0
- package/skills/.git 2/objects/b9/435c5d4baac2cfc5c83009ddd27b46b60db5f1 +0 -0
- package/skills/.git 2/objects/ba/5da17dbaec5ec2dcfdfd126aead518d1171d5c +0 -0
- package/skills/.git 2/objects/c0/bf58703aa258ba5dd63083bebaec8f223d844c +0 -0
- package/skills/.git 2/objects/c4/701a34edf1fc1bad58ccc57bd03f9426acb59a +0 -0
- package/skills/.git 2/objects/c7/5ccce9a4e5cc74d9b3174550cf6d993ca43638 +0 -0
- package/skills/.git 2/objects/c7/710d59b5a35b0f1f0a0399386643a0bd94c929 +0 -0
- package/skills/.git 2/objects/d1/fe58237112e953e5fec52da22cf38e08be3df9 +5 -0
- package/skills/.git 2/objects/d2/2bbe9fd2f74c95bc5583e803f5e435f1e2cd86 +0 -0
- package/skills/.git 2/objects/d7/e72852ea2bff74581dbf247d400120086229f4 +0 -0
- package/skills/.git 2/objects/d8/d4c3b5553e4fd72807e1d4b49ef07d9ef3ac35 +0 -0
- package/skills/.git 2/objects/dc/75050c2876f6a02ae2a53a3c886f395b622977 +0 -0
- package/skills/.git 2/objects/ee/e8546f95acec500187c08a28a8b9ee02db0dec +0 -0
- package/skills/.git 2/objects/ef/263c059208b416c2146434f10cb2b9fabcba16 +0 -0
- package/skills/.git 2/objects/f3/ae597e84d9a59b88acd21c99bde2eaf686d785 +0 -0
- package/skills/.git 2/objects/f3/f6f5673c821d3d8e76fa267a9e882e7a5387ea +0 -0
- package/skills/.git 2/objects/f9/6e6d0ad02624dd11d5848594d056caef7a5e8b +0 -0
- package/skills/.git 2/objects/ff/278988fc1edf0db3abcf18de795f4cc0b4f3e1 +0 -0
- package/skills/.git 2/refs/heads/main +1 -0
- package/skills/.git 2/refs/remotes/origin/main +1 -0
- package/skills/.pytest_cache 2/v/cache/nodeids +76 -0
- package/skills/.pytest_cache 2/v/cache/stepwise +1 -0
- package/skills/_shared/helpers.md +123 -0
- package/skills/_shared/outputs-convention.md +24 -0
- package/skills/cm-ads-tracker/SKILL.md +109 -0
- package/skills/cm-ads-tracker/evals/evals.json +55 -0
- package/skills/cm-ads-tracker/references/gtm-architecture.md +321 -0
- package/skills/cm-ads-tracker/references/industry-events.md +294 -0
- package/skills/cm-ads-tracker/references/platforms-api.md +238 -0
- package/skills/cm-ads-tracker/templates/capi-payload.md +79 -0
- package/skills/cm-ads-tracker/templates/datalayer-push.js +104 -0
- package/skills/cm-ads-tracker/templates/gtm-variables.js +56 -0
- package/skills/cm-brainstorm-idea/SKILL.md +423 -0
- package/skills/cm-code-review/SKILL.md +151 -0
- package/skills/cm-content-factory/SKILL.md +416 -0
- package/skills/cm-continuity/SKILL.md +399 -0
- package/skills/cm-dashboard/SKILL.md +533 -0
- package/skills/cm-dashboard/ui/app.js +1270 -0
- package/skills/cm-dashboard/ui/index.html +206 -0
- package/skills/cm-dashboard/ui/style.css +440 -0
- package/skills/cm-debugging/SKILL.md +412 -0
- package/skills/cm-deep-search/SKILL.md +242 -0
- package/skills/cm-design-system/SKILL.md +97 -0
- package/skills/cm-design-system/resources/halo-modern.md +40 -0
- package/skills/cm-design-system/resources/lunaris-advanced.md +40 -0
- package/skills/cm-design-system/resources/nitro-enterprise.md +39 -0
- package/skills/cm-design-system/resources/shadcn-default.md +37 -0
- package/skills/cm-dockit/README.md +100 -0
- package/skills/cm-dockit/SKILL.md +302 -0
- package/skills/cm-dockit/index.html +443 -0
- package/skills/cm-dockit/package-lock.json +1850 -0
- package/skills/cm-dockit/package.json +14 -0
- package/skills/cm-dockit/prompts/analysis.md +34 -0
- package/skills/cm-dockit/prompts/api-reference.md +24 -0
- package/skills/cm-dockit/prompts/architecture.md +21 -0
- package/skills/cm-dockit/prompts/data-flow.md +20 -0
- package/skills/cm-dockit/prompts/database.md +21 -0
- package/skills/cm-dockit/prompts/deployment.md +22 -0
- package/skills/cm-dockit/prompts/flows.md +21 -0
- package/skills/cm-dockit/prompts/jtbd.md +20 -0
- package/skills/cm-dockit/prompts/personas.md +24 -0
- package/skills/cm-dockit/prompts/sop-modules.md +40 -0
- package/skills/cm-dockit/scripts/doc-gen.sh +121 -0
- package/skills/cm-dockit/scripts/dockit-dashboard.sh +142 -0
- package/skills/cm-dockit/scripts/dockit-runner.sh +607 -0
- package/skills/cm-dockit/scripts/dockit-task.sh +166 -0
- package/skills/cm-dockit/skills/analyze-codebase.md +174 -0
- package/skills/cm-dockit/skills/api-reference.md +237 -0
- package/skills/cm-dockit/skills/changelog-guide.md +195 -0
- package/skills/cm-dockit/skills/content-guidelines.md +190 -0
- package/skills/cm-dockit/skills/sop-guide.md +184 -0
- package/skills/cm-dockit/skills/tech-docs.md +287 -0
- package/skills/cm-dockit/templates/markdown/structure.md +60 -0
- package/skills/cm-dockit/templates/vitepress-premium/.vitepress/config.mts +110 -0
- package/skills/cm-dockit/templates/vitepress-premium/.vitepress/theme/custom.css +189 -0
- package/skills/cm-dockit/templates/vitepress-premium/.vitepress/theme/index.ts +4 -0
- package/skills/cm-dockit/templates/vitepress-premium/package.json +19 -0
- package/skills/cm-dockit/templates/vitepress-premium/tests/frontend.test.ts +45 -0
- package/skills/cm-dockit/tests/runner.test.ts +66 -0
- package/skills/cm-dockit/workflows/export-markdown.md +82 -0
- package/skills/cm-dockit/workflows/generate-docs.md +68 -0
- package/skills/cm-dockit/workflows/setup-vitepress.md +181 -0
- package/skills/cm-example/SKILL.md +26 -0
- package/skills/cm-execution/SKILL.md +268 -0
- package/skills/cm-git-worktrees/SKILL.md +164 -0
- package/skills/cm-how-it-work/SKILL.md +189 -0
- package/skills/cm-identity-guard/SKILL.md +412 -0
- package/skills/cm-jtbd/SKILL.md +98 -0
- package/skills/cm-planning/SKILL.md +130 -0
- package/skills/cm-project-bootstrap/SKILL.md +161 -0
- package/skills/cm-project-bootstrap/templates/AGENTS.md +42 -0
- package/skills/cm-project-bootstrap/templates/frontend-safety.test.js +51 -0
- package/skills/cm-project-bootstrap/templates/i18n-sync.test.js +38 -0
- package/skills/cm-project-bootstrap/templates/pr-template.md +12 -0
- package/skills/cm-project-bootstrap/templates/project-identity.json +29 -0
- package/skills/cm-project-bootstrap/templates/vitest.config.js +10 -0
- package/skills/cm-quality-gate/SKILL.md +218 -0
- package/skills/cm-readit/SKILL.md +289 -0
- package/skills/cm-readit/audio-player.md +206 -0
- package/skills/cm-readit/examples/blog-reader.js +352 -0
- package/skills/cm-readit/examples/voice-cro.js +390 -0
- package/skills/cm-readit/tts-engine.md +262 -0
- package/skills/cm-readit/ui-patterns.md +362 -0
- package/skills/cm-readit/voice-cro.md +223 -0
- package/skills/cm-safe-deploy/SKILL.md +120 -0
- package/skills/cm-safe-deploy/templates/deploy.sh +89 -0
- package/skills/cm-safe-i18n/SKILL.md +473 -0
- package/skills/cm-secret-shield/SKILL.md +580 -0
- package/skills/cm-skill-chain/SKILL.md +78 -0
- package/skills/cm-skill-index/SKILL.md +318 -0
- package/skills/cm-skill-mastery/SKILL.md +169 -0
- package/skills/cm-start/SKILL.md +65 -0
- package/skills/cm-status/SKILL.md +12 -0
- package/skills/cm-tdd/SKILL.md +370 -0
- package/skills/cm-terminal/SKILL.md +177 -0
- package/skills/cm-test-gate/SKILL.md +242 -0
- package/skills/cm-ui-preview/SKILL.md +291 -0
- package/skills/cm-ux-master/DESIGN_STANDARD_TEMPLATE.md +54 -0
- package/skills/cm-ux-master/SKILL.md +114 -0
- package/skills/cro-methodology/SKILL.md +98 -0
- package/skills/cro-methodology/references/COPYWRITING.md +178 -0
- package/skills/cro-methodology/references/OBJECTIONS.md +135 -0
- package/skills/cro-methodology/references/PERSUASION.md +158 -0
- package/skills/cro-methodology/references/RESEARCH.md +220 -0
- package/skills/cro-methodology/references/funnel-analysis.md +365 -0
- package/skills/cro-methodology/references/testing-methodology.md +330 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cm-readit
|
|
3
|
+
description: Turn any website into an audio-enabled experience. Covers TTS reading mode (SpeechSynthesis API), pre-recorded MP3 audio player, and Voice CRO trigger system. Zero dependencies, works on any static or dynamic site. Use when adding read-aloud, audio player, or voice-based conversion features.
|
|
4
|
+
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# CM ReadIt — Web Audio Experience Skill
|
|
8
|
+
|
|
9
|
+
> **Philosophy:** Reading is passive. Listening is intimate. Voice builds trust faster than any headline.
|
|
10
|
+
> **Core Principle:** Zero dependencies. Progressive enhancement. Respect user's device and preferences.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 🎯 Selective Reading Rule (MANDATORY)
|
|
15
|
+
|
|
16
|
+
| File | Status | When to Read |
|
|
17
|
+
|------|--------|--------------|
|
|
18
|
+
| [tts-engine.md](tts-engine.md) | 🔴 **REQUIRED** | Adding TTS / read-aloud to any page |
|
|
19
|
+
| [audio-player.md](audio-player.md) | ⚪ Optional | Pre-recorded MP3 playback |
|
|
20
|
+
| [voice-cro.md](voice-cro.md) | ⚪ Optional | Trigger-based voice sales / CRO |
|
|
21
|
+
| [ui-patterns.md](ui-patterns.md) | ⚪ Optional | Player bar & bottom sheet design |
|
|
22
|
+
|
|
23
|
+
> 🔴 **tts-engine.md = ALWAYS READ when implementing TTS. Others = only if relevant.**
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Quick Decision Tree
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
"I need audio on my website"
|
|
31
|
+
│
|
|
32
|
+
├─ Read article content aloud (text-to-speech)
|
|
33
|
+
│ └─ Use: TTS Engine → tts-engine.md
|
|
34
|
+
│ ├─ Blog / article pages → Content Reader pattern
|
|
35
|
+
│ ├─ Documentation → Section Reader pattern
|
|
36
|
+
│ └─ E-commerce → Product Description Reader pattern
|
|
37
|
+
│
|
|
38
|
+
├─ Play pre-recorded audio files (MP3/WAV)
|
|
39
|
+
│ └─ Use: Audio Player → audio-player.md
|
|
40
|
+
│ ├─ Podcasts / interviews → Playlist pattern
|
|
41
|
+
│ ├─ Sales pitch / welcome → Triggered playback
|
|
42
|
+
│ └─ Background ambient → Loop pattern
|
|
43
|
+
│
|
|
44
|
+
├─ Voice-based conversion optimization (CRO)
|
|
45
|
+
│ └─ Use: Voice CRO → voice-cro.md
|
|
46
|
+
│ ├─ Landing pages → Trigger-based bottom sheet
|
|
47
|
+
│ ├─ Service pages → Per-page audio scripts
|
|
48
|
+
│ └─ Course pages → Social proof audio
|
|
49
|
+
│
|
|
50
|
+
└─ Combination (TTS + CRO)
|
|
51
|
+
└─ Read tts-engine.md + voice-cro.md
|
|
52
|
+
└─ Ensure no conflict (TTS reader vs CRO player)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 🧠 Core Principles (Internalize These)
|
|
58
|
+
|
|
59
|
+
### 1. The 3 Audio Engines
|
|
60
|
+
|
|
61
|
+
| Engine | API | Source | Best For |
|
|
62
|
+
|--------|-----|--------|----------|
|
|
63
|
+
| **TTS Reader** | `SpeechSynthesis` | Page text content | Blogs, articles, docs |
|
|
64
|
+
| **Audio Player** | `HTMLAudioElement` | Pre-recorded MP3 | Sales, podcasts, guides |
|
|
65
|
+
| **Voice CRO** | `Audio` + triggers | MP3 + behavior detection | Landing pages, sales |
|
|
66
|
+
|
|
67
|
+
### 2. Progressive Enhancement
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
Feature detection → Graceful degradation → Never break the page
|
|
71
|
+
|
|
72
|
+
if (!('speechSynthesis' in window)) return; // TTS
|
|
73
|
+
if (!window.Audio) return; // Audio
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Rule:** Audio features are ENHANCEMENTS. The page must function 100% without them.
|
|
77
|
+
|
|
78
|
+
### 3. Content Extraction Principle
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
Clone → Strip → Clean → Split → Speak
|
|
82
|
+
|
|
83
|
+
DON'T read the raw DOM.
|
|
84
|
+
DO clone, remove noise, extract clean text.
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Strip list (always remove before speaking):**
|
|
88
|
+
- CTAs, promotions, ads
|
|
89
|
+
- Navigation, footer, sidebar
|
|
90
|
+
- Images, videos, iframes, SVGs
|
|
91
|
+
- Scripts, styles, hidden elements
|
|
92
|
+
- Tags, badges, metadata
|
|
93
|
+
|
|
94
|
+
### 4. The Chunking Problem
|
|
95
|
+
|
|
96
|
+
Browsers have a **hard limit** on utterance length (~3000-5000 chars depending on browser/OS). Long text must be split into chunks.
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
Split Strategy:
|
|
100
|
+
├─ Split on sentence boundaries (. ! ? \n)
|
|
101
|
+
├─ Max chunk: 2500 chars (safe across all browsers)
|
|
102
|
+
├─ Preserve sentence integrity (never split mid-sentence)
|
|
103
|
+
└─ Chain chunks via onend callback
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 5. Voice Selection Priority
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
Language voices:
|
|
110
|
+
1. Local service voice (faster, works offline)
|
|
111
|
+
2. Network voice (higher quality, needs internet)
|
|
112
|
+
3. Any voice matching language prefix
|
|
113
|
+
4. null (browser default)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 6. Chrome Keep-Alive Bug
|
|
117
|
+
|
|
118
|
+
> ⚠️ **CRITICAL:** Chrome silently stops SpeechSynthesis after ~15 seconds of continuous speech. This is the #1 gotcha.
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
// Workaround: pause/resume every 10s
|
|
122
|
+
setInterval(() => {
|
|
123
|
+
if (synth.speaking && !synth.paused) {
|
|
124
|
+
synth.pause();
|
|
125
|
+
synth.resume();
|
|
126
|
+
}
|
|
127
|
+
}, 10000);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 7. synth.cancel() Triggers onerror
|
|
131
|
+
|
|
132
|
+
> ⚠️ **GOTCHA:** Calling `synth.cancel()` fires the `onerror` event on any active utterance with error type `'canceled'` or `'interrupted'`.
|
|
133
|
+
|
|
134
|
+
**Solution:** Use a guard flag or check error type:
|
|
135
|
+
```javascript
|
|
136
|
+
u.onerror = function(e) {
|
|
137
|
+
if (e.error === 'canceled' || e.error === 'interrupted') return;
|
|
138
|
+
stopReading();
|
|
139
|
+
};
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 🏗️ Architecture Pattern
|
|
145
|
+
|
|
146
|
+
### Minimal TTS Reader (Copy-Paste Starting Point)
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
┌─────────────────────────────────────────┐
|
|
150
|
+
│ IIFE │
|
|
151
|
+
│ │
|
|
152
|
+
│ ┌─ Feature Detection ─┐ │
|
|
153
|
+
│ │ speechSynthesis? │ │
|
|
154
|
+
│ └──────────┬───────────┘ │
|
|
155
|
+
│ ▼ │
|
|
156
|
+
│ ┌─ Content Extraction ─┐ │
|
|
157
|
+
│ │ Clone → Strip → Clean│ │
|
|
158
|
+
│ └──────────┬────────────┘ │
|
|
159
|
+
│ ▼ │
|
|
160
|
+
│ ┌─ Chunking Engine ────┐ │
|
|
161
|
+
│ │ Split on sentences │ │
|
|
162
|
+
│ │ Max 2500 chars │ │
|
|
163
|
+
│ └──────────┬────────────┘ │
|
|
164
|
+
│ ▼ │
|
|
165
|
+
│ ┌─ Utterance Builder ──┐ │
|
|
166
|
+
│ │ Set voice/rate/pitch │ │
|
|
167
|
+
│ │ Chain via onend │ │
|
|
168
|
+
│ └──────────┬────────────┘ │
|
|
169
|
+
│ ▼ │
|
|
170
|
+
│ ┌─ Player UI ──────────┐ │
|
|
171
|
+
│ │ Bar: play/pause/stop │ │
|
|
172
|
+
│ │ Progress indicator │ │
|
|
173
|
+
│ │ Trigger button │ │
|
|
174
|
+
│ └──────────┬────────────┘ │
|
|
175
|
+
│ ▼ │
|
|
176
|
+
│ ┌─ Keep-Alive Timer ───┐ │
|
|
177
|
+
│ │ pause/resume @ 10s │ │
|
|
178
|
+
│ └───────────────────────┘ │
|
|
179
|
+
└──────────────────────────────────────────┘
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Lifecycle
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
Init → Detect → Inject Trigger Button
|
|
186
|
+
│
|
|
187
|
+
User clicks ▶
|
|
188
|
+
│
|
|
189
|
+
Extract Text → Chunk → Build Utterances
|
|
190
|
+
│
|
|
191
|
+
synth.speak(chunk[0])
|
|
192
|
+
│
|
|
193
|
+
chunk[0].onend → speak(chunk[1]) → ... → speak(chunk[N])
|
|
194
|
+
│ │
|
|
195
|
+
Keep-Alive Timer running chunk[N].onend
|
|
196
|
+
│ │
|
|
197
|
+
User clicks ⏸ → synth.pause() stopReading()
|
|
198
|
+
User clicks ▶ → synth.resume() cleanup UI
|
|
199
|
+
User clicks ✕ → synth.cancel()
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 📐 Implementation Checklist
|
|
205
|
+
|
|
206
|
+
### For TTS Reader
|
|
207
|
+
- [ ] Feature detection (`speechSynthesis` in window)
|
|
208
|
+
- [ ] Content container identified (ID or selector)
|
|
209
|
+
- [ ] Strip list defined (what to remove before reading)
|
|
210
|
+
- [ ] Chunk size set (default 2500)
|
|
211
|
+
- [ ] Voice selection logic (language-specific)
|
|
212
|
+
- [ ] Player bar UI (play/pause/close + progress)
|
|
213
|
+
- [ ] Trigger button injected (topbar or floating)
|
|
214
|
+
- [ ] Chrome keep-alive timer (10s interval)
|
|
215
|
+
- [ ] `onerror` guard (handle cancel/interrupted)
|
|
216
|
+
- [ ] `beforeunload` cleanup
|
|
217
|
+
- [ ] `prefers-reduced-motion` respect
|
|
218
|
+
- [ ] Mobile safe-area padding
|
|
219
|
+
|
|
220
|
+
### For Audio Player
|
|
221
|
+
- [ ] Audio files hosted and accessible
|
|
222
|
+
- [ ] Preload strategy (`none` → load on demand)
|
|
223
|
+
- [ ] Play/pause toggle with state management
|
|
224
|
+
- [ ] Progress bar with `currentTime/duration`
|
|
225
|
+
- [ ] Error handling (network, format, autoplay policy)
|
|
226
|
+
- [ ] Session state (dismissed = don't show again)
|
|
227
|
+
|
|
228
|
+
### For Voice CRO
|
|
229
|
+
- [ ] Per-page config object (delay, scroll threshold, audio URLs)
|
|
230
|
+
- [ ] Trigger conditions (time + scroll AND/OR interaction)
|
|
231
|
+
- [ ] Bottom sheet UI (icon, text, CTA, dismiss)
|
|
232
|
+
- [ ] Player bar UI (toggle, progress, CTA button)
|
|
233
|
+
- [ ] Session dismissal tracking
|
|
234
|
+
- [ ] Stats tracking (shown/listened/dismissed)
|
|
235
|
+
- [ ] No conflict with TTS Reader
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## ⚠️ Common Pitfalls
|
|
240
|
+
|
|
241
|
+
| Pitfall | Symptom | Fix |
|
|
242
|
+
|---------|---------|-----|
|
|
243
|
+
| Chrome stops after 15s | Audio cuts mid-sentence | Keep-alive timer (pause/resume) |
|
|
244
|
+
| `synth.cancel()` fires onerror | Settings sheet closes immediately | Guard flag or check error type |
|
|
245
|
+
| Voices not loaded | No voice available | Listen for `voiceschanged` event |
|
|
246
|
+
| Chunk too large | Utterance fails silently | Max 2500 chars per chunk |
|
|
247
|
+
| Reading CTA text | TTS reads "Book Now" button text | Strip non-content elements |
|
|
248
|
+
| Autoplay blocked | Audio won't start on mobile | Require user interaction first |
|
|
249
|
+
| Multiple audio conflicts | TTS + CRO play simultaneously | Mutual exclusion check |
|
|
250
|
+
| No cleanup on nav | Audio keeps playing | `beforeunload` → `synth.cancel()` |
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## 🌐 Multi-Language Support
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
Voice selection by language:
|
|
258
|
+
├─ Vietnamese: v.lang === 'vi-VN' || v.lang.startsWith('vi')
|
|
259
|
+
├─ English: v.lang === 'en-US' || v.lang.startsWith('en')
|
|
260
|
+
├─ Japanese: v.lang === 'ja-JP' || v.lang.startsWith('ja')
|
|
261
|
+
├─ Korean: v.lang === 'ko-KR' || v.lang.startsWith('ko')
|
|
262
|
+
└─ Any: Pass language code as config parameter
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Set `utterance.lang` to match the content language for correct pronunciation.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## 📚 Reference Files
|
|
270
|
+
|
|
271
|
+
| File | Content |
|
|
272
|
+
|------|---------|
|
|
273
|
+
| [tts-engine.md](tts-engine.md) | Complete SpeechSynthesis API reference, chunking strategies, voice selection |
|
|
274
|
+
| [audio-player.md](audio-player.md) | HTMLAudioElement patterns, preload strategies, error handling |
|
|
275
|
+
| [voice-cro.md](voice-cro.md) | Trigger system, bottom sheet patterns, CRO analytics |
|
|
276
|
+
| [ui-patterns.md](ui-patterns.md) | Player bar CSS, bottom sheet CSS, animations, responsive design |
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## 🔗 Reference Implementations
|
|
281
|
+
|
|
282
|
+
| File | Description |
|
|
283
|
+
|------|-------------|
|
|
284
|
+
| [examples/blog-reader.js](examples/blog-reader.js) | Complete TTS reader — Substack-style, 350 LOC |
|
|
285
|
+
| [examples/voice-cro.js](examples/voice-cro.js) | Complete Voice CRO trigger system — 390 LOC |
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
> **Remember:** Voice is the most personal interface. A well-placed audio feature can increase engagement 3-5x. But unwanted audio is the fastest way to lose a user. **Always require user initiation. Never autoplay.**
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Audio Player — Pre-Recorded MP3 Patterns
|
|
2
|
+
|
|
3
|
+
> For when you have pre-recorded audio files (sales pitch, podcast, guide) instead of generating speech from text.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## API Quick Reference
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
const audio = new Audio('/path/to/file.mp3');
|
|
11
|
+
|
|
12
|
+
// Core methods
|
|
13
|
+
audio.play() // Returns Promise (may reject: autoplay policy)
|
|
14
|
+
audio.pause()
|
|
15
|
+
audio.load() // Reload source
|
|
16
|
+
|
|
17
|
+
// Properties
|
|
18
|
+
audio.src // Source URL
|
|
19
|
+
audio.currentTime // Current position (seconds)
|
|
20
|
+
audio.duration // Total duration (NaN until loaded)
|
|
21
|
+
audio.paused // boolean
|
|
22
|
+
audio.ended // boolean
|
|
23
|
+
audio.volume // 0.0 — 1.0
|
|
24
|
+
audio.playbackRate // 0.25 — 4.0
|
|
25
|
+
audio.preload // 'none' | 'metadata' | 'auto'
|
|
26
|
+
|
|
27
|
+
// Events
|
|
28
|
+
audio.onplay = fn;
|
|
29
|
+
audio.onpause = fn;
|
|
30
|
+
audio.onended = fn;
|
|
31
|
+
audio.onerror = fn;
|
|
32
|
+
audio.ontimeupdate = fn; // Fires during playback (~4x/second)
|
|
33
|
+
audio.onloadedmetadata = fn; // duration now available
|
|
34
|
+
audio.oncanplay = fn; // Enough data to start playing
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Patterns
|
|
40
|
+
|
|
41
|
+
### Simple Play/Pause Toggle
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
let audio = null;
|
|
45
|
+
let isPlaying = false;
|
|
46
|
+
|
|
47
|
+
function play(src) {
|
|
48
|
+
if (!audio) audio = new Audio(src);
|
|
49
|
+
|
|
50
|
+
const promise = audio.play();
|
|
51
|
+
if (promise) {
|
|
52
|
+
promise
|
|
53
|
+
.then(() => { isPlaying = true; updateUI(); })
|
|
54
|
+
.catch(() => { isPlaying = false; updateUI(); });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function togglePause() {
|
|
59
|
+
if (!audio) return;
|
|
60
|
+
if (audio.paused) {
|
|
61
|
+
audio.play();
|
|
62
|
+
isPlaying = true;
|
|
63
|
+
} else {
|
|
64
|
+
audio.pause();
|
|
65
|
+
isPlaying = false;
|
|
66
|
+
}
|
|
67
|
+
updateUI();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function stop() {
|
|
71
|
+
if (audio) {
|
|
72
|
+
audio.pause();
|
|
73
|
+
audio.currentTime = 0;
|
|
74
|
+
audio = null;
|
|
75
|
+
}
|
|
76
|
+
isPlaying = false;
|
|
77
|
+
updateUI();
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Progress Tracking
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
function startProgressTracking(audioEl, barEl) {
|
|
85
|
+
const update = () => {
|
|
86
|
+
if (!audioEl || !barEl) return;
|
|
87
|
+
if (audioEl.duration) {
|
|
88
|
+
barEl.style.width = (audioEl.currentTime / audioEl.duration * 100) + '%';
|
|
89
|
+
}
|
|
90
|
+
if (!audioEl.paused && !audioEl.ended) {
|
|
91
|
+
requestAnimationFrame(update);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
audioEl.addEventListener('play', () => requestAnimationFrame(update));
|
|
96
|
+
requestAnimationFrame(update);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 2-Part Audio Flow (Intro → Full)
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
function playIntro(cfg) {
|
|
104
|
+
playingPart = 1;
|
|
105
|
+
showPlayer();
|
|
106
|
+
|
|
107
|
+
playAudio(cfg.audio[0], () => {
|
|
108
|
+
// Intro done → offer full version
|
|
109
|
+
showNextButton();
|
|
110
|
+
updateLabel('Bạn muốn nghe thêm?');
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function playFull(cfg) {
|
|
115
|
+
playingPart = 2;
|
|
116
|
+
hideNextButton();
|
|
117
|
+
|
|
118
|
+
playAudio(cfg.audio[1], () => {
|
|
119
|
+
// Full done → show CTA
|
|
120
|
+
updateLabel('Cảm ơn bạn đã lắng nghe!');
|
|
121
|
+
showCTA();
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Preload Strategies
|
|
129
|
+
|
|
130
|
+
| Strategy | Value | When to Use |
|
|
131
|
+
|----------|-------|------------|
|
|
132
|
+
| `none` | Don't preload | Default. Save bandwidth. Load on demand. |
|
|
133
|
+
| `metadata` | Load duration/size | When showing duration in UI |
|
|
134
|
+
| `auto` | Preload full file | Small files (<500KB) that will definitely play |
|
|
135
|
+
|
|
136
|
+
**Recommendation:** Always default to `'none'`. Only preload when user has indicated intent to listen.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Autoplay Policy
|
|
141
|
+
|
|
142
|
+
> ⚠️ All modern browsers block autoplay of audio without user interaction.
|
|
143
|
+
|
|
144
|
+
**Rule:** NEVER try to autoplay. Always require a user gesture (click/tap) before first `audio.play()`.
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
// ❌ WRONG: This will be blocked
|
|
148
|
+
window.onload = () => new Audio('/intro.mp3').play();
|
|
149
|
+
|
|
150
|
+
// ✅ CORRECT: User initiates
|
|
151
|
+
button.addEventListener('click', () => {
|
|
152
|
+
new Audio('/intro.mp3').play();
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Error Handling
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
audio.addEventListener('error', (e) => {
|
|
162
|
+
switch (audio.error?.code) {
|
|
163
|
+
case MediaError.MEDIA_ERR_ABORTED:
|
|
164
|
+
// User aborted — ignore
|
|
165
|
+
break;
|
|
166
|
+
case MediaError.MEDIA_ERR_NETWORK:
|
|
167
|
+
// Network error — show retry
|
|
168
|
+
showRetryButton();
|
|
169
|
+
break;
|
|
170
|
+
case MediaError.MEDIA_ERR_DECODE:
|
|
171
|
+
// Decode error — file corrupted
|
|
172
|
+
showError('File audio bị lỗi');
|
|
173
|
+
break;
|
|
174
|
+
case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:
|
|
175
|
+
// Format not supported
|
|
176
|
+
showError('Trình duyệt không hỗ trợ');
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Format Support
|
|
185
|
+
|
|
186
|
+
| Format | Chrome | Safari | Firefox | Edge |
|
|
187
|
+
|--------|--------|--------|---------|------|
|
|
188
|
+
| MP3 | ✅ | ✅ | ✅ | ✅ |
|
|
189
|
+
| AAC | ✅ | ✅ | ✅ | ✅ |
|
|
190
|
+
| OGG | ✅ | ❌ | ✅ | ✅ |
|
|
191
|
+
| WAV | ✅ | ✅ | ✅ | ✅ |
|
|
192
|
+
| WebM | ✅ | ❌ | ✅ | ✅ |
|
|
193
|
+
|
|
194
|
+
**Recommendation:** Use **MP3** for maximum compatibility. 128kbps is sufficient for voice.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## File Size Guidelines
|
|
199
|
+
|
|
200
|
+
| Content Type | Duration | Recommended Bitrate | Approx. Size |
|
|
201
|
+
|-------------|----------|-------------------|--------------|
|
|
202
|
+
| Voice only | 30s | 64 kbps | ~240 KB |
|
|
203
|
+
| Voice + ambient | 60s | 128 kbps | ~960 KB |
|
|
204
|
+
| High quality | 2 min | 192 kbps | ~2.8 MB |
|
|
205
|
+
|
|
206
|
+
**Rule of thumb:** Keep audio files under **1 MB** for mobile users. Split long content into intro + full.
|