Files
BreakEscape/planning_notes/npc/03_PHONE_UI.md
Z. Cliffe Schreuders 887e5f6443 Add NPC integration planning documents and example scenario
- Created `05_EXAMPLE_SCENARIO.md` with a complete Ink script for the Biometric Breach scenario featuring NPCs Alice and Bob.
- Added `QUICK_REFERENCE.md` as a cheat sheet for NPC system components, event types, and common patterns.
- Introduced `README.md` as an index for NPC integration planning, outlining document structure and key concepts.
2025-10-29 00:18:22 +00:00

17 KiB
Raw Blame History

Phone Chat UI Design

Overview

The Phone Chat UI extends the existing PhoneMessagesMinigame to support interactive NPC conversations with Ink-generated dialogue and choices. It maintains the pixel-art aesthetic while adding conversational features.

UI Architecture

┌─────────────────────────────────────────────────────────────────┐
│                    Phone Chat Minigame                           │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  < Back     CONTACTS                        ⚙️  ×       │   │ Header
│  ├─────────────────────────────────────────────────────────┤   │
│  │  ┌─────────────────────────────────────────────────┐    │   │
│  │  │ 👤 Alice Chen                        🔴 2       │    │   │
│  │  │    Security Analyst                              │    │   │
│  │  ├─────────────────────────────────────────────────┤    │   │
│  │  │ 👤 Bob Martinez                                 │    │   │
│  │  │    IT Administrator                             │    │   │ Contact List
│  │  ├─────────────────────────────────────────────────┤    │   │
│  │  │ 👤 Sarah Kim                                    │    │   │
│  │  │    Lab Technician                               │    │   │
│  │  └─────────────────────────────────────────────────┘    │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘

OR (when viewing conversation):

┌─────────────────────────────────────────────────────────────────┐
│                    Phone Chat Minigame                           │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  < Back     Alice Chen                      ⚙️  ×       │   │ Header
│  ├─────────────────────────────────────────────────────────┤   │
│  │  ╔═══════════════════════════════════════════════════╗  │   │
│  │  ║ Hey! Security breach detected.            2:15 AM ║  │   │ NPC Message
│  │  ╚═══════════════════════════════════════════════════╝  │   │
│  │                                                          │   │
│  │         ┌─────────────────────────────────────┐         │   │
│  │         │ I'll investigate right away         │ 2:16 AM │   │ Player Message
│  │         └─────────────────────────────────────┘         │   │
│  │                                                          │   │
│  │  ╔═══════════════════════════════════════════════════╗  │   │
│  │  ║ Great! Check reception first.            2:16 AM ║  │   │ NPC Message
│  │  ╚═══════════════════════════════════════════════════╝  │   │
│  │                                                          │   │ Message
│  │  [What should I look for?]                              │   │ Thread
│  │  [Can you help me access the lab?]                      │   │
│  │  [I need to go]                                         │   │ Choice Buttons
│  │                                                          │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘

Component Breakdown

1. Phone Container

Class: .phone-chat-minigame-container

  • Inherits from .phone-messages-container (existing)
  • Sized similarly to existing phone minigame (400px wide)
  • Pixel-art border with clip-path
  • Modal overlay (semi-transparent background)

2. Phone Header

Class: .phone-chat-header

Elements:

  • Back button (returns to contact list)
  • Title (Contact name or "CONTACTS")
  • Settings icon (voice, notifications)
  • Close button (X)

States:

  • Contact List View: "CONTACTS"
  • Conversation View: "{NPC Name}"

3. Contact List View

Class: .phone-chat-contacts

Each contact entry shows:

  • Avatar (pixel-art portrait, 64x64)
  • Name (bold, 14pt)
  • Role/subtitle (italic, 10pt)
  • Unread badge (red circle with count)
  • Last message preview (truncated, 10pt gray)
  • Timestamp (right-aligned, 8pt gray)

Styling:

.phone-chat-contact {
  display: flex;
  align-items: center;
  padding: 10px;
  border-bottom: 2px solid #000;
  cursor: pointer;
  background: #e0e0e0;
}

.phone-chat-contact:hover {
  background: #d0d0d0;
}

.phone-chat-contact.has-unread {
  background: #fff3cd; /* Slight yellow tint */
}

.phone-chat-contact-avatar {
  width: 64px;
  height: 64px;
  image-rendering: pixelated;
  border: 2px solid #000;
  margin-right: 10px;
}

.phone-chat-contact-info {
  flex: 1;
}

.phone-chat-contact-name {
  font-size: 14pt;
  font-weight: bold;
  color: #000;
}

.phone-chat-contact-role {
  font-size: 10pt;
  font-style: italic;
  color: #666;
}

.phone-chat-contact-preview {
  font-size: 10pt;
  color: #999;
  margin-top: 5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.phone-chat-unread-badge {
  width: 24px;
  height: 24px;
  background: #ff0000;
  color: #fff;
  border: 2px solid #000;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10pt;
  font-weight: bold;
}

4. Conversation View

Class: .phone-chat-conversation

Message Thread:

  • Scrollable container
  • Messages stack vertically
  • NPC messages left-aligned
  • Player messages right-aligned
  • Timestamps next to each message
  • Auto-scroll to bottom on new message

Message Styling:

.phone-chat-message {
  display: flex;
  margin: 10px;
  animation: message-appear 0.3s ease-out;
}

@keyframes message-appear {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* NPC messages (left-aligned) */
.phone-chat-message.npc {
  justify-content: flex-start;
}

.phone-chat-message.npc .message-bubble {
  background: #e0e0e0;
  color: #000;
  border: 2px solid #000;
  padding: 10px;
  max-width: 70%;
  position: relative;
}

/* Speech bubble tail (left side) */
.phone-chat-message.npc .message-bubble::before {
  content: '';
  position: absolute;
  left: -10px;
  top: 10px;
  width: 0;
  height: 0;
  border-top: 8px solid transparent;
  border-bottom: 8px solid transparent;
  border-right: 10px solid #000;
}

.phone-chat-message.npc .message-bubble::after {
  content: '';
  position: absolute;
  left: -7px;
  top: 11px;
  width: 0;
  height: 0;
  border-top: 7px solid transparent;
  border-bottom: 7px solid transparent;
  border-right: 9px solid #e0e0e0;
}

/* Player messages (right-aligned) */
.phone-chat-message.player {
  justify-content: flex-end;
}

.phone-chat-message.player .message-bubble {
  background: #a0d0ff;
  color: #000;
  border: 2px solid #000;
  padding: 10px;
  max-width: 70%;
  position: relative;
}

/* Speech bubble tail (right side) */
.phone-chat-message.player .message-bubble::before {
  content: '';
  position: absolute;
  right: -10px;
  top: 10px;
  width: 0;
  height: 0;
  border-top: 8px solid transparent;
  border-bottom: 8px solid transparent;
  border-left: 10px solid #000;
}

.phone-chat-message.player .message-bubble::after {
  content: '';
  position: absolute;
  right: -7px;
  top: 11px;
  width: 0;
  height: 0;
  border-top: 7px solid transparent;
  border-bottom: 7px solid transparent;
  border-left: 9px solid #a0d0ff;
}

.phone-chat-message-timestamp {
  font-size: 8pt;
  color: #666;
  align-self: flex-end;
  margin: 0 5px;
}

5. Choice Buttons

Class: .phone-chat-choices

  • Appear at bottom of conversation
  • Each choice is a button with full width
  • Stacked vertically
  • Clear visual separation from messages
.phone-chat-choices {
  padding: 10px;
  border-top: 2px solid #000;
  background: #f5f5f5;
}

.phone-chat-choice-button {
  width: 100%;
  padding: 12px;
  margin-bottom: 8px;
  background: #fff;
  color: #000;
  border: 2px solid #000;
  cursor: pointer;
  font-family: 'VT323', monospace;
  font-size: 14pt;
  text-align: left;
  position: relative;
}

.phone-chat-choice-button:hover {
  background: #e0e0e0;
  transform: translate(-2px, -2px);
  box-shadow: 2px 2px 0 #000;
}

.phone-chat-choice-button:active {
  transform: translate(0, 0);
  box-shadow: none;
}

.phone-chat-choice-button::before {
  content: '▶ ';
  color: #666;
}

6. Typing Indicator

Class: .phone-chat-typing

Shows when NPC is "typing" (delay before message appears):

.phone-chat-typing {
  display: flex;
  align-items: center;
  margin: 10px;
  padding: 10px;
  background: #e0e0e0;
  border: 2px solid #000;
  width: fit-content;
}

.phone-chat-typing-dots {
  display: flex;
  gap: 4px;
}

.phone-chat-typing-dot {
  width: 8px;
  height: 8px;
  background: #666;
  animation: typing-bounce 1.4s infinite ease-in-out;
}

.phone-chat-typing-dot:nth-child(1) {
  animation-delay: -0.32s;
}

.phone-chat-typing-dot:nth-child(2) {
  animation-delay: -0.16s;
}

@keyframes typing-bounce {
  0%, 80%, 100% {
    transform: scale(0);
  }
  40% {
    transform: scale(1);
  }
}

Bark Notification System

Separate from phone chat - appears during gameplay.

Bark Popup

Class: .npc-bark-notification

  • Small popup in corner of screen
  • Shows NPC avatar, name, and message preview
  • Clickable to open full phone chat
  • Auto-dismisses after 5 seconds (configurable)
  • Queue system for multiple barks

Position: Bottom-right corner, above inventory

.npc-bark-notification {
  position: fixed;
  bottom: 120px;
  right: 20px;
  width: 320px;
  background: #fff;
  border: 2px solid #000;
  box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.3);
  padding: 12px;
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  animation: bark-slide-in 0.3s ease-out;
  z-index: 9999;
}

@keyframes bark-slide-in {
  from {
    transform: translateX(400px);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

.npc-bark-notification:hover {
  background: #f0f0f0;
  transform: translateY(-2px);
  box-shadow: 4px 6px 0 rgba(0, 0, 0, 0.3);
}

.npc-bark-avatar {
  width: 48px;
  height: 48px;
  image-rendering: pixelated;
  border: 2px solid #000;
}

.npc-bark-content {
  flex: 1;
}

.npc-bark-name {
  font-size: 12pt;
  font-weight: bold;
  color: #000;
  margin-bottom: 4px;
}

.npc-bark-message {
  font-size: 10pt;
  color: #333;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.npc-bark-close {
  width: 20px;
  height: 20px;
  background: #ff0000;
  color: #fff;
  border: 2px solid #000;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 12pt;
  font-weight: bold;
}

.npc-bark-close:hover {
  background: #cc0000;
}

Bark Queue Stacking

When multiple barks arrive, stack them vertically:

.npc-bark-notification:nth-child(2) {
  bottom: 240px; /* 120 + 120 */
}

.npc-bark-notification:nth-child(3) {
  bottom: 360px; /* 120 + 120 + 120 */
}

/* Max 3 barks shown at once */
.npc-bark-notification:nth-child(n+4) {
  display: none;
}

Phone Access Button

New UI Element: Floating button to access player's phone

.phone-access-button {
  position: fixed;
  bottom: 20px;
  right: 20px;
  width: 64px;
  height: 64px;
  background: #5fcf69; /* Game Boy green */
  border: 2px solid #000;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3);
  z-index: 9998;
}

.phone-access-button:hover {
  background: #4fb759;
  transform: translate(-2px, -2px);
  box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.3);
}

.phone-access-button-icon {
  width: 40px;
  height: 40px;
  image-rendering: pixelated;
}

.phone-access-button-badge {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 24px;
  height: 24px;
  background: #ff0000;
  color: #fff;
  border: 2px solid #000;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10pt;
  font-weight: bold;
}

Interaction Flow

Opening Phone Chat

  1. Via Bark Notification:

    • Player clicks bark popup
    • Phone opens directly to that NPC's conversation
    • Bark dismissed
  2. Via Phone Button:

    • Player clicks phone button (bottom-right)
    • Phone opens to contact list
    • Unread badges visible
  3. Via In-World Phone:

    • Player interacts with phone object in room
    • Phone opens to contact list or specific message

Navigating Conversations

  1. Contact List → Conversation:

    • Click contact
    • Conversation loads with history
    • Unread messages marked as read
    • Badge cleared
  2. Conversation → Contact List:

    • Click "< Back" button
    • Returns to contact list
    • Conversation state saved
  3. Making Choices:

    • Click choice button
    • Player's message appears in thread
    • NPC "typing" indicator shows
    • NPC response appears after delay
    • New choices presented (if any)

Closing Phone Chat

  • Click X button (top-right)
  • Press ESC key
  • Click outside modal (if enabled)
  • Game resumes

Responsive Behavior

Phone Always on Top

  • Z-index: 10000 (higher than other UI)
  • Pauses game when open
  • Blurs background slightly

Mobile Considerations (Future)

  • Full-screen on small displays
  • Touch-friendly button sizes
  • Swipe gestures for navigation

Accessibility

  • Keyboard Navigation:

    • Tab through choices
    • Enter to select
    • ESC to close
  • Screen Readers:

    • ARIA labels on all interactive elements
    • Message thread readable in order
  • Visual Clarity:

    • High contrast text
    • Clear focus indicators
    • Minimum 12pt font size

Data Structure

Contact Object

{
  id: 'alice',
  name: 'Alice Chen',
  role: 'Security Analyst',
  phone: '555-0123',
  avatar: 'assets/npc/avatars/npc_alice.png',
  inkStory: InkStory, // ink-js story instance
  currentKnot: 'alice_hub',
  unreadCount: 2,
  lastMessageTime: 1234567890,
  lastMessagePreview: 'Check reception first.',
  messages: [/* message history */]
}

Message Object

{
  id: 'msg_001',
  sender: 'npc', // or 'player'
  text: 'Hey! Security breach detected.',
  timestamp: 1234567890,
  read: true,
  isChoice: false // true if this was a player choice selection
}

Conversation State

{
  npcId: 'alice',
  history: [/* message objects */],
  inkState: '{ ... }', // serialized Ink state JSON
  currentChoices: [
    { index: 0, text: 'What should I look for?' },
    { index: 1, text: 'Can you help me?' }
  ],
  lastUpdateTime: 1234567890
}

Animation Timings

  • Message Appear: 0.3s ease-out
  • Typing Indicator: 1-3s before message
  • Choice Button Hover: 0.1s
  • Bark Slide In: 0.3s ease-out
  • Bark Auto-Dismiss: 5s delay

Next Steps

See 04_IMPLEMENTATION.md for the step-by-step coding plan to build this system.