Wiki, Tutorial, Event, And Dialog Design¶
Purpose¶
This document captures the planned direction for an in-game wiki/help system and its relationship to tutorials, player-facing encounters, dialogs, and the journal.
The core decision is to separate human-facing content from gameplay structure:
- Content files own prose, headings, images, and links.
- Structural encounter/event files own triggers, queueing, time behavior, choices, conditions, outcomes, and persistence.
This keeps writing and translation practical while preserving explicit runtime ownership for gameplay mutation.
Goals¶
The system should support:
- In-game wiki/help pages authored as Markdown.
- Reusing the same Markdown content for the website through Zensical.
- Contextual help mode where the cursor becomes a
?and clicked UI/world targets open a relevant wiki page. - Tutorial encounters that can reuse wiki article content instead of requiring a separate tutorial-only framework.
- A journal that records tutorials, discoveries, decisions, warnings, and objective notes.
- Later scenario encounters and dialogs with choices, conditions, consequences, and multi-step progression.
- Future localization by keeping most translatable text in content files rather than mixing it deeply into gameplay data.
Non-Goals For The First Version¶
The first version should not become:
- A full quest engine.
- A general scripting language.
- A dedicated tutorial system separate from events.
- A branching RPG conversation framework with deep NPC memory.
- A cutscene or camera-choreography system.
- A localization pipeline.
- A complex authoring UI.
- A way to mutate gameplay directly from Markdown metadata.
Content Layer¶
Markdown content should live under a dedicated docs subfolder, for example:
docs/wiki/
index.md
tutorial/
first-steps.md
gameplay/
travel.md
inspect.md
time.md
gathering.md
water.md
rest.md
hunting.md
survival/
fatigue.md
hydration.md
nutrition.md
world/
terrain.md
tracks.md
knowledge-map.md
The exact folder structure can evolve because file paths are only discovery locations. Runtime references use article IDs, not paths.
Content ID Resolution¶
The canonical article ID is the id in Markdown frontmatter:
The content registry scans the configured wiki roots, reads article frontmatter, and builds an ID-to-file registry:
Encounter definitions, journal entries, and UI help targets reference gameplay.travel.
Markdown prose links use normal CommonMark file links so the same files work in
Obsidian and Zensical:
At import time, the content registry resolves those file links relative to the
source article, reads the target article frontmatter ID, and rewrites the
runtime body link to the target article ID. The in-game panel therefore opens
gameplay.travel, while the authored Markdown remains a valid file link.
This means travel.md can later move to
docs/wiki/actions/movement/travel.md without changing saved event state,
journal entries, or UI data-wiki-id attributes, as long as the frontmatter ID
stays gameplay.travel and authored Markdown links are updated to the new file
path.
If an article has no frontmatter ID, the registry may derive a temporary ID from the relative path for development, but that derived ID should not be used by events, save state, or stable UI targets. Referenced articles need explicit frontmatter IDs.
Duplicate IDs are invalid and should fail the registry build/load with a clear error.
Markdown Format¶
Wiki pages must use CommonMark links because Zensical expects normal Markdown link syntax:
Obsidian-style links such as [[Travel]] should not be the canonical authoring
format for these pages. Runtime-ID links such as [Travel](gameplay.travel) are
also not valid authored wiki links because they are dead links for Obsidian and
Zensical. The registry resolves file links to runtime IDs during import.
Article Metadata¶
Article frontmatter should stay focused on presentation and indexing:
---
id: tutorial.first_steps
title: Read the Land
summary: Learn the basic survival loop.
cover: tutorial/read-the-land.png
category: tutorial
tags: [travel, inspect, time]
related: [gameplay.travel, gameplay.inspect]
---
# Read the Land
Survival depends on where you move, what you know, and how much time you spend.
Use **PF** to preview travel before committing.
Good article metadata:
idtitlesummarycovercategorytagsrelatedsortOrder
Avoid article metadata for:
- event triggers
- inventory mutation
- condition changes
- activity starts or stops
- stat checks
- random outcome tables
- quest progression
- scenario-state mutation
Rule of thumb: if changing it affects gameplay behavior, save compatibility, or state transitions, it belongs in structural data, not content metadata.
Structure Layer¶
Structural files describe runtime behavior and reference content IDs. They can use JSON or YAML. YAML may be more author-friendly, while JSON remains useful as the normalized runtime/interchange shape. These files create player-facing encounters or journal notices; Markdown files remain presentation-neutral prose.
Example article-backed tutorial event:
id: tutorial.first_steps
contentId: tutorial.first_steps
trigger:
type: gameplay_started
once: true
presentation:
surface: encounter
level: blocking
mode: article
time:
mode: pause
journal:
addOnClose: true
The event definition owns when and how the content appears. The Markdown article owns what the player reads.
Do not use Markdown frontmatter tags to make an article become an encounter. The same Markdown article can appear in the Wiki side dock, a Journal entry, or a blocking Encounter. The structural definition chooses the surface:
surface: encounter: center-screen focused panel for blocking tutorials, dialogs, and decisions.surface: journal: non-blocking journal/feed/status presentation.surface: silent: no direct UI beyond state or journal outcomes.
For compatibility, missing surface defaults from level: blocking means
encounter, notice means journal, and silent means silent.
Player-facing UI and docs should use Encounter for authored blocking/tutorial/dialog
definitions. Internal code can keep eventRuntime, eventDebug* DOM IDs, storage
keys, and assets/data/events/ paths short-term for compatibility; those names
are legacy implementation details, not the player-facing concept.
Content validation failures must be visible on the title screen during startup
and map load. Broken wiki links, missing encounter contentId references, and
duplicate map-local event IDs are authoring errors; the default-map loader should
not hide them by falling back to another candidate or to placeholder textures.
RD > Encounters > Debug can expose the same validation as a read-only in-game
health check, including article and encounter counts plus the latest validation
details.
Encounter definitions may include semantic UI highlight requests under
presentation.uiHighlights. These should use stable target IDs such as
hud.inspect or hud.activity.pathfinding, not DOM IDs. A UI owner maps those
semantic IDs to elements and applies color, thickness, and pulse presentation
while the encounter is active.
Event And Tutorial Model¶
Tutorials should use the same event system as scenario events. There is no clear benefit to maintaining a separate tutorial framework.
The first tutorial can be a simple article-backed blocking event:
- Gameplay starts.
- Event runtime queues
tutorial.first_stepsif it has not been seen. - Encounter panel opens
contentId: tutorial.first_stepsin the center of the screen. - Time pauses while the tutorial is open.
- Closing the article marks the event as seen.
- A journal entry is added if configured.
- Previous game speed is restored.
This proves wiki content, event triggering, queueing, time behavior, journal integration, and persistence without building the richer choice/dialog system immediately.
Encounter Presentation Levels¶
Events should support different interruption strengths:
blocking: opens a modal or focused panel and usually pauses or changes game speed.notice: adds a lightweight notice and journal entry without opening a blocking modal.silent: updates journal/state without interrupting the player.
Example:
Low-priority discoveries should generally become journal entries rather than blocking dialogs.
Time Behavior¶
Time behavior should be configured per event rather than hardcoded globally.
Supported modes should include:
pause: set game speed to0xwhile open, then restore the previous speed.keep: leave current game speed unchanged.setSpeed: set a configured speed while open, then restore the previous speed.
Example:
The default for blocking tutorial and dialog events should likely be pause.
Queueing¶
The event runtime should be queue-based:
- Triggered blocking events enter a queue.
- If no event is active, the highest-priority queued blocking event opens.
- Only one blocking event is active at a time.
- Notices and silent events do not block the queue.
- Closing the active event advances to the next eligible queued event.
The queue should prevent tutorial, discovery, warning, and scenario events from competing for the same UI surface.
Journal¶
The journal should exist from the start because tutorials, discoveries, scenario notes, and later objectives need a persistent player-facing memory.
Initial journal entry shape:
{
"id": "journal_001",
"sourceEventId": "tutorial.first_steps",
"contentId": "tutorial.first_steps",
"timeTick": 120,
"category": "Tutorial",
"tags": ["tutorial", "travel", "inspect"]
}
The journal can render the referenced content article or a shorter journal summary later. The first version can keep entries simple:
- list entries
- open referenced article/content
- record time/category/tags
- persist entries
Potential categories:
TutorialDiscoveryDecisionObjectiveWarning
Wiki Help Mode¶
A dedicated help mode should allow contextual lookup:
- Player toggles Wiki/Help mode.
- Cursor changes to
?. - Next click asks the clicked target for a wiki/content ID.
- If a target exists, open the wiki panel at that article.
- If no specific target exists, fall back to a contextual or general article.
DOM UI can expose IDs directly:
<button data-wiki-id="gameplay.travel">PF</button>
<button data-wiki-id="gameplay.inspect">Inspect</button>
<button data-wiki-id="survival.fatigue">Fatigue</button>
Terrain and world targets can be added later through map-space hit testing or context sampling:
UI targets are the easiest first slice because they can use data-wiki-id
without adding terrain hit-test complexity.
Richer Events And Dialogs¶
Article-backed events are enough for tutorials and simple messages, but richer scenario events need structural choices and outcomes.
Example hybrid event:
id: tracks.fresh_wolf_sign
contentId: discoveries.fresh_wolf_sign
trigger:
type: trail_discovered
minStrength: 0.7
presentation:
surface: encounter
level: blocking
mode: dialog
time:
mode: pause
choices:
- id: mark
labelKey: choices.mark_it
consequenceVisibility: exact
outcomes:
- type: journal/add
contentId: discoveries.fresh_wolf_sign
- type: map/addMarker
markerType: tracks
- id: follow
labelKey: choices.follow_it
consequenceVisibility: hinted
requires:
activityAvailable: hunting
command:
type: core/activity/startHunting
- id: ignore
labelKey: choices.ignore
consequenceVisibility: hidden
close: true
This keeps prose in content while event structure handles gameplay logic.
Multi-Step Dialog Planning¶
The first implementation can ship with one article or one node, but the model should not block multi-step dialogs later.
A later node-based event can look like:
id: tutorial.basic_loop
startNode: intro
nodes:
intro:
contentId: tutorial.first_steps
choices:
- id: continue
next: travel
- id: skip
close: true
travel:
contentId: gameplay.travel
choices:
- id: continue
next: inspect
inspect:
contentId: gameplay.inspect
choices:
- id: finish
outcomes:
- type: journal/add
contentId: tutorial.first_steps
close: true
The first runtime can normalize article-only events into a one-node internal shape so later dialog support is an extension instead of a rewrite.
Consequence Visibility¶
Choice consequences should support different clarity levels:
exact: show precise mechanical effects, such as cost or reward.hinted: describe likely cost or risk without exact numbers.hidden: show no explicit mechanical preview.knowledgeBased: reveal exact or improved information only if the player has enough knowledge, technique, or confidence.
This supports a mix of transparent tutorials, uncertain survival decisions, and knowledge-gated expert readings.
Runtime Ownership¶
Suggested owner modules:
contentRegistry: loads and resolves content IDs to Markdown articles and metadata.wikiRuntime: owns reference article browsing, navigation history, and article opening.wikiPanelRuntime: renders the supported Markdown subset into the side-docked Wiki.wikiModeRuntime: owns?mode and click-to-wiki target resolution.eventRuntime: owns triggers, queue, active event state, node progression, presentation requests, and event persistence. Player-facing blocking output is now called an Encounter to avoid confusion with the technicalEventBus.encounterPanelRuntime: renders active blocking encounters in the center focus panel with choices, Escape handling, and focus trap.journalRuntime: owns journal entries, snapshots, and persistence.
The existing technical event bus remains only for post-change notifications and invalidation. It should not become the scenario event or dialog command system.
Mutation Guardrail¶
The event/dialog runtime should not directly mutate unrelated gameplay domains.
Good:
Good:
Bad:
Bad:
Gameplay mutation should stay with explicit commands and runtime owners.
Data Locations¶
Support both global and map-local event definitions:
Global definitions should cover reusable tutorials and generic survival events. Map-local definitions should cover scenario-specific events, objectives, and story beats.
For content, keep the canonical Markdown under docs/wiki/ so Zensical and the
game can use the same source. If the game cannot load from docs/ in packaged
Tauri builds, the build/package step can copy the selected wiki subset into the
runtime asset output while preserving content IDs.
Persistence¶
Persisting event and journal state early is useful because tutorials and events quickly become broken if seen/dismissed state is lost.
Persist:
- seen/dismissed event IDs
- current active event and node if saved mid-event
- queued blocking events if needed
- journal entries
- important choice history
- event-local flags/cooldowns for repeatable events
Avoid mixing mutable player progress into authored content files. A future savegame layer is the cleaner long-term destination. Until then, use a clearly mutable runtime sidecar or save payload rather than editing article files.
Potential temporary sidecar:
Localization Direction¶
The content/structure split supports translation because structural IDs remain stable while content resolves through the active language.
Possible future layout:
or:
The structural event still references the same content ID:
The active language decides which Markdown file satisfies that ID.
Choice labels can later move to localization keys:
First Implementation Slice¶
A practical first slice:
- Add
docs/wiki/article convention and a small first set of pages. - Add a content registry that can resolve article IDs and metadata.
- Add a wiki panel that renders a safe CommonMark subset.
- Add a journal runtime and minimal journal panel/list.
- Add
data-wiki-idto key gameplay HUD controls. - Add
?wiki mode for DOM UI targets. - Add an event runtime with article-backed blocking encounters, queueing, pause behavior, seen-state, and journal-on-close.
- Add
tutorial.first_stepsas the first authored tutorial event.
Suggested first pages:
docs/wiki/tutorial/first-steps.md
docs/wiki/gameplay/travel.md
docs/wiki/gameplay/inspect.md
docs/wiki/gameplay/time.md
The first tutorial should be short and link outward to deeper wiki articles rather than trying to explain every system in a modal.
Open Questions¶
- Should the game load Markdown directly from
docs/wiki/, or should packaging copy/build the wiki subset intoassets/wiki/? - Should
docs/wiki/index.mdbe a generated index or manually authored? - Should journal entries render full articles, article summaries, or dedicated journal snippets?
- Should notices use a toast UI immediately, or only appear in the journal for the first version?
- Should map-local event files be allowed to override global event IDs, or only add new IDs?
- Should a blocking article close button always mark the event seen, or should events be able to require an explicit final action?