6 agents × 2 rounds examining 9 content layers. Produced D-032 through D-039, THE FRIEND NPC pattern, converged tag taxonomy, and Sova Transit District setting. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
42 KiB
Round 2: Gestalt (Systems Design) - Synthesis
Workshop: v0.1 Content Gap Analysis Date: 2026-02-11 Scope: Mechanical convergence across all Round 1 outputs + Jeroen's Round 2 directives
0. Directives Acknowledged
Before I get into synthesis, let me confirm the constraints from Jeroen's Round 2 direction. These are locked. No further debate:
| Directive | Status | Mechanical Implication |
|---|---|---|
| Separate monologue pools per character | Confirmed, non-negotiable | Two parallel content trees. character is a hard partition tag, not a filter. |
| Color = relationship to player | Approved | Entity color is a client-side derivation from RelationshipState component + knowledge state. Not an NPC property. |
| Audio included in v0.1 | Confirmed | 6-8 AI-generated files. Sound event system architecture must support this. Visual fallback for everything beyond those files. |
| One NPC per character = THE FRIEND | Confirmed | Two production-level NPCs. Full pipeline depth test. All systems exercised on these two. |
| Wiki structure for taxonomy | Non-negotiable | Miri handling. Tag taxonomy I define here must integrate with wiki structure. |
| Line pool format (YAML) | Needs validation | Mellanie and Paula must sign off. That's what this section does. |
1. Converged Line Pool Format
Let me break down what this actually means mechanically. Three people proposed tag schemas in Round 1. Let me reconcile them.
Schema Comparison
| Tag | Gestalt R1 | Mellanie R1 | Paula R1 (implied) | Converged |
|---|---|---|---|---|
id |
{template}_{type}_{###} |
{template}-{role}-{situation}-{##} |
Not specified | Keep Gestalt format — machine-parseable, stable |
text |
string | string | string | Keep |
role / speaker |
role (enum per template) |
speaker (enum per template) |
Implied by NPC profile | role — the template role, not the NPC name. NPC assignment is runtime. |
character |
N/A (on monologue only) | character (smuggler/detective/any) |
Implied | character — but ONLY on monologue lines. Dialogue lines are character-agnostic; the access tier handles filtering. |
access |
list<enum> | single enum | Per-line, hard filter | list<enum> — a line can be eligible for multiple access tiers |
trust |
enum (surface/real/secret) | enum (same) | Three disclosure tiers, progressive | Aligned. No change. |
situation |
list<enum> | list<enum> | Relationship history + context | list<enum> — see converged situation taxonomy below |
topic |
list<enum> | single enum | Mood + topic for Layer 4 | list<enum> — lines can cover multiple topics |
mood |
list<enum> | single enum | Mood for weighted selection | list<enum> |
location |
N/A (implicit from file) | enum | N/A | Drop from line-level. Location is implicit from the file's directory. Adding it per-line is redundant and an error source. |
type |
N/A (implicit from file) | type (dialogue/monologue/env/ticker) |
N/A | Drop from line-level. Content type is implicit from file name (dialogue.yaml vs monologue.yaml). |
tags |
list<string> freeform | N/A | N/A | Keep — escape hatch for author intent that doesn't fit taxonomy |
dual_lens |
map (per-character notes) | N/A | Critical for authoring | Keep — authoring-only, not consumed by engine |
notes |
string | N/A | N/A | Keep — authoring-only |
trigger |
On monologue only | N/A | N/A | Keep for monologue — the observation event that fires the line |
prerequisite |
On monologue only | N/A | N/A | Keep for monologue — knowledge state gate |
Converged Tag Taxonomy — FINAL (pending Mellanie/Paula sign-off)
Structural tags (required on every dialogue line):
| Tag | Type | Values | Maps to D-028 Layer |
|---|---|---|---|
id |
string | {template}_{d|m|e}_{###} |
N/A (indexing) |
text |
string | The authored line | N/A (content) |
role |
enum | Template-defined roles | N/A (speaker assignment) |
access |
list<enum> | public, insider, authority, peer, hostile |
Layer 1 (hard filter) |
trust |
enum | surface, real, secret |
Layer 3 (hard filter) |
situation |
list<enum> | See taxonomy below | Layer 2 (context filter) |
Selection tags (recommended, fallback to defaults if empty):
| Tag | Type | Values | Maps to D-028 Layer | Default |
|---|---|---|---|---|
topic |
list<enum> | See taxonomy below | Layer 4 (weighted selection) | [general] |
mood |
list<enum> | See taxonomy below | Layer 4 (weighted selection) | [neutral] |
tags |
list<string> | Freeform | N/A (author use) | [] |
Authoring-only tags (not consumed by engine):
| Tag | Type | Purpose |
|---|---|---|
dual_lens |
map | Per-character interpretation notes |
notes |
string | Author intent, dependencies, context |
Monologue-specific tags (in addition to above):
| Tag | Type | Values | Purpose |
|---|---|---|---|
character |
enum | smuggler, detective |
Hard partition. Separate pools per Jeroen's directive. |
trigger |
enum | See trigger taxonomy below | Observation event that fires this line |
prerequisite |
map or null | Knowledge state conditions | Gate: line only eligible if character knows X |
Alignment with Paula's Four Layers
This is the critical validation. Does the converged schema express all four D-028 layers?
| D-028 Layer | How It's Expressed | Tag(s) | Filter Type |
|---|---|---|---|
| Layer 1: Access tier | access tag on every line. Engine checks player character's current access tier at the NPC's social site. |
access |
Hard filter. Line invisible if access doesn't match. |
| Layer 2: Relationship history | situation tag + engine-tracked interaction state. Engine maintains per-NPC counters (interaction_count, last_interaction_time, notable_events). These counters activate/deactivate situation eligibility. first_meeting is true once. repeated_visit activates after 3+ visits. greeted_before is tracked by engine, not tagged per-line. |
situation + engine state |
Context filter. Narrows eligible pool based on relationship progression. |
| Layer 3: Trust-gated gossip | trust tag on every line. Engine tracks trust progression per NPC (starts at surface, can reach real/secret through repeated positive interactions). |
trust |
Hard filter. Line invisible if current trust level is below line's trust tier. |
| Layer 4: Unprompted disclosure | topic + mood tags. Engine selects from eligible lines (post-Layer 1/2/3 filtering) weighted by match between NPC's current mood state and line's mood tag, and between NPC's current concern topics and line's topic tag. |
topic + mood + engine state |
Weighted selection. Soft ranking, not hard filter. Neutral mood always available as fallback. |
Verdict: The converged schema fully expresses all four layers. Layers 1 and 3 are hard filters (binary tag match). Layer 2 is engine-state-to-situation mapping. Layer 4 is weighted selection across two tag dimensions.
Paula's concern about greeted_before:true — this is NOT a per-line tag. It's engine state. The engine tracks whether these characters have met before and activates the first_meeting or repeated_visit situation accordingly. The content author doesn't tag individual lines with interaction history — they tag situations, and the engine decides which situations are active.
Key Changes from My Round 1 Proposal
- Dropped
locationfrom line-level tags — location is directory-level. This removes a redundancy Mellanie flagged. - Dropped
typefrom line-level tags — content type is file-level. This reduces Mellanie's 8 tags to 6 structural + 2 selection = 8 total, but 2 fewer per-line. - Added
characteras monologue-only hard partition — confirms Jeroen's directive mechanically. - Clarified that
accessis list, not single — a line can be eligible for bothinsiderandpeer. - Made
topicandmoodlist types — a line can cover multiple topics and be appropriate for multiple moods.
Situation Taxonomy v0.1 (Converged)
Merged from my Round 1 list + Mellanie's proposal:
| Situation | Description | Activation |
|---|---|---|
greeting |
First interaction this game-day | Engine: no interaction logged today |
first_meeting |
Characters have never interacted | Engine: interaction_count == 0 |
routine |
Normal daily activity | Engine: NPC in scheduled routine state |
morning / afternoon / evening / night |
Day phase (D-031) | Engine: current SimulationTime phase |
repeated_visit |
Player has visited this NPC 3+ times | Engine: interaction_count >= 3 |
interrogation |
Player is asking pointed questions | Engine: dialogue topic escalation detected |
witnessed_secret |
Player has observed something they shouldn't | Engine: KnowledgeInventory contains secret-tagged fact about this NPC |
idle |
NPC is between scheduled activities | Engine: NPC routine state = idle |
working |
NPC is performing job routine | Engine: NPC routine state = job |
social |
NPC is in social activity (bar, break) | Engine: NPC routine state = social |
confrontation |
Triangle tension has escalated | Engine: triangle pressure threshold exceeded |
post_event |
Responding to a recent simulation event | Engine: event log contains recent entry for this NPC |
absence_noticed |
An expected NPC is missing | Engine: NPC not in expected location during expected time |
13 situations for v0.1. Mellanie's gossip and observed_anomaly situations are covered by social + topic filtering and post_event respectively. I'm not adding them as separate situations because they're better expressed as topic + mood combinations.
Topic Taxonomy v0.1
| Topic | Description |
|---|---|
work |
Job-related: tasks, schedules, complaints |
social |
Relationships, personal life, family |
cargo |
Freight, manifests, shipments — setting-specific |
money |
Finances, costs, spending |
rumors |
Gossip, hearsay, speculation |
identity |
Who someone is, where they're from, what they do |
deflection |
Avoiding a topic, changing subject |
complaint |
Grievances, frustrations |
general |
Weather, food, neutral small talk |
9 topics for v0.1. Mellanie's crime topic is deliberately excluded — NPCs don't think of what they do as "crime." It's cargo or money from their perspective. The dual-lens interpretation is what makes those topics crime-adjacent for the detective.
Mood Taxonomy v0.1
| Mood | Description |
|---|---|
neutral |
Default state. Calm, unremarkable. |
happy |
Positive, upbeat, satisfied |
tired |
Low energy, going through motions |
annoyed |
Irritated, short-tempered |
nervous |
Anxious, fidgety, checking surroundings |
defensive |
Guarded, deflecting, walls up |
friendly |
Warm, open, welcoming |
cautious |
Careful, measuring words |
8 moods for v0.1. Mellanie's tense, relaxed, and suspicious map to nervous, happy/neutral, and cautious respectively. I'm consolidating to prevent near-duplicate moods that make authoring harder without adding selection granularity.
Monologue Trigger Taxonomy v0.1
Unchanged from Round 1. 9 triggers:
| Trigger | Description |
|---|---|
enter_location |
Player enters a new area |
observe_npc |
Player sees NPC doing something notable |
hear_sound |
Sound event from fog edge |
observe_anomaly |
NPC deviates from known routine |
post_conversation |
After dialogue ends |
discover_evidence |
Player examines an informational object |
witness_interaction |
Player sees two NPCs interacting |
time_idle |
Player hasn't acted for a while |
return_visit |
Player returns to a previously visited area |
2. Mellanie's Tag Proposal vs. Mine — Convergence
Mellanie proposed 8 tags. I proposed a more granular set. Here's where we landed:
| Mellanie's Tag | My Tag | Resolution |
|---|---|---|
character |
character (monologue only) |
Aligned. Monologue-only, hard partition. Not on dialogue lines. |
access |
access |
Aligned. I upgraded to list<enum>; she had single. List is correct. |
trust |
trust |
Aligned. Identical. |
location |
(directory-level) | Dropped from per-line. Directory structure handles this. Mellanie agreed provisional format is fine. |
situation |
situation |
Aligned. Her values are a subset of mine. Using the full 13-situation taxonomy. |
mood |
mood |
Aligned. Consolidated to 8 moods. |
topic |
topic |
Aligned. Expanded to 9 topics. |
type |
(file-level) | Dropped from per-line. File naming convention handles this. |
Net result: 6 per-line structural tags + 3 per-line selection/freeform tags = 9 tags per dialogue line. For monologue lines: +3 monologue-specific tags = 12 tags per monologue line.
Mellanie's "tag smoke test" request is smart. Before she writes 165 lines for the workplace, she writes 20, tags them, and I validate the filtering behavior. This should happen as the first line previewer test case.
3. THE FRIEND: Production-Level NPC Specification
Okay, let me map this to mechanics. Jeroen says THE FRIEND is a production-level complex NPC — one per character, full pipeline depth test. Ozzie defined the emotional design in Round 1. Let me define what "production-level" means for the ECS and content pipeline.
What "Production-Level" Means Mechanically
THE FRIEND exercises every system we're building. It's the NPC that proves the pipeline works end-to-end:
| System | What THE FRIEND Tests | Minimum Requirement |
|---|---|---|
| 10-axis model (D-024) | All 10 axes populated with meaningful values that change during play | Axes must shift in response to simulation events |
| Access tiers (D-028 L1) | THE FRIEND has different access tiers per character | Smuggler: insider+peer. Detective: varies (starts public, can reach peer) |
| Relationship history (D-028 L2) | Interaction count tracked, situation progression works | first_meeting -> greeting -> repeated_visit must trigger different lines |
| Trust progression (D-028 L3) | Trust level advances through positive interactions | Surface -> Real progression visible in dialogue depth change |
| Unprompted disclosure (D-028 L4) | THE FRIEND volunteers information when mood + topic align | At least 3 unprompted lines that fire based on NPC mood state |
| Tell system | Observable behavioral markers for internal state | All 5 tell categories must be demonstrable on THE FRIEND |
| Routine system | Predictable daily schedule with deviations | Morning/afternoon/evening locations defined. At least 1 deviation event |
| Triangle membership | Belongs to at least 1 triangle | Triangle pressure must affect THE FRIEND's behavior observably |
| Contradiction arc (Ozzie) | Discoverable through observation, not dialogue | The contradiction must emerge from routine deviation + tell, then be confirmed/complicated by dialogue |
| Monologue integration | Player character comments on THE FRIEND specifically | Named monologue lines referencing THE FRIEND's behavior, not generic role observations |
| Dual-lens divergence | Same NPC, fundamentally different relationship per character | THE FRIEND is a different person emotionally to the smuggler vs. detective |
THE FRIEND: ECS Component Profile
Each FRIEND NPC needs these components at minimum:
Entity: THE_FRIEND_smuggler / THE_FRIEND_detective
Components:
- NpcIdentity { name, role, home_template, reference_templates[] }
- Want { current_want, intensity, blocked_by }
- Secret { content, known_by[], exposure_risk }
- Relationships[3] { target_entity, valence, trust_level, interaction_count, last_interaction }
- ToleranceThreshold { current_value, max_value, triggers[] }
- DailyRoutine { schedule: Map<DayPhase, Location>, deviations[] }
- InformationInventory { known_facts[], rumors[], secrets_held[] }
- Contentment { value, trend, causes[] }
- PersonalityTraits { trait_a, trait_b, trait_c }
- TellState { active_tells: Map<TellCategory, Intensity> }
- SkillSet { skills[], combat_trained: bool }
- AccessTierMap { Map<Entity, AccessTier> } // per-observer access
- TriangleMembership { triangle_ids[], role_in_triangle: Map<TriangleId, Role> }
- MoodState { current_mood, trend, causes[] }
THE FRIEND: Content Requirements
Per FRIEND NPC, Mellanie needs to author:
| Content Type | Volume | Notes |
|---|---|---|
| Dialogue lines (all access tiers) | 25-35 lines | Must cover public, insider, peer, hostile. More lines than any other NPC. |
| Trust-gated dialogue (surface/real/secret) | 15-20 lines | Including at least 3 secret-tier lines that reveal the contradiction |
| Unprompted disclosure lines | 5-8 lines | Mood-triggered, topic-relevant. THE FRIEND initiates conversation. |
| Monologue lines (smuggler reacting to FRIEND) | 10-15 lines | Named references. "There goes Kael." Not "That dock worker." |
| Monologue lines (detective reacting to FRIEND) | 10-15 lines | Different framing. Analytical, not personal. |
| Tell observation monologue | 5-8 lines per character | "Kael's tapping his foot again." / "Subject displays stress indicators." |
| Contradiction discovery monologue | 3-5 lines per character | The moment the player realizes THE FRIEND isn't what they seemed |
Total per FRIEND: ~70-100 authored lines (including both character perspectives). This is roughly half the content budget of an entire template's dialogue pool — for one NPC. That's the cost of production-level. It's worth it because this NPC carries D-027 success criterion #3.
THE FRIEND: Mapping to Paula's NPCs
Looking at Paula's Round 1 relationship web:
| Character | THE FRIEND candidate | Why |
|---|---|---|
| Smuggler | NPC-B (Logistics Worker 1 / Kael Davan) | Smuggler's closest colleague. Ring member. Works together daily. Trust + shared risk = deepest pre-existing bond. Contradiction: Kael is reliable to the smuggler, but is cracking under pressure / making mistakes / possibly considering turning. |
| Detective | NPC-D (Dock Inspector) or NPC-G (Security Officer) | The detective needs a contact who becomes a relationship. NPC-D has the gambling debt (exploitable, sympathetic). NPC-G has institutional proximity (a peer the detective trusts professionally). Recommendation: NPC-D — the gambling debt creates the contradiction (seems corrupt, might just be desperate) and connects to Triangle B (Card Game Debt). |
Paula should confirm these assignments in her Round 2. The FRIEND NPCs are the first profiles she should write at Tier 1 depth.
4. Missing Tickets for Systems/Mechanical Work
I've cross-referenced all Round 1 outputs against the existing ticket pool. Here are the systems tickets that should exist but don't (or need upgrading):
New Tickets Needed
| Title | Type | Priority | Rationale | Depends On |
|---|---|---|---|---|
| Dialogue selection pipeline implementation | Feature | Critical | The 4-layer filtering engine: access -> situation -> trust -> weighted(mood, topic). This is the core runtime system that makes content playable. Nothing in the existing tickets covers the actual selection algorithm. | Line pool format (this document), NPC component architecture |
| Monologue trigger system | Feature | Critical | Engine component that fires monologue events based on observation triggers (enter_location, observe_npc, etc.). Must select from character-specific pool, apply prerequisite gates, track variety (no repeats). | Perception system (#124), Character knowledge state |
| NPC mood state machine | Feature | High | NPCs need a mood component that changes based on simulation events (triangle pressure, time of day, recent interactions). Mood drives Layer 4 selection + tell system. | 10-axis NPC components |
| Trust progression system | Feature | High | Engine tracks trust level per player-NPC pair. Progresses through surface -> real -> secret based on interaction quality and frequency. Must be observable (player can sense trust improving). | Relationship tracking, dialogue system |
| Interaction tracking component | Feature | High | Per-NPC-pair counter: interaction_count, last_interaction_time, notable_events log. Drives Layer 2 situation activation. | NPC component architecture |
| Tell state derivation system | Feature | Medium | System that reads NPC axis values (Secret + Tolerance = nervous, Contentment low = frustrated, etc.) and outputs observable tell states consumed by monologue trigger system. | 10-axis NPC components, monologue trigger system |
| Sound event system architecture | Feature | High | Event emitter for sound occurrences. Emits typed events (footsteps, voices, machinery, alarm) with position, intensity, and range. Client renders as audio file OR visual indicator + monologue, depending on available assets. | Perception system (#124) |
| YAML content loader | Feature | High | Rust system that parses content YAML files into indexed, queryable line pools at startup. Must support hot-reload for previewer/authoring workflow. | Line pool format (this document) |
| Line variety tracker | Feature | Medium | Prevents the same line from firing repeatedly. Tracks recently-used line IDs per NPC per session. Selects from eligible pool excluding recent history. | Dialogue selection pipeline |
| Knowledge state component | Feature | High | Per-character component tracking known facts, tagged by source, confidence, and emotional weight. Gates monologue prerequisites and informs situation activation. Paula's KnowledgeInventory proposal. |
NPC component architecture |
| Observation event generator | Feature | Critical | System that detects observable NPC behaviors (routine deviation, interaction between NPCs, absence from expected location) and generates events consumed by monologue trigger system. This is the bridge between simulation and player perception. | NPC routine system, perception system |
| Tag taxonomy wiki page | Documentation | High | The converged taxonomy from this document, formatted for the wiki structure Miri is building. Reference document for all content authors. | This document, Miri's wiki structure |
| THE FRIEND: Smuggler's NPC profile | Story | Critical | Full Tier 1 profile for the smuggler's FRIEND (NPC-B / Kael Davan). All 10 axes, voice paragraph, triangle positions, contradiction arc. | Dual Lens Guide (#261) |
| THE FRIEND: Detective's NPC profile | Story | Critical | Full Tier 1 profile for the detective's FRIEND (NPC-D / Dock Inspector). Same depth. | Dual Lens Guide (#261) |
Existing Tickets That Need Scope Updates
| Ticket | Current Scope | Needed Addition |
|---|---|---|
| #90 (Tell system) | Unclear | Scope to 5 tell categories (nervous, angry, friendly, guarded, routine deviation). Text-via-monologue as v0.1 renderer, not visual animation. |
| #124 (Sound system) | Unclear | Must include sound event emitter architecture supporting both audio playback AND visual indicator fallback. See Section 6 below. |
| #193 (Line previewer) | "Authoring tool" | Concrete MVP scope defined. See Section 7 below. |
| #168 (Tag taxonomy) | "Agreement needed" | This document IS the agreement. Ticket should be updated to reference this converged taxonomy. |
5. How Mechanical Systems Support Content Needs
Let me map every content need from Round 1 to a mechanical system. This is the crosswalk that ensures nothing falls through the cracks.
Content Need -> System Mapping
| Content Need (from Round 1) | Required System | Status | Gap? |
|---|---|---|---|
| Dialogue lines filtered by access tier | Dialogue selection pipeline (Layer 1) | Not built | YES - needs ticket |
| Dialogue changes based on relationship history | Interaction tracking + situation activation (Layer 2) | Not built | YES - needs ticket |
| Trust-gated disclosure | Trust progression system (Layer 3) | Not built | YES - needs ticket |
| NPCs volunteer information based on mood | NPC mood state machine + weighted selection (Layer 4) | Not built | YES - needs ticket |
| Monologue fires on observation events | Observation event generator + monologue trigger system | Not built | YES - needs ticket |
| Separate monologue per character | Character-partitioned content pools | Not built | Covered by YAML loader + character tag |
| Tells observable through monologue | Tell state derivation + monologue integration | Not built | YES - needs ticket |
| NPC routine creates observable patterns | NPC routine system (D-024 Daily routine axis) | Partially ticketed | Needs scope for deviations and absence detection |
| Dual-lens interpretation of same event | Per-character monologue pools + knowledge prerequisites | Not built | Covered by monologue trigger system + prerequisite field |
| Mirror moments on replay | Same trigger, different character pool | Architectural | Covered by design — separate pools keyed to same triggers |
| Flat NPCs don't feel flat | Routine system + 1 memorable trait + role voice pool | Not built | Personality trait modifier in dialogue selection |
| THE FRIEND contradiction arc | Triangle pressure + tell escalation + routine deviation | Not built | Composition of several systems (triangle, tell, routine) |
| Environmental text readable in world | Environmental text rendering in Godot client | Not built | Needs client-side ticket |
| News ticker / Meridian feed | Ticker content system + time-based rotation | Not built | Needs ticket for both content + rendering |
| Audio atmosphere (6-8 files) | Sound event system + audio playback | Not built | YES - see Section 6 |
| Diegetic tutorial via monologue | Opening hook monologue + trigger on first-time events | Not built | Covered by monologue trigger system + first_meeting / first-visit gates |
Summary: 17 content needs, 0 fully built, 12 need new tickets, 5 covered by existing ticket scope updates.
The critical path for systems is:
NPC Component Architecture (10 axes)
|
+-> NPC Routine System
| |
| +-> Observation Event Generator
| |
| +-> Monologue Trigger System
|
+-> NPC Mood State Machine
| |
| +-> Tell State Derivation
|
+-> Interaction Tracking
| |
| +-> Trust Progression
|
+-> YAML Content Loader
|
+-> Dialogue Selection Pipeline (4 layers)
|
+-> Line Variety Tracker
Everything fans out from the NPC component architecture. That's Sprint 1 server work. The YAML loader and dialogue pipeline can be developed in parallel once the component schema is stable.
6. Audio Event System: Minimal Architecture
Jeroen confirmed audio in v0.1: 6-8 AI-generated files. Ozzie's minimum viable list from Round 1:
- Station ambient loop (1 file)
- Location variants: workplace, bar, corridors (3 files)
- Footsteps — walk/run (2 files)
- Monologue appearance chime (1 file)
- (Optional) UI interaction sound (1 file)
That's 7-8 files. Here's the minimal architecture that supports them while remaining extensible:
Sound Event System Architecture
[Simulation Server]
SoundEventEmitter
- emits: SoundEvent { type, position, intensity, range_category }
- types: Footstep, Voice, Machinery, Alert, Ambient
- range_category: Close, Medium, Long (D-018)
|
v
[ObserverSnapshot]
sound_events: Vec<SoundEvent> // only events within perception range
|
v
[Godot Client]
SoundRenderer
- receives SoundEvents from snapshot
- looks up audio asset for event type
- if asset exists: play audio (with distance attenuation + stereo panning)
- if asset missing: render visual indicator + fire monologue trigger
|
+-> AudioAssetRegistry
| Maps SoundEvent.type -> audio file path (or null)
| v0.1 registry:
| Footstep -> footstep_walk.ogg, footstep_run.ogg
| Ambient(workplace) -> ambient_workplace.ogg
| Ambient(bar) -> ambient_bar.ogg
| Ambient(corridor) -> ambient_corridor.ogg
| Alert(monologue) -> monologue_chime.ogg
| * -> null (visual fallback)
|
+-> VisualSoundIndicator
| Renders fog-edge ripple/pulse for events without audio
| Color-coded per Araminta's spec:
| neutral (#c8d0e0), voices (#e8c547), danger (#d45d5d)
|
+-> AmbientManager
Manages location-based ambient loops
Crossfades between ambient tracks on location transition
The span gate hum (Miri's suggestion) is the base layer
Key Design Principles
-
Events first, assets second. The simulation always emits sound events. The client decides how to render them. Zero audio files = everything renders as visual + monologue. 8 files = partial audio with visual fallback for the rest. Full audio suite = rich soundscape. The architecture doesn't change.
-
The ambient manager is separate from event-driven sounds. Ambient loops play continuously based on location. Sound events are discrete occurrences (footsteps, voices, alerts). These are two different subsystems that share the audio output.
-
Monologue chime is a UI sound, not a simulation sound. It's triggered by the client when monologue text appears, not by the simulation. It doesn't go through the SoundEvent system.
-
Distance attenuation is simple for v0.1. Close range = full volume. Medium range = 50% volume + slight muffle. Long range = no direct audio (insert notification only). Three tiers, not continuous falloff.
What This Requires from Implementation
- Server side:
SoundEventEmittersystem that checks entity actions each tick and emits typed events. Perception filter includes events within hearing range inObserverSnapshot.sound_events. - Client side:
SoundRenderernode in Godot that processes snapshot sound events.AudioAssetRegistryas a simple dictionary.VisualSoundIndicatorfor fog-edge rendering.AmbientManagerfor location loops. - Asset pipeline: 7-8 .ogg files, generated or sourced. Integrated into Godot project's audio resources.
This is a small architecture for a large capability surface. It handles v0.1's 8 files and scales to hundreds without structural changes.
7. Line Previewer (#193): Concrete MVP Scope
The line previewer was flagged by me, Mellanie, and Ozzie in Round 1 as critical. Let me scope the MVP concretely.
What the Previewer Does
The previewer answers one question: "Given this NPC state and this player state, what line fires?"
It's the authoring equivalent of a compiler — it tells the content author whether their tags produce the intended behavior before the line is integrated into the game.
MVP Feature Set
| Feature | Description | Priority |
|---|---|---|
| Load YAML | Parse a content YAML file (dialogue or monologue) into indexed pool | Must have |
| Set filter context | CLI arguments or interactive prompts for: access tier, trust level, active situations, NPC mood, topic filter, character (for monologue) | Must have |
| Show matching lines | Display all lines that pass the 4-layer filter with the given context | Must have |
| Show selected line | Apply weighted selection to show which single line would fire | Must have |
| Explain selection | Show WHY each line was included/excluded (which filter passed/failed) | Must have |
| Sequence mode | Play N lines in order simulating a walk-through (Ozzie's "preview sequence" request) | Should have |
| Coverage report | Show which access/trust/situation combinations have zero eligible lines (dead conversation detection) | Should have |
| Hot reload | Watch YAML file for changes, re-run filter on save | Nice to have |
| Batch validation | Run all YAML files through a consistency checker (missing required tags, invalid enum values, duplicate IDs) | Should have |
Implementation
Language: Rust. The previewer should use the same YAML parser and selection logic that the game server will use. This means the previewer IS a test harness for the dialogue pipeline — if the previewer selects correctly, the game will select correctly.
Interface: CLI. No GUI needed. Terminal output with color-coded pass/fail on filters.
# Show what the detective hears from a dock_worker at insider access, surface trust,
# morning routine, neutral mood
$ cargo run --bin previewer -- \
--file content/templates/logistics-hub/dialogue.yaml \
--role dock_worker \
--access authority \
--trust surface \
--situation greeting,morning,routine \
--mood neutral \
--verbose
[PASS] access=authority [PASS] trust=surface [PASS] situation=greeting
-> lh_d_002: "You're new around here? Or just... visiting?"
topic=[social, identity] mood=[cautious, neutral] weight=0.85
[PASS] access=authority [PASS] trust=surface [FAIL] situation=first_meeting (requires interaction_count==0)
-> lh_d_005: "Morning. Can I help you with something?"
(excluded: situation mismatch)
Selected: lh_d_002 (weight: 0.85, variety_penalty: 0.0)
Sequence Mode (Ozzie's Request)
$ cargo run --bin previewer -- \
--file content/templates/bar/monologue.yaml \
--character smuggler \
--sequence enter_bar \
--mood neutral
[Sequence: enter_bar — smuggler]
1. (enter_location) "The Last Shift. Lera's already got my usual poured."
2. (observe_npc) "Kael's at the corner booth. He looks rough tonight."
3. (observe_npc) "Drin's telling the same story again. Third time this week."
4. (time_idle) "Should probably check in with Kael. He doesn't usually drink alone."
This gives Mellanie and Ozzie a way to "feel" the content flow without running the full game. It's the emotional smoke test.
Effort Estimate
The previewer shares 80% of its code with the dialogue pipeline implementation. Building it first means the pipeline is already tested when it's integrated into the server. The unique work is the CLI interface, the verbose explain mode, and the sequence playback — maybe 2-3 days of Dudley/Tyre's time on top of the pipeline work they'd do anyway.
Recommendation: Build the previewer AS the first implementation of the dialogue pipeline. Don't build them separately. The previewer is the pipeline running in standalone mode with verbose output.
8. Cross-Agent Synthesis: Convergence Map
Here's where every Round 1 contributor's proposals landed after synthesis:
Fully Aligned (no further discussion needed)
| Topic | Status | Contributors Aligned |
|---|---|---|
| Separate monologue pools per character | Locked (Jeroen directive) | All |
| Color = relationship to player | Locked (Jeroen directive) | Araminta (proposed), Gestalt (endorsed) |
| YAML as authoring format | Aligned | Gestalt (proposed), Mellanie (accepted with conditions) |
| 5 tell categories for v0.1 | Aligned | Gestalt (proposed), Araminta (visual notes), Ozzie (emotional validation) |
| Diegetic tutorial via monologue | Aligned | Gestalt (mechanical), Mellanie (content), Paula (narrative) |
| 30/50/20 entanglement ratio | Aligned (D-029 confirmed) | All |
| Monologue is v0.1 tell renderer | Aligned | Gestalt, Araminta, Mellanie |
Converged in This Document
| Topic | Resolution | Key Decision |
|---|---|---|
| Tag taxonomy | Converged 8-tag system (6 structural + 2 selection + freeform) | See Section 1 |
| Situation taxonomy | 13 situations from Gestalt + Mellanie merge | See Section 1 |
| Access tier model | list<enum> with 5 values | Gestalt's model, Paula's content, aligned |
| Line pool file structure | Directory = template/location, file = content type | Dropped per-line location and type tags |
| THE FRIEND mechanical spec | Full pipeline depth test with ~70-100 authored lines per NPC | See Section 3 |
| Audio architecture | Event-driven with asset registry + visual fallback | See Section 6 |
| Line previewer MVP | Rust CLI sharing pipeline code, 7 must-have features | See Section 7 |
Needs Round 2 Confirmation from Others
| Topic | Who Needs to Confirm | What I Need |
|---|---|---|
| Converged tag taxonomy | Mellanie | Can you author with 6+3 tags per line? Is the mood/topic consolidation workable? |
| Converged tag taxonomy | Paula | Does the Layer 2 approach (engine-state-to-situation mapping, not per-line relationship tags) satisfy your 4-layer requirements? |
| THE FRIEND NPC assignments | Paula | Confirm NPC-B (Kael) for smuggler, NPC-D for detective. Or propose alternatives. |
| Miri's setting tags | Miri | Your proposed lattice_tier, shift_phase, district_familiarity, institutional_context — these should be engine-state context, not per-line tags. The engine knows the player is a newcomer; it activates first_meeting situations. Do you agree? |
| Spatial layout timing | Araminta | Your spatial layouts are needed before or in parallel with content packs. Confirmed? Can they be done independently of content? |
| Audio asset creation | Ozzie | 7-8 AI-generated files. Who generates them? What's the quality bar? Do we need a ticket for audio asset generation? |
9. Emergent Interactions: Where Systems Collide
This is my favorite part. Let me map the places where independently designed systems will interact to produce emergent gameplay — the stuff nobody scripted.
Interaction Map
| System A | System B | Emergent Result |
|---|---|---|
| NPC Routine + Observation Events | Player sees NPC in unexpected place at unexpected time | Monologue fires: "That's not where they usually go." Player decides to follow or ignore. Neither designer planned the specific moment. |
| Trust Progression + Triangle Pressure | NPC's trust in player increases while triangle pressure increases | NPC discloses something they shouldn't under pressure. The disclosure is selected by the dialogue pipeline combining high trust + high stress mood. Not scripted — emergent from system state. |
| Access Tier Shift + Monologue Dual-Lens | Player's access tier changes at a social site (e.g., detective becomes a bar regular) | New dialogue lines become available AND the monologue reflects the shift ("They're starting to warm up to me"). The player FEELS the social change through two channels simultaneously. |
| Sound Events + Fog of Perception + Monologue | Player hears voices through a wall they can't see past | Sound event at fog edge -> visual indicator -> monologue interprets ("Sounds like an argument. Can't make out the words.") Player decides to move closer or not. The three systems produce a decision point. |
| THE FRIEND Contradiction + Tell System + Monologue | THE FRIEND's tell state escalates (nervous) while their dialogue stays friendly | The player gets conflicting signals: dialogue says "everything's fine," monologue says "they keep checking the door." The player must decide which signal to trust. Asymmetric information within a single NPC. |
| NPC Mood + Time Phase + Unprompted Disclosure | An NPC's mood worsens over the course of a day; by evening at the bar, they're drunk and frustrated | Layer 4 selects from mood: [annoyed, tired] + trust: real pool. The NPC says something they wouldn't have said that morning. Time + mood + alcohol = emergent information leak. |
This is why systems-first design works. None of these moments are scripted events. They're collisions between independently designed systems operating on shared state. The content authors write the individual lines; the systems decide when and how those lines combine. The result is stories the designers didn't anticipate.
10. Open Questions for Round 3 / Sprint Planning
| Question | Owner | Context |
|---|---|---|
| Does the 4x generation expansion apply to THE FRIEND's custom lines? Or are all 70-100 hand-authored? | Mellanie + Gestalt | Generation expansion on high-specificity NPC lines risks losing the hand-crafted voice. Recommend: no expansion on FRIEND lines. Every line hand-authored. |
| Who creates the 7-8 audio files? | Ozzie + Justine | AI-generated is confirmed, but the pipeline needs defining. Which AI tool? What format? Who evaluates quality? |
| Should the line previewer be a sprint deliverable or a tooling side-project? | Tyre + Dudley | I recommend sprint deliverable — it's the dialogue pipeline in standalone mode. Building it IS building the pipeline. |
| How does the knowledge prerequisite system handle "partial knowledge"? | Gestalt + Paula | A monologue line gated on knows: smuggling_operation — does the player need to know the full operation, or just that something suspicious is happening? Need a knowledge hierarchy: suspects < knows_of < knows_details. |
| Triangle pressure threshold — what triggers escalation? | Gestalt + Paula | Triangles need a numeric pressure value that increases based on events. When it crosses a threshold, confrontation situation activates. Need to define the events that increase pressure. |
Gestalt out. The taxonomy is converged. The FRIEND is specified. The audio architecture is minimal and extensible. The previewer is scoped. Now we need Mellanie and Paula to validate the tag schema, and Dudley to start building the NPC component architecture. The systems are ready to support the content. Let's build.