Files
IGP-Fan-Reference/docs/Feature Proposals.md
T

228 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Feature Proposals: Glossary & Tech Tree
## Glossary / Mechanics Explainer
### Goal
Provide inline tooltips and a browsable reference for game-specific terms (resources, mechanics, roles, etc.) with automatic cross-linking whenever those terms appear in entity descriptions, notes, or tooltips.
### Data Model
Add a new model under `Model/`:
**`Model/Glossary/GlossaryTermModel.cs`**
```
- Id (string, e.g. "glossary_pyre")
- Term (string, e.g. "Pyre")
- ShortDefinition (string, ~1-2 sentences for tooltips)
- LongDefinition (string, markdown-capable for glossary page)
- Category (string, e.g. "Resource", "Mechanic", "Faction", "Role")
- RelatedTermIds (List<string> — cross-links to other glossary terms)
- RelatedEntityIds (List<string> — entities that exemplify this term)
```
**Term Catalog** — Seed ~2040 terms covering:
- Resources: Alloy, Ether, Pyre, Energy, Supply
- Mechanics: Vanguard, Morph, Pyre Spells, Immortals, Suppression, Overgrowth, Shield
- Roles (from `DescriptiveType.cs`): Frontliner, Skirmisher, Support, Generalist, etc.
- Factions: Aru, Q'Rath, etc.
- Stats: Armor types (Light, Medium, Heavy, Etheric, Structure), Movement types
- RTS concepts: Tier, Tech, Morph, Harass, Timing
### Service Layer
**`Services/Website/GlossaryService.cs`** — implement `IGlossaryService` (add interface to `IServices.cs`):
- `GetTerm(string id) — GlossaryTermModel?`
- `SearchTerms(string query) — List<GlossaryTermModel>`
- `GetTermsByCategory(string category) — List<GlossaryTermModel>`
- `GetAllTerms() — List<GlossaryTermModel>`
- `LinkifyText(string text) — MarkupString` — scans text for known terms and wraps them in tooltip/clickable links
### Component Layer
**`Components/Display/GlossaryTooltipComponent.razor`**
- Wraps a term name with a hover tooltip showing `ShortDefinition`
- On click, opens the glossary detail (either a dialog or navigates to a glossary page)
- Reuses the existing `InfoTooltipComponent` pattern (css hover) but upgraded to be interactive
**`Components/Inputs/GlossaryLabelComponent.razor`**
- Like `EntityLabelComponent` but for glossary terms
- Renders a styled `<button>` or `<span>` with the term name
- On click, opens a `GlossaryDialogComponent` (or navigates to glossary page)
**Auto-linking in entity descriptions:**
- Add a `Linkify()` extension method or service call that processes entity descriptions/flavor text as they're rendered
- Scan for known term names (longest-match-first to avoid partial matches)
- Replace with `<GlossaryLabelComponent>` or `<GlossaryTooltipComponent>` tags
- Apply this in `EntityInfoComponent` where description/flavor text is rendered as `MarkupString`
**Pages:**
**`Web/Pages/Glossary/GlossaryPage.razor`** — route `/glossary`
- Category filter tabs (Resources, Mechanics, Factions, Roles)
- Search bar
- Grid/list of term cards
- Click term to expand or navigate to detail
**`Web/Pages/Glossary/GlossaryDetailPage.razor`** — route `/glossary/{termId}`
- Long definition rendered as markdown
- Related terms as clickable chips
- Related entities listed with `EntityLabelComponent`
**`Web/Dialog/GlossaryDialogComponent.razor`** — modal dialog version
- Reuses the pattern from `EntityDialogComponent`
- Shows term details in a side-panel or overlay
### Integration Points
| Component | Change |
|---|---|
| `EntityInfoComponent.razor` | Pipe description, flavor text, and notes through `GlossaryService.LinkifyText()` |
| `InfoTooltipComponent.razor` | Optionally accept glossary term ID to auto-populate tooltip text |
| `NoteService` / notes rendering | Apply `LinkifyText()` when rendering markdown notes |
| `SearchService` | Index glossary terms so they appear in global search results |
### Glossary Dialog Service
**`Services/Website/GlossaryDialogService.cs`** — implement `IGlossaryDialogService`:
- Mirrors `IEntityDialogService` pattern
- `AddDialog(string termId)`, `CloseDialog()`, `BackDialog()`, etc.
- Renders `GlossaryDialogComponent` alongside `EntityDialogComponent` in the portal
---
## Interactive Tech Tree
### Goal
Visualize entity dependencies as an interactive directed acyclic graph (DAG): production chains (what builds what), upgrade paths (what upgrades what), and requirement gates (what requires what building/research).
### Data Model — Build a Graph
The raw data already exists in the entity parts:
- `EntityProductionModel.ProducedBy` — which building trains/builds this entity
- `EntityRequirementModel.Id` + `RequirementType` — what entity is required (production building, research building, research upgrade, or morph target)
- `EntityIdUpgradeModel.Id` — which tech upgrades apply to this entity
- `EntityVanguardAddedModel.ReplaceId` — immortal replacement relationship
**`Services/Immortal/TechTreeService.cs`** — new service to build the graph:
```
class TechTreeService:
BuildGraph() -> GraphModel:
- Iterate all entities via EntityData.Get()
- For each entity, extract production/requirement/upgrade edges
- Build adjacency list (forward + reverse)
- Build reverse index: "what does this entity unlock?"
class GraphModel:
Nodes: List<NodeModel> (entity ID, name, entity type, faction)
Edges: List<EdgeModel> (source, target, relation type)
```
**`Model/TechTree/`** — new folder:
- `TechTreeGraphModel.cs` — NodeModel, EdgeModel, relation types (Produces, Requires, Upgrades, Replaces)
- `TechTreeEdgeType.cs` — enum: `Produces`, `RequiresProduction`, `RequiresResearch`, `Morph`, `Upgrades`, `VanguardReplaces`
### Service Layer — `TechTreeService`
```
BuildGraph(string? factionFilter = null, string? rootEntityId = null):
- Build full DAG from entity data
- Optionally filter to one faction
- Optionally compute the subgraph reachable from a root entity
GetUpgradePath(string entityId):
- Return the chain of upgrades for a specific unit
GetPrerequisites(string entityId):
- Return all direct requirements as a flat list
GetUnlocks(string entityId):
- Reverse-lookup: what entities does this building/upgrade unlock?
```
### Rendering Approaches
**Option A: SVG via Blazor components (lightweight, no dependencies)**
- Render nodes as positioned `<div>` or `<g>` elements using calculated layout
- Edges as SVG `<path>` or `<line>` elements
- Manual or grid-based layout (less optimal for complex graphs)
- Pros: Zero JS deps, works with Blazor lifecycle
- Cons: Layout algorithm must be custom
**Option B: Dagre + D3.js via JS interop (recommended)**
- Ship Dagre (MIT) for automatic DAG layout (layered, minimal crossing)
- Use D3.js or plain SVG for rendering
- Blazor calls `IJSRuntime.InvokeAsync<GraphLayout>("renderTechTree", graphData)`
- JS interop returns node positions; Blazor re-renders using those positions
- Pros: Mature layout algorithms, zoom/pan, animated
- Cons: JS dependency, async interop complexity
**Option C: vis.js / vis-network**
- Higher-level network visualization library
- JS interop to pass graph data, returns click events
- Pros: Feature-rich, less JS code
- Cons: Heavier dependency
### Component Layer
**`Components/TechTree/TechTreeGraphComponent.razor`** — main renderer:
- Parameter: `GraphModel Graph`
- Parameter: `string? FactionFilter`
- Parameter: `string? HighlightEntityId`
- Render modes: full tech tree, per-faction, per-entity subgraph
**`Components/TechTree/TechTreeNodeComponent.razor`** — individual node:
- Entity name, type icon, tier badge
- Color-coded by entity type (reuse `.army`, `.building`, `.ability` classes)
- Click opens `EntityDialogComponent`
- Hover shows mini tooltip with key stats (cost, HP, DPS)
**`Components/TechTree/TechTreeEdgeComponent.razor`** — SVG edge:
- Styled differently per relation type (solid for produces, dashed for requires, dotted for upgrade)
- Arrowhead at the target
- Hover shows relation type label
**`Web/Pages/TechTree/TechTreePage.razor`** — route `/tech-tree`:
- Faction selector (tabs or dropdown)
- Search box to focus on a specific entity
- Zoom controls (fit, zoom in, zoom out)
- Legend showing edge types and node colors
- Toggle: show all nodes vs. only reachable from selected root
### Layout Algorithm (if going pure Blazor/SVG)
Use a simple layered (Sugiyama-style) layout:
1. Assign all root nodes (no incoming edges) to Layer 0
2. BFS to assign each node to `max(parent layer) + 1`
3. Within each layer, space nodes evenly with tier grouping
4. Render edges between layers as SVG quadratic bezier curves
For a more polished result, integrate Dagre via JS interop — it handles cycle prevention, edge routing, and compact layout automatically.
### Implementation Roadmap
| Step | Scope | Effort |
|---|---|---|
| 1. `TechTreeService.BuildGraph()` | Model + Service | Small |
| 2. Reverse index (`GetUnlocks`) | Service | Small |
| 3. Prototype SVG render (static, grid layout) | Component | Medium |
| 4. Interactive features (zoom, pan, click) | Component | Medium |
| 5. Faction filtering + search highlight | Component | Small |
| 6. Dagre JS interop for auto-layout | JS + Blazor | Medium |
| 7. Node hover tooltip with stats | Component | Small |
| 8. Legend, edge styling, animations | CSS + Component | Small |
### Integration Points
| Service/Component | Change |
|---|---|
| `EntityRequirementModel` | Already sufficient — no changes needed |
| `EntityProductionModel.ProducedBy` | Already sufficient |
| `EntityIdUpgradeModel` | Used to add upgrade edges |
| `EntityLabelComponent` | Reused inside tech tree nodes for consistent look |
| `EntityDialogService` | Opened on node click for detail view |
| `EntityFilterService` | Reuse faction filter logic for tech tree page |
| `NavigationService` | Add `TechTree` section to navigation |