Files
stickman/docs/specs/speech_message_emoji_timing.md

33 lines
5.5 KiB
Markdown

# Speech Message, Emoji, Timing, and Whole-Bubble Effects
Status: **Approved for implementation** (2026-09-29). This addendum extends the live stage speech-style toolbar. It supersedes prior requirements that Effects need a selected token or that Message, Emoji, and Timing remain as inspector cards.
## Interaction
- The stage toolbar has two grouped rows: **Speech** (Message, Timing) and **Style** (Frame, Letters, Effects), followed by **Done styling**. Keep large pictorial buttons, a visible active chooser, responsive placement, and no horizontal scrolling.
- **Message** is a highlighted toolbar button that opens a nearby, ribbon-titled editor panel styled like the Frame/Letters/Effects chooser. It does not dim the stage. The panel contains the current bubble's text field and a **😀 Emoji** button directly below it. The button opens an emoji grid in the same panel. Choosing an emoji inserts it at the text caret and leaves the panel open. Keep the text field fixed in place and let the panel grow downward when the grid opens. Text selection in this editor is for text editing only; style targets are selected on the stage bubble.
- While the Message panel is open, stage/object input stays locked. Clicking Message again, choosing another toolbar category, or pressing Escape closes the panel. Closing it edits only the recoverable composer draft. **Save speech** remains the sole queue/rule commit point; composer Cancel still discards the editing session.
- A stage tap selects a word, punctuation token, or emoji. With a token selected, Letters and Effects change that token. With no token selected, Letters and Effects change all text in the selected bubble. Frame always changes the whole selected bubble. An empty bubble has Effects disabled until it has text.
- If a message edit changes text, preserve unaffected word-style spans and carry existing explicit style properties onto the remaining or replacement token content when an edit touches a styled span. Tokens created outside a styled span inherit explicit style properties from the preceding token; when insertion is at the beginning, inherit from the following token. Only text that is fully deleted loses its style. Do not use fuzzy text matching to move styles between repeated words.
- Preserve the existing one-second, non-blocking effect sample. A selected-token effect previews only that token. A bubble-default effect previews all tokens in the bubble. The saved effect remains static in edit mode after the sample and animates during speech playback.
- **Timing** uses the existing action-wide `duration_mode` choices and IDs: Normal → `just_enough`, Slow → `longer`, Slower → `longest`. It sets how long each bubble remains visible; the existing Show arrangement, Reveal, and Entrance controls stay in the inspector.
- Remove Message, Emoji, and Timing from the inspector. Keep bubble management, Show, Replay, Save speech, and Cancel there. Omit the Inspector's Placement section: children position each bubble directly by dragging it on the stage. Continue loading and saving existing placement data so manually positioned bubbles retain their locations.
## Payload and ownership
- Add `visual.effect` as the bubble's default effect (`none`, `shake`, `wave`, or `bounce`). Missing values in old scenes normalize to `none`.
- `visual.word_styles[].effect` overrides the bubble default. Accept `none` as an explicit per-token override so a selected token can opt out of a bubble-wide effect.
- Choosing an effect with no token selected sets `visual.effect` and clears per-token effect overrides, ensuring the choice reaches every token. Choosing an effect on a selected token changes only that token. Choosing **No effect** on a selected token removes its override when the bubble default is `none`, or stores an explicit `none` override when the bubble default is animated.
- Choosing **No effect** with no selected token sets the bubble default to `none` and clears all per-token effect overrides.
- `SpeechComposer` remains the sole draft and recovery writer. `SpeechStyleToolbar` owns stage-side controls and emits Message/Timing/choice requests. `SandboxStage` opens/closes the modal, blocks world input while it is open, and restores the toolbar afterward. `SpeechBubble` renders bubble defaults plus token overrides.
- No scene-version or action-ID change. Preserve existing saved `duration_mode` values and legacy single-text speech behavior.
## Acceptance
- Message is highlighted while its nearby, non-dimming editor panel is open. The text field stays still when Emoji opens and the panel grows downward; emoji inserts at the caret, and stage selection cannot occur while the panel is open.
- Effects with no token selected apply and preview across every word, punctuation token, and emoji in the selected non-empty bubble. Selected-token effects affect only that token. Old scenes with no bubble default effect remain unchanged.
- Bubble-level and token-level effects survive save, scene reload, queue editing, and playback. A token can suppress an inherited bubble effect with No effect.
- Timing selection updates the existing action-wide duration field, with the established Normal/Slow/Slower behavior. Show controls remain available in the inspector.
- Styling remains attached when text inside a styled word is erased or replaced. Inserted tokens outside an existing styled span inherit the preceding token's explicit style, or the following token's style at the start. Text editor selection never changes the stage style target.
- Draft recovery and the separate Save speech/Cancel semantics remain intact.