Skip to content

Commit 25c1b86

Browse files
committed
examples + new tags
1 parent ef5dd62 commit 25c1b86

File tree

5 files changed

+349
-39
lines changed

5 files changed

+349
-39
lines changed

README.md

Lines changed: 103 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ Script
4949
└── Words (with individual properties)
5050
```
5151

52+
### Title (`#` Level)
53+
54+
An optional `#` header immediately after the front matter. It serves as the document title for display purposes. Parsers should treat it as metadata — it does not create a segment or affect WPM/emotion inheritance. If omitted, the `title` field from the front matter is used instead. If both are present, the `#` header takes precedence for display.
55+
5256
## Format Specification
5357

5458
### Front Matter (YAML)
@@ -94,22 +98,28 @@ Segments are major sections of the script.
9498
## [SegmentName|120WPM|Emotion|Timing]
9599
```
96100

97-
All parameters after the name are optional and position-dependent, separated by `|`.
101+
All parameters after the name are optional, separated by `|`. Parameters are identified by format, not by position:
102+
103+
- An integer (or integer + `WPM` suffix) → **WPM**
104+
- A known emotion keyword → **Emotion**
105+
- A time pattern (`MM:SS` or `MM:SS-MM:SS`) → **Timing**
106+
107+
This means parameters can appear in any order and unneeded ones can simply be omitted — no empty `||` slots required.
98108

99109
**Examples:**
100-
- `## [Intro|140WPM|Warm]`
101-
- `## [Urgent Update|150WPM|Urgent|0:30-1:10]`
102-
- `## [Overview||Neutral]` — inherits default WPM
110+
- `## [Intro|Warm]` — inherits base WPM, sets emotion
111+
- `## [Urgent Update|145WPM|Urgent|0:30-1:10]` — overrides WPM, sets emotion and timing
112+
- `## [Overview|Neutral]` — inherits WPM, sets emotion
103113
- `## [Simple Segment]` — name only, inherits everything
104114

105115
**Segment Parameters:**
106116

107-
| Position | Parameter | Format | Description |
108-
|----------|-----------|--------|-------------|
109-
| 1 | **Name** | free text | Human-readable label shown in editors. Required. |
110-
| 2 | **WPM** | `NNN` or `NNNWPM` | Integer speed override. Omit or leave empty to inherit. |
111-
| 3 | **Emotion** | preset name | Emotion preset (see table below). Defaults to `Neutral`. |
112-
| 4 | **Timing** | `MM:SS` or `MM:SS-MM:SS` | Duration hint. Stored for tooling; playback computes timing from word counts. |
117+
| Parameter | Format | Description |
118+
|-----------|--------|-------------|
119+
| **Name** | free text | Human-readable label shown in editors. Required (first value before the first `\|`). |
120+
| **WPM** | `NNN` or `NNNWPM` | Integer speed override. Omit to inherit. |
121+
| **Emotion** | preset name | Emotion preset (see table below). Omit to inherit (defaults to `Neutral` at document level). |
122+
| **Timing** | `MM:SS` or `MM:SS-MM:SS` | Duration hint. Stored for tooling; playback computes timing from word counts. |
113123

114124
**Leading text:** Content between a segment header and its first block is preserved as introductory text that inherits the segment's speed and emotion.
115125

@@ -122,17 +132,18 @@ Blocks are topic groups within a segment.
122132
```
123133

124134
**Examples:**
125-
- `### [Opening Block|140WPM]`
126-
- `### [Speed Variations|140WPM|Focused]`
127-
- `### [Happy Section]`
135+
- `### [Opening Block]` — inherits segment WPM and emotion
136+
- `### [Speed Variations|Focused]` — inherits WPM, overrides emotion
137+
- `### [Key Stats|130WPM]` — overrides WPM, inherits emotion
138+
- `### [Climax|150WPM|Urgent]` — overrides both
128139

129140
**Block Parameters:**
130141

131-
| Position | Parameter | Format | Description |
132-
|----------|-----------|--------|-------------|
133-
| 1 | **Name** | free text | Descriptive label. Required. |
134-
| 2 | **WPM** | `NNN` or `NNNWPM` | Integer speed override. Inherits segment WPM if omitted. |
135-
| 3 | **Emotion** | preset name | Emotion override. Inherits segment emotion if omitted. |
142+
| Parameter | Format | Description |
143+
|-----------|--------|-------------|
144+
| **Name** | free text | Descriptive label. Required (first value before the first `\|`). |
145+
| **WPM** | `NNN` or `NNNWPM` | Integer speed override. Inherits segment WPM if omitted. |
146+
| **Emotion** | preset name | Emotion override. Inherits segment emotion if omitted. |
136147

137148
### Inline Markers
138149

@@ -158,7 +169,7 @@ Inline markers are embedded within phrase text to control presentation.
158169
#### Speed Changes
159170

160171
```markdown
161-
[180WPM]text here[/180WPM] # Temporary absolute speed change
172+
[150WPM]text here[/150WPM] # Temporary absolute speed change
162173
[xslow]very careful[/xslow] # Relative: base_wpm × 0.6 (40% slower than base)
163174
[slow]important point[/slow] # Relative: base_wpm × 0.8 (20% slower than base)
164175
[fast]quick mention[/fast] # Relative: base_wpm × 1.25 (25% faster than base)
@@ -176,7 +187,7 @@ Inline markers are embedded within phrase text to control presentation.
176187
| `[fast]` | 1.25× | 175 |
177188
| `[xfast]` | 1.5× | 210 |
178189

179-
**Note:** All relative speed tags are **relative to the base speed**, not absolute values. Tags stack multiplicatively when nested: `[xslow][slow]text[/slow][/xslow]` = base × 0.6 × 0.8 = 48% of base.
190+
**Note:** All relative speed tags are **relative to the base speed**, not absolute values. The multiplier is calculated as `1 + (offset / 100)`. For example, `slow` with offset `-20` → multiplier `1 + (-20/100)` = `0.8`. Tags stack multiplicatively when nested: `[xslow][slow]text[/slow][/xslow]` = base × 0.6 × 0.8 = 48% of base.
180191

181192
#### Runtime Speed Control
182193

@@ -211,6 +222,17 @@ The **+/−** buttons on the reading page change the **base speed** for the curr
211222
[pronunciation:KAM-uhl]camel[/pronunciation] # Simple guide
212223
```
213224

225+
#### Stress Marks
226+
227+
```markdown
228+
[stress:de-VE-lop-ment]development[/stress] # Stressed syllable in UPPERCASE
229+
[stress:IN-fra-struc-ture]infrastructure[/stress]
230+
```
231+
232+
The guide string uses hyphens to separate syllables. The stressed syllable is written in **UPPERCASE**; unstressed syllables are lowercase. For words with secondary stress, use an acute accent on the vowel: `[stress:rè-su-MÉ]résumé[/stress]`.
233+
234+
Renderers should display the stress guide as a tooltip, subtitle, or overlay — not replace the word itself.
235+
214236
## Keyword Reference
215237

216238
### Emotions (case-insensitive)
@@ -249,7 +271,7 @@ Colors are **semantic names** — renderers map them to actual hex values approp
249271
| `white` | #F8F9FA | High | Default text on dark BG |
250272
| `gray` | #ADB5BD | Medium | Subdued, secondary text |
251273

252-
> **Note:** `black` is **not a valid inline color** — it is invisible on the dark teleprompter background. Parsers strip `[black]` tags and render content unstyled.
274+
> **Note:** `black` is **not a valid inline color** — it is invisible on the dark teleprompter background. Parsers should strip `[black]` tags and render the enclosed content unstyled (no color applied).
253275
254276
`highlight` is a **formatting tag**, not a color — it applies a semi-transparent yellow **background overlay**: `[highlight]key point[/highlight]`.
255277

@@ -264,14 +286,16 @@ Colors are **semantic names** — renderers map them to actual hex values approp
264286
| **Markdown emphasis** | `*text*` | Converted to emphasis level 1 |
265287
| **Strong emphasis** | `**text**` | Converted to emphasis level 2 |
266288
| **Highlight** | `[highlight]text[/highlight]` | Visual highlighting |
267-
| **Speed (absolute)** | `[NWPM]text[/NWPM]` | Temporary speed change |
289+
| **Speed (absolute)** | `[NWPM]text[/NWPM]` | Temporary absolute speed change (e.g., `[150WPM]`) |
268290
| **Speed (preset)** | `[xslow]text[/xslow]` | Extra slow: base × 0.6 |
269291
| **Speed (preset)** | `[slow]text[/slow]` | Slow: base × 0.8 |
270292
| **Speed (preset)** | `[fast]text[/fast]` | Fast: base × 1.25 |
271293
| **Speed (preset)** | `[xfast]text[/xfast]` | Extra fast: base × 1.5 |
294+
| **Speed (reset)** | `[normal]text[/normal]` | Reset to base speed: base × 1.0 |
272295
| **Edit point** | `[edit_point]` or `[edit_point:priority]` | Mark edit location |
273296
| **Phonetic** | `[phonetic:IPA]text[/phonetic]` | IPA pronunciation guide |
274-
| **Pronunciation** | `[pronunciation:guide]text[/pronunciation]` | Simple pronunciation |
297+
| **Pronunciation** | `[pronunciation:guide]text[/pronunciation]` | Simple pronunciation guide |
298+
| **Stress** | `[stress:SYL-la-ble]text[/stress]` | Syllable stress (UPPERCASE = stressed) |
275299
| **Color** | `[red]text[/red]`, `[green]...[/green]`, etc. | Apply color styling (see Colors table) |
276300
| **Emotion** | `[warm]text[/warm]`, `[urgent]...[/urgent]`, etc. | Apply emotion-based color styling (see Emotions table) |
277301

@@ -301,7 +325,7 @@ All speed presets are **relative to base_wpm** — they apply a multiplier, not
301325
|----------|--------|-------|
302326
| `\[` | `[` | Literal bracket in text |
303327
| `\]` | `]` | Literal bracket in text |
304-
| `\|` | `\|` | Literal pipe in segment/block names |
328+
| `\|` | `|` | Literal pipe in segment/block names |
305329
| `\/` | `/` | Literal slash (not a pause) |
306330
| `\*` | `*` | Literal asterisk (not emphasis) |
307331
| `\\` | `\` | Literal backslash |
@@ -319,11 +343,13 @@ Properties flow downward through the hierarchy. Each level can override its pare
319343

320344
If a child omits a value, it inherits from its nearest ancestor.
321345

346+
**Best practice:** Only specify WPM or emotion when they **differ** from the inherited value. If `base_wpm` is 140 and a segment runs at 140 WPM, omit the WPM parameter — `## [Intro|Warm]` not `## [Intro|140WPM|Warm]`. Similarly, if a block's emotion matches its parent segment, omit it — `### [Details]` not `### [Details|140WPM|Warm]`. Redundant declarations add noise and make overrides harder to spot.
347+
322348
### WPM Resolution
323349

324350
For any word, the effective WPM is determined by (highest priority first):
325351

326-
1. Inline speed tag (`[180WPM]...[/180WPM]`, `[xslow]`, `[slow]`, `[fast]`, `[xfast]`)
352+
1. Inline speed tag (`[150WPM]...[/150WPM]`, `[xslow]`, `[slow]`, `[normal]`, `[fast]`, `[xfast]`)
327353
2. Block header WPM
328354
3. Segment header WPM
329355
4. `base_wpm` from front matter
@@ -341,19 +367,44 @@ For any word, the effective WPM is determined by (highest priority first):
341367

342368
When emotion changes between segments or blocks, renderers should apply a smooth visual transition (recommended: 3-second fade between color schemes).
343369

370+
### Color and Emotion Precedence
371+
372+
When inline color and emotion tags are nested, the **innermost tag wins** for the enclosed span. For example, `[warm][red]text[/red][/warm]` renders "text" in red, not the warm emotion color. Block-level emotion serves as the default styling; inline tags override it for their span only.
373+
374+
### Phrase Boundaries
375+
376+
A **phrase** is a unit of text delimited by:
377+
- Sentence-ending punctuation: `.` `?` `!`
378+
- Pause markers: `/`, `//`, `[pause:...]`
379+
- Block or segment boundaries
380+
381+
Phrases are the smallest unit for timing calculation. Words within a phrase are counted for WPM computation using whitespace tokenization: each whitespace-separated token counts as one word. Hyphenated words (e.g., `state-of-the-art`) count as one word. Tags and tag syntax are not counted.
382+
344383
### Tag Nesting
345384

346385
- Tags must be properly closed: `[red]text[/red]`.
347386
- Tags must not cross-nest: `[red][emphasis]text[/red][/emphasis]` is **invalid**.
348387
- Valid nesting: `[red][emphasis]text[/emphasis][/red]`.
388+
- If a tag is never closed, the parser should implicitly close it at the end of the current block.
389+
390+
### Nested Speed Resolution
391+
392+
When speed tags are nested, relative tags (`[slow]`, `[fast]`, etc.) stack multiplicatively against the **base speed** — not against each other:
393+
394+
- `[slow]text[/slow]` = base × 0.8
395+
- `[xslow][slow]text[/slow][/xslow]` = base × 0.6 × 0.8 = base × 0.48
396+
397+
When an absolute speed tag (`[150WPM]`) contains a relative tag, the absolute value becomes the new base for the inner tag:
398+
399+
- `[150WPM][slow]text[/slow][/150WPM]` = 150 × 0.8 = 120 WPM
349400

350401
### Content Without Segments
351402

352403
If a TPS file has no `##` segment headers, the entire content (after front matter) is treated as a single implicit segment with `Neutral` emotion and default WPM.
353404

354-
### Simple Segment Headers
405+
### Simple Headers
355406

356-
Plain markdown `## Title` headers (without `[...]` brackets) are also recognized as segments with default (neutral) emotion and inherited WPM.
407+
Plain markdown `## Title` and `### Title` headers (without `[...]` brackets) are also recognized as segments and blocks respectively, with default (neutral) emotion and inherited WPM.
357408

358409
## Rendering Context
359410

@@ -362,7 +413,7 @@ TPS is designed for **teleprompter use** — text is always rendered on a **dark
362413
### Dark Background Rules
363414

364415
1. **Text base color** is white/light (`#F8F9FA` or similar). All inline colors must be **lighter variants** that contrast well against dark backgrounds.
365-
2. **`black` is not a valid inline color** — it would be invisible. Renderers should map `[black]` to `gray` or ignore it.
416+
2. **`black` is not a valid inline color** — it would be invisible. Renderers should strip `[black]` tags and render the enclosed content unstyled.
366417
3. **Minimum contrast** — all color keywords must produce at least **WCAG AA 4.5:1** contrast ratio against the dark background.
367418
4. **Emotion color schemes** (background, text, accent) are pre-defined per emotion. They are not raw hex values — they are tuned for the dark rendering context with appropriate alpha channels.
368419
5. **`highlight`** uses a semi-transparent yellow background overlay, not a text color change.
@@ -382,6 +433,8 @@ The Actor profile targets natural spoken delivery — reading aloud from a telep
382433

383434
**Default `base_wpm`: 140** — sits in the middle of the standard range. Most people read comfortably at 130–150 WPM from a teleprompter.
384435

436+
**Duration formula:** `phrase_duration_ms = (word_count / effective_wpm) × 60000`. Total duration is the sum of all phrase durations plus all pause durations.
437+
385438
**Advice for script authors:**
386439
- Start at 130 WPM for new speakers, increase gradually.
387440
- Use `[xslow]...[/xslow]` for critical warnings or very important statements.
@@ -431,22 +484,24 @@ speed_offsets:
431484
author: Jane Doe
432485
---
433486

434-
## [Intro|140WPM|Warm]
487+
# Product Launch
488+
489+
## [Intro|Warm]
435490

436-
### [Opening Block|140WPM]
491+
### [Opening Block]
437492
Good morning everyone, / and [emphasis]welcome[/emphasis] to what I believe /
438493
will be a [green]transformative moment[/green] for our company. //
439494

440495
[pause:2s]
441496

442-
### [Purpose Block|150WPM]
497+
### [Purpose Block|145WPM]
443498
[emphasis]Today[/emphasis], / we're not just launching a product – /
444499
we're introducing a [highlight]solution[/highlight] that will [emphasis]revolutionize[/emphasis] /
445-
how our customers interact with technology. //
500+
how our customers interact with [stress:tech-NO-lo-gy]technology[/stress]. //
446501

447-
## [Problem|150WPM|Concerned]
502+
## [Problem|135WPM|Concerned]
448503

449-
### [Statistics Block|150WPM|Neutral]
504+
### [Statistics Block|Neutral]
450505
But first, / let's address the [xslow][red]elephant in the room[/red][/xslow]. /
451506
Our industry has been [emphasis]struggling[/emphasis] with a fundamental problem. //
452507

@@ -456,18 +511,18 @@ According to recent studies, /
456511
[slow][emphasis]73% of users abandon[/emphasis] applications within the first three interactions[/slow] /
457512
due to [highlight]complexity and poor user experience[/highlight]. //
458513

459-
### [Impact Block|140WPM]
514+
### [Impact Block]
460515
This affects [emphasis]millions[/emphasis] of people worldwide, /
461516
costing businesses [red]billions in revenue[/red] annually. //
462517

463-
## [Solution|160WPM|Focused]
518+
## [Solution|Focused]
464519

465-
### [Introduction Block|150WPM]
520+
### [Introduction Block]
466521
That's where our [blue][emphasis]new platform[/emphasis][/blue] comes in. /
467522
We've developed a [green]local-first teleprompter workflow[/green] that /
468523
[highlight]simplifies complex processes[/highlight] and [emphasis]enhances user experience[/emphasis]. //
469524

470-
### [Benefits Block|160WPM|Excited]
525+
### [Benefits Block|150WPM|Excited]
471526
With our solution, / you can expect a [green][emphasis]50% reduction[/emphasis][/green] in user abandonment /
472527
and a [green][emphasis]30% increase[/emphasis][/green] in engagement. //
473528

@@ -479,6 +534,16 @@ and a [green][emphasis]30% increase[/emphasis][/green] in engagement. //
479534
[edit_point:medium]
480535
```
481536

537+
## Examples
538+
539+
The [`examples/`](examples/) directory contains sample TPS files demonstrating the format:
540+
541+
| File | Description |
542+
|------|-------------|
543+
| [`basic.tps`](examples/basic.tps) | Minimal valid TPS file — front matter, title, segments, blocks, pauses, emphasis. |
544+
| [`advanced.tps`](examples/advanced.tps) | All format features — speed controls, inline WPM, colors, emotions, pronunciation, edit points, tag nesting. |
545+
| [`multi-segment.tps`](examples/multi-segment.tps) | Multi-segment script with varying speed and emotion across segments. |
546+
482547
## File Extension
483548

484549
- Primary: `.tps` (TelePrompterScript)

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.0.0
1+
1.1.0

0 commit comments

Comments
 (0)