- Added support for voice messages prefixed with "voice:" in Ink files. - Updated UI rendering to display voice message UI with play button and transcript. - Implemented automatic conversion for scenario JSON with voice properties. - Created test examples for pure voice messages and mixed content. - Fixed issues with NPC registration and message duplication in test scenarios. - Documented feature details, use cases, and testing procedures.
9.6 KiB
Voice Messages in Phone Chat
Overview
The phone-chat minigame now supports voice messages alongside regular text messages. When a message starts with voice:, it's automatically rendered with a voice message UI instead of a simple text bubble.
Quick Start
In Ink Files
Simply prefix any message with voice::
=== start ===
voice: Hi, this is the IT Team. Security breach detected in server room. Changed access code to 4829.
-> END
In Scenario JSON (Auto-Conversion)
The runtime converter automatically adds voice: prefix for phone objects with voice property:
{
"type": "phone",
"name": "IT Alert",
"phoneId": "player_phone",
"voice": "Security breach detected in server room. Changed access code to 4829.",
"sender": "IT Team"
}
Result: Automatically converted to voice message UI! ✅
Result
Instead of a text bubble, the player sees:
- 🎵 Audio waveform visualization
- ▶️ Play button (decorative)
- 📄 Transcript section with the message text
How It Works
Detection
The addMessage() method in phone-chat-ui.js checks if text starts with "voice:":
const isVoiceMessage = trimmedText.toLowerCase().startsWith('voice:');
Rendering
Voice messages get this HTML structure:
<div class="message-bubble npc">
<div class="voice-message-display">
<div class="audio-controls">
<div class="play-button">
<img src="assets/icons/play.png" alt="Audio" class="icon">
</div>
<img src="assets/mini-games/audio.png" alt="Audio" class="audio-sprite">
</div>
<div class="transcript">
<strong>Transcript:</strong><br>
Message text here
</div>
</div>
<div class="message-time">2:18</div>
</div>
Regular messages get standard text bubble:
<div class="message-bubble npc">
<div class="message-text">Message text here</div>
<div class="message-time">2:18</div>
</div>
Ink Compatibility
Is "voice:" Compatible with Ink?
YES! ✅ It's just text content.
- Ink treats
voice: ...as plain text content - No special Ink syntax required
- Works in any knot, stitch, or branch
- Compatible with choices, conditionals, etc.
Example 1: Simple Voice Message
=== start ===
voice: This is a voice message from security.
-> END
Example 2: Mixed Content
=== start ===
Hello! This is a regular text message.
+ [Tell me more]
-> voice_response
=== voice_response ===
voice: Here's a voice message with sensitive information. The code is 4829.
+ [Got it!]
Great, talk soon!
-> END
Example 3: Multiple Voice Messages
=== start ===
voice: First voice message here.
+ [Continue]
voice: Second voice message follows the first.
+ + [Understood]
Perfect! All done.
-> END
Use Cases
1. Security Alerts
voice: Security alert: Unauthorized access detected in server room at 02:15 AM.
✅ Makes alerts feel more urgent and official
2. Voicemail Messages
voice: Hey, it's the director. I need you to investigate the breach ASAP. Call me when you find something.
✅ Realistic voicemail experience
3. Sensitive Information
voice: The access code is 5-9-2-3. I repeat: five, nine, two, three. Memorize this.
✅ Important codes feel more secure
4. Emotional Moments
voice: I'm scared... I think someone is following me. Please come quickly.
✅ Voice adds emotional weight
5. Technical Instructions
voice: Navigate to the server room, enter PIN 4829, then disable the firewall using the admin console.
✅ Step-by-step instructions feel clearer
Runtime Conversion
Automatic Voice Detection
The PhoneMessageConverter automatically adds voice: prefix when converting simple messages:
// In phone-message-converter.js
static toInkJSON(phoneObject) {
let messageText = phoneObject.voice || phoneObject.text || '';
// Add "voice: " prefix if this is a voice message
if (phoneObject.voice) {
messageText = `voice: ${messageText}`;
}
// Create Ink JSON with prefixed text...
}
Scenario Integration
Old scenario format:
{
"type": "phone",
"voice": "This is a voicemail",
"sender": "Director"
}
Automatically becomes:
voice: This is a voicemail
Which renders as: Voice Message UI 🎤
Text vs Voice
phoneObject.voice→ Rendered as voice messagephoneObject.text→ Rendered as regular text bubble
// Voice message UI
{"type": "phone", "voice": "Urgent alert!", "sender": "Security"}
// Regular text bubble
{"type": "phone", "text": "Just checking in", "sender": "Alice"}
Styling
CSS Classes
Voice messages use existing CSS from css/phone.css:
.voice-message-display- Container with flex column layout.audio-controls- Play button + waveform sprite.audio-sprite- Pixelated audio waveform image.play-button- Decorative play icon.transcript- Text content with bordered box
Customization
All voice messages use:
- Pixel-art aesthetic (
image-rendering: pixelated) - 2px borders (no rounded corners)
- VT323 monospace font
- Hover effect on audio controls (scale 1.5x)
Testing
Test Page
Open test-phone-chat-minigame.html:
- Click "Register Test NPCs"
- Click "📱 Open Phone"
- Look for "IT Team" contact
- Click to open voice message
Expected Behavior
- Contact list shows "IT Team"
- Opening shows voice message UI (play button + waveform)
- Transcript displays below audio controls
- Timestamp shows in bottom-right
Test NPCs
- IT Team: Pure voice message (single message)
- David - Tech Support: Mixed text + voice messages (interactive)
Advantages
1. Visual Variety
Mix text and voice messages for more engaging conversations:
- Regular messages → casual chat
- Voice messages → important/urgent content
2. Game Design Flexibility
Different message types convey different meanings:
- Text = typed message (casual)
- Voice = recorded audio (formal/urgent)
3. Realism
Real phones have both SMS and voice messages, making the game feel more authentic.
4. Zero Configuration
No special setup needed:
- Works with existing Ink files
- No new assets required
- Backward compatible (old files still work)
Limitations
Current Implementation
- No actual audio playback: The play button is decorative
- Static visualization: Audio waveform doesn't animate
- No recording: Players can't send voice messages back
Future Enhancements
Could add:
- Real audio file playback
- Animated waveforms during "playback"
- Player voice message responses (choice branches)
- Audio file attachment support
Best Practices
When to Use Voice Messages
✅ DO use voice for:
- Security alerts/warnings
- Voicemail from NPCs
- Urgent/time-sensitive information
- Emotional/dramatic moments
- Important codes/instructions
- Messages from authority figures
❌ DON'T use voice for:
- Every message (loses impact)
- Long paragraphs (hard to read in transcript)
- Back-and-forth conversations (feels unnatural)
- Player responses (currently not supported)
Writing Style
Voice messages should sound spoken:
// ✅ Good (natural speech)
voice: Hey, it's me. Just wanted to let you know the meeting's at 3.
// ❌ Bad (too formal/written)
voice: This is a message to inform you that the scheduled meeting will commence at 15:00 hours.
Keep them concise:
// ✅ Good (clear and brief)
voice: Code changed to 4829.
// ❌ Bad (too long)
voice: I wanted to reach out to you to inform you that the security access code has been modified and the new code that you should use from now on is 4829.
Implementation Details
Code Location
- Detection & Rendering:
js/minigames/phone-chat/phone-chat-ui.js(lines 277-350) - CSS Styling:
css/phone.css(lines 311-370) - Assets:
assets/icons/play.png(play button icon)assets/mini-games/audio.png(waveform sprite)
How Messages Flow
- Ink story outputs text:
"voice: Message here" phone-chat-minigame.jscallsui.addMessage('npc', text)phone-chat-ui.jsdetects"voice:"prefix- Renders voice UI instead of text bubble
- Transcript = text after
"voice:"prefix
Backward Compatibility
- Old Ink files without
"voice:"render as regular text - No breaking changes to existing scenarios
- Works with runtime conversion (simple messages)
- Compatible with timed messages
Examples
Example 1: Emergency Alert
=== start ===
voice: Emergency alert! Fire detected on floor 3. Evacuate immediately via stairwell B.
-> END
Example 2: Clue Drop
=== investigation ===
I found something interesting...
+ [What is it?]
voice: I can't type this. The password is "BlueFalcon2024". Delete this message after reading.
-> END
Example 3: Story Progression
=== chapter_end ===
Good work today!
+ [Thanks!]
voice: By the way, the director wants to see you tomorrow at 9 AM. Don't be late.
+ + [Got it]
See you then!
-> END
Summary
Question: How do I add voice messages to NPC conversations?
Answer: Just prefix the text with voice: in your Ink file!
voice: Your message here
Result:
- ✅ Automatic voice message UI
- ✅ Play button + waveform visualization
- ✅ Transcript display
- ✅ Works in any Ink story
- ✅ Mix with regular text messages
It just works! 🎤
Document Version: 1.0
Date: 2025-10-30
Status: Implemented & Tested