# Ink Story Writing Best Practices for Break Escape
## Speaker Tags - Critical for Dialogue Attribution
Every dialogue block in Break Escape Ink stories must include a speaker tag comment. This tells the game engine WHO is speaking so it displays the correct character portrait and name.
### Speaker Tag Format
```ink
=== dialogue_block ===
# speaker:npc
This dialogue comes from the main NPC being talked to
```
### Tag Types
| Tag Format | Usage | Example |
|-----------|-------|---------|
| `# speaker:npc` | Main NPC in single-NPC conversation | `# speaker:npc` |
| `# speaker:player` | Player speaking | `# speaker:player` |
| `# speaker:npc:sprite_id` | Specific character in multi-NPC scene | `# speaker:npc:test_npc_back` |
### Missing Tags? They Default Correctly!
**Important**: If a speaker tag is MISSING, the dialogue automatically attributes to the main NPC. This means:
- **Single-NPC conversations** can omit tags (simpler Ink)
- **Multi-character conversations** MUST include tags to show who's speaking
- **Player dialogue** can be explicitly tagged or inferred
### Examples
#### Single-Character (Tags Optional)
```ink
=== hub ===
I'm here to help you progress.
What can I do for you?
-> hub
```
↑ Both lines default to the main NPC (this.npc.id)
#### Single-Character (Tags Explicit)
```ink
=== hub ===
# speaker:npc
I'm here to help you progress.
# speaker:npc
What can I do for you?
-> hub
```
↑ Same result, but more explicit
#### Multi-Character (Tags Required!)
```ink
=== meeting ===
# speaker:npc:test_npc_back
Hey, meet my colleague from the back office.
# speaker:npc:test_npc_front
Nice to meet you! I manage the backend systems.
# speaker:player
That sounds interesting.
# speaker:npc:test_npc_back
We work great together!
```
↑ Tags MUST be present so the correct portraits appear
### Technical Implementation
The game engine uses these tags to:
1.**Determine which character portrait to show** - Main NPC or secondary character
2.**Set the speaker label** - Shows character name above dialogue
3.**Style the dialogue bubble** - NPC vs Player styling
4.**Track multi-character conversations** - Knows who said what when
**Code location**: `js/minigames/person-chat/person-chat-minigame.js` → `determineSpeaker()` and `createDialogueBlocks()`
**Important**: `*` choice state is NOT persisted between game loads. If a player exits the game and reloads, all `*` choices will be available again. This is simpler than tracking state with variables and is acceptable for most use cases.
Every NPC can track an **influence** variable representing your relationship with them. When influence changes, Break Escape displays visual feedback to the player.
**CRITICAL REQUIREMENT**: You MUST include `#influence_increased` after every `influence +=` statement and `#influence_decreased` after every `influence -=` statement. These tags are required for the game to display visual feedback to players. This applies regardless of the variable name used (e.g., `influence`, `rapport`, `favour`, `trust`, etc.).
**CRITICAL**: You MUST include `#influence_increased` immediately after every `influence +=` statement. Without this tag, the game will not display the visual feedback to the player.
**CRITICAL**: You MUST include `#influence_decreased` immediately after every `influence -=` statement. Without this tag, the game will not display the visual feedback to the player.
- **ALWAYS include influence tags**: Every `influence +=` must be followed by `#influence_increased`, and every `influence -=` must be followed by `#influence_decreased`. This is REQUIRED for the game to display visual feedback to players.
| `#influence_increased` | Shows positive relationship change | Green | **YES** - Must follow every `influence +=` |
| `#influence_decreased` | Shows negative relationship change | Red | **YES** - Must follow every `influence -=` |
**IMPORTANT**: These tags are NOT optional. They must be included wherever you modify influence variables, regardless of variable name (e.g., `influence`, `rapport`, `favour`, `trust`, etc.). Without these tags, players will not see visual feedback when their relationship with NPCs changes.
**Ink does NOT support markdown-style bold formatting.** Using `**text**` will cause the asterisks to appear literally in the output, which looks unprofessional.
❌ **WRONG:**
```ink
Here's a **Lab Sheet Workstation** in this room.
```
✅ **RIGHT:**
```ink
Here's a Lab Sheet Workstation in this room.
```
If you need emphasis, use capitalization, quotes, or descriptive language instead of markdown formatting.
### Do NOT Start Lines with `*` (Except for Choices)
**Lines cannot start with `*` in Ink**, except when it's part of a valid choice syntax (`* [choice text]` or `+ [choice text]`).
❌ **WRONG:**
```ink
**Navigation in normal mode:**
- "h" "j" "k" "l" move cursor
```
✅ **RIGHT:**
```ink
Navigation in normal mode:
- "h" "j" "k" "l" move cursor
```
If you need section headers, use plain text without asterisks.
### Do NOT Ignore "Apparent Loose End" Warnings
**"Apparent loose end" warnings from the Ink compiler are likely syntax errors** and should be investigated, not ignored. These warnings typically indicate:
- Missing knot definitions (referenced but not defined)
- Incorrect choice syntax
- Unclosed conditionals or loops
- Invalid divert targets
- Markdown formatting such as ** at the start of a line.
Always fix these warnings before considering your Ink story complete. They can cause runtime errors or unexpected behavior in the game.
### Avoid Lists in Dialogue (Use Sentences Instead)
**Dialogue is displayed line-by-line to players**, so lists with bullet points create a poor reading experience. Players must click through each list item individually, which feels tedious.
❌ **WRONG:**
```ink
You've shown you can:
- Navigate Linux systems effectively
- Use SSH for remote access
- Perform security testing with tools like Hydra
- Escalate privileges when needed
```
✅ **RIGHT:**
```ink
You've shown you can navigate Linux systems effectively, use SSH for remote access, perform security testing with tools like Hydra, and escalate privileges when needed.
```
**Best Practice:** Convert lists to flowing sentences using commas and "and" for the final item. This creates natural, readable dialogue that players can skip through more easily.
### Keep Exit Conversations Brief
**Exit conversations should be 1-2 lines maximum** before the `#exit_conversation` tag. Players are trying to leave, so don't make them read through multiple paragraphs.
❌ **WRONG:**
```ink
=== end_conversation ===
Whenever you need a refresher on Linux fundamentals, I'm here.
You've demonstrated solid understanding and good security awareness. Keep that mindset.
Now get to that terminal and start practicing. Theory is useful, but hands-on experience is how you actually learn.
See you in the field, Agent.
#exit_conversation
```
✅ **RIGHT:**
```ink
=== end_conversation ===
See you in the field, Agent.
#exit_conversation
```
Or with conditional content:
```ink
=== end_conversation ===
{instructor_rapport >= 40:
You've demonstrated solid understanding. See you in the field, Agent.
- else:
See you in the field, Agent.
}
#exit_conversation
```
**Best Practice:** Keep farewell messages short and to the point. Players appreciate quick exits.
A: Yes! After showing choices, the hub is reached. Use `-> hub` to loop.
**Q: What if I need to end a conversation for story reasons?**
A: Use a choice with dialogue that feels like an ending, then loop back to hub. Or use `#exit_conversation` to close the minigame while keeping state.
**Q: What's the difference between `once` and `sticky`?**
A: `once` shows content only once then hides it. `sticky` shows different content based on conditions. Use `once` for introductions, use `sticky` to change menu text.
**Q: Can I have unlimited options in a hub?**
A: Yes! But for good UX, keep it to 3-5 main options plus "Leave". Use conditionals to show/hide options based on player progress.